rafcode 2.3.0 → 2.4.1-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.
Files changed (129) hide show
  1. package/.claude/settings.local.json +3 -1
  2. package/CLAUDE.md +21 -4
  3. package/RAF/ahvrih-rate-forge/decisions.md +70 -0
  4. package/RAF/ahvrih-rate-forge/input.md +44 -0
  5. package/RAF/ahvrih-rate-forge/outcomes/01-remove-claude-command-config.md +58 -0
  6. package/RAF/ahvrih-rate-forge/outcomes/02-fix-mixed-attempt-cost.md +46 -0
  7. package/RAF/ahvrih-rate-forge/outcomes/03-rate-limit-estimation.md +82 -0
  8. package/RAF/ahvrih-rate-forge/outcomes/04-show-version-in-do-logs.md +45 -0
  9. package/RAF/ahvrih-rate-forge/outcomes/05-sync-main-before-worktree.md +96 -0
  10. package/RAF/ahvrih-rate-forge/outcomes/06-sync-readme-with-codebase.md +45 -0
  11. package/RAF/ahvrih-rate-forge/outcomes/07-no-session-persistence.md +26 -0
  12. package/RAF/ahvrih-rate-forge/outcomes/08-plan-execution-metadata.md +130 -0
  13. package/RAF/ahvrih-rate-forge/plans/01-remove-claude-command-config.md +36 -0
  14. package/RAF/ahvrih-rate-forge/plans/02-fix-mixed-attempt-cost.md +33 -0
  15. package/RAF/ahvrih-rate-forge/plans/03-rate-limit-estimation.md +82 -0
  16. package/RAF/ahvrih-rate-forge/plans/04-show-version-in-do-logs.md +32 -0
  17. package/RAF/ahvrih-rate-forge/plans/05-sync-main-before-worktree.md +40 -0
  18. package/RAF/ahvrih-rate-forge/plans/06-sync-readme-with-codebase.md +61 -0
  19. package/RAF/ahvrih-rate-forge/plans/07-no-session-persistence.md +28 -0
  20. package/RAF/ahvrih-rate-forge/plans/08-plan-execution-metadata.md +123 -0
  21. package/RAF/ahwidh-quick-fix-gremlin/decisions.md +37 -0
  22. package/RAF/ahwidh-quick-fix-gremlin/input.md +35 -0
  23. package/RAF/ahwidh-quick-fix-gremlin/outcomes/01-fix-name-generation-prompt.md +33 -0
  24. package/RAF/ahwidh-quick-fix-gremlin/outcomes/02-fix-amend-commit-scope.md +43 -0
  25. package/RAF/ahwidh-quick-fix-gremlin/outcomes/03-fix-diverged-main-branch-sync.md +32 -0
  26. package/RAF/ahwidh-quick-fix-gremlin/outcomes/04-wire-rate-limit-to-do-command.md +61 -0
  27. package/RAF/ahwidh-quick-fix-gremlin/outcomes/05-add-config-get-set-flags.md +125 -0
  28. package/RAF/ahwidh-quick-fix-gremlin/outcomes/06-sync-worktree-branch-before-execution.md +96 -0
  29. package/RAF/ahwidh-quick-fix-gremlin/outcomes/07-update-frontmatter-format.md +107 -0
  30. package/RAF/ahwidh-quick-fix-gremlin/outcomes/08-remove-plan-token-report.md +76 -0
  31. package/RAF/ahwidh-quick-fix-gremlin/plans/01-fix-name-generation-prompt.md +52 -0
  32. package/RAF/ahwidh-quick-fix-gremlin/plans/02-fix-amend-commit-scope.md +48 -0
  33. package/RAF/ahwidh-quick-fix-gremlin/plans/03-fix-diverged-main-branch-sync.md +49 -0
  34. package/RAF/ahwidh-quick-fix-gremlin/plans/04-wire-rate-limit-to-do-command.md +78 -0
  35. package/RAF/ahwidh-quick-fix-gremlin/plans/05-add-config-get-set-flags.md +101 -0
  36. package/RAF/ahwidh-quick-fix-gremlin/plans/06-sync-worktree-branch-before-execution.md +92 -0
  37. package/RAF/ahwidh-quick-fix-gremlin/plans/07-update-frontmatter-format.md +105 -0
  38. package/RAF/ahwidh-quick-fix-gremlin/plans/08-remove-plan-token-report.md +50 -0
  39. package/README.md +27 -7
  40. package/dist/commands/config.d.ts.map +1 -1
  41. package/dist/commands/config.js +209 -6
  42. package/dist/commands/config.js.map +1 -1
  43. package/dist/commands/do.d.ts.map +1 -1
  44. package/dist/commands/do.js +140 -21
  45. package/dist/commands/do.js.map +1 -1
  46. package/dist/commands/plan.d.ts.map +1 -1
  47. package/dist/commands/plan.js +27 -5
  48. package/dist/commands/plan.js.map +1 -1
  49. package/dist/core/claude-runner.d.ts +0 -6
  50. package/dist/core/claude-runner.d.ts.map +1 -1
  51. package/dist/core/claude-runner.js +4 -9
  52. package/dist/core/claude-runner.js.map +1 -1
  53. package/dist/core/failure-analyzer.d.ts.map +1 -1
  54. package/dist/core/failure-analyzer.js +3 -3
  55. package/dist/core/failure-analyzer.js.map +1 -1
  56. package/dist/core/pull-request.js +3 -3
  57. package/dist/core/pull-request.js.map +1 -1
  58. package/dist/core/state-derivation.d.ts +5 -0
  59. package/dist/core/state-derivation.d.ts.map +1 -1
  60. package/dist/core/state-derivation.js +14 -4
  61. package/dist/core/state-derivation.js.map +1 -1
  62. package/dist/core/worktree.d.ts +44 -0
  63. package/dist/core/worktree.d.ts.map +1 -1
  64. package/dist/core/worktree.js +247 -0
  65. package/dist/core/worktree.js.map +1 -1
  66. package/dist/prompts/amend.d.ts.map +1 -1
  67. package/dist/prompts/amend.js +28 -11
  68. package/dist/prompts/amend.js.map +1 -1
  69. package/dist/prompts/planning.d.ts.map +1 -1
  70. package/dist/prompts/planning.js +28 -11
  71. package/dist/prompts/planning.js.map +1 -1
  72. package/dist/types/config.d.ts +30 -13
  73. package/dist/types/config.d.ts.map +1 -1
  74. package/dist/types/config.js +14 -10
  75. package/dist/types/config.js.map +1 -1
  76. package/dist/utils/config.d.ts +47 -4
  77. package/dist/utils/config.d.ts.map +1 -1
  78. package/dist/utils/config.js +176 -30
  79. package/dist/utils/config.js.map +1 -1
  80. package/dist/utils/frontmatter.d.ts +53 -0
  81. package/dist/utils/frontmatter.d.ts.map +1 -0
  82. package/dist/utils/frontmatter.js +115 -0
  83. package/dist/utils/frontmatter.js.map +1 -0
  84. package/dist/utils/name-generator.d.ts.map +1 -1
  85. package/dist/utils/name-generator.js +9 -19
  86. package/dist/utils/name-generator.js.map +1 -1
  87. package/dist/utils/session-parser.d.ts +44 -0
  88. package/dist/utils/session-parser.d.ts.map +1 -0
  89. package/dist/utils/session-parser.js +122 -0
  90. package/dist/utils/session-parser.js.map +1 -0
  91. package/dist/utils/terminal-symbols.d.ts +22 -3
  92. package/dist/utils/terminal-symbols.d.ts.map +1 -1
  93. package/dist/utils/terminal-symbols.js +52 -18
  94. package/dist/utils/terminal-symbols.js.map +1 -1
  95. package/dist/utils/token-tracker.d.ts +20 -0
  96. package/dist/utils/token-tracker.d.ts.map +1 -1
  97. package/dist/utils/token-tracker.js +57 -2
  98. package/dist/utils/token-tracker.js.map +1 -1
  99. package/package.json +1 -1
  100. package/src/commands/config.ts +242 -7
  101. package/src/commands/do.ts +177 -23
  102. package/src/commands/plan.ts +27 -4
  103. package/src/core/claude-runner.ts +4 -16
  104. package/src/core/failure-analyzer.ts +3 -3
  105. package/src/core/pull-request.ts +3 -3
  106. package/src/core/state-derivation.ts +20 -4
  107. package/src/core/worktree.ts +266 -0
  108. package/src/prompts/amend.ts +28 -11
  109. package/src/prompts/config-docs.md +91 -29
  110. package/src/prompts/planning.ts +28 -11
  111. package/src/types/config.ts +46 -21
  112. package/src/utils/config.ts +200 -33
  113. package/src/utils/frontmatter.ts +140 -0
  114. package/src/utils/name-generator.ts +9 -19
  115. package/src/utils/terminal-symbols.ts +68 -16
  116. package/src/utils/token-tracker.ts +65 -2
  117. package/tests/unit/claude-runner-interactive.test.ts +8 -6
  118. package/tests/unit/claude-runner.test.ts +5 -66
  119. package/tests/unit/commit-planning-artifacts-worktree.test.ts +6 -14
  120. package/tests/unit/commit-planning-artifacts.test.ts +4 -12
  121. package/tests/unit/config-command.test.ts +176 -6
  122. package/tests/unit/config.test.ts +268 -45
  123. package/tests/unit/frontmatter.test.ts +276 -0
  124. package/tests/unit/name-generator.test.ts +1 -1
  125. package/tests/unit/post-execution-picker.test.ts +6 -0
  126. package/tests/unit/terminal-symbols.test.ts +142 -0
  127. package/tests/unit/token-tracker.test.ts +304 -1
  128. package/tests/unit/validation.test.ts +6 -4
  129. package/tests/unit/worktree.test.ts +309 -0
