rafcode 1.2.0 → 2.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.md +118 -22
- package/RAF/aaaabt-verbose-chronicle/decisions.md +25 -0
- package/RAF/aaaabt-verbose-chronicle/input.md +3 -0
- package/RAF/aaaabt-verbose-chronicle/outcomes/01-amend-iteration-references.md +25 -0
- package/RAF/aaaabt-verbose-chronicle/outcomes/02-verbose-task-name-display.md +31 -0
- package/RAF/aaaabt-verbose-chronicle/outcomes/03-verbose-streaming-fix.md +48 -0
- package/RAF/aaaabt-verbose-chronicle/outcomes/04-commit-verification-before-halt.md +56 -0
- package/RAF/aaaabt-verbose-chronicle/plans/01-amend-iteration-references.md +35 -0
- package/RAF/aaaabt-verbose-chronicle/plans/02-verbose-task-name-display.md +38 -0
- package/RAF/aaaabt-verbose-chronicle/plans/03-verbose-streaming-fix.md +45 -0
- package/RAF/aaaabt-verbose-chronicle/plans/04-commit-verification-before-halt.md +62 -0
- package/RAF/aaaacu-worktree-weaver/decisions.md +88 -0
- package/RAF/aaaacu-worktree-weaver/input.md +27 -0
- package/RAF/aaaacu-worktree-weaver/outcomes/01-git-worktree-utilities.md +41 -0
- package/RAF/aaaacu-worktree-weaver/outcomes/02-worktree-plan-command.md +44 -0
- package/RAF/aaaacu-worktree-weaver/outcomes/03-worktree-do-command.md +58 -0
- package/RAF/aaaacu-worktree-weaver/outcomes/04-auto-merge-and-cleanup.md +40 -0
- package/RAF/aaaacu-worktree-weaver/outcomes/05-worktree-tests.md +43 -0
- package/RAF/aaaacu-worktree-weaver/outcomes/06-update-documentation.md +33 -0
- package/RAF/aaaacu-worktree-weaver/plans/01-git-worktree-utilities.md +51 -0
- package/RAF/aaaacu-worktree-weaver/plans/02-worktree-plan-command.md +93 -0
- package/RAF/aaaacu-worktree-weaver/plans/03-worktree-do-command.md +81 -0
- package/RAF/aaaacu-worktree-weaver/plans/04-auto-merge-and-cleanup.md +51 -0
- package/RAF/aaaacu-worktree-weaver/plans/05-worktree-tests.md +52 -0
- package/RAF/aaaacu-worktree-weaver/plans/06-update-documentation.md +55 -0
- package/RAF/aaaacv-trim-the-fat/decisions.md +34 -0
- package/RAF/aaaacv-trim-the-fat/input.md +5 -0
- package/RAF/aaaacv-trim-the-fat/outcomes/01-add-worktree-support-to-status.md +43 -0
- package/RAF/aaaacv-trim-the-fat/outcomes/02-remove-multi-project-from-do.md +50 -0
- package/RAF/aaaacv-trim-the-fat/outcomes/03-commit-artifacts-on-amend.md +35 -0
- package/RAF/aaaacv-trim-the-fat/outcomes/04-worktree-aware-exit-messages.md +36 -0
- package/RAF/aaaacv-trim-the-fat/plans/01-add-worktree-support-to-status.md +43 -0
- package/RAF/aaaacv-trim-the-fat/plans/02-remove-multi-project-from-do.md +44 -0
- package/RAF/aaaacv-trim-the-fat/plans/03-commit-artifacts-on-amend.md +38 -0
- package/RAF/aaaacv-trim-the-fat/plans/04-worktree-aware-exit-messages.md +38 -0
- package/RAF/aaaacw-prune-cycle/decisions.md +25 -0
- package/RAF/aaaacw-prune-cycle/input.md +5 -0
- package/RAF/aaaacw-prune-cycle/outcomes/01-create-worktree-from-branch.md +32 -0
- package/RAF/aaaacw-prune-cycle/outcomes/02-cleanup-worktree-on-success.md +33 -0
- package/RAF/aaaacw-prune-cycle/outcomes/03-amend-recreate-worktree.md +40 -0
- package/RAF/aaaacw-prune-cycle/plans/01-create-worktree-from-branch.md +31 -0
- package/RAF/aaaacw-prune-cycle/plans/02-cleanup-worktree-on-success.md +38 -0
- package/RAF/aaaacw-prune-cycle/plans/03-amend-recreate-worktree.md +50 -0
- package/RAF/aaaacx-epoch-shift/decisions.md +25 -0
- package/RAF/aaaacx-epoch-shift/input.md +1 -0
- package/RAF/aaaacx-epoch-shift/outcomes/01-epoch-id-generation.md +34 -0
- package/RAF/aaaacx-epoch-shift/outcomes/02-update-pattern-matching.md +32 -0
- package/RAF/aaaacx-epoch-shift/outcomes/03-update-tests.md +59 -0
- package/RAF/aaaacx-epoch-shift/outcomes/04-update-documentation.md +30 -0
- package/RAF/aaaacx-epoch-shift/plans/01-epoch-id-generation.md +40 -0
- package/RAF/aaaacx-epoch-shift/plans/02-update-pattern-matching.md +60 -0
- package/RAF/aaaacx-epoch-shift/plans/03-update-tests.md +48 -0
- package/RAF/aaaacx-epoch-shift/plans/04-update-documentation.md +44 -0
- package/RAF/ahmpro-merge-guardian/decisions.md +25 -0
- package/RAF/ahmpro-merge-guardian/input.md +4 -0
- package/RAF/ahmpro-merge-guardian/outcomes/001-fix-amend-worktree-commit.md +45 -0
- package/RAF/ahmpro-merge-guardian/outcomes/002-base36-task-ids.md +55 -0
- package/RAF/ahmpro-merge-guardian/outcomes/003-worktree-pr-creation.md +41 -0
- package/RAF/ahmpro-merge-guardian/outcomes/004-post-execution-picker.md +53 -0
- package/RAF/ahmpro-merge-guardian/plans/001-fix-amend-worktree-commit.md +39 -0
- package/RAF/ahmpro-merge-guardian/plans/002-base36-task-ids.md +43 -0
- package/RAF/ahmpro-merge-guardian/plans/003-worktree-pr-creation.md +43 -0
- package/RAF/ahmpro-merge-guardian/plans/004-post-execution-picker.md +51 -0
- package/RAF/ahnbcu-letterjam/decisions.md +13 -0
- package/RAF/ahnbcu-letterjam/input.md +3 -0
- package/RAF/ahnbcu-letterjam/outcomes/01-base26-encoding.md +42 -0
- package/RAF/ahnbcu-letterjam/outcomes/02-update-tests.md +38 -0
- package/RAF/ahnbcu-letterjam/outcomes/03-migrate-command.md +51 -0
- package/RAF/ahnbcu-letterjam/outcomes/04-update-documentation.md +29 -0
- package/RAF/ahnbcu-letterjam/plans/01-base26-encoding.md +36 -0
- package/RAF/ahnbcu-letterjam/plans/02-update-tests.md +37 -0
- package/RAF/ahnbcu-letterjam/plans/03-migrate-command.md +49 -0
- package/RAF/ahnbcu-letterjam/plans/04-update-documentation.md +39 -0
- package/RAF/ahnwrk-worktree-weaver/decisions.md +19 -0
- package/RAF/ahnwrk-worktree-weaver/input.md +4 -0
- package/RAF/ahnwrk-worktree-weaver/outcomes/01-remove-co-authored-by.md +20 -0
- package/RAF/ahnwrk-worktree-weaver/outcomes/02-update-task-status-format.md +21 -0
- package/RAF/ahnwrk-worktree-weaver/outcomes/03-worktree-auto-discovery.md +34 -0
- package/RAF/ahnwrk-worktree-weaver/outcomes/04-fix-pr-description.md +30 -0
- package/RAF/ahnwrk-worktree-weaver/plans/01-remove-co-authored-by.md +26 -0
- package/RAF/ahnwrk-worktree-weaver/plans/02-update-task-status-format.md +27 -0
- package/RAF/ahnwrk-worktree-weaver/plans/03-worktree-auto-discovery.md +37 -0
- package/RAF/ahnwrk-worktree-weaver/plans/04-fix-pr-description.md +50 -0
- package/README.md +56 -10
- package/dist/commands/do.d.ts +15 -0
- package/dist/commands/do.d.ts.map +1 -1
- package/dist/commands/do.js +400 -131
- package/dist/commands/do.js.map +1 -1
- package/dist/commands/migrate.d.ts +14 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +228 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/plan.d.ts.map +1 -1
- package/dist/commands/plan.js +237 -40
- package/dist/commands/plan.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +221 -47
- package/dist/commands/status.js.map +1 -1
- package/dist/core/claude-runner.d.ts +52 -1
- package/dist/core/claude-runner.d.ts.map +1 -1
- package/dist/core/claude-runner.js +195 -17
- package/dist/core/claude-runner.js.map +1 -1
- package/dist/core/git.d.ts +29 -5
- package/dist/core/git.d.ts.map +1 -1
- package/dist/core/git.js +95 -18
- package/dist/core/git.js.map +1 -1
- package/dist/core/project-manager.d.ts.map +1 -1
- package/dist/core/project-manager.js +2 -2
- package/dist/core/project-manager.js.map +1 -1
- package/dist/core/pull-request.d.ts +84 -0
- package/dist/core/pull-request.d.ts.map +1 -0
- package/dist/core/pull-request.js +414 -0
- package/dist/core/pull-request.js.map +1 -0
- package/dist/core/state-derivation.d.ts +3 -3
- package/dist/core/state-derivation.d.ts.map +1 -1
- package/dist/core/state-derivation.js +18 -14
- package/dist/core/state-derivation.js.map +1 -1
- package/dist/core/worktree.d.ts +120 -0
- package/dist/core/worktree.d.ts.map +1 -0
- package/dist/core/worktree.js +322 -0
- package/dist/core/worktree.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/parsers/stream-renderer.d.ts +42 -0
- package/dist/parsers/stream-renderer.d.ts.map +1 -0
- package/dist/parsers/stream-renderer.js +100 -0
- package/dist/parsers/stream-renderer.js.map +1 -0
- package/dist/prompts/amend.d.ts +1 -0
- package/dist/prompts/amend.d.ts.map +1 -1
- package/dist/prompts/amend.js +25 -10
- package/dist/prompts/amend.js.map +1 -1
- package/dist/prompts/execution.js +5 -5
- package/dist/prompts/execution.js.map +1 -1
- package/dist/prompts/planning.d.ts +1 -0
- package/dist/prompts/planning.d.ts.map +1 -1
- package/dist/prompts/planning.js +11 -10
- package/dist/prompts/planning.js.map +1 -1
- package/dist/types/config.d.ts +5 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/ui/project-picker.d.ts +34 -3
- package/dist/ui/project-picker.d.ts.map +1 -1
- package/dist/ui/project-picker.js +78 -10
- package/dist/ui/project-picker.js.map +1 -1
- package/dist/utils/paths.d.ts +38 -43
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +123 -193
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/terminal-symbols.d.ts +2 -2
- package/dist/utils/terminal-symbols.js +3 -3
- package/dist/utils/terminal-symbols.js.map +1 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +2 -8
- package/dist/utils/validation.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/do.ts +471 -142
- package/src/commands/migrate.ts +269 -0
- package/src/commands/plan.ts +264 -40
- package/src/commands/status.ts +252 -45
- package/src/core/claude-runner.ts +270 -17
- package/src/core/git.ts +99 -19
- package/src/core/project-manager.ts +2 -1
- package/src/core/pull-request.ts +480 -0
- package/src/core/state-derivation.ts +18 -14
- package/src/core/worktree.ts +357 -0
- package/src/index.ts +2 -0
- package/src/parsers/stream-renderer.ts +139 -0
- package/src/prompts/amend.ts +27 -9
- package/src/prompts/execution.ts +5 -5
- package/src/prompts/planning.ts +12 -10
- package/src/types/config.ts +6 -0
- package/src/ui/project-picker.ts +110 -10
- package/src/utils/paths.ts +129 -214
- package/src/utils/terminal-symbols.ts +3 -3
- package/src/utils/validation.ts +2 -9
- package/tests/unit/amend-prompt.test.ts +85 -0
- package/tests/unit/claude-runner.test.ts +567 -1
- package/tests/unit/commit-planning-artifacts-worktree.test.ts +327 -0
- package/tests/unit/commit-planning-artifacts.test.ts +303 -35
- package/tests/unit/dependency-integration.test.ts +95 -95
- package/tests/unit/do-blocked-tasks.test.ts +53 -53
- package/tests/unit/do-command.test.ts +39 -132
- package/tests/unit/do-rerun.test.ts +65 -65
- package/tests/unit/do-worktree-cleanup.test.ts +151 -0
- package/tests/unit/execution-prompt.test.ts +71 -60
- package/tests/unit/failure-history.test.ts +19 -19
- package/tests/unit/git-commit-helpers.test.ts +103 -0
- package/tests/unit/git-stash.test.ts +4 -4
- package/tests/unit/migrate-command.test.ts +197 -0
- package/tests/unit/outcome-content.test.ts +20 -20
- package/tests/unit/paths.test.ts +269 -467
- package/tests/unit/plan-amend-worktree-recreate.test.ts +246 -0
- package/tests/unit/plan-command.test.ts +144 -93
- package/tests/unit/planning-prompt.test.ts +41 -4
- package/tests/unit/post-execution-picker.test.ts +251 -0
- package/tests/unit/project-manager.test.ts +20 -8
- package/tests/unit/project-picker.test.ts +425 -42
- package/tests/unit/pull-request.test.ts +852 -0
- package/tests/unit/state-derivation.test.ts +138 -137
- package/tests/unit/status-command.test.ts +344 -76
- package/tests/unit/stream-renderer.test.ts +286 -0
- package/tests/unit/terminal-symbols.test.ts +4 -4
- package/tests/unit/worktree-integration.test.ts +405 -0
- package/tests/unit/worktree.test.ts +523 -0
- package/tests/unit/do-multiproject.test.ts +0 -270
- /package/RAF/{001-raf-task-improvements → aaaaab-raf-task-improvements}/input.md +0 -0
- /package/RAF/{001-raf-task-improvements/outcomes/001-add-decisions-folder.md → aaaaab-raf-task-improvements/outcomes/01-add-decisions-folder.md} +0 -0
- /package/RAF/{001-raf-task-improvements/outcomes/002-fix-write-error-on-shutdown.md → aaaaab-raf-task-improvements/outcomes/02-fix-write-error-on-shutdown.md} +0 -0
- /package/RAF/{001-raf-task-improvements/outcomes/003-stash-changes-on-failure.md → aaaaab-raf-task-improvements/outcomes/03-stash-changes-on-failure.md} +0 -0
- /package/RAF/{001-raf-task-improvements/outcomes/004-add-project-name-to-commits.md → aaaaab-raf-task-improvements/outcomes/04-add-project-name-to-commits.md} +0 -0
- /package/RAF/{001-raf-task-improvements/outcomes/005-add-running-time-display.md → aaaaab-raf-task-improvements/outcomes/05-add-running-time-display.md} +0 -0
- /package/RAF/{001-raf-task-improvements/outcomes/006-add-task-name-to-logs.md → aaaaab-raf-task-improvements/outcomes/06-add-task-name-to-logs.md} +0 -0
- /package/RAF/{001-raf-task-improvements/outcomes/007-show-model-at-task-start.md → aaaaab-raf-task-improvements/outcomes/07-show-model-at-task-start.md} +0 -0
- /package/RAF/{001-raf-task-improvements/outcomes/009-remove-editor-placeholder-text.md → aaaaab-raf-task-improvements/outcomes/09-remove-editor-placeholder-text.md} +0 -0
- /package/RAF/{001-raf-task-improvements → aaaaab-raf-task-improvements}/outcomes/SUMMARY.md +0 -0
- /package/RAF/{001-raf-task-improvements/plans/001-add-decisions-folder.md → aaaaab-raf-task-improvements/plans/01-add-decisions-folder.md} +0 -0
- /package/RAF/{001-raf-task-improvements/plans/002-fix-write-error-on-shutdown.md → aaaaab-raf-task-improvements/plans/02-fix-write-error-on-shutdown.md} +0 -0
- /package/RAF/{001-raf-task-improvements/plans/003-stash-changes-on-failure.md → aaaaab-raf-task-improvements/plans/03-stash-changes-on-failure.md} +0 -0
- /package/RAF/{001-raf-task-improvements/plans/004-add-project-name-to-commits.md → aaaaab-raf-task-improvements/plans/04-add-project-name-to-commits.md} +0 -0
- /package/RAF/{001-raf-task-improvements/plans/005-add-running-time-display.md → aaaaab-raf-task-improvements/plans/05-add-running-time-display.md} +0 -0
- /package/RAF/{001-raf-task-improvements/plans/006-add-task-name-to-logs.md → aaaaab-raf-task-improvements/plans/06-add-task-name-to-logs.md} +0 -0
- /package/RAF/{001-raf-task-improvements/plans/009-remove-editor-placeholder-text.md → aaaaab-raf-task-improvements/plans/09-remove-editor-placeholder-text.md} +0 -0
- /package/RAF/{002-raf-task-improvements-execution → aaaaac-raf-task-improvements-execution}/decisions/DECISIONS.md +0 -0
- /package/RAF/{002-raf-task-improvements-execution → aaaaac-raf-task-improvements-execution}/input.md +0 -0
- /package/RAF/{002-raf-task-improvements-execution/outcomes/001-commit-show-model-at-task-start.md → aaaaac-raf-task-improvements-execution/outcomes/01-commit-show-model-at-task-start.md} +0 -0
- /package/RAF/{002-raf-task-improvements-execution/outcomes/002-delete-skipped-plan.md → aaaaac-raf-task-improvements-execution/outcomes/02-delete-skipped-plan.md} +0 -0
- /package/RAF/{002-raf-task-improvements-execution → aaaaac-raf-task-improvements-execution}/outcomes/SUMMARY.md +0 -0
- /package/RAF/{002-raf-task-improvements-execution/plans/001-commit-show-model-at-task-start.md → aaaaac-raf-task-improvements-execution/plans/01-commit-show-model-at-task-start.md} +0 -0
- /package/RAF/{002-raf-task-improvements-execution/plans/002-delete-skipped-plan.md → aaaaac-raf-task-improvements-execution/plans/02-delete-skipped-plan.md} +0 -0
- /package/RAF/{003-multi-project-execution → aaaaad-multi-project-execution}/decisions/DECISIONS.md +0 -0
- /package/RAF/{003-multi-project-execution → aaaaad-multi-project-execution}/input.md +0 -0
- /package/RAF/{003-multi-project-execution/outcomes/001-remove-state-json.md → aaaaad-multi-project-execution/outcomes/01-remove-state-json.md} +0 -0
- /package/RAF/{003-multi-project-execution/outcomes/002-update-raf-status.md → aaaaad-multi-project-execution/outcomes/02-update-raf-status.md} +0 -0
- /package/RAF/{003-multi-project-execution/outcomes/003-simplify-git-logic.md → aaaaad-multi-project-execution/outcomes/03-simplify-git-logic.md} +0 -0
- /package/RAF/{003-multi-project-execution/outcomes/004-auto-commit-planning.md → aaaaad-multi-project-execution/outcomes/04-auto-commit-planning.md} +0 -0
- /package/RAF/{003-multi-project-execution/outcomes/005-rerun-failed-tasks.md → aaaaad-multi-project-execution/outcomes/05-rerun-failed-tasks.md} +0 -0
- /package/RAF/{003-multi-project-execution/outcomes/006-multi-project-execution.md → aaaaad-multi-project-execution/outcomes/06-multi-project-execution.md} +0 -0
- /package/RAF/{003-multi-project-execution/outcomes/007-verify-timeout.md → aaaaad-multi-project-execution/outcomes/07-verify-timeout.md} +0 -0
- /package/RAF/{003-multi-project-execution/outcomes/008-move-decisions-file.md → aaaaad-multi-project-execution/outcomes/08-move-decisions-file.md} +0 -0
- /package/RAF/{003-multi-project-execution → aaaaad-multi-project-execution}/outcomes/SUMMARY.md +0 -0
- /package/RAF/{003-multi-project-execution/plans/001-remove-state-json.md → aaaaad-multi-project-execution/plans/01-remove-state-json.md} +0 -0
- /package/RAF/{003-multi-project-execution/plans/002-update-raf-status.md → aaaaad-multi-project-execution/plans/02-update-raf-status.md} +0 -0
- /package/RAF/{003-multi-project-execution/plans/003-simplify-git-logic.md → aaaaad-multi-project-execution/plans/03-simplify-git-logic.md} +0 -0
- /package/RAF/{003-multi-project-execution/plans/004-auto-commit-planning.md → aaaaad-multi-project-execution/plans/04-auto-commit-planning.md} +0 -0
- /package/RAF/{003-multi-project-execution/plans/005-rerun-failed-tasks.md → aaaaad-multi-project-execution/plans/05-rerun-failed-tasks.md} +0 -0
- /package/RAF/{003-multi-project-execution/plans/006-multi-project-execution.md → aaaaad-multi-project-execution/plans/06-multi-project-execution.md} +0 -0
- /package/RAF/{003-multi-project-execution/plans/007-verify-timeout.md → aaaaad-multi-project-execution/plans/07-verify-timeout.md} +0 -0
- /package/RAF/{003-multi-project-execution/plans/008-move-decisions-file.md → aaaaad-multi-project-execution/plans/08-move-decisions-file.md} +0 -0
- /package/RAF/{004-task-naming-optimization → aaaaae-task-naming-optimization}/decisions.md +0 -0
- /package/RAF/{004-task-naming-optimization → aaaaae-task-naming-optimization}/input.md +0 -0
- /package/RAF/{004-task-naming-optimization/outcomes/001-remove-summary-file.md → aaaaae-task-naming-optimization/outcomes/01-remove-summary-file.md} +0 -0
- /package/RAF/{004-task-naming-optimization/outcomes/002-base36-project-numbering.md → aaaaae-task-naming-optimization/outcomes/02-base36-project-numbering.md} +0 -0
- /package/RAF/{004-task-naming-optimization/outcomes/003-improve-haiku-prompt.md → aaaaae-task-naming-optimization/outcomes/03-improve-haiku-prompt.md} +0 -0
- /package/RAF/{004-task-naming-optimization → aaaaae-task-naming-optimization}/outcomes/SUMMARY.md +0 -0
- /package/RAF/{004-task-naming-optimization/plans/001-remove-summary-file.md → aaaaae-task-naming-optimization/plans/01-remove-summary-file.md} +0 -0
- /package/RAF/{004-task-naming-optimization/plans/002-base36-project-numbering.md → aaaaae-task-naming-optimization/plans/02-base36-project-numbering.md} +0 -0
- /package/RAF/{004-task-naming-optimization/plans/003-improve-haiku-prompt.md → aaaaae-task-naming-optimization/plans/03-improve-haiku-prompt.md} +0 -0
- /package/RAF/{005-task-naming-improvements → aaaaaf-task-naming-improvements}/decisions.md +0 -0
- /package/RAF/{005-task-naming-improvements → aaaaaf-task-naming-improvements}/input.md +0 -0
- /package/RAF/{005-task-naming-improvements/outcomes/001-enhance-identifier-resolution.md → aaaaaf-task-naming-improvements/outcomes/01-enhance-identifier-resolution.md} +0 -0
- /package/RAF/{005-task-naming-improvements/outcomes/002-add-identifier-support-to-status.md → aaaaaf-task-naming-improvements/outcomes/02-add-identifier-support-to-status.md} +0 -0
- /package/RAF/{005-task-naming-improvements/outcomes/003-update-do-for-full-folder-names.md → aaaaaf-task-naming-improvements/outcomes/03-update-do-for-full-folder-names.md} +0 -0
- /package/RAF/{005-task-naming-improvements/outcomes/004-implement-amend-flag-for-plan.md → aaaaaf-task-naming-improvements/outcomes/04-implement-amend-flag-for-plan.md} +0 -0
- /package/RAF/{005-task-naming-improvements/outcomes/005-commit-outcomes-on-complete.md → aaaaaf-task-naming-improvements/outcomes/05-commit-outcomes-on-complete.md} +0 -0
- /package/RAF/{005-task-naming-improvements/outcomes/006-update-execution-prompt-commit-schema.md → aaaaaf-task-naming-improvements/outcomes/06-update-execution-prompt-commit-schema.md} +0 -0
- /package/RAF/{005-task-naming-improvements/outcomes/007-allow-pending-task-amendments.md → aaaaaf-task-naming-improvements/outcomes/07-allow-pending-task-amendments.md} +0 -0
- /package/RAF/{005-task-naming-improvements/outcomes/008-fix-timeout-label.md → aaaaaf-task-naming-improvements/outcomes/08-fix-timeout-label.md} +0 -0
- /package/RAF/{005-task-naming-improvements/plans/001-enhance-identifier-resolution.md → aaaaaf-task-naming-improvements/plans/01-enhance-identifier-resolution.md} +0 -0
- /package/RAF/{005-task-naming-improvements/plans/002-add-identifier-support-to-status.md → aaaaaf-task-naming-improvements/plans/02-add-identifier-support-to-status.md} +0 -0
- /package/RAF/{005-task-naming-improvements/plans/003-update-do-for-full-folder-names.md → aaaaaf-task-naming-improvements/plans/03-update-do-for-full-folder-names.md} +0 -0
- /package/RAF/{005-task-naming-improvements/plans/004-implement-amend-flag-for-plan.md → aaaaaf-task-naming-improvements/plans/04-implement-amend-flag-for-plan.md} +0 -0
- /package/RAF/{005-task-naming-improvements/plans/005-commit-outcomes-on-complete.md → aaaaaf-task-naming-improvements/plans/05-commit-outcomes-on-complete.md} +0 -0
- /package/RAF/{005-task-naming-improvements/plans/006-update-execution-prompt-commit-schema.md → aaaaaf-task-naming-improvements/plans/06-update-execution-prompt-commit-schema.md} +0 -0
- /package/RAF/{005-task-naming-improvements/plans/007-allow-pending-task-amendments.md → aaaaaf-task-naming-improvements/plans/07-allow-pending-task-amendments.md} +0 -0
- /package/RAF/{005-task-naming-improvements/plans/008-fix-timeout-label.md → aaaaaf-task-naming-improvements/plans/08-fix-timeout-label.md} +0 -0
- /package/RAF/{006-fix-double-summary-headers → aaaaag-fix-double-summary-headers}/decisions.md +0 -0
- /package/RAF/{006-fix-double-summary-headers → aaaaag-fix-double-summary-headers}/input.md +0 -0
- /package/RAF/{006-fix-double-summary-headers/outcomes/001-fix-double-summary-headers.md → aaaaag-fix-double-summary-headers/outcomes/01-fix-double-summary-headers.md} +0 -0
- /package/RAF/{006-fix-double-summary-headers/outcomes/002-update-readme-for-npm.md → aaaaag-fix-double-summary-headers/outcomes/02-update-readme-for-npm.md} +0 -0
- /package/RAF/{006-fix-double-summary-headers/outcomes/003-npm-publish-instructions.md → aaaaag-fix-double-summary-headers/outcomes/03-npm-publish-instructions.md} +0 -0
- /package/RAF/{006-fix-double-summary-headers/outcomes/004-flexible-project-lookup.md → aaaaag-fix-double-summary-headers/outcomes/04-flexible-project-lookup.md} +0 -0
- /package/RAF/{006-fix-double-summary-headers/plans/001-fix-double-summary-headers.md → aaaaag-fix-double-summary-headers/plans/01-fix-double-summary-headers.md} +0 -0
- /package/RAF/{006-fix-double-summary-headers/plans/002-update-readme-for-npm.md → aaaaag-fix-double-summary-headers/plans/02-update-readme-for-npm.md} +0 -0
- /package/RAF/{006-fix-double-summary-headers/plans/003-npm-publish-instructions.md → aaaaag-fix-double-summary-headers/plans/03-npm-publish-instructions.md} +0 -0
- /package/RAF/{006-fix-double-summary-headers/plans/004-flexible-project-lookup.md → aaaaag-fix-double-summary-headers/plans/04-flexible-project-lookup.md} +0 -0
- /package/RAF/{007-improve-outcome-format → aaaaah-improve-outcome-format}/decisions.md +0 -0
- /package/RAF/{007-improve-outcome-format → aaaaah-improve-outcome-format}/input.md +0 -0
- /package/RAF/{007-improve-outcome-format/outcomes/001-update-execution-prompt.md → aaaaah-improve-outcome-format/outcomes/01-update-execution-prompt.md} +0 -0
- /package/RAF/{007-improve-outcome-format/outcomes/002-update-state-derivation.md → aaaaah-improve-outcome-format/outcomes/02-update-state-derivation.md} +0 -0
- /package/RAF/{007-improve-outcome-format/outcomes/003-update-do-command-outcome-handling.md → aaaaah-improve-outcome-format/outcomes/03-update-do-command-outcome-handling.md} +0 -0
- /package/RAF/{007-improve-outcome-format/outcomes/004-implement-failure-analysis.md → aaaaah-improve-outcome-format/outcomes/04-implement-failure-analysis.md} +0 -0
- /package/RAF/{007-improve-outcome-format/outcomes/005-update-documentation.md → aaaaah-improve-outcome-format/outcomes/05-update-documentation.md} +0 -0
- /package/RAF/{007-improve-outcome-format/plans/001-update-execution-prompt.md → aaaaah-improve-outcome-format/plans/01-update-execution-prompt.md} +0 -0
- /package/RAF/{007-improve-outcome-format/plans/002-update-state-derivation.md → aaaaah-improve-outcome-format/plans/02-update-state-derivation.md} +0 -0
- /package/RAF/{007-improve-outcome-format/plans/003-update-do-command-outcome-handling.md → aaaaah-improve-outcome-format/plans/03-update-do-command-outcome-handling.md} +0 -0
- /package/RAF/{007-improve-outcome-format/plans/004-implement-failure-analysis.md → aaaaah-improve-outcome-format/plans/04-implement-failure-analysis.md} +0 -0
- /package/RAF/{007-improve-outcome-format/plans/005-update-documentation.md → aaaaah-improve-outcome-format/plans/05-update-documentation.md} +0 -0
- /package/RAF/{008-beautiful-do → aaaaai-beautiful-do}/decisions.md +0 -0
- /package/RAF/{008-beautiful-do → aaaaai-beautiful-do}/input.md +0 -0
- /package/RAF/{008-beautiful-do/outcomes/001-terminal-symbols.md → aaaaai-beautiful-do/outcomes/01-terminal-symbols.md} +0 -0
- /package/RAF/{008-beautiful-do/outcomes/002-refactor-do-output.md → aaaaai-beautiful-do/outcomes/02-refactor-do-output.md} +0 -0
- /package/RAF/{008-beautiful-do/outcomes/003-refactor-status-output.md → aaaaai-beautiful-do/outcomes/03-refactor-status-output.md} +0 -0
- /package/RAF/{008-beautiful-do/outcomes/004-simplify-logger.md → aaaaai-beautiful-do/outcomes/04-simplify-logger.md} +0 -0
- /package/RAF/{008-beautiful-do/outcomes/005-add-tests.md → aaaaai-beautiful-do/outcomes/05-add-tests.md} +0 -0
- /package/RAF/{008-beautiful-do/plans/001-terminal-symbols.md → aaaaai-beautiful-do/plans/01-terminal-symbols.md} +0 -0
- /package/RAF/{008-beautiful-do/plans/002-refactor-do-output.md → aaaaai-beautiful-do/plans/02-refactor-do-output.md} +0 -0
- /package/RAF/{008-beautiful-do/plans/003-refactor-status-output.md → aaaaai-beautiful-do/plans/03-refactor-status-output.md} +0 -0
- /package/RAF/{008-beautiful-do/plans/004-simplify-logger.md → aaaaai-beautiful-do/plans/04-simplify-logger.md} +0 -0
- /package/RAF/{008-beautiful-do/plans/005-add-tests.md → aaaaai-beautiful-do/plans/05-add-tests.md} +0 -0
- /package/RAF/{009-system-promt-ammend → aaaaaj-system-promt-ammend}/decisions.md +0 -0
- /package/RAF/{009-system-promt-ammend → aaaaaj-system-promt-ammend}/input.md +0 -0
- /package/RAF/{009-system-promt-ammend/outcomes/001-model-override.md → aaaaaj-system-promt-ammend/outcomes/01-model-override.md} +0 -0
- /package/RAF/{009-system-promt-ammend/outcomes/002-system-prompt-append.md → aaaaaj-system-promt-ammend/outcomes/02-system-prompt-append.md} +0 -0
- /package/RAF/{009-system-promt-ammend/outcomes/003-retry-context.md → aaaaaj-system-promt-ammend/outcomes/03-retry-context.md} +0 -0
- /package/RAF/{009-system-promt-ammend/plans/001-model-override.md → aaaaaj-system-promt-ammend/plans/01-model-override.md} +0 -0
- /package/RAF/{009-system-promt-ammend/plans/002-system-prompt-append.md → aaaaaj-system-promt-ammend/plans/02-system-prompt-append.md} +0 -0
- /package/RAF/{009-system-promt-ammend/plans/003-retry-context.md → aaaaaj-system-promt-ammend/plans/03-retry-context.md} +0 -0
- /package/RAF/{010-outcome-marker-fallback → aaaabk-outcome-marker-fallback}/decisions.md +0 -0
- /package/RAF/{010-outcome-marker-fallback → aaaabk-outcome-marker-fallback}/input.md +0 -0
- /package/RAF/{010-outcome-marker-fallback/outcomes/001-outcome-file-marker-fallback.md → aaaabk-outcome-marker-fallback/outcomes/01-outcome-file-marker-fallback.md} +0 -0
- /package/RAF/{010-outcome-marker-fallback/outcomes/002-creative-project-naming.md → aaaabk-outcome-marker-fallback/outcomes/02-creative-project-naming.md} +0 -0
- /package/RAF/{010-outcome-marker-fallback/plans/001-outcome-file-marker-fallback.md → aaaabk-outcome-marker-fallback/plans/01-outcome-file-marker-fallback.md} +0 -0
- /package/RAF/{010-outcome-marker-fallback/plans/002-creative-project-naming.md → aaaabk-outcome-marker-fallback/plans/02-creative-project-naming.md} +0 -0
- /package/RAF/{011-do-task-in-commit → aaaabl-do-task-in-commit}/decisions.md +0 -0
- /package/RAF/{011-do-task-in-commit → aaaabl-do-task-in-commit}/input.md +0 -0
- /package/RAF/{011-do-task-in-commit/outcomes/001-update-execution-prompt.md → aaaabl-do-task-in-commit/outcomes/01-update-execution-prompt.md} +0 -0
- /package/RAF/{011-do-task-in-commit/outcomes/002-update-tests.md → aaaabl-do-task-in-commit/outcomes/02-update-tests.md} +0 -0
- /package/RAF/{011-do-task-in-commit/outcomes/003-update-documentation.md → aaaabl-do-task-in-commit/outcomes/03-update-documentation.md} +0 -0
- /package/RAF/{011-do-task-in-commit/plans/001-update-execution-prompt.md → aaaabl-do-task-in-commit/plans/01-update-execution-prompt.md} +0 -0
- /package/RAF/{011-do-task-in-commit/plans/002-update-tests.md → aaaabl-do-task-in-commit/plans/02-update-tests.md} +0 -0
- /package/RAF/{011-do-task-in-commit/plans/003-update-documentation.md → aaaabl-do-task-in-commit/plans/03-update-documentation.md} +0 -0
- /package/RAF/{012-name-picker-buffet → aaaabm-name-picker-buffet}/decisions.md +0 -0
- /package/RAF/{012-name-picker-buffet → aaaabm-name-picker-buffet}/input.md +0 -0
- /package/RAF/{012-name-picker-buffet/outcomes/001-name-picker-for-raf-plan.md → aaaabm-name-picker-buffet/outcomes/01-name-picker-for-raf-plan.md} +0 -0
- /package/RAF/{012-name-picker-buffet/outcomes/002-interactive-project-picker-for-raf-do.md → aaaabm-name-picker-buffet/outcomes/02-interactive-project-picker-for-raf-do.md} +0 -0
- /package/RAF/{012-name-picker-buffet/outcomes/003-raf-status-truncation.md → aaaabm-name-picker-buffet/outcomes/03-raf-status-truncation.md} +0 -0
- /package/RAF/{012-name-picker-buffet/outcomes/004-failure-reason-details.md → aaaabm-name-picker-buffet/outcomes/04-failure-reason-details.md} +0 -0
- /package/RAF/{012-name-picker-buffet/outcomes/005-remove-raf-commits.md → aaaabm-name-picker-buffet/outcomes/05-remove-raf-commits.md} +0 -0
- /package/RAF/{012-name-picker-buffet/outcomes/006-update-execution-prompt-for-commits.md → aaaabm-name-picker-buffet/outcomes/06-update-execution-prompt-for-commits.md} +0 -0
- /package/RAF/{012-name-picker-buffet/outcomes/007-fix-plan-mode-user-prompt.md → aaaabm-name-picker-buffet/outcomes/07-fix-plan-mode-user-prompt.md} +0 -0
- /package/RAF/{012-name-picker-buffet/outcomes/008-add-auto-flag-for-plan-mode.md → aaaabm-name-picker-buffet/outcomes/08-add-auto-flag-for-plan-mode.md} +0 -0
- /package/RAF/{012-name-picker-buffet/plans/001-name-picker-for-raf-plan.md → aaaabm-name-picker-buffet/plans/01-name-picker-for-raf-plan.md} +0 -0
- /package/RAF/{012-name-picker-buffet/plans/002-interactive-project-picker-for-raf-do.md → aaaabm-name-picker-buffet/plans/02-interactive-project-picker-for-raf-do.md} +0 -0
- /package/RAF/{012-name-picker-buffet/plans/003-raf-status-truncation.md → aaaabm-name-picker-buffet/plans/03-raf-status-truncation.md} +0 -0
- /package/RAF/{012-name-picker-buffet/plans/004-failure-reason-details.md → aaaabm-name-picker-buffet/plans/04-failure-reason-details.md} +0 -0
- /package/RAF/{012-name-picker-buffet/plans/005-remove-raf-commits.md → aaaabm-name-picker-buffet/plans/05-remove-raf-commits.md} +0 -0
- /package/RAF/{012-name-picker-buffet/plans/006-update-execution-prompt-for-commits.md → aaaabm-name-picker-buffet/plans/06-update-execution-prompt-for-commits.md} +0 -0
- /package/RAF/{012-name-picker-buffet/plans/007-fix-plan-mode-user-prompt.md → aaaabm-name-picker-buffet/plans/07-fix-plan-mode-user-prompt.md} +0 -0
- /package/RAF/{012-name-picker-buffet/plans/008-add-auto-flag-for-plan-mode.md → aaaabm-name-picker-buffet/plans/08-add-auto-flag-for-plan-mode.md} +0 -0
- /package/RAF/{013-dependencies-watchdog → aaaabn-dependencies-watchdog}/decisions.md +0 -0
- /package/RAF/{013-dependencies-watchdog → aaaabn-dependencies-watchdog}/input.md +0 -0
- /package/RAF/{013-dependencies-watchdog/outcomes/001-define-dependency-syntax.md → aaaabn-dependencies-watchdog/outcomes/01-define-dependency-syntax.md} +0 -0
- /package/RAF/{013-dependencies-watchdog/outcomes/002-update-planning-prompts.md → aaaabn-dependencies-watchdog/outcomes/02-update-planning-prompts.md} +0 -0
- /package/RAF/{013-dependencies-watchdog/outcomes/003-parse-dependencies-update-state.md → aaaabn-dependencies-watchdog/outcomes/03-parse-dependencies-update-state.md} +0 -0
- /package/RAF/{013-dependencies-watchdog/outcomes/004-implement-dependency-checking-in-do.md → aaaabn-dependencies-watchdog/outcomes/04-implement-dependency-checking-in-do.md} +0 -0
- /package/RAF/{013-dependencies-watchdog/outcomes/005-update-execution-prompts.md → aaaabn-dependencies-watchdog/outcomes/05-update-execution-prompts.md} +0 -0
- /package/RAF/{013-dependencies-watchdog/outcomes/006-add-tests.md → aaaabn-dependencies-watchdog/outcomes/06-add-tests.md} +0 -0
- /package/RAF/{013-dependencies-watchdog/outcomes/007-add-act-alias.md → aaaabn-dependencies-watchdog/outcomes/07-add-act-alias.md} +0 -0
- /package/RAF/{013-dependencies-watchdog/outcomes/008-add-exit-message.md → aaaabn-dependencies-watchdog/outcomes/08-add-exit-message.md} +0 -0
- /package/RAF/{013-dependencies-watchdog/plans/001-define-dependency-syntax.md → aaaabn-dependencies-watchdog/plans/01-define-dependency-syntax.md} +0 -0
- /package/RAF/{013-dependencies-watchdog/plans/002-update-planning-prompts.md → aaaabn-dependencies-watchdog/plans/02-update-planning-prompts.md} +0 -0
- /package/RAF/{013-dependencies-watchdog/plans/003-parse-dependencies-update-state.md → aaaabn-dependencies-watchdog/plans/03-parse-dependencies-update-state.md} +0 -0
- /package/RAF/{013-dependencies-watchdog/plans/004-implement-dependency-checking-in-do.md → aaaabn-dependencies-watchdog/plans/04-implement-dependency-checking-in-do.md} +0 -0
- /package/RAF/{013-dependencies-watchdog/plans/005-update-execution-prompts.md → aaaabn-dependencies-watchdog/plans/05-update-execution-prompts.md} +0 -0
- /package/RAF/{013-dependencies-watchdog/plans/006-add-tests.md → aaaabn-dependencies-watchdog/plans/06-add-tests.md} +0 -0
- /package/RAF/{013-dependencies-watchdog/plans/007-add-act-alias.md → aaaabn-dependencies-watchdog/plans/07-add-act-alias.md} +0 -0
- /package/RAF/{013-dependencies-watchdog/plans/008-add-exit-message.md → aaaabn-dependencies-watchdog/plans/08-add-exit-message.md} +0 -0
- /package/RAF/{014-watchdog → aaaabo-watchdog}/decisions.md +0 -0
- /package/RAF/{014-watchdog → aaaabo-watchdog}/input.md +0 -0
- /package/RAF/{014-watchdog/outcomes/001-amend-flag-position.md → aaaabo-watchdog/outcomes/01-amend-flag-position.md} +0 -0
- /package/RAF/{014-watchdog/outcomes/002-details-only-on-failure.md → aaaabo-watchdog/outcomes/02-details-only-on-failure.md} +0 -0
- /package/RAF/{014-watchdog/plans/001-amend-flag-position.md → aaaabo-watchdog/plans/01-amend-flag-position.md} +0 -0
- /package/RAF/{014-watchdog/plans/002-details-only-on-failure.md → aaaabo-watchdog/plans/02-details-only-on-failure.md} +0 -0
- /package/RAF/{015-name-lottery → aaaabp-name-lottery}/decisions.md +0 -0
- /package/RAF/{015-name-lottery → aaaabp-name-lottery}/input.md +0 -0
- /package/RAF/{015-name-lottery/outcomes/001-auto-pick-project-name.md → aaaabp-name-lottery/outcomes/01-auto-pick-project-name.md} +0 -0
- /package/RAF/{015-name-lottery/outcomes/002-mention-plan-files-in-commit.md → aaaabp-name-lottery/outcomes/02-mention-plan-files-in-commit.md} +0 -0
- /package/RAF/{015-name-lottery/outcomes/003-fix-input-md-in-amend-flow.md → aaaabp-name-lottery/outcomes/03-fix-input-md-in-amend-flow.md} +0 -0
- /package/RAF/{015-name-lottery/plans/001-auto-pick-project-name.md → aaaabp-name-lottery/plans/01-auto-pick-project-name.md} +0 -0
- /package/RAF/{015-name-lottery/plans/002-mention-plan-files-in-commit.md → aaaabp-name-lottery/plans/02-mention-plan-files-in-commit.md} +0 -0
- /package/RAF/{015-name-lottery/plans/003-fix-input-md-in-amend-flow.md → aaaabp-name-lottery/plans/03-fix-input-md-in-amend-flow.md} +0 -0
- /package/RAF/{016-planning-scalpel → aaaabq-planning-scalpel}/decisions.md +0 -0
- /package/RAF/{016-planning-scalpel → aaaabq-planning-scalpel}/input.md +0 -0
- /package/RAF/{016-planning-scalpel/outcomes/001-update-git-commit-instructions.md → aaaabq-planning-scalpel/outcomes/01-update-git-commit-instructions.md} +0 -0
- /package/RAF/{016-planning-scalpel/plans/001-update-git-commit-instructions.md → aaaabq-planning-scalpel/plans/01-update-git-commit-instructions.md} +0 -0
- /package/RAF/{017-decision-vault → aaaabr-decision-vault}/decisions.md +0 -0
- /package/RAF/{017-decision-vault → aaaabr-decision-vault}/input.md +0 -0
- /package/RAF/{017-decision-vault/outcomes/001-create-git-commit-utility.md → aaaabr-decision-vault/outcomes/01-create-git-commit-utility.md} +0 -0
- /package/RAF/{017-decision-vault/outcomes/002-integrate-commit-into-plan.md → aaaabr-decision-vault/outcomes/02-integrate-commit-into-plan.md} +0 -0
- /package/RAF/{017-decision-vault/outcomes/003-add-tests-for-planning-commit.md → aaaabr-decision-vault/outcomes/03-add-tests-for-planning-commit.md} +0 -0
- /package/RAF/{017-decision-vault/plans/001-create-git-commit-utility.md → aaaabr-decision-vault/plans/01-create-git-commit-utility.md} +0 -0
- /package/RAF/{017-decision-vault/plans/002-integrate-commit-into-plan.md → aaaabr-decision-vault/plans/02-integrate-commit-into-plan.md} +0 -0
- /package/RAF/{017-decision-vault/plans/003-add-tests-for-planning-commit.md → aaaabr-decision-vault/plans/03-add-tests-for-planning-commit.md} +0 -0
- /package/RAF/{018-workflow-forge → aaaabs-workflow-forge}/decisions.md +0 -0
- /package/RAF/{018-workflow-forge → aaaabs-workflow-forge}/input.md +0 -0
- /package/RAF/{018-workflow-forge/outcomes/001-add-task-number-progress.md → aaaabs-workflow-forge/outcomes/01-add-task-number-progress.md} +0 -0
- /package/RAF/{018-workflow-forge/outcomes/002-update-plan-do-prompts.md → aaaabs-workflow-forge/outcomes/02-update-plan-do-prompts.md} +0 -0
- /package/RAF/{018-workflow-forge/plans/001-add-task-number-progress.md → aaaabs-workflow-forge/plans/01-add-task-number-progress.md} +0 -0
- /package/RAF/{018-workflow-forge/plans/002-update-plan-do-prompts.md → aaaabs-workflow-forge/plans/02-update-plan-do-prompts.md} +0 -0
package/src/utils/paths.ts
CHANGED
|
@@ -3,94 +3,94 @@ import * as path from 'node:path';
|
|
|
3
3
|
|
|
4
4
|
export const RAF_DIR = 'RAF';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const BASE36_START = 1000; // First base36 project number
|
|
9
|
-
const MAX_NUMERIC = 999; // Last numeric project number
|
|
6
|
+
/** RAF epoch: 2026-01-01T00:00:00Z */
|
|
7
|
+
export const RAF_EPOCH = 1767225600;
|
|
10
8
|
|
|
11
|
-
/**
|
|
12
|
-
|
|
13
|
-
* The encoding offsets by 1000, so:
|
|
14
|
-
* - 1000 -> 'a00'
|
|
15
|
-
* - 1001 -> 'a01'
|
|
16
|
-
* - 1035 -> 'a0z'
|
|
17
|
-
* - 1036 -> 'a10'
|
|
18
|
-
* - etc.
|
|
19
|
-
*
|
|
20
|
-
* First character uses a-z (10-35 in base36, letters only).
|
|
21
|
-
* Second and third characters use 0-9a-z (0-35 in base36).
|
|
22
|
-
*/
|
|
23
|
-
export function encodeBase36(num: number): string {
|
|
24
|
-
if (num < BASE36_START) {
|
|
25
|
-
throw new Error(`encodeBase36 only accepts numbers >= ${BASE36_START}, got ${num}`);
|
|
26
|
-
}
|
|
9
|
+
/** ID width: 6 characters, 'a'-padded base26 */
|
|
10
|
+
const ID_WIDTH = 6;
|
|
27
11
|
|
|
28
|
-
|
|
29
|
-
|
|
12
|
+
/** Base26 alphabet: a=0, b=1, ..., z=25 */
|
|
13
|
+
const BASE26_ALPHABET = 'abcdefghijklmnopqrstuvwxyz';
|
|
30
14
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const firstCharIndex = Math.floor(offset / (36 * 36));
|
|
34
|
-
if (firstCharIndex >= 26) {
|
|
35
|
-
throw new Error(`Project number ${num} exceeds maximum base36 capacity (max: ${BASE36_START + 26 * 36 * 36 - 1})`);
|
|
36
|
-
}
|
|
37
|
-
const firstChar = BASE36_CHARS[10 + firstCharIndex]; // Start from 'a' (index 10)
|
|
38
|
-
|
|
39
|
-
// Second and third characters: remaining value in base36
|
|
40
|
-
const remainder = offset % (36 * 36);
|
|
41
|
-
const secondCharIndex = Math.floor(remainder / 36);
|
|
42
|
-
const thirdCharIndex = remainder % 36;
|
|
15
|
+
/** Task ID width: 2 characters, zero-padded base36 */
|
|
16
|
+
const TASK_ID_WIDTH = 2;
|
|
43
17
|
|
|
44
|
-
|
|
45
|
-
|
|
18
|
+
/** Regex pattern for matching base36 task IDs (2-char: 00-zz) */
|
|
19
|
+
export const TASK_ID_PATTERN = '[0-9a-z]{2}';
|
|
46
20
|
|
|
47
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Encode a task number (0-based or 1-based) to a 2-character zero-padded base36 string.
|
|
23
|
+
* E.g., 1 -> "01", 10 -> "0a", 36 -> "10", 1295 -> "zz"
|
|
24
|
+
*/
|
|
25
|
+
export function encodeTaskId(num: number): string {
|
|
26
|
+
if (num < 0) {
|
|
27
|
+
throw new Error(`encodeTaskId only accepts non-negative integers, got ${num}`);
|
|
28
|
+
}
|
|
29
|
+
if (num > 36 * 36 - 1) {
|
|
30
|
+
throw new Error(`encodeTaskId: value ${num} exceeds max 2-char base36 (1295)`);
|
|
31
|
+
}
|
|
32
|
+
return num.toString(36).padStart(TASK_ID_WIDTH, '0');
|
|
48
33
|
}
|
|
49
34
|
|
|
50
35
|
/**
|
|
51
|
-
* Decode a
|
|
52
|
-
*
|
|
36
|
+
* Decode a 2-character base36 task ID string back to a number.
|
|
37
|
+
* E.g., "01" -> 1, "0a" -> 10, "10" -> 36
|
|
38
|
+
* Returns null if invalid format.
|
|
53
39
|
*/
|
|
54
|
-
export function
|
|
55
|
-
if (str.length !==
|
|
40
|
+
export function decodeTaskId(str: string): number | null {
|
|
41
|
+
if (str.length !== TASK_ID_WIDTH) {
|
|
56
42
|
return null;
|
|
57
43
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const firstChar = lower.charAt(0);
|
|
61
|
-
const secondChar = lower.charAt(1);
|
|
62
|
-
const thirdChar = lower.charAt(2);
|
|
63
|
-
|
|
64
|
-
// First character must be a letter (a-z)
|
|
65
|
-
const firstIndex = BASE36_CHARS.indexOf(firstChar);
|
|
66
|
-
if (firstIndex < 10 || firstIndex > 35) {
|
|
67
|
-
return null; // Not a letter
|
|
44
|
+
if (!/^[0-9a-z]{2}$/.test(str.toLowerCase())) {
|
|
45
|
+
return null;
|
|
68
46
|
}
|
|
47
|
+
return parseInt(str.toLowerCase(), 36);
|
|
48
|
+
}
|
|
69
49
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Encode a non-negative integer to a 6-character 'a'-padded base26 string (a-z alphabet).
|
|
52
|
+
* E.g., 0 → "aaaaaa", 1 → "aaaaab", 25 → "aaaaaz", 26 → "aaaaba"
|
|
53
|
+
*/
|
|
54
|
+
export function encodeBase26(num: number): string {
|
|
55
|
+
if (num < 0) {
|
|
56
|
+
throw new Error(`encodeBase26 only accepts non-negative integers, got ${num}`);
|
|
57
|
+
}
|
|
58
|
+
let result = '';
|
|
59
|
+
let remaining = num;
|
|
60
|
+
for (let i = 0; i < ID_WIDTH; i++) {
|
|
61
|
+
result = BASE26_ALPHABET[remaining % 26]! + result;
|
|
62
|
+
remaining = Math.floor(remaining / 26);
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
73
66
|
|
|
74
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Decode a 6-character base26 string (a-z alphabet) back to a non-negative integer.
|
|
69
|
+
* Returns the decoded number, or null if invalid format.
|
|
70
|
+
*/
|
|
71
|
+
export function decodeBase26(str: string): number | null {
|
|
72
|
+
if (str.length !== ID_WIDTH) {
|
|
75
73
|
return null;
|
|
76
74
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
75
|
+
if (!/^[a-z]{6}$/.test(str.toLowerCase())) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const lower = str.toLowerCase();
|
|
79
|
+
let result = 0;
|
|
80
|
+
for (let i = 0; i < ID_WIDTH; i++) {
|
|
81
|
+
result = result * 26 + (lower.charCodeAt(i) - 97); // 'a' = 97
|
|
82
|
+
}
|
|
83
|
+
return result;
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
/**
|
|
86
|
-
* Check if a string is a valid
|
|
87
|
-
* Valid format: starts with a-z, followed by two base36 chars (0-9, a-z).
|
|
87
|
+
* Check if a string is a valid 6-character base26 project prefix (a-z only).
|
|
88
88
|
*/
|
|
89
|
-
export function
|
|
90
|
-
if (str.length !==
|
|
89
|
+
export function isBase26Prefix(str: string): boolean {
|
|
90
|
+
if (str.length !== ID_WIDTH) {
|
|
91
91
|
return false;
|
|
92
92
|
}
|
|
93
|
-
return /^[a-z]
|
|
93
|
+
return /^[a-z]{6}$/.test(str.toLowerCase());
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
export function getRafDir(): string {
|
|
@@ -106,45 +106,39 @@ export function ensureRafDir(): string {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
export function getNextProjectNumber(rafDir: string): number {
|
|
109
|
+
const id = Math.floor(Date.now() / 1000) - RAF_EPOCH;
|
|
110
|
+
|
|
109
111
|
if (!fs.existsSync(rafDir)) {
|
|
110
|
-
return
|
|
112
|
+
return id;
|
|
111
113
|
}
|
|
112
114
|
|
|
115
|
+
// Collect existing IDs for collision detection
|
|
116
|
+
const existingIds = new Set<number>();
|
|
113
117
|
const entries = fs.readdirSync(rafDir, { withFileTypes: true });
|
|
114
|
-
const numbers: number[] = [];
|
|
115
118
|
|
|
116
119
|
for (const entry of entries) {
|
|
117
120
|
if (entry.isDirectory()) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
numbers.push(parseInt(numericMatch[1], 10));
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Try base36 format
|
|
126
|
-
const base36Match = entry.name.match(/^([a-z][0-9a-z]{2})-/i);
|
|
127
|
-
if (base36Match && base36Match[1]) {
|
|
128
|
-
const decoded = decodeBase36(base36Match[1].toLowerCase());
|
|
121
|
+
const match = entry.name.match(/^([a-z]{6})-/i);
|
|
122
|
+
if (match && match[1]) {
|
|
123
|
+
const decoded = decodeBase26(match[1].toLowerCase());
|
|
129
124
|
if (decoded !== null) {
|
|
130
|
-
|
|
125
|
+
existingIds.add(decoded);
|
|
131
126
|
}
|
|
132
127
|
}
|
|
133
128
|
}
|
|
134
129
|
}
|
|
135
130
|
|
|
136
|
-
|
|
137
|
-
|
|
131
|
+
// Increment until we find a free slot
|
|
132
|
+
let candidate = id;
|
|
133
|
+
while (existingIds.has(candidate)) {
|
|
134
|
+
candidate++;
|
|
138
135
|
}
|
|
139
136
|
|
|
140
|
-
return
|
|
137
|
+
return candidate;
|
|
141
138
|
}
|
|
142
139
|
|
|
143
140
|
export function formatProjectNumber(num: number): string {
|
|
144
|
-
|
|
145
|
-
return num.toString().padStart(3, '0');
|
|
146
|
-
}
|
|
147
|
-
return encodeBase36(num);
|
|
141
|
+
return encodeBase26(num);
|
|
148
142
|
}
|
|
149
143
|
|
|
150
144
|
export function getProjectDir(rafDir: string, projectName: string): string | null {
|
|
@@ -156,15 +150,8 @@ export function getProjectDir(rafDir: string, projectName: string): string | nul
|
|
|
156
150
|
|
|
157
151
|
for (const entry of entries) {
|
|
158
152
|
if (entry.isDirectory()) {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
if (numericMatch && numericMatch[1] === projectName) {
|
|
162
|
-
return path.join(rafDir, entry.name);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Try base36 format
|
|
166
|
-
const base36Match = entry.name.match(/^[a-z][0-9a-z]{2}-(.+)$/i);
|
|
167
|
-
if (base36Match && base36Match[1] === projectName) {
|
|
153
|
+
const match = entry.name.match(/^[a-z]{6}-(.+)$/i);
|
|
154
|
+
if (match && match[1] === projectName) {
|
|
168
155
|
return path.join(rafDir, entry.name);
|
|
169
156
|
}
|
|
170
157
|
}
|
|
@@ -175,81 +162,52 @@ export function getProjectDir(rafDir: string, projectName: string): string | nul
|
|
|
175
162
|
|
|
176
163
|
/**
|
|
177
164
|
* Extract project number prefix from a project path.
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
* E.g., "/Users/foo/RAF/a00-my-project" -> "a00"
|
|
181
|
-
* Returns the prefix string (e.g., "001" or "a00") or null if not found.
|
|
165
|
+
* E.g., "/Users/foo/RAF/abcdef-my-project" -> "abcdef"
|
|
166
|
+
* Returns the 6-char base26 prefix string or null if not found.
|
|
182
167
|
*/
|
|
183
168
|
export function extractProjectNumber(projectPath: string): string | null {
|
|
184
169
|
const folderName = path.basename(projectPath);
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if (numericMatch && numericMatch[1]) {
|
|
189
|
-
return numericMatch[1];
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// Try base36 format (letter followed by two alphanumeric chars)
|
|
193
|
-
const base36Match = folderName.match(/^([a-z][0-9a-z]{2})-/i);
|
|
194
|
-
if (base36Match && base36Match[1]) {
|
|
195
|
-
return base36Match[1].toLowerCase();
|
|
170
|
+
const match = folderName.match(/^([a-z]{6})-/i);
|
|
171
|
+
if (match && match[1]) {
|
|
172
|
+
return match[1].toLowerCase();
|
|
196
173
|
}
|
|
197
|
-
|
|
198
174
|
return null;
|
|
199
175
|
}
|
|
200
176
|
|
|
201
177
|
/**
|
|
202
178
|
* Parse a project prefix string to its numeric value.
|
|
203
|
-
*
|
|
179
|
+
* Accepts a 6-character base26 string (a-z only).
|
|
204
180
|
* Returns the numeric project number or null if invalid.
|
|
205
181
|
*/
|
|
206
182
|
export function parseProjectPrefix(prefix: string): number | null {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
return parseInt(prefix, 10);
|
|
183
|
+
if (isBase26Prefix(prefix)) {
|
|
184
|
+
return decodeBase26(prefix);
|
|
210
185
|
}
|
|
211
|
-
|
|
212
|
-
// Try base36
|
|
213
|
-
if (isBase36Prefix(prefix)) {
|
|
214
|
-
return decodeBase36(prefix);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
186
|
return null;
|
|
218
187
|
}
|
|
219
188
|
|
|
220
189
|
/**
|
|
221
190
|
* Extract project name from a project path (without number prefix).
|
|
222
|
-
*
|
|
223
|
-
* E.g., "/Users/foo/RAF/001-my-project" -> "my-project"
|
|
224
|
-
* E.g., "/Users/foo/RAF/a00-my-project" -> "my-project"
|
|
191
|
+
* E.g., "/Users/foo/RAF/abcdef-my-project" -> "my-project"
|
|
225
192
|
* Returns the project name or null if not found.
|
|
226
193
|
*/
|
|
227
194
|
export function extractProjectName(projectPath: string): string | null {
|
|
228
195
|
const folderName = path.basename(projectPath);
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if (numericMatch && numericMatch[1]) {
|
|
233
|
-
return numericMatch[1];
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Try base36 format
|
|
237
|
-
const base36Match = folderName.match(/^[a-z][0-9a-z]{2}-(.+)$/i);
|
|
238
|
-
if (base36Match && base36Match[1]) {
|
|
239
|
-
return base36Match[1];
|
|
196
|
+
const match = folderName.match(/^[a-z]{6}-(.+)$/i);
|
|
197
|
+
if (match && match[1]) {
|
|
198
|
+
return match[1];
|
|
240
199
|
}
|
|
241
|
-
|
|
242
200
|
return null;
|
|
243
201
|
}
|
|
244
202
|
|
|
245
203
|
/**
|
|
246
204
|
* Extract task name from a plan filename (without number prefix and extension).
|
|
247
|
-
* E.g., "
|
|
205
|
+
* E.g., "02-fix-login-bug.md" -> "fix-login-bug"
|
|
248
206
|
* Returns the task name or null if not found.
|
|
249
207
|
*/
|
|
250
208
|
export function extractTaskNameFromPlanFile(planFilename: string): string | null {
|
|
251
209
|
const basename = path.basename(planFilename, '.md');
|
|
252
|
-
const match = basename.match(
|
|
210
|
+
const match = basename.match(/^[0-9a-z]{2}-(.+)$/);
|
|
253
211
|
return match && match[1] ? match[1] : null;
|
|
254
212
|
}
|
|
255
213
|
|
|
@@ -263,25 +221,13 @@ export function listProjects(rafDir: string): Array<{ number: number; name: stri
|
|
|
263
221
|
|
|
264
222
|
for (const entry of entries) {
|
|
265
223
|
if (entry.isDirectory()) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
projects.push({
|
|
270
|
-
number: parseInt(numericMatch[1], 10),
|
|
271
|
-
name: numericMatch[2],
|
|
272
|
-
path: path.join(rafDir, entry.name),
|
|
273
|
-
});
|
|
274
|
-
continue;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// Try base36 format
|
|
278
|
-
const base36Match = entry.name.match(/^([a-z][0-9a-z]{2})-(.+)$/i);
|
|
279
|
-
if (base36Match && base36Match[1] && base36Match[2]) {
|
|
280
|
-
const decoded = decodeBase36(base36Match[1].toLowerCase());
|
|
224
|
+
const match = entry.name.match(/^([a-z]{6})-(.+)$/i);
|
|
225
|
+
if (match && match[1] && match[2]) {
|
|
226
|
+
const decoded = decodeBase26(match[1].toLowerCase());
|
|
281
227
|
if (decoded !== null) {
|
|
282
228
|
projects.push({
|
|
283
229
|
number: decoded,
|
|
284
|
-
name:
|
|
230
|
+
name: match[2],
|
|
285
231
|
path: path.join(rafDir, entry.name),
|
|
286
232
|
});
|
|
287
233
|
}
|
|
@@ -336,25 +282,13 @@ function parseProjectFolder(
|
|
|
336
282
|
rafDir: string,
|
|
337
283
|
folderName: string
|
|
338
284
|
): { number: number; name: string; path: string; folder: string } | null {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
return {
|
|
343
|
-
number: parseInt(numericMatch[1], 10),
|
|
344
|
-
name: numericMatch[2],
|
|
345
|
-
path: path.join(rafDir, folderName),
|
|
346
|
-
folder: folderName,
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// Try base36 format
|
|
351
|
-
const base36Match = folderName.match(/^([a-z][0-9a-z]{2})-(.+)$/i);
|
|
352
|
-
if (base36Match && base36Match[1] && base36Match[2]) {
|
|
353
|
-
const decoded = decodeBase36(base36Match[1].toLowerCase());
|
|
285
|
+
const match = folderName.match(/^([a-z]{6})-(.+)$/i);
|
|
286
|
+
if (match && match[1] && match[2]) {
|
|
287
|
+
const decoded = decodeBase26(match[1].toLowerCase());
|
|
354
288
|
if (decoded !== null) {
|
|
355
289
|
return {
|
|
356
290
|
number: decoded,
|
|
357
|
-
name:
|
|
291
|
+
name: match[2],
|
|
358
292
|
path: path.join(rafDir, folderName),
|
|
359
293
|
folder: folderName,
|
|
360
294
|
};
|
|
@@ -368,14 +302,12 @@ function parseProjectFolder(
|
|
|
368
302
|
* Resolve a project identifier with detailed result including ambiguity detection.
|
|
369
303
|
*
|
|
370
304
|
* Supported identifier formats (checked in this order):
|
|
371
|
-
* 1. Full folder name (e.g., "
|
|
305
|
+
* 1. Full folder name (e.g., "abcdef-fix-stuff")
|
|
372
306
|
* - Must be an exact match to an existing folder
|
|
373
|
-
* - Pattern:
|
|
374
|
-
* 2.
|
|
375
|
-
* - Looks up by project number
|
|
376
|
-
* 3.
|
|
377
|
-
* - Looks up by base36 project number (for projects >= 1000)
|
|
378
|
-
* 4. Project name (e.g., "my-project", "fix-stuff")
|
|
307
|
+
* - Pattern: 6-char base26 prefix, followed by hyphen and name
|
|
308
|
+
* 2. Base26 prefix (e.g., "abcdef")
|
|
309
|
+
* - Looks up by decoded project number
|
|
310
|
+
* 3. Project name (e.g., "my-project", "fix-stuff")
|
|
379
311
|
* - Looks up by the name portion of the folder (after the prefix)
|
|
380
312
|
* - Case-insensitive matching
|
|
381
313
|
* - Returns error if multiple projects have the same name
|
|
@@ -392,14 +324,12 @@ export function resolveProjectIdentifierWithDetails(
|
|
|
392
324
|
return { path: null, error: 'not_found' };
|
|
393
325
|
}
|
|
394
326
|
|
|
395
|
-
// Pattern to match full folder names:
|
|
396
|
-
|
|
397
|
-
const fullFolderPattern = /^(\d{2,3}|[a-z][0-9a-z]{2})-(.+)$/i;
|
|
327
|
+
// Pattern to match full folder names: XXXXXX-name (6-char base26 prefix)
|
|
328
|
+
const fullFolderPattern = /^[a-z]{6}-(.+)$/i;
|
|
398
329
|
const fullFolderMatch = identifier.match(fullFolderPattern);
|
|
399
330
|
|
|
400
331
|
// Check if identifier is a full folder name (exact match required)
|
|
401
332
|
if (fullFolderMatch) {
|
|
402
|
-
// Check for exact case-insensitive match by listing directory
|
|
403
333
|
const entries = fs.readdirSync(rafDir, { withFileTypes: true });
|
|
404
334
|
for (const entry of entries) {
|
|
405
335
|
if (entry.isDirectory() && entry.name.toLowerCase() === identifier.toLowerCase()) {
|
|
@@ -407,22 +337,15 @@ export function resolveProjectIdentifierWithDetails(
|
|
|
407
337
|
}
|
|
408
338
|
}
|
|
409
339
|
// Full folder name format but doesn't exist as a folder.
|
|
410
|
-
// Fall through to name-based matching
|
|
411
|
-
// (e.g., "fix-double-summary-headers" looks like "fix-xxx" but is actually a name).
|
|
340
|
+
// Fall through to name-based matching.
|
|
412
341
|
}
|
|
413
342
|
|
|
414
|
-
// Check if it's a
|
|
415
|
-
const
|
|
343
|
+
// Check if it's a base26 identifier (e.g., "abcdef")
|
|
344
|
+
const isBase26 = isBase26Prefix(identifier);
|
|
416
345
|
|
|
417
|
-
// Check if it's a base36 identifier (e.g., "a00", "a01")
|
|
418
|
-
const isBase36 = isBase36Prefix(identifier);
|
|
419
|
-
|
|
420
|
-
// Convert base36 to numeric for matching
|
|
421
346
|
let targetNumber: number | null = null;
|
|
422
|
-
if (
|
|
423
|
-
targetNumber =
|
|
424
|
-
} else if (isBase36) {
|
|
425
|
-
targetNumber = decodeBase36(identifier);
|
|
347
|
+
if (isBase26) {
|
|
348
|
+
targetNumber = decodeBase26(identifier);
|
|
426
349
|
}
|
|
427
350
|
|
|
428
351
|
const entries = fs.readdirSync(rafDir, { withFileTypes: true });
|
|
@@ -433,16 +356,13 @@ export function resolveProjectIdentifierWithDetails(
|
|
|
433
356
|
const project = parseProjectFolder(rafDir, entry.name);
|
|
434
357
|
|
|
435
358
|
if (project) {
|
|
436
|
-
if (targetNumber !== null) {
|
|
437
|
-
// Match by number (
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
if (project.name.toLowerCase() === identifier.toLowerCase()) {
|
|
444
|
-
nameMatches.push(project);
|
|
445
|
-
}
|
|
359
|
+
if (targetNumber !== null && project.number === targetNumber) {
|
|
360
|
+
// Match by number (base26 identifier)
|
|
361
|
+
return { path: project.path };
|
|
362
|
+
}
|
|
363
|
+
// Also collect name matches (for fallback if number match fails)
|
|
364
|
+
if (project.name.toLowerCase() === identifier.toLowerCase()) {
|
|
365
|
+
nameMatches.push(project);
|
|
446
366
|
}
|
|
447
367
|
}
|
|
448
368
|
}
|
|
@@ -467,23 +387,18 @@ export function resolveProjectIdentifierWithDetails(
|
|
|
467
387
|
* Resolve a project identifier to a full project path.
|
|
468
388
|
*
|
|
469
389
|
* Supported identifier formats (checked in this order):
|
|
470
|
-
* 1. Full folder name (e.g., "
|
|
390
|
+
* 1. Full folder name (e.g., "abcdef-fix-stuff")
|
|
471
391
|
* - Must be an exact match to an existing folder
|
|
472
|
-
* - Pattern:
|
|
473
|
-
* 2.
|
|
474
|
-
* - Looks up by project number
|
|
475
|
-
* 3.
|
|
476
|
-
* - Looks up by base36 project number (for projects >= 1000)
|
|
477
|
-
* 4. Project name (e.g., "my-project", "fix-stuff")
|
|
392
|
+
* - Pattern: 6-char base26 prefix, followed by hyphen and name
|
|
393
|
+
* 2. Base26 prefix (e.g., "abcdef")
|
|
394
|
+
* - Looks up by decoded project number
|
|
395
|
+
* 3. Project name (e.g., "my-project", "fix-stuff")
|
|
478
396
|
* - Looks up by the name portion of the folder (after the prefix)
|
|
479
397
|
* - Case-insensitive matching
|
|
480
398
|
*
|
|
481
399
|
* Note: For ambiguity detection (multiple projects with same name), use
|
|
482
400
|
* resolveProjectIdentifierWithDetails instead.
|
|
483
401
|
*
|
|
484
|
-
* This function is designed to be extensible for future task-level references
|
|
485
|
-
* like "001-project/002-task".
|
|
486
|
-
*
|
|
487
402
|
* @param rafDir - The RAF directory containing project folders
|
|
488
403
|
* @param identifier - The identifier to resolve
|
|
489
404
|
* @returns The full project path or null if not found (or ambiguous)
|
|
@@ -36,8 +36,8 @@ function truncate(str: string, maxLength: number): string {
|
|
|
36
36
|
* @param status - Task status
|
|
37
37
|
* @param name - Task name
|
|
38
38
|
* @param elapsedMs - Optional elapsed time in milliseconds
|
|
39
|
-
* @param taskId - Optional task ID
|
|
40
|
-
* @returns Formatted string like "●
|
|
39
|
+
* @param taskId - Optional task ID prefix display
|
|
40
|
+
* @returns Formatted string like "● 001-auth-login 1:23" or "✓ 001-auth-login 1/5"
|
|
41
41
|
*/
|
|
42
42
|
export function formatTaskProgress(
|
|
43
43
|
current: number,
|
|
@@ -49,7 +49,7 @@ export function formatTaskProgress(
|
|
|
49
49
|
): string {
|
|
50
50
|
const symbol = SYMBOLS[status];
|
|
51
51
|
const displayName = truncate(name || 'task', 40);
|
|
52
|
-
const idPrefix = taskId ?
|
|
52
|
+
const idPrefix = taskId ? `${taskId}-` : '';
|
|
53
53
|
|
|
54
54
|
// Show elapsed time for running tasks, completed tasks, and failed tasks
|
|
55
55
|
if (elapsedMs !== undefined) {
|
package/src/utils/validation.ts
CHANGED
|
@@ -58,15 +58,8 @@ export function validateProjectExists(rafDir: string, projectName: string): stri
|
|
|
58
58
|
|
|
59
59
|
for (const entry of entries) {
|
|
60
60
|
if (entry.isDirectory()) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (numericMatch && numericMatch[1] === projectName) {
|
|
64
|
-
return path.join(rafDir, entry.name);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Match base36 pattern like "a00-project-name"
|
|
68
|
-
const base36Match = entry.name.match(/^[a-z][0-9a-z]{2}-(.+)$/i);
|
|
69
|
-
if (base36Match && base36Match[1] === projectName) {
|
|
61
|
+
const match = entry.name.match(/^[a-z]{6}-(.+)$/i);
|
|
62
|
+
if (match && match[1] === projectName) {
|
|
70
63
|
return path.join(rafDir, entry.name);
|
|
71
64
|
}
|
|
72
65
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { getAmendPrompt, AmendPromptParams } from '../../src/prompts/amend.js';
|
|
2
|
+
|
|
3
|
+
describe('Amend Prompt', () => {
|
|
4
|
+
const baseParams: AmendPromptParams = {
|
|
5
|
+
projectPath: '/test/project',
|
|
6
|
+
existingTasks: [
|
|
7
|
+
{
|
|
8
|
+
id: '01',
|
|
9
|
+
status: 'completed',
|
|
10
|
+
planFile: 'plans/01-setup.md',
|
|
11
|
+
taskName: 'setup',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
id: '02',
|
|
15
|
+
status: 'pending',
|
|
16
|
+
planFile: 'plans/02-feature.md',
|
|
17
|
+
taskName: 'feature',
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
nextTaskNumber: 3,
|
|
21
|
+
newTaskDescription: 'Add a new feature',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
describe('getAmendPrompt', () => {
|
|
25
|
+
it('should return systemPrompt and userMessage', () => {
|
|
26
|
+
const result = getAmendPrompt(baseParams);
|
|
27
|
+
|
|
28
|
+
expect(result).toHaveProperty('systemPrompt');
|
|
29
|
+
expect(result).toHaveProperty('userMessage');
|
|
30
|
+
expect(typeof result.systemPrompt).toBe('string');
|
|
31
|
+
expect(typeof result.userMessage).toBe('string');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should include project path in system prompt', () => {
|
|
35
|
+
const { systemPrompt } = getAmendPrompt(baseParams);
|
|
36
|
+
|
|
37
|
+
expect(systemPrompt).toContain('/test/project');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should include existing tasks in system prompt', () => {
|
|
41
|
+
const { systemPrompt } = getAmendPrompt(baseParams);
|
|
42
|
+
|
|
43
|
+
expect(systemPrompt).toContain('Task 01');
|
|
44
|
+
expect(systemPrompt).toContain('Task 02');
|
|
45
|
+
expect(systemPrompt).toContain('[COMPLETED]');
|
|
46
|
+
expect(systemPrompt).toContain('[PENDING]');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should show raf do without --worktree when worktreeMode is false', () => {
|
|
50
|
+
const params: AmendPromptParams = {
|
|
51
|
+
...baseParams,
|
|
52
|
+
worktreeMode: false,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const { systemPrompt } = getAmendPrompt(params);
|
|
56
|
+
|
|
57
|
+
expect(systemPrompt).toContain('raf do <project>');
|
|
58
|
+
expect(systemPrompt).not.toContain('--worktree');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should show raf do without --worktree when worktreeMode is undefined', () => {
|
|
62
|
+
const { systemPrompt } = getAmendPrompt(baseParams);
|
|
63
|
+
|
|
64
|
+
expect(systemPrompt).toContain('raf do <project>');
|
|
65
|
+
expect(systemPrompt).not.toContain('--worktree');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should show raf do with --worktree when worktreeMode is true', () => {
|
|
69
|
+
const params: AmendPromptParams = {
|
|
70
|
+
...baseParams,
|
|
71
|
+
worktreeMode: true,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const { systemPrompt } = getAmendPrompt(params);
|
|
75
|
+
|
|
76
|
+
expect(systemPrompt).toContain('raf do <project> --worktree');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should include new task description in user message', () => {
|
|
80
|
+
const { userMessage } = getAmendPrompt(baseParams);
|
|
81
|
+
|
|
82
|
+
expect(userMessage).toContain('Add a new feature');
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
});
|