rafcode 2.1.1 → 2.3.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/RAF/ahtahs-token-reaper/decisions.md +37 -0
- package/RAF/ahtahs-token-reaper/input.md +20 -0
- package/RAF/ahtahs-token-reaper/outcomes/01-extend-token-tracker-data-model.md +42 -0
- package/RAF/ahtahs-token-reaper/outcomes/02-accumulate-usage-in-retry-loop.md +31 -0
- package/RAF/ahtahs-token-reaper/outcomes/03-per-attempt-display-formatting.md +60 -0
- package/RAF/ahtahs-token-reaper/outcomes/04-add-model-name-to-claude-call-logs.md +57 -0
- package/RAF/ahtahs-token-reaper/outcomes/05-handle-invalid-config-in-raf-config.md +46 -0
- package/RAF/ahtahs-token-reaper/outcomes/06-fix-verbose-toggle-timer-display.md +38 -0
- package/RAF/ahtahs-token-reaper/plans/01-extend-token-tracker-data-model.md +36 -0
- package/RAF/ahtahs-token-reaper/plans/02-accumulate-usage-in-retry-loop.md +36 -0
- package/RAF/ahtahs-token-reaper/plans/03-per-attempt-display-formatting.md +43 -0
- package/RAF/ahtahs-token-reaper/plans/04-add-model-name-to-claude-call-logs.md +38 -0
- package/RAF/ahtahs-token-reaper/plans/05-handle-invalid-config-in-raf-config.md +36 -0
- package/RAF/ahtahs-token-reaper/plans/06-fix-verbose-toggle-timer-display.md +40 -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 +195 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/do.d.ts.map +1 -1
- package/dist/commands/do.js +55 -7
- package/dist/commands/do.js.map +1 -1
- package/dist/commands/plan.d.ts.map +1 -1
- package/dist/commands/plan.js +5 -3
- 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 +9 -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 +65 -7
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +297 -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 +25 -0
- package/dist/utils/terminal-symbols.d.ts.map +1 -1
- package/dist/utils/terminal-symbols.js +87 -0
- package/dist/utils/terminal-symbols.js.map +1 -1
- package/dist/utils/token-tracker.d.ts +55 -0
- package/dist/utils/token-tracker.d.ts.map +1 -0
- package/dist/utils/token-tracker.js +142 -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 +230 -0
- package/src/commands/do.ts +64 -6
- package/src/commands/plan.ts +5 -3
- 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 +9 -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 +357 -21
- package/src/utils/name-generator.ts +84 -71
- package/src/utils/terminal-symbols.ts +103 -0
- package/src/utils/token-tracker.ts +177 -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 +242 -0
- package/tests/unit/config.test.ts +632 -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 +245 -0
- package/tests/unit/timer-verbose-integration.test.ts +170 -0
- package/tests/unit/token-tracker.test.ts +685 -0
- package/tests/unit/verbose-toggle.test.ts +204 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
|
|
4
|
+
// Mock logger to capture output
|
|
5
|
+
const mockDim = jest.fn();
|
|
6
|
+
jest.unstable_mockModule('../../src/utils/logger.js', () => ({
|
|
7
|
+
logger: {
|
|
8
|
+
dim: mockDim,
|
|
9
|
+
info: jest.fn(),
|
|
10
|
+
debug: jest.fn(),
|
|
11
|
+
warn: jest.fn(),
|
|
12
|
+
error: jest.fn(),
|
|
13
|
+
},
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
const { VerboseToggle } = await import('../../src/utils/verbose-toggle.js');
|
|
17
|
+
|
|
18
|
+
describe('VerboseToggle', () => {
|
|
19
|
+
// Save original stdin properties
|
|
20
|
+
const originalIsTTY = process.stdin.isTTY;
|
|
21
|
+
const originalSetRawMode = process.stdin.setRawMode;
|
|
22
|
+
const originalResume = process.stdin.resume;
|
|
23
|
+
const originalPause = process.stdin.pause;
|
|
24
|
+
|
|
25
|
+
let mockSetRawMode: jest.Mock;
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
jest.clearAllMocks();
|
|
29
|
+
mockSetRawMode = jest.fn();
|
|
30
|
+
Object.defineProperty(process.stdin, 'isTTY', { value: true, writable: true, configurable: true });
|
|
31
|
+
(process.stdin as any).setRawMode = mockSetRawMode;
|
|
32
|
+
(process.stdin as any).resume = jest.fn();
|
|
33
|
+
(process.stdin as any).pause = jest.fn();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
afterEach(() => {
|
|
37
|
+
// Restore original stdin
|
|
38
|
+
Object.defineProperty(process.stdin, 'isTTY', { value: originalIsTTY, writable: true, configurable: true });
|
|
39
|
+
if (originalSetRawMode) {
|
|
40
|
+
(process.stdin as any).setRawMode = originalSetRawMode;
|
|
41
|
+
}
|
|
42
|
+
(process.stdin as any).resume = originalResume;
|
|
43
|
+
(process.stdin as any).pause = originalPause;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('initializes with the provided verbose state', () => {
|
|
47
|
+
const toggle = new VerboseToggle(true);
|
|
48
|
+
expect(toggle.isVerbose).toBe(true);
|
|
49
|
+
|
|
50
|
+
const toggle2 = new VerboseToggle(false);
|
|
51
|
+
expect(toggle2.isVerbose).toBe(false);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('is not active before start()', () => {
|
|
55
|
+
const toggle = new VerboseToggle(false);
|
|
56
|
+
expect(toggle.isActive).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('becomes active after start() on a TTY', () => {
|
|
60
|
+
const toggle = new VerboseToggle(false);
|
|
61
|
+
toggle.start();
|
|
62
|
+
expect(toggle.isActive).toBe(true);
|
|
63
|
+
expect(mockSetRawMode).toHaveBeenCalledWith(true);
|
|
64
|
+
toggle.stop();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('shows toggle hint on start', () => {
|
|
68
|
+
const toggle = new VerboseToggle(false);
|
|
69
|
+
toggle.start();
|
|
70
|
+
expect(mockDim).toHaveBeenCalledWith(' Press Tab to toggle verbose mode');
|
|
71
|
+
toggle.stop();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('skips start when stdin is not a TTY', () => {
|
|
75
|
+
Object.defineProperty(process.stdin, 'isTTY', { value: false, writable: true, configurable: true });
|
|
76
|
+
const toggle = new VerboseToggle(false);
|
|
77
|
+
toggle.start();
|
|
78
|
+
expect(toggle.isActive).toBe(false);
|
|
79
|
+
expect(mockSetRawMode).not.toHaveBeenCalled();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('toggles verbose state on Tab keypress', () => {
|
|
83
|
+
const toggle = new VerboseToggle(false);
|
|
84
|
+
toggle.start();
|
|
85
|
+
|
|
86
|
+
// Simulate Tab key (0x09)
|
|
87
|
+
process.stdin.emit('data', Buffer.from([0x09]));
|
|
88
|
+
expect(toggle.isVerbose).toBe(true);
|
|
89
|
+
expect(mockDim).toHaveBeenCalledWith(' [verbose: on]');
|
|
90
|
+
|
|
91
|
+
// Toggle back
|
|
92
|
+
process.stdin.emit('data', Buffer.from([0x09]));
|
|
93
|
+
expect(toggle.isVerbose).toBe(false);
|
|
94
|
+
expect(mockDim).toHaveBeenCalledWith(' [verbose: off]');
|
|
95
|
+
|
|
96
|
+
toggle.stop();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('emits SIGINT on Ctrl+C keypress', () => {
|
|
100
|
+
const toggle = new VerboseToggle(false);
|
|
101
|
+
toggle.start();
|
|
102
|
+
|
|
103
|
+
const sigintHandler = jest.fn();
|
|
104
|
+
process.once('SIGINT', sigintHandler);
|
|
105
|
+
|
|
106
|
+
// Simulate Ctrl+C (0x03)
|
|
107
|
+
process.stdin.emit('data', Buffer.from([0x03]));
|
|
108
|
+
expect(sigintHandler).toHaveBeenCalled();
|
|
109
|
+
|
|
110
|
+
toggle.stop();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('ignores non-Tab, non-Ctrl+C keypresses', () => {
|
|
114
|
+
const toggle = new VerboseToggle(false);
|
|
115
|
+
toggle.start();
|
|
116
|
+
|
|
117
|
+
// Simulate 'a' keypress
|
|
118
|
+
process.stdin.emit('data', Buffer.from([0x61]));
|
|
119
|
+
expect(toggle.isVerbose).toBe(false);
|
|
120
|
+
|
|
121
|
+
toggle.stop();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('handles multiple bytes in a single data event', () => {
|
|
125
|
+
const toggle = new VerboseToggle(false);
|
|
126
|
+
toggle.start();
|
|
127
|
+
|
|
128
|
+
// Two Tab keys in one buffer
|
|
129
|
+
process.stdin.emit('data', Buffer.from([0x09, 0x09]));
|
|
130
|
+
// Should toggle twice → back to false
|
|
131
|
+
expect(toggle.isVerbose).toBe(false);
|
|
132
|
+
|
|
133
|
+
toggle.stop();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('restores stdin on stop()', () => {
|
|
137
|
+
const toggle = new VerboseToggle(false);
|
|
138
|
+
toggle.start();
|
|
139
|
+
toggle.stop();
|
|
140
|
+
|
|
141
|
+
expect(toggle.isActive).toBe(false);
|
|
142
|
+
expect(mockSetRawMode).toHaveBeenCalledWith(false);
|
|
143
|
+
expect(process.stdin.pause).toHaveBeenCalled();
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('is safe to call stop() multiple times', () => {
|
|
147
|
+
const toggle = new VerboseToggle(false);
|
|
148
|
+
toggle.start();
|
|
149
|
+
toggle.stop();
|
|
150
|
+
toggle.stop(); // should not throw
|
|
151
|
+
expect(toggle.isActive).toBe(false);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('is safe to call start() multiple times', () => {
|
|
155
|
+
const toggle = new VerboseToggle(false);
|
|
156
|
+
toggle.start();
|
|
157
|
+
toggle.start(); // should not start again
|
|
158
|
+
expect(mockSetRawMode).toHaveBeenCalledTimes(1);
|
|
159
|
+
toggle.stop();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('does not respond to keypress after stop()', () => {
|
|
163
|
+
const toggle = new VerboseToggle(false);
|
|
164
|
+
toggle.start();
|
|
165
|
+
toggle.stop();
|
|
166
|
+
|
|
167
|
+
// Clear mocks to check no new calls
|
|
168
|
+
mockDim.mockClear();
|
|
169
|
+
|
|
170
|
+
// This should not trigger any toggle
|
|
171
|
+
process.stdin.emit('data', Buffer.from([0x09]));
|
|
172
|
+
expect(toggle.isVerbose).toBe(false);
|
|
173
|
+
// Only the hint message was logged (already cleared by mockClear), no toggle messages
|
|
174
|
+
expect(mockDim).not.toHaveBeenCalled();
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('works correctly across multiple tasks (stop and restart)', () => {
|
|
178
|
+
const toggle = new VerboseToggle(false);
|
|
179
|
+
|
|
180
|
+
// First task
|
|
181
|
+
toggle.start();
|
|
182
|
+
process.stdin.emit('data', Buffer.from([0x09]));
|
|
183
|
+
expect(toggle.isVerbose).toBe(true);
|
|
184
|
+
toggle.stop();
|
|
185
|
+
|
|
186
|
+
// State persists after stop
|
|
187
|
+
expect(toggle.isVerbose).toBe(true);
|
|
188
|
+
|
|
189
|
+
// Restart for second task
|
|
190
|
+
toggle.start();
|
|
191
|
+
expect(toggle.isVerbose).toBe(true); // Still true from previous toggle
|
|
192
|
+
process.stdin.emit('data', Buffer.from([0x09]));
|
|
193
|
+
expect(toggle.isVerbose).toBe(false);
|
|
194
|
+
toggle.stop();
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('handles setRawMode throwing an error', () => {
|
|
198
|
+
mockSetRawMode.mockImplementation(() => { throw new Error('Cannot set raw mode'); });
|
|
199
|
+
const toggle = new VerboseToggle(false);
|
|
200
|
+
toggle.start();
|
|
201
|
+
// Should gracefully skip activation
|
|
202
|
+
expect(toggle.isActive).toBe(false);
|
|
203
|
+
});
|
|
204
|
+
});
|