@@ -0,0 +1,48 @@
1
+ effort: low
2
+ ---
3
+ # Task: Fix amend mode commit to exclude plan files
4
+
5
+ ## Objective
6
+ Change the amend commit to only include `input.md` and `decisions.md`, not the new plan files.
7
+
8
+ ## Context
9
+ In `raf plan --amend`, the commit includes new plan files alongside `input.md` and `decisions.md`. Plan files should be committed by Claude during task execution instead, matching how initial planning only commits `input.md` and `decisions.md`.
10
+
11
+ ## Requirements
12
+ - Remove `additionalFiles: newPlanPaths` from the amend commit call
13
+ - Keep the `isAmend: true` flag (commit message should still use "Amend:" prefix)
14
+ - Initial planning commit behavior must remain unchanged
15
+
16
+ ## Implementation Steps
17
+
18
+ 1. **Edit `src/commands/plan.ts`** at lines 650-656. Change:
19
+ ```typescript
20
+ // Commit planning artifacts (input.md, decisions.md, and new plan files)
21
+ const newPlanPaths = newPlanFiles.map(f => path.join(plansDir, f));
22
+ await commitPlanningArtifacts(projectPath, {
23
+ cwd: worktreePath ?? undefined,
24
+ additionalFiles: newPlanPaths,
25
+ isAmend: true,
26
+ });
27
+ ```
28
+ To:
29
+ ```typescript
30
+ // Commit planning artifacts (input.md, decisions.md only — plan files committed during execution)
31
+ await commitPlanningArtifacts(projectPath, {
32
+ cwd: worktreePath ?? undefined,
33
+ isAmend: true,
34
+ });
35
+ ```
36
+ Remove the `newPlanPaths` variable as well since it's no longer used.
37
+
38
+ 2. **Update tests** — Check `tests/unit/commit-planning-artifacts.test.ts` and `tests/unit/commit-planning-artifacts-worktree.test.ts` for any amend-specific tests that assert plan files are committed. Update them to verify plan files are NOT included.
39
+
40
+ ## Acceptance Criteria
41
+ - [ ] Amend commit only stages `input.md` and `decisions.md`
42
+ - [ ] `additionalFiles` is not passed in the amend code path
43
+ - [ ] Initial planning commit behavior unchanged
44
+ - [ ] Existing tests updated and passing
45
+
46
+ ## Notes
47
+ - The `commitPlanningArtifacts` function itself doesn't need changes — just stop passing `additionalFiles` from the amend caller
48
+ - The `additionalFiles` parameter on `commitPlanningArtifacts` can remain in the interface for future use
@@ -0,0 +1,49 @@
1
+ effort: low
2
+ ---
3
+ # Task: Fix diverged main branch sync to report failure
4
+
5
+ ## Objective
6
+ Change `pullMainBranch()` to return `success: false` when the local main branch has diverged from remote, so callers surface the issue as a warning.
7
+
8
+ ## Context
9
+ PR #5 review comment: When `git fetch origin main:main` fails because local main has diverged, the code falls back to `git fetch origin main` and returns `success: true` with an `error` message. Callers only check `success === false` to warn, so the divergence is silently ignored. Worktree/PR flows then proceed on stale base refs.
10
+
11
+ The fix: return `success: false` so callers show the warning. Per user decision, this should be a visible warning that lets execution continue (not a hard error).
12
+
13
+ ## Requirements
14
+ - Change `success: true` to `success: false` in the diverged branch path
15
+ - Callers already handle `success: false` with `logger.warn()` — no caller changes needed
16
+ - The plain `git fetch origin main` should still run (we still want the remote ref updated)
17
+
18
+ ## Implementation Steps
19
+
20
+ 1. **Edit `src/core/worktree.ts`** at lines 533-538. Change:
21
+ ```typescript
22
+ return {
23
+ success: true,
24
+ mainBranch,
25
+ hadChanges: false,
26
+ error: `Local ${mainBranch} has diverged from origin, not updated`,
27
+ };
28
+ ```
29
+ To:
30
+ ```typescript
31
+ return {
32
+ success: false,
33
+ mainBranch,
34
+ hadChanges: false,
35
+ error: `Local ${mainBranch} has diverged from origin, not updated`,
36
+ };
37
+ ```
38
+
39
+ 2. **Update tests** — Find tests for `pullMainBranch` (likely in `tests/unit/worktree.test.ts`) and update the diverged branch test case to assert `success: false`.
40
+
41
+ ## Acceptance Criteria
42
+ - [ ] Diverged branch path returns `success: false`
43
+ - [ ] Callers show a warning via `logger.warn()` (already happens for `success: false`)
44
+ - [ ] Execution continues after the warning (callers don't abort on sync failure)
45
+ - [ ] Tests updated and passing
46
+
47
+ ## Notes
48
+ - The second `git fetch origin main` (plain fetch) still runs successfully — it updates `origin/main` remote ref even though local `main` isn't updated. This is fine.
49
+ - Callers in `do.ts` (line 243-250) and `plan.ts` already have the pattern: `if (!syncResult.success) { logger.warn(...) }` — no changes needed there.
@@ -0,0 +1,78 @@
1
+ effort: low
2
+ ---
3
+ # Task: Wire rate-limit estimate display config to do command
4
+
5
+ ## Objective
6
+ Pass the `display` config settings (`showRateLimitEstimate`, `showCacheTokens`) through to `formatTaskTokenSummary()` and `formatTokenTotalSummary()` calls in the do command.
7
+
8
+ ## Context
9
+ PR #5 review comment: The formatter defaults `showRateLimitEstimate` to `false` in its destructuring, but `raf do` calls both formatters without passing `TokenSummaryOptions`. Despite `display.showRateLimitEstimate` defaulting to `true` in config, the feature is effectively dead code.
10
+
11
+ ## Requirements
12
+ - Read display config settings and pass them as `TokenSummaryOptions` to both formatters
13
+ - Calculate and pass `rateLimitPercentage` from `TokenTracker`
14
+ - Per-task summaries should show cumulative rate limit percentage
15
+ - Grand total summary should show the final cumulative percentage
16
+
17
+ ## Implementation Steps
18
+
19
+ 1. **Edit `src/commands/do.ts`** — Build `TokenSummaryOptions` from config and pass to formatters.
20
+
21
+ Near the top of `runDoCommand()` (after tokenTracker is created), import and read display config:
22
+ ```typescript
23
+ import { getShowRateLimitEstimate, getShowCacheTokens } from '../utils/config.js';
24
+ ```
25
+
26
+ 2. **Update per-task token display** (lines 1218-1220 and 1246-1248). Change both locations from:
27
+ ```typescript
28
+ logger.dim(formatTaskTokenSummary(entry, (u) => tokenTracker.calculateCost(u)));
29
+ ```
30
+ To:
31
+ ```typescript
32
+ const taskRateLimitPct = tokenTracker.getCumulativeRateLimitPercentage();
33
+ logger.dim(formatTaskTokenSummary(entry, (u) => tokenTracker.calculateCost(u), {
34
+ showCacheTokens: getShowCacheTokens(),
35
+ showRateLimitEstimate: getShowRateLimitEstimate(),
36
+ rateLimitPercentage: taskRateLimitPct,
37
+ }));
38
+ ```
39
+
40
+ 3. **Update grand total display** (lines 1360-1361). Change from:
41
+ ```typescript
42
+ logger.dim(formatTokenTotalSummary(totals.usage, totals.cost));
43
+ ```
44
+ To:
45
+ ```typescript
46
+ const totalRateLimitPct = tokenTracker.getCumulativeRateLimitPercentage();
47
+ logger.dim(formatTokenTotalSummary(totals.usage, totals.cost, {
48
+ showCacheTokens: getShowCacheTokens(),
49
+ showRateLimitEstimate: getShowRateLimitEstimate(),
50
+ rateLimitPercentage: totalRateLimitPct,
51
+ }));
52
+ ```
53
+
54
+ 4. **Update the default value** in `formatTokenTotalSummary` (line 258 of `terminal-symbols.ts`). Change:
55
+ ```typescript
56
+ const { showCacheTokens = true, showRateLimitEstimate = false, rateLimitPercentage } = options;
57
+ ```
58
+ To:
59
+ ```typescript
60
+ const { showCacheTokens = true, showRateLimitEstimate = true, rateLimitPercentage } = options;
61
+ ```
62
+ This makes the default behavior match the config default (`display.showRateLimitEstimate: true`), so any callers that don't pass options still get the feature.
63
+
64
+ Also update `formatTokenLine` if it has a similar default for `showRateLimitEstimate`.
65
+
66
+ 5. **Update tests** — Adjust any test expectations that rely on `showRateLimitEstimate` defaulting to `false`.
67
+
68
+ ## Acceptance Criteria
69
+ - [ ] Per-task token summaries show rate limit percentage when `display.showRateLimitEstimate` is `true`
70
+ - [ ] Grand total summary shows rate limit percentage
71
+ - [ ] Setting `display.showRateLimitEstimate: false` in config suppresses the display
72
+ - [ ] `display.showCacheTokens` config is also wired through
73
+ - [ ] Tests pass
74
+
75
+ ## Notes
76
+ - The `TokenTracker.getCumulativeRateLimitPercentage()` method already exists and works correctly
77
+ - The `getShowRateLimitEstimate()` and `getShowCacheTokens()` config helpers already exist in `src/utils/config.ts`
78
+ - All the pieces are in place — this task just wires them together
@@ -0,0 +1,101 @@
1
+ effort: medium
2
+ ---
3
+ # Task: Add --get and --set flags to raf config
4
+
5
+ ## Objective
6
+ Add `raf config --get [key]` and `raf config --set <key> <value>` for quick config viewing/editing without launching the interactive Claude wizard.
7
+
8
+ ## Context
9
+ Currently `raf config` always launches an interactive Claude session (Sonnet). For quick operations like checking a single value or changing a model, this is slow and expensive. The `--get` and `--set` flags provide instant, non-interactive alternatives.
10
+
11
+ ## Requirements
12
+ - `raf config --get` (no key): Print full merged config as JSON (defaults + overrides)
13
+ - `raf config --get models.plan`: Print plain value (e.g., `opus`) — no key prefix, no quotes for strings
14
+ - `raf config --set models.plan sonnet`: Set a leaf-level config value
15
+ - Only support leaf-level keys (dot-notation like `models.plan`, `timeout`, `display.showRateLimitEstimate`)
16
+ - Do NOT support setting entire nested objects (e.g., `--set models '{...}'`)
17
+ - If `--get` or `--set` is present, do NOT launch the interactive wizard
18
+ - If value matches default after `--set`, remove the key from config file (keep config minimal)
19
+ - If removing the last key from a section empties it, remove the section too
20
+ - Validate the value before saving (use existing validation)
21
+ - `--set` and `--get` are mutually exclusive; show error if both provided
22
+ - `--reset` takes precedence / is mutually exclusive with `--get`/`--set`
23
+
24
+ ## Implementation Steps
25
+
26
+ 1. **Edit `src/commands/config.ts`** — Add new options to the command:
27
+ ```typescript
28
+ .option('--get [key]', 'Show config value (all config if no key, or specific dot-notation key)')
29
+ .option('--set <key> <value>', 'Set a config value using dot-notation key')
30
+ ```
31
+ Note: Commander.js handles `--set key value` with two arguments. You may need to use `.option('--set <key_value...>')` or handle it as a positional pair. Consider using a variadic option that takes exactly 2 values.
32
+
33
+ 2. **Update the `ConfigCommandOptions` interface**:
34
+ ```typescript
35
+ interface ConfigCommandOptions {
36
+ reset?: boolean;
37
+ get?: true | string; // true when --get with no key, string when --get <key>
38
+ set?: string[]; // [key, value]
39
+ }
40
+ ```
41
+
42
+ 3. **Update the action handler** to check for `--get`/`--set` before launching the wizard:
43
+ ```typescript
44
+ if (options.reset) { await handleReset(); return; }
45
+ if (options.get !== undefined) { handleGet(options.get); return; }
46
+ if (options.set) { handleSet(options.set); return; }
47
+ // ... existing wizard launch
48
+ ```
49
+
50
+ 4. **Implement `handleGet(key?: string | true)`**:
51
+ - If `key` is `true` (no argument): Print `JSON.stringify(resolveConfig(), null, 2)`
52
+ - If `key` is a string: Use dot-notation to traverse the resolved config object
53
+ - Print the value: strings plain, numbers/booleans as-is, objects as JSON
54
+ - If key not found, print error and exit with code 1
55
+
56
+ 5. **Implement `handleSet(args: string[])`**:
57
+ - Parse `args` as `[key, value]`
58
+ - Read the current user config file (or start with `{}`)
59
+ - Parse the value: try `JSON.parse(value)` first (for numbers, booleans), fall back to string
60
+ - Use dot-notation to set the leaf value in the user config object
61
+ - Check if the value matches the default at that path — if so, remove the key instead
62
+ - If removing leaves an empty parent object, remove the parent too
63
+ - Validate the resulting config with `validateConfig()`
64
+ - Save with `saveConfig()`
65
+ - If config becomes empty `{}`, delete the file entirely
66
+ - Print confirmation message
67
+
68
+ 6. **Add helper functions**:
69
+ - `getNestedValue(obj, dotPath)` — traverse an object by dot-notation path
70
+ - `setNestedValue(obj, dotPath, value)` — set a leaf value by dot-notation path
71
+ - `deleteNestedValue(obj, dotPath)` — remove a leaf and clean up empty parents
72
+ - `getDefaultValue(dotPath)` — get the default value at a dot-notation path from `DEFAULT_CONFIG`
73
+
74
+ 7. **Add tests** in `tests/unit/config-command.test.ts` (or update existing):
75
+ - `--get` with no key returns full config JSON
76
+ - `--get models.plan` returns just the value
77
+ - `--get nonexistent.key` exits with error
78
+ - `--set models.plan sonnet` updates the config file
79
+ - `--set timeout 120` parses as number
80
+ - `--set autoCommit false` parses as boolean
81
+ - `--set models.plan opus` (default value) removes the key from file
82
+ - Setting last key in section removes the section
83
+ - Validation errors are reported
84
+
85
+ ## Acceptance Criteria
86
+ - [ ] `raf config --get` prints full merged config as formatted JSON
87
+ - [ ] `raf config --get models.plan` prints plain value (e.g., `opus`)
88
+ - [ ] `raf config --set models.plan sonnet` updates config file
89
+ - [ ] Setting value to default removes it from config file
90
+ - [ ] Empty sections cleaned up after removal
91
+ - [ ] Value parsing handles strings, numbers, and booleans
92
+ - [ ] Invalid keys/values show clear error messages
93
+ - [ ] Interactive wizard NOT launched when --get or --set is present
94
+ - [ ] Tests pass
95
+
96
+ ## Notes
97
+ - The `resolveConfig()` function already merges defaults + overrides, perfect for `--get`
98
+ - The `saveConfig()` function already handles file creation and formatting
99
+ - The `validateConfig()` function validates the entire user config, so validate after modification
100
+ - For `--get`, use the resolved (merged) config; for `--set`, read/write only the user config file
101
+ - Commander.js variadic options: `--set <key> <value>` can be done with `.option('--set <items...>')` which collects remaining args
@@ -0,0 +1,92 @@
1
+ effort: medium
2
+ ---
3
+ # Task: Sync worktree branch with main before execution
4
+
5
+ ## Objective
6
+ Before executing tasks in a worktree, rebase the worktree branch onto the latest main branch to ensure it's up-to-date.
7
+
8
+ ## Dependencies
9
+ 03
10
+
11
+ ## Context
12
+ When using `raf do` in worktree mode, the worktree branch may be behind main (e.g., if other worktree projects were merged into main since this branch was created). Rebasing before execution ensures the branch starts from the latest main, reducing merge conflicts later.
13
+
14
+ ## Requirements
15
+ - After `pullMainBranch()` syncs main, rebase the worktree branch onto main
16
+ - Only do this in worktree mode in `raf do`
17
+ - If rebase has conflicts: abort the rebase, show a warning, and continue execution without sync
18
+ - The rebase should happen after worktree project selection but before task execution begins
19
+ - Respect the `syncMainBranch` config setting — skip if disabled
20
+
21
+ ## Implementation Steps
22
+
23
+ 1. **Add a `rebaseOntoMain` function to `src/core/worktree.ts`**:
24
+ ```typescript
25
+ export interface RebaseResult {
26
+ success: boolean;
27
+ error?: string;
28
+ }
29
+
30
+ export function rebaseOntoMain(mainBranch: string, cwd: string): RebaseResult {
31
+ try {
32
+ execSync(`git rebase ${mainBranch}`, {
33
+ encoding: 'utf-8',
34
+ stdio: 'pipe',
35
+ cwd,
36
+ });
37
+ return { success: true };
38
+ } catch (error) {
39
+ // Abort the failed rebase to restore clean state
40
+ try {
41
+ execSync('git rebase --abort', {
42
+ encoding: 'utf-8',
43
+ stdio: 'pipe',
44
+ cwd,
45
+ });
46
+ } catch {
47
+ // Ignore abort errors
48
+ }
49
+ const msg = error instanceof Error ? error.message : String(error);
50
+ return { success: false, error: msg };
51
+ }
52
+ }
53
+ ```
54
+
55
+ 2. **Edit `src/commands/do.ts`** — Add the rebase step after `pullMainBranch()` in the worktree mode section (after line 251, before task execution). The rebase should run inside the worktree directory:
56
+ ```typescript
57
+ // After pullMainBranch sync and worktree project selection...
58
+ // Rebase worktree branch onto main before execution
59
+ if (getSyncMainBranch() && worktreeCwd) {
60
+ const mainBranch = syncResult?.mainBranch ?? detectMainBranch();
61
+ if (mainBranch) {
62
+ const rebaseResult = rebaseOntoMain(mainBranch, worktreeCwd);
63
+ if (rebaseResult.success) {
64
+ logger.info(`Rebased onto ${mainBranch}`);
65
+ } else {
66
+ logger.warn(`Could not rebase onto ${mainBranch}: ${rebaseResult.error}`);
67
+ logger.warn('Continuing with current branch state.');
68
+ }
69
+ }
70
+ }
71
+ ```
72
+ Note: The exact placement depends on where `worktreeCwd` is set. Find the right location — it should be after the worktree is validated/created and `worktreeCwd` is determined, but before the task execution loop begins.
73
+
74
+ 3. **Determine the main branch name** — The `pullMainBranch()` result includes `mainBranch`. Store it so it can be used for the rebase. If `pullMainBranch()` wasn't called (syncMainBranch disabled), you can detect main branch with the existing `detectMainBranch()` utility from `worktree.ts`.
75
+
76
+ 4. **Add tests** for the new `rebaseOntoMain` function:
77
+ - Successful rebase
78
+ - Rebase with conflicts → aborts and returns failure
79
+ - Verify `git rebase --abort` is called on failure
80
+
81
+ ## Acceptance Criteria
82
+ - [ ] Worktree branch is rebased onto main before task execution
83
+ - [ ] Conflicts cause rebase abort + warning, execution continues
84
+ - [ ] Rebase only happens in worktree mode
85
+ - [ ] Respects `syncMainBranch` config setting
86
+ - [ ] Main branch name correctly determined from sync result or detection
87
+ - [ ] Tests pass
88
+
89
+ ## Notes
90
+ - The rebase should use the local main branch ref (which was just synced by `pullMainBranch`)
91
+ - If `pullMainBranch` failed (e.g., diverged — now returns `success: false` after task 03), the rebase should still attempt using whatever local main is available
92
+ - This runs in the worktree directory (`cwd`), not the main repo
@@ -0,0 +1,105 @@
1
+ ---
2
+ effort: medium
3
+ ---
4
+ # Task: Update plan frontmatter to standard Obsidian format
5
+
6
+ ## Objective
7
+ Change the plan file frontmatter format from closing-delimiter-only to standard Obsidian/YAML frontmatter with both opening and closing `---` delimiters.
8
+
9
+ ## Context
10
+ Currently plan files use a non-standard format with only a closing `---`:
11
+ ```
12
+ effort: medium
13
+ ---
14
+ # Task: ...
15
+ ```
16
+
17
+ Standard Obsidian (and Jekyll/Hugo/etc.) frontmatter uses `---` on both top and bottom:
18
+ ```
19
+ ---
20
+ effort: medium
21
+ ---
22
+ # Task: ...
23
+ ```
24
+
25
+ This change aligns RAF with the widely-used standard format, improving compatibility with Obsidian and other markdown tools.
26
+
27
+ ## Requirements
28
+ - Update the frontmatter parser to support the standard `---`/`---` format
29
+ - Also keep backward compatibility with the old closing-only format (existing plan files should still parse)
30
+ - Update all prompts that instruct Claude to generate frontmatter
31
+ - Update CLAUDE.md documentation
32
+ - Update existing plan files in this project to use the new format (if any are being generated)
33
+
34
+ ## Implementation Steps
35
+
36
+ 1. **Edit `src/utils/frontmatter.ts`** — Update `parsePlanFrontmatter()` to handle both formats:
37
+ - Check if content starts with `---` (after optional leading whitespace/newline)
38
+ - If it does: standard format — find the closing `---` after it, extract content between the two delimiters
39
+ - If it doesn't: legacy format — find the first `---` and treat everything before it as frontmatter (current behavior)
40
+
41
+ Updated parsing logic:
42
+ ```typescript
43
+ export function parsePlanFrontmatter(content: string): FrontmatterParseResult {
44
+ const result: FrontmatterParseResult = { frontmatter: {}, hasFrontmatter: false, warnings: [] };
45
+ const trimmedContent = content.trimStart();
46
+
47
+ let frontmatterSection: string;
48
+
49
+ if (trimmedContent.startsWith('---')) {
50
+ // Standard format: ---\nkey: value\n---
51
+ const afterOpener = trimmedContent.substring(3);
52
+ // Skip the rest of the opener line (handles "---\n" or "--- \n")
53
+ const openerEnd = afterOpener.indexOf('\n');
54
+ if (openerEnd === -1) return result;
55
+ const rest = afterOpener.substring(openerEnd + 1);
56
+ const closerIndex = rest.indexOf('---');
57
+ if (closerIndex === -1) return result;
58
+ frontmatterSection = rest.substring(0, closerIndex);
59
+ } else {
60
+ // Legacy format: key: value\n---
61
+ const delimiterIndex = content.indexOf('---');
62
+ if (delimiterIndex === -1) return result;
63
+ frontmatterSection = content.substring(0, delimiterIndex);
64
+ }
65
+
66
+ // ... rest of key: value parsing remains the same
67
+ }
68
+ ```
69
+
70
+ 2. **Update prompts** — Edit these files to show the new format with opening `---`:
71
+ - `src/prompts/planning.ts` — Update the frontmatter example/instructions
72
+ - `src/prompts/amend.ts` — Same update
73
+ - Search for any other prompts that reference frontmatter format
74
+
75
+ 3. **Update CLAUDE.md** — Change the plan file format documentation from:
76
+ ```
77
+ effort: medium
78
+ ---
79
+ ```
80
+ To:
81
+ ```
82
+ ---
83
+ effort: medium
84
+ ---
85
+ ```
86
+
87
+ 4. **Update tests** in `tests/unit/frontmatter.test.ts`:
88
+ - Add tests for the new standard format (opening + closing `---`)
89
+ - Keep tests for legacy format (closing only) to verify backward compatibility
90
+ - Test edge cases: extra whitespace before opening `---`, empty frontmatter block (`---\n---`)
91
+
92
+ 5. **Update this project's planning prompt** — The system prompt at the top of this conversation also references the frontmatter format. This is injected by RAF, so updating the prompts in step 2 covers future projects.
93
+
94
+ ## Acceptance Criteria
95
+ - [ ] Parser handles standard `---`/`---` format correctly
96
+ - [ ] Parser still handles legacy closing-only format (backward compatibility)
97
+ - [ ] Planning prompts generate the new standard format
98
+ - [ ] CLAUDE.md documentation updated
99
+ - [ ] Tests cover both old and new formats
100
+ - [ ] All existing tests pass
101
+
102
+ ## Notes
103
+ - Backward compatibility is important since existing projects have plan files in the old format
104
+ - The parser should be robust: handle `---` with trailing spaces, `---` with trailing content on the same line, etc.
105
+ - Obsidian treats `---` at the very start of a file as YAML frontmatter — this is the standard we're adopting
@@ -0,0 +1,50 @@
1
+ effort: low
2
+ ---
3
+ # Task: Remove Token Report from Plan Command
4
+
5
+ ## Objective
6
+ Remove all token usage reporting from `raf plan` and `raf plan --amend`, including the session-parser module that only exists to support this feature.
7
+
8
+ ## Context
9
+ The token report shown after planning sessions is not useful — planning is an interactive session where token cost is less relevant than during automated task execution. Removing it simplifies the plan command and eliminates dead code.
10
+
11
+ ## Requirements
12
+ - Remove token reporting from both `runPlanCommand()` and `runAmendCommand()` in `src/commands/plan.ts`
13
+ - Delete the `displayPlanSessionTokenSummary()` function entirely
14
+ - Delete `src/utils/session-parser.ts` (only consumer is the plan command)
15
+ - Delete `tests/unit/session-parser.test.ts`
16
+ - Remove the `sessionId` parameter from `claudeRunner.runInteractive()` in `src/core/claude-runner.ts` (no other callers use it)
17
+ - Clean up all unused imports in affected files
18
+
19
+ ## Implementation Steps
20
+
21
+ 1. **Edit `src/commands/plan.ts`:**
22
+ - Remove imports: `TokenTracker`, `formatTokenTotalSummary`, `TokenSummaryOptions`, `parseSessionById`, `crypto`
23
+ - Remove `getDisplayConfig` and `getPricingConfig` from the config import (if not used elsewhere in the file)
24
+ - In `runPlanCommand()`: remove `sessionId` generation, `sessionCwd` variable, remove `sessionId` from `claudeRunner.runInteractive()` options, remove `displayPlanSessionTokenSummary()` call
25
+ - In `runAmendCommand()`: same removals as above
26
+ - Delete the entire `displayPlanSessionTokenSummary()` function (around lines 702-741)
27
+
28
+ 2. **Edit `src/core/claude-runner.ts`:**
29
+ - Remove `sessionId` from the `runInteractive()` method's options interface/parameter
30
+ - Remove any internal usage of `sessionId` (e.g., passing `--session-id` flag to Claude CLI)
31
+
32
+ 3. **Delete files:**
33
+ - `src/utils/session-parser.ts`
34
+ - `tests/unit/session-parser.test.ts`
35
+
36
+ 4. **Verify:** Run `npm run build` and `npm test` to ensure no broken imports or failing tests
37
+
38
+ ## Acceptance Criteria
39
+ - [ ] `raf plan` no longer displays a token usage summary after the planning session
40
+ - [ ] `raf plan --amend` no longer displays a token usage summary after the amendment session
41
+ - [ ] `src/utils/session-parser.ts` is deleted
42
+ - [ ] `tests/unit/session-parser.test.ts` is deleted
43
+ - [ ] `sessionId` parameter removed from `runInteractive()` API
44
+ - [ ] No unused imports remain in modified files
45
+ - [ ] Build passes (`npm run build`)
46
+ - [ ] Tests pass (`npm test`)
47
+
48
+ ## Notes
49
+ - The `TokenTracker`, `formatTokenTotalSummary`, and `formatTaskTokenSummary` utilities in `token-tracker.ts` and `terminal-symbols.ts` are still used by `raf do` — do NOT delete those modules
50
+ - The `display` and `pricing` config sections remain valid for `raf do` usage — do NOT remove them from config types/defaults
package/README.md CHANGED
@@ -76,7 +76,7 @@ raf do # Interactive picker
76
76
  raf do abcdef # Execute by project ID
77
77
  raf do my-project # Execute by name
78
78
  raf do --worktree # Pick and execute a worktree project
79
- raf do my-feature -w --merge # Execute in worktree, merge on success
79
+ raf do my-feature -w # Execute in worktree (picker will ask what to do after)
80
80
  ```
81
81
 
82
82
  Note: In non-verbose mode, the completion summary reflects the tasks executed in that run (the remaining tasks at start), so the elapsed time maps to those tasks.
@@ -163,18 +163,39 @@ Worktree mode runs planning and execution in an isolated git worktree, keeping y
163
163
  # Plan in a worktree (creates branch and worktree directory)
164
164
  raf plan my-feature --worktree
165
165
 
166
- # Execute tasks in the worktree, merge back on success
167
- raf do my-feature --worktree --merge
166
+ # Execute tasks in the worktree
167
+ raf do my-feature --worktree
168
168
  ```
169
169
 
170
+ ### Post-execution picker
171
+
172
+ When running `raf do` in worktree mode, an interactive picker appears **before** task execution asking what to do after tasks complete:
173
+
174
+ - **Merge into current branch** — Merge the worktree branch back (fast-forward preferred, merge commit fallback)
175
+ - **Create a GitHub PR** — Push the branch and create a pull request (requires `gh` CLI)
176
+ - **Leave branch as-is** — Do nothing, keep the branch for later
177
+
178
+ The chosen action only runs if all tasks succeed. On task failure, the action is skipped and the worktree is kept for inspection.
179
+
180
+ ### PR creation
181
+
182
+ The "Create a GitHub PR" option:
183
+
184
+ - Requires `gh` CLI installed and authenticated (`gh auth login`)
185
+ - Auto-detects the base branch from `origin/HEAD`
186
+ - Generates a PR title from the project name
187
+ - Uses Claude to summarize your input, decisions, and outcomes into a PR body
188
+ - Auto-pushes the branch to origin if needed
189
+
190
+ If `gh` is missing or unauthenticated, the option falls back to "Leave branch" with a warning.
191
+
170
192
  ### How it works
171
193
 
172
194
  - `--worktree` creates a git worktree at `~/.raf/worktrees/<repo>/<project>/` with a new branch named after the project folder (e.g., `abcdef-my-feature`)
173
195
  - All planning artifacts, code changes, and commits happen in the worktree branch
174
- - `--merge` on `raf do` merges the branch back after all tasks succeed (fast-forward preferred, merge commit as fallback)
196
+ - After successful post-actions (merge, PR, or leave), the worktree directory is cleaned up automatically the git branch is preserved
175
197
  - On merge conflicts, the merge is aborted and you get instructions for manual resolution
176
- - If tasks fail, the worktree branch is preserved for inspection
177
- - Worktrees persist after completion — clean them up manually with `git worktree remove` when done
198
+ - If tasks fail, the worktree is kept for inspection
178
199
 
179
200
  ## Command Reference
180
201
 
@@ -196,7 +217,6 @@ raf do my-feature --worktree --merge
196
217
  | `-m, --model <name>` | Claude model (sonnet, haiku, opus) |
197
218
  | `--sonnet` | Shorthand for `--model sonnet` |
198
219
  | `-w, --worktree` | Execute tasks in a git worktree |
199
- | `--merge` | Merge worktree branch after successful completion (requires `--worktree`) |
200
220
 
201
221
  Alias: `raf act`
202
222
 
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiHpC,wBAAgB,mBAAmB,IAAI,OAAO,CAgB7C"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA4UpC,wBAAgB,mBAAmB,IAAI,OAAO,CAsC7C"}