rafcode 2.1.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +4 -1
- package/CLAUDE.md +59 -11
- package/RAF/ahslfe-config-wizard/decisions.md +34 -0
- package/RAF/ahslfe-config-wizard/input.md +1 -0
- package/RAF/ahslfe-config-wizard/outcomes/01-define-config-schema.md +38 -0
- package/RAF/ahslfe-config-wizard/outcomes/02-refactor-codebase-to-use-config.md +67 -0
- package/RAF/ahslfe-config-wizard/outcomes/03-create-config-documentation.md +37 -0
- package/RAF/ahslfe-config-wizard/outcomes/04-implement-raf-config-command.md +47 -0
- package/RAF/ahslfe-config-wizard/outcomes/05-update-claude-md.md +26 -0
- package/RAF/ahslfe-config-wizard/plans/01-define-config-schema.md +73 -0
- package/RAF/ahslfe-config-wizard/plans/02-refactor-codebase-to-use-config.md +74 -0
- package/RAF/ahslfe-config-wizard/plans/03-create-config-documentation.md +57 -0
- package/RAF/ahslfe-config-wizard/plans/04-implement-raf-config-command.md +66 -0
- package/RAF/ahslfe-config-wizard/plans/05-update-claude-md.md +60 -0
- package/RAF/ahstvo-token-tracker/decisions.md +44 -0
- package/RAF/ahstvo-token-tracker/input.md +3 -0
- package/RAF/ahstvo-token-tracker/outcomes/01-full-model-id-support.md +43 -0
- package/RAF/ahstvo-token-tracker/outcomes/02-name-generation-no-session.md +33 -0
- package/RAF/ahstvo-token-tracker/outcomes/03-unify-stream-json-execution.md +48 -0
- package/RAF/ahstvo-token-tracker/outcomes/04-token-tracking-cost-calculation.md +53 -0
- package/RAF/ahstvo-token-tracker/outcomes/05-token-cost-console-reporting.md +57 -0
- package/RAF/ahstvo-token-tracker/outcomes/06-runtime-verbose-toggle.md +53 -0
- package/RAF/ahstvo-token-tracker/outcomes/07-readme-config-docs.md +36 -0
- package/RAF/ahstvo-token-tracker/plans/01-full-model-id-support.md +35 -0
- package/RAF/ahstvo-token-tracker/plans/02-name-generation-no-session.md +36 -0
- package/RAF/ahstvo-token-tracker/plans/03-unify-stream-json-execution.md +44 -0
- package/RAF/ahstvo-token-tracker/plans/04-token-tracking-cost-calculation.md +56 -0
- package/RAF/ahstvo-token-tracker/plans/05-token-cost-console-reporting.md +55 -0
- package/RAF/ahstvo-token-tracker/plans/06-runtime-verbose-toggle.md +48 -0
- package/RAF/ahstvo-token-tracker/plans/07-readme-config-docs.md +44 -0
- package/README.md +34 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +173 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/do.d.ts.map +1 -1
- package/dist/commands/do.js +47 -6
- package/dist/commands/do.js.map +1 -1
- package/dist/commands/plan.d.ts.map +1 -1
- package/dist/commands/plan.js +3 -2
- package/dist/commands/plan.js.map +1 -1
- package/dist/core/claude-runner.d.ts +19 -2
- package/dist/core/claude-runner.d.ts.map +1 -1
- package/dist/core/claude-runner.js +43 -96
- package/dist/core/claude-runner.js.map +1 -1
- package/dist/core/failure-analyzer.d.ts.map +1 -1
- package/dist/core/failure-analyzer.js +6 -3
- package/dist/core/failure-analyzer.js.map +1 -1
- package/dist/core/git.d.ts.map +1 -1
- package/dist/core/git.js +10 -3
- package/dist/core/git.js.map +1 -1
- package/dist/core/pull-request.d.ts +1 -1
- package/dist/core/pull-request.d.ts.map +1 -1
- package/dist/core/pull-request.js +7 -4
- package/dist/core/pull-request.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/parsers/stream-renderer.d.ts +16 -1
- package/dist/parsers/stream-renderer.d.ts.map +1 -1
- package/dist/parsers/stream-renderer.js +34 -4
- package/dist/parsers/stream-renderer.js.map +1 -1
- package/dist/prompts/execution.d.ts.map +1 -1
- package/dist/prompts/execution.js +11 -1
- package/dist/prompts/execution.js.map +1 -1
- package/dist/types/config.d.ts +95 -4
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +63 -3
- package/dist/types/config.js.map +1 -1
- package/dist/utils/config.d.ts +59 -7
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +276 -21
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/name-generator.d.ts +3 -7
- package/dist/utils/name-generator.d.ts.map +1 -1
- package/dist/utils/name-generator.js +75 -61
- package/dist/utils/name-generator.js.map +1 -1
- package/dist/utils/terminal-symbols.d.ts +21 -0
- package/dist/utils/terminal-symbols.d.ts.map +1 -1
- package/dist/utils/terminal-symbols.js +62 -0
- package/dist/utils/terminal-symbols.js.map +1 -1
- package/dist/utils/token-tracker.d.ts +45 -0
- package/dist/utils/token-tracker.d.ts.map +1 -0
- package/dist/utils/token-tracker.js +107 -0
- package/dist/utils/token-tracker.js.map +1 -0
- package/dist/utils/validation.d.ts +5 -5
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +10 -6
- package/dist/utils/validation.js.map +1 -1
- package/dist/utils/verbose-toggle.d.ts +33 -0
- package/dist/utils/verbose-toggle.d.ts.map +1 -0
- package/dist/utils/verbose-toggle.js +94 -0
- package/dist/utils/verbose-toggle.js.map +1 -0
- package/package.json +1 -1
- package/src/commands/config.ts +204 -0
- package/src/commands/do.ts +56 -5
- package/src/commands/plan.ts +3 -2
- package/src/core/claude-runner.ts +59 -115
- package/src/core/failure-analyzer.ts +6 -3
- package/src/core/git.ts +10 -3
- package/src/core/pull-request.ts +7 -4
- package/src/index.ts +2 -0
- package/src/parsers/stream-renderer.ts +54 -4
- package/src/prompts/config-docs.md +331 -0
- package/src/prompts/execution.ts +13 -1
- package/src/types/config.ts +156 -7
- package/src/utils/config.ts +335 -21
- package/src/utils/name-generator.ts +84 -71
- package/src/utils/terminal-symbols.ts +68 -0
- package/src/utils/token-tracker.ts +135 -0
- package/src/utils/validation.ts +15 -10
- package/src/utils/verbose-toggle.ts +103 -0
- package/tests/unit/claude-runner.test.ts +171 -7
- package/tests/unit/config-command.test.ts +163 -0
- package/tests/unit/config.test.ts +608 -30
- package/tests/unit/name-generator.test.ts +99 -75
- package/tests/unit/pull-request.test.ts +2 -0
- package/tests/unit/stream-renderer.test.ts +83 -0
- package/tests/unit/terminal-symbols.test.ts +157 -0
- package/tests/unit/token-tracker.test.ts +352 -0
- package/tests/unit/verbose-toggle.test.ts +204 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Task: Add Token Tracking and Cost Calculation
|
|
2
|
+
|
|
3
|
+
## Objective
|
|
4
|
+
Implement token usage accumulation across tasks and cost calculation using configurable per-model pricing.
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
After task execution is unified to stream-json (task 03), each task returns `UsageData` with token counts. This task adds the infrastructure to accumulate usage across multiple tasks and calculate estimated costs based on configurable pricing.
|
|
8
|
+
|
|
9
|
+
## Dependencies
|
|
10
|
+
01, 03
|
|
11
|
+
|
|
12
|
+
## Requirements
|
|
13
|
+
- Add pricing config to the RAF config schema with current prices as defaults
|
|
14
|
+
- Pricing is per-model, per-direction (input vs output), in dollars per million tokens
|
|
15
|
+
- Support pricing tiers: standard (prompts <= 200K tokens) and extended (prompts > 200K tokens) for Opus and Sonnet; flat rate for Haiku
|
|
16
|
+
- Cache read tokens should use a discounted price (typically 90% off input price — check Claude pricing page)
|
|
17
|
+
- Cache creation tokens should use standard input price
|
|
18
|
+
- Accumulate usage data across all tasks in a project execution run
|
|
19
|
+
- Calculate estimated cost from token counts × configurable prices
|
|
20
|
+
|
|
21
|
+
## Implementation Steps
|
|
22
|
+
1. Define pricing types and add pricing config to the config schema in `src/types/config.ts` with default values:
|
|
23
|
+
- Opus: $15/MTok input, $75/MTok output (standard tier)
|
|
24
|
+
- Sonnet: $3/MTok input, $15/MTok output
|
|
25
|
+
- Haiku: $1/MTok input, $5/MTok output
|
|
26
|
+
- Cache read discount: 90% off input price
|
|
27
|
+
- Cache creation: same as input price
|
|
28
|
+
2. Add config validation for pricing fields in `src/utils/config.ts`
|
|
29
|
+
3. Add pricing accessor helpers (e.g., `getPricing(model)`)
|
|
30
|
+
4. Create a `TokenTracker` utility (e.g., `src/utils/token-tracker.ts`) that:
|
|
31
|
+
- Accepts `UsageData` from each task execution
|
|
32
|
+
- Accumulates totals (input, output, cache read, cache creation tokens per model)
|
|
33
|
+
- Calculates cost from token counts × configured prices
|
|
34
|
+
- Provides per-task summaries and a grand total
|
|
35
|
+
5. Map model IDs from CLI output (e.g., `claude-opus-4-6`) to pricing tiers — the modelUsage keys are full model IDs, so need a mapping from full ID to pricing category (opus/sonnet/haiku)
|
|
36
|
+
6. Update config docs in `src/prompts/config-docs.md`
|
|
37
|
+
7. Add tests for cost calculation and token accumulation
|
|
38
|
+
|
|
39
|
+
## Acceptance Criteria
|
|
40
|
+
- [ ] Pricing config added with sensible defaults matching current Claude API pricing
|
|
41
|
+
- [ ] `TokenTracker` accumulates usage across multiple tasks correctly
|
|
42
|
+
- [ ] Cost calculation is accurate: `tokens × price_per_token` for each category
|
|
43
|
+
- [ ] Per-model pricing works (different costs for opus vs sonnet vs haiku)
|
|
44
|
+
- [ ] Cache tokens use discounted pricing
|
|
45
|
+
- [ ] Config validation accepts valid pricing, rejects invalid
|
|
46
|
+
- [ ] All tests pass
|
|
47
|
+
|
|
48
|
+
## Notes
|
|
49
|
+
- Current pricing (as of 2026-02-10):
|
|
50
|
+
- Opus 4.6: $15/MTok input, $75/MTok output (standard ≤200K context)
|
|
51
|
+
- Sonnet 4.5: $3/MTok input, $15/MTok output
|
|
52
|
+
- Haiku 4.5: $1/MTok input, $5/MTok output
|
|
53
|
+
- Cache read is typically 10% of input price
|
|
54
|
+
- Cache creation is typically 25% more than input price
|
|
55
|
+
- Model ID mapping: `claude-opus-4-6` → opus pricing, `claude-sonnet-4-5-*` → sonnet pricing, etc. Use a pattern-based lookup
|
|
56
|
+
- Consider whether to track extended context pricing (>200K tokens) — may not be worth the complexity initially since RAF tasks rarely exceed 200K
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Task: Add Token/Cost Reporting to Console Output
|
|
2
|
+
|
|
3
|
+
## Objective
|
|
4
|
+
Display per-task token usage and cost estimates after each task, and a grand total after all tasks complete.
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
With token tracking infrastructure in place (task 04), this task wires it into the `raf do` execution flow to display usage reports in the terminal. This is the user-facing part of the feature.
|
|
8
|
+
|
|
9
|
+
## Dependencies
|
|
10
|
+
04
|
|
11
|
+
|
|
12
|
+
## Requirements
|
|
13
|
+
- After each task completes, print a concise usage summary line to the console
|
|
14
|
+
- After all tasks finish (or project completes), print a grand total summary
|
|
15
|
+
- Show: input tokens, output tokens, cache tokens (combined read+creation), estimated cost in USD
|
|
16
|
+
- Format numbers with thousands separators for readability (e.g., `12,345`)
|
|
17
|
+
- Format cost as USD with 2-4 decimal places (e.g., `$1.23` or `$0.0042`)
|
|
18
|
+
- Keep the output compact — avoid verbose multi-line reports for each task
|
|
19
|
+
- Respect the existing console output style (chalk colors, log levels, etc.)
|
|
20
|
+
|
|
21
|
+
## Implementation Steps
|
|
22
|
+
1. In `src/commands/do.ts`, instantiate a `TokenTracker` at the start of project execution
|
|
23
|
+
2. After each task execution, feed the returned `UsageData` into the tracker
|
|
24
|
+
3. Print a per-task summary line after each task completes (e.g., ` Tokens: 5,234 in / 1,023 out | Cache: 18,500 read | Est. cost: $0.42`)
|
|
25
|
+
4. After all tasks complete, print a total summary section with aggregated stats
|
|
26
|
+
5. Handle edge cases: tasks that fail before returning usage data, context overflow, timeouts
|
|
27
|
+
6. Use existing logging/formatting utilities (chalk, logger) for consistent styling
|
|
28
|
+
7. Update CLAUDE.md and README.md to document the token tracking feature
|
|
29
|
+
|
|
30
|
+
## Acceptance Criteria
|
|
31
|
+
- [ ] Per-task token summary displayed after each task completion
|
|
32
|
+
- [ ] Grand total displayed after all tasks finish
|
|
33
|
+
- [ ] Numbers are formatted with thousands separators
|
|
34
|
+
- [ ] Cost displayed in USD format
|
|
35
|
+
- [ ] Failed tasks that have partial usage data are still included in totals
|
|
36
|
+
- [ ] Tasks with no usage data (timeout, crash) are handled gracefully
|
|
37
|
+
- [ ] Output is compact and doesn't overwhelm the console
|
|
38
|
+
- [ ] CLAUDE.md updated with token tracking documentation
|
|
39
|
+
- [ ] All tests pass
|
|
40
|
+
|
|
41
|
+
## Notes
|
|
42
|
+
- Example per-task output format:
|
|
43
|
+
```
|
|
44
|
+
Task 01 complete ✓
|
|
45
|
+
Tokens: 5,234 in / 1,023 out | Cache: 18,500 read | Est. cost: $0.42
|
|
46
|
+
```
|
|
47
|
+
- Example total output format:
|
|
48
|
+
```
|
|
49
|
+
── Token Usage Summary ──────────────────
|
|
50
|
+
Total tokens: 45,678 in / 12,345 out
|
|
51
|
+
Cache: 125,000 read / 8,000 created
|
|
52
|
+
Estimated cost: $3.75
|
|
53
|
+
─────────────────────────────────────────
|
|
54
|
+
```
|
|
55
|
+
- These are just examples — the implementing agent should match the existing output style
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Task: Add Runtime Verbose Toggle During Task Execution
|
|
2
|
+
|
|
3
|
+
## Objective
|
|
4
|
+
Allow users to press Tab during task execution to toggle verbose mode on/off in real-time, showing or hiding tool-use activity lines.
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
After task 03 unifies all execution to stream-json, the underlying data stream always includes tool-use events. Verbose mode becomes purely a display concern — whether to print tool descriptions (e.g., "Reading src/file.ts", "Running: npm test") to the console. This makes runtime toggling straightforward: listen for Tab key on stdin and flip a boolean that controls display output.
|
|
8
|
+
|
|
9
|
+
## Dependencies
|
|
10
|
+
03
|
|
11
|
+
|
|
12
|
+
## Requirements
|
|
13
|
+
- During non-interactive task execution (`raf do`), listen for Tab keypress on `process.stdin`
|
|
14
|
+
- Pressing Tab toggles verbose display: tool-use lines are shown or hidden
|
|
15
|
+
- The initial state matches the `--verbose` flag (off by default, on if `--verbose` was passed)
|
|
16
|
+
- Display a brief indicator when toggling (e.g., `[verbose: on]` / `[verbose: off]`)
|
|
17
|
+
- stdin must be in raw mode to capture individual keypresses without requiring Enter
|
|
18
|
+
- Restore stdin to normal mode after task execution completes (or on process exit)
|
|
19
|
+
- Do not interfere with Ctrl+C signal handling (SIGINT must still work)
|
|
20
|
+
- Do not interfere with the child process — stdin is already `'ignore'` for spawned Claude
|
|
21
|
+
|
|
22
|
+
## Implementation Steps
|
|
23
|
+
1. Before starting task execution in `do.ts`, set up `process.stdin` in raw mode to capture keypresses
|
|
24
|
+
2. Listen for the Tab key (character code `\t` or `0x09`) on the stdin `data` event
|
|
25
|
+
3. Maintain a `verboseDisplay` boolean that the stream-json renderer checks before printing tool-use lines
|
|
26
|
+
4. On Tab press, flip the boolean and print a brief status indicator
|
|
27
|
+
5. Pass the `verboseDisplay` reference (or a callback/event emitter) to the stream renderer so it can check the current state for each event
|
|
28
|
+
6. On task completion (or process exit/error), restore stdin to cooked mode and remove the listener
|
|
29
|
+
7. Integrate with the shutdown handler to ensure clean terminal state on Ctrl+C
|
|
30
|
+
8. Add tests for the toggle mechanism
|
|
31
|
+
|
|
32
|
+
## Acceptance Criteria
|
|
33
|
+
- [ ] Tab key toggles verbose display during task execution
|
|
34
|
+
- [ ] Initial verbose state matches the `--verbose` CLI flag
|
|
35
|
+
- [ ] Tool-use lines appear/disappear immediately on toggle
|
|
36
|
+
- [ ] Brief status indicator shown on toggle
|
|
37
|
+
- [ ] Ctrl+C still works for graceful shutdown
|
|
38
|
+
- [ ] Terminal state is properly restored after execution
|
|
39
|
+
- [ ] No interference with child process stdin
|
|
40
|
+
- [ ] Works correctly across multiple sequential tasks
|
|
41
|
+
- [ ] All existing tests pass
|
|
42
|
+
|
|
43
|
+
## Notes
|
|
44
|
+
- Node.js `process.stdin.setRawMode(true)` is already used in `runInteractive()` so the pattern is familiar in this codebase
|
|
45
|
+
- The shutdown handler in `src/core/shutdown-handler.ts` already manages terminal cleanup — coordinate with it
|
|
46
|
+
- Since the child process has `stdio: ['ignore', 'pipe', 'pipe']`, parent stdin is free to use for keypress detection
|
|
47
|
+
- Consider showing the toggle hint at the start of execution: `Press Tab to toggle verbose mode`
|
|
48
|
+
- Edge case: if stdin is not a TTY (piped input), skip the keypress listener entirely
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Task: Document raf config in README and Strengthen README Update Policy
|
|
2
|
+
|
|
3
|
+
## Objective
|
|
4
|
+
Add `raf config` documentation to README.md and add explicit guidance in CLAUDE.md about keeping the README updated when CLI commands or important features change.
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
The `raf config` command is fully implemented but completely missing from the user-facing README. Users have no way to discover that configuration is possible, how to use it, or what can be configured. Additionally, CLAUDE.md's "Important Reminders" section should be more explicit about when README updates are required to prevent this gap from recurring.
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
### README updates
|
|
12
|
+
- Add a `raf config` section alongside the existing command documentation sections (`raf plan`, `raf do`, `raf status`)
|
|
13
|
+
- Keep it brief and consistent with the existing README style
|
|
14
|
+
- Include: command usage, what it does (interactive Claude session for config), basic config file example, 1-2 common use cases
|
|
15
|
+
- Add `raf config` to the Command Reference table at the bottom
|
|
16
|
+
- Mention the config file location (`~/.raf/raf.config.json`) and three-tier precedence (CLI flag > config > defaults)
|
|
17
|
+
- Do NOT duplicate the full config schema — reference that `raf config` itself provides interactive help
|
|
18
|
+
|
|
19
|
+
### CLAUDE.md updates
|
|
20
|
+
- Expand the "Important Reminders" section to explicitly state that README must be updated when:
|
|
21
|
+
- New CLI commands are added
|
|
22
|
+
- Existing command APIs change (new flags, changed behavior)
|
|
23
|
+
- Important features are added (like worktrees, config, token tracking)
|
|
24
|
+
- Keep the reminder actionable and specific, not vague
|
|
25
|
+
|
|
26
|
+
## Implementation Steps
|
|
27
|
+
1. Read the current README.md to understand section ordering, style, and formatting conventions
|
|
28
|
+
2. Add a `### raf config` section after the existing `raf status` section, following the same format
|
|
29
|
+
3. Include a minimal config example showing 2-3 common settings (e.g., changing default model, setting worktree default)
|
|
30
|
+
4. Add `raf config` entries to the Command Reference tables
|
|
31
|
+
5. Update CLAUDE.md's "Important Reminders" with explicit README update policy
|
|
32
|
+
|
|
33
|
+
## Acceptance Criteria
|
|
34
|
+
- [ ] README has a `raf config` section with usage and basic example
|
|
35
|
+
- [ ] `raf config` appears in the Command Reference table
|
|
36
|
+
- [ ] Config file location and precedence rules are mentioned
|
|
37
|
+
- [ ] CLAUDE.md has explicit guidance about when to update README
|
|
38
|
+
- [ ] No existing README content is broken or removed
|
|
39
|
+
- [ ] Documentation tone and style match the rest of the README
|
|
40
|
+
|
|
41
|
+
## Notes
|
|
42
|
+
- The existing README documents `raf config` options: `--reset` flag and inline prompt (`raf config "use haiku"`) — these should be mentioned
|
|
43
|
+
- Look at `src/prompts/config-docs.md` for the full config reference — pick 2-3 of the most common/useful settings for the README example
|
|
44
|
+
- The README currently has a "Features" section that lists 7 features — consider adding "Configurable" to that list if not present
|
package/README.md
CHANGED
|
@@ -52,6 +52,7 @@ That's it! RAF will guide you through breaking down your task and then execute i
|
|
|
52
52
|
- **Git Integration**: Automatic commits after each completed task
|
|
53
53
|
- **Task Dependencies**: Tasks can depend on other tasks, with automatic blocking on failure
|
|
54
54
|
- **Worktree Mode**: Isolate planning and execution in a git worktree branch with `--worktree`
|
|
55
|
+
- **Configurable**: Customize models, effort levels, timeouts, and more via `raf config`
|
|
55
56
|
|
|
56
57
|
## Commands
|
|
57
58
|
|
|
@@ -89,6 +90,33 @@ raf status # List all projects (includes worktree projects that diffe
|
|
|
89
90
|
raf status abcdef # Show details for a project (shows both main and worktree if they differ)
|
|
90
91
|
```
|
|
91
92
|
|
|
93
|
+
### `raf config`
|
|
94
|
+
|
|
95
|
+
View and edit RAF configuration through an interactive Claude session. Configuration is stored at `~/.raf/raf.config.json`. All settings are optional — only set what you want to change.
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
raf config # Interactive config editor
|
|
99
|
+
raf config "use haiku for name generation" # Start with a specific request
|
|
100
|
+
raf config --reset # Reset config to defaults
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Precedence**: CLI flags > config file > built-in defaults
|
|
104
|
+
|
|
105
|
+
Example `~/.raf/raf.config.json`:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"models": {
|
|
110
|
+
"execute": "sonnet",
|
|
111
|
+
"nameGeneration": "haiku"
|
|
112
|
+
},
|
|
113
|
+
"worktree": true,
|
|
114
|
+
"timeout": 45
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Run `raf config` without arguments and ask what's available — the session has full knowledge of every configurable option.
|
|
119
|
+
|
|
92
120
|
### `raf migrate-project-ids-base26`
|
|
93
121
|
|
|
94
122
|
Rename legacy project folders (3-char base36 or 6-char base36 with digits) to the current 6-char base26 format.
|
|
@@ -181,6 +209,12 @@ Alias: `raf act`
|
|
|
181
209
|
|
|
182
210
|
> **Note:** `raf do` and `raf plan -y` run Claude with `--dangerously-skip-permissions` for fully automated execution without interactive prompts.
|
|
183
211
|
|
|
212
|
+
### `raf config [prompt]`
|
|
213
|
+
|
|
214
|
+
| Option | Description |
|
|
215
|
+
|--------|-------------|
|
|
216
|
+
| `--reset` | Reset config file to defaults |
|
|
217
|
+
|
|
184
218
|
### `raf status [identifier]`
|
|
185
219
|
|
|
186
220
|
| Option | Description |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8GpC,wBAAgB,mBAAmB,IAAI,OAAO,CAgB7C"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import * as readline from 'node:readline';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { ClaudeRunner } from '../core/claude-runner.js';
|
|
7
|
+
import { shutdownHandler } from '../core/shutdown-handler.js';
|
|
8
|
+
import { logger } from '../utils/logger.js';
|
|
9
|
+
import { getConfigPath, getModel, getEffort, validateConfig, ConfigValidationError, } from '../utils/config.js';
|
|
10
|
+
/**
|
|
11
|
+
* Load the config documentation markdown from src/prompts/config-docs.md.
|
|
12
|
+
* Resolved relative to this file's location in the dist/ tree.
|
|
13
|
+
*/
|
|
14
|
+
function loadConfigDocs() {
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const __dirname = path.dirname(__filename);
|
|
17
|
+
// From dist/commands/config.js -> ../../src/prompts/config-docs.md
|
|
18
|
+
const docsPath = path.join(__dirname, '..', '..', 'src', 'prompts', 'config-docs.md');
|
|
19
|
+
return fs.readFileSync(docsPath, 'utf-8');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Read the current user config file contents, or a message indicating no file exists.
|
|
23
|
+
*/
|
|
24
|
+
function getCurrentConfigState(configPath) {
|
|
25
|
+
if (!fs.existsSync(configPath)) {
|
|
26
|
+
return 'No config file exists yet. All settings use defaults. The file will be created at: ' + configPath;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
30
|
+
return `Current config file (${configPath}):\n\`\`\`json\n${content}\`\`\``;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return 'Config file exists but could not be read: ' + configPath;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build the system prompt for the config editing Claude session.
|
|
38
|
+
*/
|
|
39
|
+
function buildConfigSystemPrompt(configDocs, configState) {
|
|
40
|
+
return [
|
|
41
|
+
'You are helping the user edit their RAF configuration.',
|
|
42
|
+
'You have full permission to read and write ~/.raf/raf.config.json.',
|
|
43
|
+
'',
|
|
44
|
+
'# Current Config State',
|
|
45
|
+
configState,
|
|
46
|
+
'',
|
|
47
|
+
'# Config Documentation',
|
|
48
|
+
configDocs,
|
|
49
|
+
].join('\n');
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Validate the config file after the Claude session ends and report results.
|
|
53
|
+
*/
|
|
54
|
+
function postSessionValidation(configPath) {
|
|
55
|
+
if (!fs.existsSync(configPath)) {
|
|
56
|
+
logger.info('No config file exists — using all defaults.');
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
61
|
+
const parsed = JSON.parse(content);
|
|
62
|
+
validateConfig(parsed);
|
|
63
|
+
logger.success('Config updated successfully.');
|
|
64
|
+
// Show a summary of what's set
|
|
65
|
+
const userConfig = parsed;
|
|
66
|
+
const keys = Object.keys(userConfig);
|
|
67
|
+
if (keys.length > 0) {
|
|
68
|
+
logger.info(`Custom settings: ${keys.join(', ')}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (error instanceof ConfigValidationError) {
|
|
73
|
+
logger.warn(`Config validation warning: ${error.message}`);
|
|
74
|
+
logger.warn('The file was not deleted — you can fix it manually or run `raf config` again.');
|
|
75
|
+
}
|
|
76
|
+
else if (error instanceof SyntaxError) {
|
|
77
|
+
logger.warn('Config file contains invalid JSON.');
|
|
78
|
+
logger.warn('The file was not deleted — you can fix it manually or run `raf config` again.');
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
logger.warn(`Could not validate config: ${error}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Prompt the user for Y/N confirmation via readline.
|
|
87
|
+
*/
|
|
88
|
+
async function confirm(message) {
|
|
89
|
+
const rl = readline.createInterface({
|
|
90
|
+
input: process.stdin,
|
|
91
|
+
output: process.stdout,
|
|
92
|
+
});
|
|
93
|
+
return new Promise((resolve) => {
|
|
94
|
+
rl.question(message, (answer) => {
|
|
95
|
+
rl.close();
|
|
96
|
+
resolve(answer.trim().toLowerCase() === 'y');
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
export function createConfigCommand() {
|
|
101
|
+
const command = new Command('config')
|
|
102
|
+
.description('View and edit RAF configuration with Claude')
|
|
103
|
+
.argument('[prompt...]', 'Optional initial prompt for the config session')
|
|
104
|
+
.option('--reset', 'Delete config file and restore all defaults')
|
|
105
|
+
.action(async (promptParts, options) => {
|
|
106
|
+
if (options.reset) {
|
|
107
|
+
await handleReset();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const initialPrompt = promptParts.length > 0 ? promptParts.join(' ') : undefined;
|
|
111
|
+
await runConfigSession(initialPrompt);
|
|
112
|
+
});
|
|
113
|
+
return command;
|
|
114
|
+
}
|
|
115
|
+
async function handleReset() {
|
|
116
|
+
const configPath = getConfigPath();
|
|
117
|
+
if (!fs.existsSync(configPath)) {
|
|
118
|
+
logger.info('No config file exists — already using defaults.');
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const confirmed = await confirm('This will delete ~/.raf/raf.config.json and restore all defaults. Continue? [y/N] ');
|
|
122
|
+
if (!confirmed) {
|
|
123
|
+
logger.info('Cancelled.');
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
fs.unlinkSync(configPath);
|
|
127
|
+
logger.success('Config file deleted. All settings restored to defaults.');
|
|
128
|
+
}
|
|
129
|
+
async function runConfigSession(initialPrompt) {
|
|
130
|
+
const configPath = getConfigPath();
|
|
131
|
+
const model = getModel('config');
|
|
132
|
+
const effort = getEffort('config');
|
|
133
|
+
// Set effort level env var for the Claude session
|
|
134
|
+
process.env['CLAUDE_CODE_EFFORT_LEVEL'] = effort;
|
|
135
|
+
// Load config docs
|
|
136
|
+
let configDocs;
|
|
137
|
+
try {
|
|
138
|
+
configDocs = loadConfigDocs();
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
logger.error(`Failed to load config documentation: ${error}`);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
// Build system prompt
|
|
145
|
+
const configState = getCurrentConfigState(configPath);
|
|
146
|
+
const systemPrompt = buildConfigSystemPrompt(configDocs, configState);
|
|
147
|
+
// Build user message
|
|
148
|
+
const userMessage = initialPrompt
|
|
149
|
+
?? 'Show me my current config and help me make changes.';
|
|
150
|
+
// Set up Claude runner
|
|
151
|
+
const claudeRunner = new ClaudeRunner({ model });
|
|
152
|
+
shutdownHandler.init();
|
|
153
|
+
shutdownHandler.registerClaudeRunner(claudeRunner);
|
|
154
|
+
logger.info('Starting config session with Claude...');
|
|
155
|
+
logger.info(`Using model: ${model}`);
|
|
156
|
+
logger.newline();
|
|
157
|
+
try {
|
|
158
|
+
const exitCode = await claudeRunner.runInteractive(systemPrompt, userMessage, {
|
|
159
|
+
dangerouslySkipPermissions: true,
|
|
160
|
+
});
|
|
161
|
+
if (exitCode !== 0) {
|
|
162
|
+
logger.warn(`Claude exited with code ${exitCode}`);
|
|
163
|
+
}
|
|
164
|
+
// Post-session validation
|
|
165
|
+
logger.newline();
|
|
166
|
+
postSessionValidation(configPath);
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
logger.error(`Config session failed: ${error}`);
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"do.d.ts","sourceRoot":"","sources":["../../src/commands/do.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"do.d.ts","sourceRoot":"","sources":["../../src/commands/do.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqDpC;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC;AAE3D;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,EAC1D,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,OAAO,GACf,MAAM,CAkBR;AA0BD,wBAAgB,eAAe,IAAI,OAAO,CAiBzC;AAoSD;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAuBhG"}
|
package/dist/commands/do.js
CHANGED
|
@@ -12,10 +12,12 @@ import { validatePlansExist, resolveModelOption } from '../utils/validation.js';
|
|
|
12
12
|
import { getRafDir, extractProjectNumber, extractProjectName, extractTaskNameFromPlanFile, resolveProjectIdentifierWithDetails, getOutcomeFilePath, parseProjectPrefix } from '../utils/paths.js';
|
|
13
13
|
import { pickPendingProject, getPendingProjects, getPendingWorktreeProjects } from '../ui/project-picker.js';
|
|
14
14
|
import { logger } from '../utils/logger.js';
|
|
15
|
-
import { getConfig } from '../utils/config.js';
|
|
15
|
+
import { getConfig, getEffort, getWorktreeDefault } from '../utils/config.js';
|
|
16
16
|
import { createTaskTimer, formatElapsedTime } from '../utils/timer.js';
|
|
17
17
|
import { createStatusLine } from '../utils/status-line.js';
|
|
18
|
-
import { formatProjectHeader, formatSummary, formatTaskProgress, } from '../utils/terminal-symbols.js';
|
|
18
|
+
import { formatProjectHeader, formatSummary, formatTaskProgress, formatTaskTokenSummary, formatTokenTotalSummary, } from '../utils/terminal-symbols.js';
|
|
19
|
+
import { TokenTracker } from '../utils/token-tracker.js';
|
|
20
|
+
import { VerboseToggle } from '../utils/verbose-toggle.js';
|
|
19
21
|
import { deriveProjectState, discoverProjects, getNextExecutableTask, getDerivedStats, getDerivedStatsForTasks, isProjectComplete, hasProjectFailed, parseOutcomeStatus, } from '../core/state-derivation.js';
|
|
20
22
|
import { analyzeFailure } from '../core/failure-analyzer.js';
|
|
21
23
|
import { getRepoRoot, getRepoBasename, getCurrentBranch, computeWorktreePath, computeWorktreeBaseDir, validateWorktree, listWorktreeProjects, mergeWorktreeBranch, removeWorktree, resolveWorktreeProjectByIdentifier, } from '../core/worktree.js';
|
|
@@ -60,11 +62,11 @@ export function createDoCommand() {
|
|
|
60
62
|
async function runDoCommand(projectIdentifierArg, options) {
|
|
61
63
|
const rafDir = getRafDir();
|
|
62
64
|
let projectIdentifier = projectIdentifierArg;
|
|
63
|
-
let worktreeMode = options.worktree ??
|
|
65
|
+
let worktreeMode = options.worktree ?? getWorktreeDefault();
|
|
64
66
|
// Validate and resolve model option
|
|
65
67
|
let model;
|
|
66
68
|
try {
|
|
67
|
-
model = resolveModelOption(options.model, options.sonnet);
|
|
69
|
+
model = resolveModelOption(options.model, options.sonnet, 'execute');
|
|
68
70
|
}
|
|
69
71
|
catch (error) {
|
|
70
72
|
logger.error(error.message);
|
|
@@ -543,6 +545,11 @@ async function executeSingleProject(projectPath, projectName, options) {
|
|
|
543
545
|
const projectManager = new ProjectManager();
|
|
544
546
|
shutdownHandler.init();
|
|
545
547
|
shutdownHandler.registerClaudeRunner(claudeRunner);
|
|
548
|
+
// Initialize token tracker for usage reporting
|
|
549
|
+
const tokenTracker = new TokenTracker();
|
|
550
|
+
// Set up runtime verbose toggle (Tab key to toggle during execution)
|
|
551
|
+
const verboseToggle = new VerboseToggle(verbose);
|
|
552
|
+
shutdownHandler.onShutdown(() => verboseToggle.stop());
|
|
546
553
|
// Start project timer
|
|
547
554
|
const projectStartTime = Date.now();
|
|
548
555
|
if (verbose) {
|
|
@@ -636,6 +643,8 @@ async function executeSingleProject(projectPath, projectName, options) {
|
|
|
636
643
|
lines.push('<promise>BLOCKED</promise>');
|
|
637
644
|
return lines.join('\n');
|
|
638
645
|
}
|
|
646
|
+
// Start verbose toggle listener (Tab key)
|
|
647
|
+
verboseToggle.start();
|
|
639
648
|
let task = getNextTaskToProcess(state);
|
|
640
649
|
while (task) {
|
|
641
650
|
const taskIndex = state.tasks.findIndex((t) => t.id === task.id);
|
|
@@ -701,6 +710,7 @@ async function executeSingleProject(projectPath, projectName, options) {
|
|
|
701
710
|
let attempts = 0;
|
|
702
711
|
let lastOutput = '';
|
|
703
712
|
let failureReason = '';
|
|
713
|
+
let lastUsageData;
|
|
704
714
|
// Track failure history for each attempt (attempt number -> reason)
|
|
705
715
|
const failureHistory = [];
|
|
706
716
|
// Set up timer for elapsed time tracking
|
|
@@ -743,10 +753,22 @@ async function executeSingleProject(projectPath, projectName, options) {
|
|
|
743
753
|
outcomeFilePath,
|
|
744
754
|
} : undefined;
|
|
745
755
|
// Run Claude (use worktree root as cwd if in worktree mode)
|
|
756
|
+
const executeEffort = getEffort('execute');
|
|
757
|
+
const runnerOptions = {
|
|
758
|
+
timeout,
|
|
759
|
+
outcomeFilePath,
|
|
760
|
+
commitContext,
|
|
761
|
+
cwd: worktreeCwd,
|
|
762
|
+
effortLevel: executeEffort,
|
|
763
|
+
verboseCheck: () => verboseToggle.isVerbose,
|
|
764
|
+
};
|
|
746
765
|
const result = verbose
|
|
747
|
-
? await claudeRunner.runVerbose(prompt,
|
|
748
|
-
: await claudeRunner.run(prompt,
|
|
766
|
+
? await claudeRunner.runVerbose(prompt, runnerOptions)
|
|
767
|
+
: await claudeRunner.run(prompt, runnerOptions);
|
|
749
768
|
lastOutput = result.output;
|
|
769
|
+
if (result.usageData) {
|
|
770
|
+
lastUsageData = result.usageData;
|
|
771
|
+
}
|
|
750
772
|
// Parse result
|
|
751
773
|
const parsed = parseOutput(result.output);
|
|
752
774
|
if (result.timedOut) {
|
|
@@ -857,6 +879,11 @@ Task completed. No detailed report provided.
|
|
|
857
879
|
// Minimal mode: show completed task line
|
|
858
880
|
logger.info(formatTaskProgress(taskNumber, totalTasks, 'completed', displayName, elapsedMs, task.id));
|
|
859
881
|
}
|
|
882
|
+
// Track and display token usage for this task
|
|
883
|
+
if (lastUsageData) {
|
|
884
|
+
const entry = tokenTracker.addTask(task.id, lastUsageData);
|
|
885
|
+
logger.dim(formatTaskTokenSummary(entry.usage, entry.cost));
|
|
886
|
+
}
|
|
860
887
|
completedInSession.add(task.id);
|
|
861
888
|
}
|
|
862
889
|
else {
|
|
@@ -878,6 +905,11 @@ Task completed. No detailed report provided.
|
|
|
878
905
|
// Minimal mode: show failed task line
|
|
879
906
|
logger.info(formatTaskProgress(taskNumber, totalTasks, 'failed', displayName, elapsedMs, task.id));
|
|
880
907
|
}
|
|
908
|
+
// Track token usage even for failed tasks (partial data still useful for totals)
|
|
909
|
+
if (lastUsageData) {
|
|
910
|
+
const entry = tokenTracker.addTask(task.id, lastUsageData);
|
|
911
|
+
logger.dim(formatTaskTokenSummary(entry.usage, entry.cost));
|
|
912
|
+
}
|
|
881
913
|
// Analyze failure and generate structured report
|
|
882
914
|
const analysisReport = await analyzeFailure(lastOutput, failureReason, task.id);
|
|
883
915
|
// Save failure outcome with status marker, analysis, and details
|
|
@@ -906,6 +938,8 @@ ${stashName ? `- Stash: ${stashName}` : ''}
|
|
|
906
938
|
// Get next task to process
|
|
907
939
|
task = getNextTaskToProcess(state);
|
|
908
940
|
}
|
|
941
|
+
// Stop verbose toggle listener before summary output
|
|
942
|
+
verboseToggle.stop();
|
|
909
943
|
// Ensure context is cleared for summary
|
|
910
944
|
logger.clearContext();
|
|
911
945
|
// Get final stats
|
|
@@ -957,6 +991,13 @@ ${stashName ? `- Stash: ${stashName}` : ''}
|
|
|
957
991
|
logger.info(formatSummary(sessionStats.completed, sessionStats.failed, sessionStats.pending, projectElapsedMs, sessionStats.blocked));
|
|
958
992
|
}
|
|
959
993
|
}
|
|
994
|
+
// Show token usage summary if any tasks reported usage data
|
|
995
|
+
const trackerEntries = tokenTracker.getEntries();
|
|
996
|
+
if (trackerEntries.length > 0) {
|
|
997
|
+
logger.newline();
|
|
998
|
+
const totals = tokenTracker.getTotals();
|
|
999
|
+
logger.dim(formatTokenTotalSummary(totals.usage, totals.cost));
|
|
1000
|
+
}
|
|
960
1001
|
// Show retry history for tasks that had failures (even if eventually successful)
|
|
961
1002
|
if (projectRetryHistory.length > 0) {
|
|
962
1003
|
logger.newline();
|