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.
Files changed (135) hide show
  1. package/.claude/settings.local.json +4 -1
  2. package/CLAUDE.md +59 -11
  3. package/RAF/ahslfe-config-wizard/decisions.md +34 -0
  4. package/RAF/ahslfe-config-wizard/input.md +1 -0
  5. package/RAF/ahslfe-config-wizard/outcomes/01-define-config-schema.md +38 -0
  6. package/RAF/ahslfe-config-wizard/outcomes/02-refactor-codebase-to-use-config.md +67 -0
  7. package/RAF/ahslfe-config-wizard/outcomes/03-create-config-documentation.md +37 -0
  8. package/RAF/ahslfe-config-wizard/outcomes/04-implement-raf-config-command.md +47 -0
  9. package/RAF/ahslfe-config-wizard/outcomes/05-update-claude-md.md +26 -0
  10. package/RAF/ahslfe-config-wizard/plans/01-define-config-schema.md +73 -0
  11. package/RAF/ahslfe-config-wizard/plans/02-refactor-codebase-to-use-config.md +74 -0
  12. package/RAF/ahslfe-config-wizard/plans/03-create-config-documentation.md +57 -0
  13. package/RAF/ahslfe-config-wizard/plans/04-implement-raf-config-command.md +66 -0
  14. package/RAF/ahslfe-config-wizard/plans/05-update-claude-md.md +60 -0
  15. package/RAF/ahstvo-token-tracker/decisions.md +44 -0
  16. package/RAF/ahstvo-token-tracker/input.md +3 -0
  17. package/RAF/ahstvo-token-tracker/outcomes/01-full-model-id-support.md +43 -0
  18. package/RAF/ahstvo-token-tracker/outcomes/02-name-generation-no-session.md +33 -0
  19. package/RAF/ahstvo-token-tracker/outcomes/03-unify-stream-json-execution.md +48 -0
  20. package/RAF/ahstvo-token-tracker/outcomes/04-token-tracking-cost-calculation.md +53 -0
  21. package/RAF/ahstvo-token-tracker/outcomes/05-token-cost-console-reporting.md +57 -0
  22. package/RAF/ahstvo-token-tracker/outcomes/06-runtime-verbose-toggle.md +53 -0
  23. package/RAF/ahstvo-token-tracker/outcomes/07-readme-config-docs.md +36 -0
  24. package/RAF/ahstvo-token-tracker/plans/01-full-model-id-support.md +35 -0
  25. package/RAF/ahstvo-token-tracker/plans/02-name-generation-no-session.md +36 -0
  26. package/RAF/ahstvo-token-tracker/plans/03-unify-stream-json-execution.md +44 -0
  27. package/RAF/ahstvo-token-tracker/plans/04-token-tracking-cost-calculation.md +56 -0
  28. package/RAF/ahstvo-token-tracker/plans/05-token-cost-console-reporting.md +55 -0
  29. package/RAF/ahstvo-token-tracker/plans/06-runtime-verbose-toggle.md +48 -0
  30. package/RAF/ahstvo-token-tracker/plans/07-readme-config-docs.md +44 -0
  31. package/RAF/ahtahs-token-reaper/decisions.md +37 -0
  32. package/RAF/ahtahs-token-reaper/input.md +20 -0
  33. package/RAF/ahtahs-token-reaper/outcomes/01-extend-token-tracker-data-model.md +42 -0
  34. package/RAF/ahtahs-token-reaper/outcomes/02-accumulate-usage-in-retry-loop.md +31 -0
  35. package/RAF/ahtahs-token-reaper/outcomes/03-per-attempt-display-formatting.md +60 -0
  36. package/RAF/ahtahs-token-reaper/outcomes/04-add-model-name-to-claude-call-logs.md +57 -0
  37. package/RAF/ahtahs-token-reaper/outcomes/05-handle-invalid-config-in-raf-config.md +46 -0
  38. package/RAF/ahtahs-token-reaper/outcomes/06-fix-verbose-toggle-timer-display.md +38 -0
  39. package/RAF/ahtahs-token-reaper/plans/01-extend-token-tracker-data-model.md +36 -0
  40. package/RAF/ahtahs-token-reaper/plans/02-accumulate-usage-in-retry-loop.md +36 -0
  41. package/RAF/ahtahs-token-reaper/plans/03-per-attempt-display-formatting.md +43 -0
  42. package/RAF/ahtahs-token-reaper/plans/04-add-model-name-to-claude-call-logs.md +38 -0
  43. package/RAF/ahtahs-token-reaper/plans/05-handle-invalid-config-in-raf-config.md +36 -0
  44. package/RAF/ahtahs-token-reaper/plans/06-fix-verbose-toggle-timer-display.md +40 -0
  45. package/README.md +34 -0
  46. package/dist/commands/config.d.ts +3 -0
  47. package/dist/commands/config.d.ts.map +1 -0
  48. package/dist/commands/config.js +195 -0
  49. package/dist/commands/config.js.map +1 -0
  50. package/dist/commands/do.d.ts.map +1 -1
  51. package/dist/commands/do.js +55 -7
  52. package/dist/commands/do.js.map +1 -1
  53. package/dist/commands/plan.d.ts.map +1 -1
  54. package/dist/commands/plan.js +5 -3
  55. package/dist/commands/plan.js.map +1 -1
  56. package/dist/core/claude-runner.d.ts +19 -2
  57. package/dist/core/claude-runner.d.ts.map +1 -1
  58. package/dist/core/claude-runner.js +43 -96
  59. package/dist/core/claude-runner.js.map +1 -1
  60. package/dist/core/failure-analyzer.d.ts.map +1 -1
  61. package/dist/core/failure-analyzer.js +6 -3
  62. package/dist/core/failure-analyzer.js.map +1 -1
  63. package/dist/core/git.d.ts.map +1 -1
  64. package/dist/core/git.js +10 -3
  65. package/dist/core/git.js.map +1 -1
  66. package/dist/core/pull-request.d.ts +1 -1
  67. package/dist/core/pull-request.d.ts.map +1 -1
  68. package/dist/core/pull-request.js +9 -4
  69. package/dist/core/pull-request.js.map +1 -1
  70. package/dist/index.js +2 -0
  71. package/dist/index.js.map +1 -1
  72. package/dist/parsers/stream-renderer.d.ts +16 -1
  73. package/dist/parsers/stream-renderer.d.ts.map +1 -1
  74. package/dist/parsers/stream-renderer.js +34 -4
  75. package/dist/parsers/stream-renderer.js.map +1 -1
  76. package/dist/prompts/execution.d.ts.map +1 -1
  77. package/dist/prompts/execution.js +11 -1
  78. package/dist/prompts/execution.js.map +1 -1
  79. package/dist/types/config.d.ts +95 -4
  80. package/dist/types/config.d.ts.map +1 -1
  81. package/dist/types/config.js +63 -3
  82. package/dist/types/config.js.map +1 -1
  83. package/dist/utils/config.d.ts +65 -7
  84. package/dist/utils/config.d.ts.map +1 -1
  85. package/dist/utils/config.js +297 -21
  86. package/dist/utils/config.js.map +1 -1
  87. package/dist/utils/name-generator.d.ts +3 -7
  88. package/dist/utils/name-generator.d.ts.map +1 -1
  89. package/dist/utils/name-generator.js +75 -61
  90. package/dist/utils/name-generator.js.map +1 -1
  91. package/dist/utils/terminal-symbols.d.ts +25 -0
  92. package/dist/utils/terminal-symbols.d.ts.map +1 -1
  93. package/dist/utils/terminal-symbols.js +87 -0
  94. package/dist/utils/terminal-symbols.js.map +1 -1
  95. package/dist/utils/token-tracker.d.ts +55 -0
  96. package/dist/utils/token-tracker.d.ts.map +1 -0
  97. package/dist/utils/token-tracker.js +142 -0
  98. package/dist/utils/token-tracker.js.map +1 -0
  99. package/dist/utils/validation.d.ts +5 -5
  100. package/dist/utils/validation.d.ts.map +1 -1
  101. package/dist/utils/validation.js +10 -6
  102. package/dist/utils/validation.js.map +1 -1
  103. package/dist/utils/verbose-toggle.d.ts +33 -0
  104. package/dist/utils/verbose-toggle.d.ts.map +1 -0
  105. package/dist/utils/verbose-toggle.js +94 -0
  106. package/dist/utils/verbose-toggle.js.map +1 -0
  107. package/package.json +1 -1
  108. package/src/commands/config.ts +230 -0
  109. package/src/commands/do.ts +64 -6
  110. package/src/commands/plan.ts +5 -3
  111. package/src/core/claude-runner.ts +59 -115
  112. package/src/core/failure-analyzer.ts +6 -3
  113. package/src/core/git.ts +10 -3
  114. package/src/core/pull-request.ts +9 -4
  115. package/src/index.ts +2 -0
  116. package/src/parsers/stream-renderer.ts +54 -4
  117. package/src/prompts/config-docs.md +331 -0
  118. package/src/prompts/execution.ts +13 -1
  119. package/src/types/config.ts +156 -7
  120. package/src/utils/config.ts +357 -21
  121. package/src/utils/name-generator.ts +84 -71
  122. package/src/utils/terminal-symbols.ts +103 -0
  123. package/src/utils/token-tracker.ts +177 -0
  124. package/src/utils/validation.ts +15 -10
  125. package/src/utils/verbose-toggle.ts +103 -0
  126. package/tests/unit/claude-runner.test.ts +171 -7
  127. package/tests/unit/config-command.test.ts +242 -0
  128. package/tests/unit/config.test.ts +632 -30
  129. package/tests/unit/name-generator.test.ts +99 -75
  130. package/tests/unit/pull-request.test.ts +2 -0
  131. package/tests/unit/stream-renderer.test.ts +83 -0
  132. package/tests/unit/terminal-symbols.test.ts +245 -0
  133. package/tests/unit/timer-verbose-integration.test.ts +170 -0
  134. package/tests/unit/token-tracker.test.ts +685 -0
  135. 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
+ });