@herbcaudill/ralph 0.2.0 → 0.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 (175) hide show
  1. package/bin/ralph.js +1 -1
  2. package/dist/cli.d.ts +2 -19
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +30 -65
  5. package/dist/cli.js.map +1 -1
  6. package/dist/components/App.d.ts +10 -0
  7. package/dist/components/App.d.ts.map +1 -0
  8. package/dist/components/App.js +16 -0
  9. package/dist/components/App.js.map +1 -0
  10. package/dist/components/EventDisplay.d.ts +7 -0
  11. package/dist/components/EventDisplay.d.ts.map +1 -0
  12. package/dist/components/EventDisplay.js +64 -0
  13. package/dist/components/EventDisplay.js.map +1 -0
  14. package/dist/components/EventDisplay.replay.test.d.ts +2 -0
  15. package/dist/components/EventDisplay.replay.test.d.ts.map +1 -0
  16. package/dist/components/EventDisplay.replay.test.js +403 -0
  17. package/dist/components/EventDisplay.replay.test.js.map +1 -0
  18. package/dist/components/EventDisplay.test.d.ts +2 -0
  19. package/dist/components/EventDisplay.test.d.ts.map +1 -0
  20. package/dist/components/EventDisplay.test.js +223 -0
  21. package/dist/components/EventDisplay.test.js.map +1 -0
  22. package/dist/components/Header.d.ts +8 -0
  23. package/dist/components/Header.d.ts.map +1 -0
  24. package/dist/components/Header.js +15 -0
  25. package/dist/components/Header.js.map +1 -0
  26. package/dist/components/Header.test.d.ts +2 -0
  27. package/dist/components/Header.test.d.ts.map +1 -0
  28. package/dist/components/Header.test.js +27 -0
  29. package/dist/components/Header.test.js.map +1 -0
  30. package/dist/components/InitRalph.d.ts +3 -0
  31. package/dist/components/InitRalph.d.ts.map +1 -0
  32. package/dist/components/InitRalph.js +100 -0
  33. package/dist/components/InitRalph.js.map +1 -0
  34. package/dist/components/IterationRunner.d.ts +7 -0
  35. package/dist/components/IterationRunner.d.ts.map +1 -0
  36. package/dist/components/IterationRunner.js +285 -0
  37. package/dist/components/IterationRunner.js.map +1 -0
  38. package/dist/components/IterationRunner.test.d.ts +2 -0
  39. package/dist/components/IterationRunner.test.d.ts.map +1 -0
  40. package/dist/components/IterationRunner.test.js +109 -0
  41. package/dist/components/IterationRunner.test.js.map +1 -0
  42. package/dist/components/ReplayLog.d.ts +7 -0
  43. package/dist/components/ReplayLog.d.ts.map +1 -0
  44. package/dist/components/ReplayLog.js +51 -0
  45. package/dist/components/ReplayLog.js.map +1 -0
  46. package/dist/components/StreamingText.d.ts +7 -0
  47. package/dist/components/StreamingText.d.ts.map +1 -0
  48. package/dist/components/StreamingText.js +36 -0
  49. package/dist/components/StreamingText.js.map +1 -0
  50. package/dist/components/StreamingText.test.d.ts +2 -0
  51. package/dist/components/StreamingText.test.d.ts.map +1 -0
  52. package/dist/components/StreamingText.test.js +86 -0
  53. package/dist/components/StreamingText.test.js.map +1 -0
  54. package/dist/components/ToolUse.d.ts +8 -0
  55. package/dist/components/ToolUse.d.ts.map +1 -0
  56. package/dist/components/ToolUse.js +10 -0
  57. package/dist/components/ToolUse.js.map +1 -0
  58. package/dist/components/ToolUse.test.d.ts +2 -0
  59. package/dist/components/ToolUse.test.d.ts.map +1 -0
  60. package/dist/components/ToolUse.test.js +43 -0
  61. package/dist/components/ToolUse.test.js.map +1 -0
  62. package/dist/components/eventToBlocks.d.ts +12 -0
  63. package/dist/components/eventToBlocks.d.ts.map +1 -0
  64. package/dist/components/eventToBlocks.js +142 -0
  65. package/dist/components/eventToBlocks.js.map +1 -0
  66. package/dist/components/eventToBlocks.test.d.ts +2 -0
  67. package/dist/components/eventToBlocks.test.d.ts.map +1 -0
  68. package/dist/components/eventToBlocks.test.js +412 -0
  69. package/dist/components/eventToBlocks.test.js.map +1 -0
  70. package/dist/index.d.ts +1 -0
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +3 -21
  73. package/dist/index.js.map +1 -1
  74. package/dist/lib/cleanupAllWorktrees.d.ts +5 -0
  75. package/dist/lib/cleanupAllWorktrees.d.ts.map +1 -0
  76. package/dist/lib/cleanupAllWorktrees.js +25 -0
  77. package/dist/lib/cleanupAllWorktrees.js.map +1 -0
  78. package/dist/lib/cleanupWorktree.d.ts +6 -0
  79. package/dist/lib/cleanupWorktree.d.ts.map +1 -0
  80. package/dist/lib/cleanupWorktree.js +33 -0
  81. package/dist/lib/cleanupWorktree.js.map +1 -0
  82. package/dist/lib/copyRalphFilesFromWorktree.d.ts +5 -0
  83. package/dist/lib/copyRalphFilesFromWorktree.d.ts.map +1 -0
  84. package/dist/lib/copyRalphFilesFromWorktree.js +19 -0
  85. package/dist/lib/copyRalphFilesFromWorktree.js.map +1 -0
  86. package/dist/lib/copyRalphFilesToWorktree.d.ts +5 -0
  87. package/dist/lib/copyRalphFilesToWorktree.d.ts.map +1 -0
  88. package/dist/lib/copyRalphFilesToWorktree.js +21 -0
  89. package/dist/lib/copyRalphFilesToWorktree.js.map +1 -0
  90. package/dist/lib/createWorktree.d.ts +6 -0
  91. package/dist/lib/createWorktree.d.ts.map +1 -0
  92. package/dist/lib/createWorktree.js +34 -0
  93. package/dist/lib/createWorktree.js.map +1 -0
  94. package/dist/lib/getClaudeVersion.d.ts +2 -0
  95. package/dist/lib/getClaudeVersion.d.ts.map +1 -0
  96. package/dist/lib/getClaudeVersion.js +17 -0
  97. package/dist/lib/getClaudeVersion.js.map +1 -0
  98. package/dist/lib/getClaudeVersion.test.d.ts +2 -0
  99. package/dist/lib/getClaudeVersion.test.d.ts.map +1 -0
  100. package/dist/lib/getClaudeVersion.test.js +39 -0
  101. package/dist/lib/getClaudeVersion.test.js.map +1 -0
  102. package/dist/lib/getGitRoot.d.ts +5 -0
  103. package/dist/lib/getGitRoot.d.ts.map +1 -0
  104. package/dist/lib/getGitRoot.js +18 -0
  105. package/dist/lib/getGitRoot.js.map +1 -0
  106. package/dist/lib/installDependencies.d.ts +5 -0
  107. package/dist/lib/installDependencies.d.ts.map +1 -0
  108. package/dist/lib/installDependencies.js +23 -0
  109. package/dist/lib/installDependencies.js.map +1 -0
  110. package/dist/lib/installDependencies.test.d.ts +2 -0
  111. package/dist/lib/installDependencies.test.d.ts.map +1 -0
  112. package/dist/lib/installDependencies.test.js +37 -0
  113. package/dist/lib/installDependencies.test.js.map +1 -0
  114. package/dist/lib/mergeWorktreeToMain.d.ts +6 -0
  115. package/dist/lib/mergeWorktreeToMain.d.ts.map +1 -0
  116. package/dist/lib/mergeWorktreeToMain.js +44 -0
  117. package/dist/lib/mergeWorktreeToMain.js.map +1 -0
  118. package/dist/lib/popStash.d.ts +5 -0
  119. package/dist/lib/popStash.d.ts.map +1 -0
  120. package/dist/lib/popStash.js +17 -0
  121. package/dist/lib/popStash.js.map +1 -0
  122. package/dist/lib/rel.test.d.ts +2 -0
  123. package/dist/lib/rel.test.d.ts.map +1 -0
  124. package/dist/lib/rel.test.js +36 -0
  125. package/dist/lib/rel.test.js.map +1 -0
  126. package/dist/lib/replayLog.d.ts.map +1 -1
  127. package/dist/lib/replayLog.js +20 -6
  128. package/dist/lib/replayLog.js.map +1 -1
  129. package/dist/lib/runIteration.d.ts.map +1 -1
  130. package/dist/lib/runIteration.js +18 -8
  131. package/dist/lib/runIteration.js.map +1 -1
  132. package/dist/lib/shortenTempPaths.test.d.ts +2 -0
  133. package/dist/lib/shortenTempPaths.test.d.ts.map +1 -0
  134. package/dist/lib/shortenTempPaths.test.js +46 -0
  135. package/dist/lib/shortenTempPaths.test.js.map +1 -0
  136. package/dist/lib/signalHandler.d.ts +3 -0
  137. package/dist/lib/signalHandler.d.ts.map +1 -0
  138. package/dist/lib/signalHandler.js +19 -0
  139. package/dist/lib/signalHandler.js.map +1 -0
  140. package/dist/lib/stashChanges.d.ts +6 -0
  141. package/dist/lib/stashChanges.d.ts.map +1 -0
  142. package/dist/lib/stashChanges.js +27 -0
  143. package/dist/lib/stashChanges.js.map +1 -0
  144. package/dist/lib/types.d.ts +8 -0
  145. package/dist/lib/types.d.ts.map +1 -0
  146. package/dist/lib/types.js +5 -0
  147. package/dist/lib/types.js.map +1 -0
  148. package/dist/lib/worktree.d.ts +43 -0
  149. package/dist/lib/worktree.d.ts.map +1 -0
  150. package/dist/lib/worktree.js +210 -0
  151. package/dist/lib/worktree.js.map +1 -0
  152. package/dist/ui/EventProcessor.d.ts +11 -0
  153. package/dist/ui/EventProcessor.d.ts.map +1 -0
  154. package/dist/ui/EventProcessor.js +95 -0
  155. package/dist/ui/EventProcessor.js.map +1 -0
  156. package/dist/ui/IterationApp.d.ts +10 -0
  157. package/dist/ui/IterationApp.d.ts.map +1 -0
  158. package/dist/ui/IterationApp.js +21 -0
  159. package/dist/ui/IterationApp.js.map +1 -0
  160. package/dist/ui/IterationUI.d.ts +13 -0
  161. package/dist/ui/IterationUI.d.ts.map +1 -0
  162. package/dist/ui/IterationUI.js +19 -0
  163. package/dist/ui/IterationUI.js.map +1 -0
  164. package/dist/ui/TextDisplay.d.ts +7 -0
  165. package/dist/ui/TextDisplay.d.ts.map +1 -0
  166. package/dist/ui/TextDisplay.js +41 -0
  167. package/dist/ui/TextDisplay.js.map +1 -0
  168. package/dist/ui/ToolUseDisplay.d.ts +10 -0
  169. package/dist/ui/ToolUseDisplay.d.ts.map +1 -0
  170. package/dist/ui/ToolUseDisplay.js +10 -0
  171. package/dist/ui/ToolUseDisplay.js.map +1 -0
  172. package/package.json +23 -4
  173. package/templates/progress.md +1 -1
  174. package/templates/prompt.md +11 -1
  175. package/templates/todo.md +0 -1
@@ -0,0 +1,403 @@
1
+ import React from "react";
2
+ import { render } from "ink-testing-library";
3
+ import { describe, it, expect, vi } from "vitest";
4
+ import { readFileSync } from "fs";
5
+ import { join } from "path";
6
+ import { EventDisplay } from "./EventDisplay.js";
7
+ /**
8
+ * Helper function to replay an event log file and return the rendered output
9
+ */
10
+ async function replay(logFile) {
11
+ // Read the event log
12
+ const logPath = join(process.cwd(), "test/event-logs", logFile);
13
+ const logContent = readFileSync(logPath, "utf-8");
14
+ // Parse JSON events (multi-line JSON objects separated by blank lines)
15
+ const events = [];
16
+ const jsonObjects = logContent.split("\n\n");
17
+ for (const jsonStr of jsonObjects) {
18
+ if (!jsonStr.trim())
19
+ continue;
20
+ try {
21
+ const event = JSON.parse(jsonStr);
22
+ events.push(event);
23
+ }
24
+ catch {
25
+ // Skip invalid JSON
26
+ }
27
+ }
28
+ // Render with all events
29
+ const { lastFrame } = render(React.createElement(EventDisplay, { events: events }));
30
+ // Wait for rendering
31
+ await vi.waitFor(() => {
32
+ const output = lastFrame() ?? "";
33
+ expect(output.length).toBeGreaterThan(0);
34
+ }, { timeout: 1000 });
35
+ return lastFrame() ?? "";
36
+ }
37
+ describe("EventDisplay replay tests", () => {
38
+ it("replays 1.txt", async () => {
39
+ expect(await replay("1.txt")).toMatchInlineSnapshot(`
40
+ "I'll start by checking the types, unit tests, and end-to-end tests as instructed.
41
+
42
+ TodoWrite
43
+ [~] Run typecheck to verify types
44
+ [ ] Run unit tests via pnpm test
45
+ [ ] Run end-to-end tests via pnpm test:pw
46
+
47
+ $ pnpm typecheck
48
+
49
+ Good! Types check successfully. Now let me run the unit tests.
50
+
51
+ TodoWrite
52
+ [x] Run typecheck to verify types
53
+ [~] Run unit tests via pnpm test
54
+ [ ] Run end-to-end tests via pnpm test:pw
55
+
56
+ $ pnpm test
57
+
58
+ Perfect! Unit tests pass. Now let me run the end-to-end tests.
59
+
60
+ TodoWrite
61
+ [x] Run typecheck to verify types
62
+ [x] Run unit tests via pnpm test
63
+ [~] Run end-to-end tests via pnpm test:pw
64
+
65
+ $ pnpm test:pw"
66
+ `);
67
+ });
68
+ it("replays 2.txt", async () => {
69
+ expect(await replay("2.txt")).toMatchInlineSnapshot(`
70
+ "I'll start by checking that the project builds successfully and running tests.
71
+
72
+ $ pnpm build
73
+
74
+ $ pnpm test
75
+
76
+ Good! The build is successful and all tests pass. Now let me check the todo list to find the
77
+ highest-priority task.
78
+
79
+ Read .ralph/todo.md
80
+
81
+ Looking at the todo list, I'll prioritize the "Inline code blocks are being put in separate
82
+ paragraphs" issue. This is a functional bug affecting the display quality, whereas the others are
83
+ enhancements. Let me investigate this issue first.
84
+
85
+ Read src/components/StreamingText.tsx
86
+
87
+ Let me check the tests to understand the expected behavior and see if there's a failing test case:
88
+
89
+ Read src/components/StreamingText.test.tsx
90
+
91
+ I need to understand where StreamingText is being used and what the actual problem is. Let me check
92
+ where it's called from and look at some example output:
93
+
94
+ Grep StreamingText
95
+
96
+ Read src/components/EventDisplay.tsx
97
+
98
+ I see the issue now! In EventDisplay.tsx:70, there's a <Box flexDirection="column" gap={1}> which
99
+ wraps each StreamingText component. Each StreamingText (which represents text blocks) is being
100
+ placed in its own box with a gap, causing inline code to appear in separate paragraphs.
101
+
102
+ The problem is that each text block from Claude's message content is being rendered as a separate
103
+ StreamingText component with gaps between them. This works fine for separate paragraphs, but inline
104
+ code within a sentence gets split incorrectly.
105
+
106
+ Let me look at how the events are being split into blocks:
107
+
108
+ Read src/components/eventToBlocks.ts
109
+
110
+ Now I understand the issue. Claude's message content can have multiple text blocks (e.g., "Here's
111
+ the code: ", then a tool_use block, then " and that's it"). Each text block becomes a separate
112
+ ContentBlock with type "text", and EventDisplay renders each one as a separate <StreamingText>
113
+ component in a Box with gap={1}, causing unwanted spacing.
114
+
115
+ The fix should be to merge consecutive text blocks together. Let me write a test first to
116
+ demonstrate the problem:
117
+
118
+ Read src/components/EventDisplay.test.tsx
119
+
120
+ Now let me add a test that demonstrates the inline code block problem and then fix it:
121
+
122
+ Edit src/components/EventDisplay.test.tsx
123
+
124
+ Now let me run the test to confirm it fails (demonstrating the problem):
125
+
126
+ $ pnpm test EventDisplay.test.tsx
127
+
128
+ Perfect! The test fails as expected, confirming the bug. Now I need to fix it by modifying
129
+ eventToBlocks to merge consecutive text blocks:
130
+
131
+ Edit src/components/eventToBlocks.ts
132
+
133
+ Now I need to also flush the text buffer at the end of the loop:
134
+
135
+ Edit src/components/eventToBlocks.ts
136
+
137
+ Now let me run the tests again to verify the fix works:
138
+
139
+ $ pnpm test EventDisplay.test.tsx
140
+
141
+ The test still fails. This suggests the problem might also be in EventDisplay, not just
142
+ eventToBlocks. Let me debug by adding a simpler test to see what's happening in eventToBlocks:
143
+
144
+ Read src/components/eventToBlocks.test.ts
145
+
146
+ I see! The existing test "extracts multiple text blocks" expects them NOT to be merged. I need to
147
+ update this test and add a new one specifically for consecutive text blocks:
148
+
149
+ Edit src/components/eventToBlocks.test.ts
150
+
151
+ Now let me add a test for text blocks separated by tool calls:
152
+
153
+ Read src/components/eventToBlocks.test.ts
154
+
155
+ Let me add a test that specifically checks text blocks separated by tool calls:
156
+
157
+ Edit src/components/eventToBlocks.test.ts
158
+
159
+ Now let me run all tests to verify my changes to eventToBlocks work:
160
+
161
+ $ pnpm test eventToBlocks.test.ts
162
+
163
+ I need to look at this failing test:
164
+
165
+ Read src/components/eventToBlocks.test.ts
166
+
167
+ This test expects 3 separate IDs for 3 text blocks, but my code now merges them into 1. I need to
168
+ update this test to reflect the new behavior:
169
+
170
+ Edit src/components/eventToBlocks.test.ts
171
+
172
+ Now let me run the eventToBlocks tests again:
173
+
174
+ $ pnpm test eventToBlocks.test.ts
175
+
176
+ Great! Now let me run the EventDisplay test again:
177
+
178
+ $ pnpm test EventDisplay.test.tsx
179
+
180
+ The problem is still happening at the EventDisplay level. Let me check what's actually being
181
+ rendered. The issue must be in how EventDisplay merges the events. Let me look more carefully at the
182
+ EventDisplay logic:
183
+
184
+ Read src/components/EventDisplay.tsx
185
+
186
+ I see! The EventDisplay is doing its own deduplication, but it's NOT merging consecutive text
187
+ blocks. The text blocks in the test data remain separate even after eventToBlocks merges them,
188
+ because my test is creating a single event with 3 separate text blocks in content.
189
+
190
+ Wait, let me re-check the flow. EventDisplay calls eventToBlocks on each merged event. So if
191
+ eventToBlocks correctly merges text blocks, then EventDisplay should get a single merged text block.
192
+ Let me debug by adding a console log or looking at what's actually happening.
193
+
194
+ Let me write a simpler test to see what's going on:
195
+
196
+ $ cat > test-merge.ts << 'EOF'
197
+ import { eventToBlocks } from "./src/components/eventToBlocks.js"
198
+
199
+ const event = {
200
+ type: "assistant",
201
+ message: {
202
+ id: "msg_123",
203
+ content: [
204
+ { type: "text", text: "Use the " },
205
+ { type: "text", text: "\`console.log()\`" },
206
+ { type: "text", text: " function to debug." },
207
+ ],
208
+ },
209
+ }
210
+
211
+ const result = eventToBlocks(event)
212
+ console.log("Result:", JSON.stringify(result, null, 2))
213
+ EOF
214
+ tsx test-merge.ts
215
+
216
+ Let me check if my fix is actually working by looking at the eventToBlocks implementation more
217
+ carefully. Actually, let me just trace through what should happen:
218
+
219
+ 1. eventToBlocks receives an event with 3 text blocks
220
+ 2. It loops through content
221
+ 3. First text block: adds "Use the " to textBuffer
222
+ 4. Second text block: adds "console.log()" to textBuffer (now "Use the console.log()")
223
+ 5. Third text block: adds " function to debug." to textBuffer (now "Use the console.log() function
224
+ to debug.")
225
+ 6. After the loop, it flushes the textBuffer as one merged text block
226
+
227
+ That should work! Let me check if there's an issue with my implementation. Let me re-read the code:
228
+
229
+ Read src/components/eventToBlocks.ts
230
+
231
+ The code looks correct. Let me check if the EventDisplay is receiving the correct merged content. I
232
+ think the issue might be in how EventDisplay deduplicates and merges content before calling
233
+ eventToBlocks. Let me look at that logic again:
234
+
235
+ Read src/components/EventDisplay.tsx
236
+
237
+ Ah! I see the problem now. In the test, we're providing a single event with one message containing 3
238
+ text blocks. EventDisplay keeps the text blocks separate in uniqueContent (lines 36-54), so they
239
+ stay as 3 separate blocks before being passed to eventToBlocks. Then eventToBlocks merges them. But
240
+ there's still the Box with gap={1} that creates spacing.
241
+
242
+ Wait, actually looking at the logic again - eventToBlocks should merge them, and return a single
243
+ ContentBlock. Then that single block gets rendered as a single <StreamingText> component. So there
244
+ should be no gaps.
245
+
246
+ Let me add some logging to see what's actually happening. But actually, I think the problem is that
247
+ the test is checking for newlines in the output. Ink's Box with flexDirection="column" adds newlines
248
+ between elements. So even if I have 1 StreamingText, the Box might still add newlines around it.
249
+
250
+ Actually wait - if eventToBlocks returns 1 block, then there's only 1 child in the Box, so there
251
+ should be no gaps. Let me trace through more carefully what the test is doing:
252
+
253
+ In the test, we render <EventDisplay events={[...]} />. The EventDisplay:
254
+ 1. Filters to assistant messages
255
+ 2. Merges by message ID (only 1 message)
256
+ 3. Deduplicates (all 3 text blocks are unique)
257
+ 4. Calls eventToBlocks on the merged event
258
+ 5. eventToBlocks should merge the 3 text blocks into 1
259
+ 6. Renders the blocks
260
+
261
+ Let me print what lastFrame() actually returns by modifying the test temporarily:
262
+
263
+ Edit src/components/EventDisplay.test.tsx
264
+
265
+ $ pnpm test EventDisplay.test.tsx 2>&1 | grep -A 20 "merges consecutive"
266
+
267
+ Aha! The output is "Use the\\n\\nconsole.log()\\n\\n function to debug." - there are TWO newlines
268
+ between each part! This tells me that the 3 text blocks are NOT being merged by eventToBlocks.
269
+ They're still coming through as 3 separate parts.
270
+
271
+ This means the EventDisplay deduplication logic is keeping them separate, OR there's a bug in my
272
+ eventToBlocks implementation. Let me add logging to eventToBlocks to see:
273
+
274
+ Edit src/components/eventToBlocks.ts
275
+
276
+ $ pnpm test EventDisplay.test.tsx 2>&1 | grep -A 30 "eventToBlocks content"
277
+
278
+ Perfect! So eventToBlocks IS receiving the 3 separate text blocks:
279
+ json
280
+ [
281
+ { "type": "text", "text": "Use the " },
282
+ { "type": "text", "text": "console.log()" },
283
+ { "type": "text", "text": " function to debug." }
284
+ ]
285
+
286
+
287
+ But the output still shows them on 3 separate lines. This means my merging logic isn't working. Let
288
+ me add more logging to see what's happening in the loop:
289
+
290
+ Edit src/components/eventToBlocks.ts
291
+
292
+ Edit src/components/eventToBlocks.ts
293
+
294
+ $ pnpm test EventDisplay.test.tsx 2>&1 | grep -A 50 "merges consecutive text blocks to prevent
295
+ unwanted gaps"
296
+
297
+ EXCELLENT! The merging IS working correctly:
298
+ - eventToBlocks returns: [{ "type": "text", "content": "Use the console.log() function to debug.",
299
+ "id": "msg_123-0" }]
300
+
301
+ But the output is still: "Use the\\n\\nconsole.log()\\n\\n function to debug."
302
+
303
+ This means the problem is in how StreamingText is rendering! The backticks in the merged text are
304
+ being split up by StreamingText's markdown processing. Let me check the StreamingText component
305
+ logic again - it must be detecting the backticks and rendering them as separate Text components, and
306
+ those are getting newlines between them!
307
+
308
+ Oh wait, I see it now! Look at EventDisplay:69-76:
309
+
310
+ tsx
311
+ <Box flexDirection="column" gap={1}>
312
+ {contentBlocks.map(block =>
313
+ block.type === "text" ?
314
+ <StreamingText key={block.id} content={block.content} />
315
+ : <ToolUse key={block.id} name={block.name} arg={block.arg} />,
316
+ )}
317
+ </Box>
318
+
319
+
320
+ The Box has gap={1}, which adds gaps between CHILDREN. StreamingText renders multiple <Text>
321
+ components (one for each formatted segment), and those become CHILDREN of the parent, not siblings.
322
+ Wait, no - StreamingText returns a fragment <>...</> containing multiple Text components.
323
+
324
+ Actually, I think the issue is that Ink is rendering the separate Text components with gaps. Let me
325
+ check StreamingText more carefully - it returns a fragment with separate Text components. Those Text
326
+ components might be getting wrapped or treated differently by Ink.
327
+
328
+ Actually, I think the real fix is to render StreamingText as inline, not in a column layout. But
329
+ wait, the Box flexDirection="column" affects the layout of contentBlocks (Text vs ToolUse), not the
330
+ internal layout of StreamingText.
331
+
332
+ Let me check if the problem is in how StreamingText uses fragments. When you return a fragment with
333
+ multiple <Text> components in Ink, they might be rendered on separate lines. Let me check:
334
+
335
+ Read src/components/StreamingText.tsx
336
+
337
+ The issue is that StreamingText returns a fragment with multiple <Text> components. In Ink, these
338
+ might be rendered as separate blocks. The fix is to wrap them in a single <Text> component or use
339
+ the <Text wrap="wrap"> with inline rendering.
340
+
341
+ Let me look at how Ink handles multiple Text components. Actually, the fix is simple - wrap all the
342
+ text parts in a single Box or Text component with inline rendering:
343
+
344
+ Edit src/components/StreamingText.tsx
345
+
346
+ Edit src/components/StreamingText.tsx
347
+
348
+ Now let me remove the console.log statements and test:
349
+
350
+ Edit src/components/eventToBlocks.ts
351
+
352
+ Edit src/components/eventToBlocks.ts
353
+
354
+ Edit src/components/EventDisplay.test.tsx
355
+
356
+ Now let me run all tests:
357
+
358
+ $ pnpm test
359
+
360
+ Perfect! All tests pass now. Let me verify the build still works:
361
+
362
+ $ pnpm build
363
+
364
+ Excellent! Now let me update the todo list and progress file, then commit:
365
+
366
+ Read .ralph/todo.md
367
+
368
+ Edit .ralph/todo.md
369
+
370
+ Read .ralph/progress.md
371
+
372
+ Edit .ralph/progress.md
373
+
374
+ Now let me format the code with Prettier:
375
+
376
+ $ pnpm format
377
+
378
+ Good! Now let me commit all these changes:
379
+
380
+ $ git add -A && git diff --cached --stat
381
+
382
+ $ git commit -m "$(cat <<'EOF'
383
+ Fix inline code blocks appearing in separate paragraphs
384
+
385
+ - Modified eventToBlocks.ts to merge consecutive text blocks using a textBuffer
386
+ - Wrapped StreamingText content in Box component for proper inline rendering
387
+ - Added test case to verify consecutive text blocks are merged
388
+ - Updated existing tests to reflect new merging behavior
389
+
390
+ Fixes issue where inline code like \`console.log()\` was rendered on separate
391
+ lines with gaps instead of flowing inline with surrounding text.
392
+
393
+ Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
394
+ EOF
395
+ )"
396
+
397
+ Perfect! Let me verify git status:
398
+
399
+ $ git status"
400
+ `);
401
+ });
402
+ });
403
+ //# sourceMappingURL=EventDisplay.replay.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventDisplay.replay.test.js","sourceRoot":"","sources":["../../src/components/EventDisplay.replay.test.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEhD;;GAEG;AACH,KAAK,UAAU,MAAM,CAAC,OAAe;IACnC,qBAAqB;IACrB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,iBAAiB,EAAE,OAAO,CAAC,CAAA;IAC/D,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IAEjD,uEAAuE;IACvE,MAAM,MAAM,GAAmC,EAAE,CAAA;IACjD,MAAM,WAAW,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IAC5C,KAAK,MAAM,OAAO,IAAI,WAAW,EAAE,CAAC;QAClC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;YAAE,SAAQ;QAC7B,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;YACjC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,oBAAoB;QACtB,CAAC;IACH,CAAC;IAED,yBAAyB;IACzB,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,oBAAC,YAAY,IAAC,MAAM,EAAE,MAAM,GAAI,CAAC,CAAA;IAE9D,qBAAqB;IACrB,MAAM,EAAE,CAAC,OAAO,CACd,GAAG,EAAE;QACH,MAAM,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,CAAA;QAChC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAA;IAC1C,CAAC,EACD,EAAE,OAAO,EAAE,IAAI,EAAE,CAClB,CAAA;IAED,OAAO,SAAS,EAAE,IAAI,EAAE,CAAA;AAC1B,CAAC;AAED,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,EAAE,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE;QAC7B,MAAM,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;KA2BnD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE;QAC7B,MAAM,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA2UnD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=EventDisplay.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventDisplay.test.d.ts","sourceRoot":"","sources":["../../src/components/EventDisplay.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,223 @@
1
+ import React from "react";
2
+ import { render } from "ink-testing-library";
3
+ import { describe, it, expect, vi } from "vitest";
4
+ import { EventDisplay } from "./EventDisplay.js";
5
+ describe("EventDisplay", () => {
6
+ it("filters out stream_event types and only shows assistant messages", async () => {
7
+ const events = [
8
+ {
9
+ type: "stream_event",
10
+ event: {
11
+ type: "content_block_delta",
12
+ delta: { type: "text_delta", text: "Streaming..." },
13
+ },
14
+ },
15
+ {
16
+ type: "assistant",
17
+ message: {
18
+ id: "msg_123",
19
+ content: [{ type: "text", text: "Complete message" }],
20
+ },
21
+ },
22
+ ];
23
+ const { lastFrame } = render(React.createElement(EventDisplay, { events: events }));
24
+ await vi.waitFor(() => {
25
+ const output = lastFrame() ?? "";
26
+ expect(output).toContain("Complete message");
27
+ // Should not show streaming events
28
+ expect(output).not.toContain("Streaming...");
29
+ });
30
+ });
31
+ it("deduplicates events with the same message ID", async () => {
32
+ const events = [
33
+ {
34
+ type: "assistant",
35
+ message: {
36
+ id: "msg_123",
37
+ content: [{ type: "text", text: "First version" }],
38
+ },
39
+ },
40
+ {
41
+ type: "assistant",
42
+ message: {
43
+ id: "msg_123",
44
+ content: [
45
+ { type: "text", text: "First version" },
46
+ { type: "text", text: "Updated version" },
47
+ ],
48
+ },
49
+ },
50
+ ];
51
+ const { lastFrame } = render(React.createElement(EventDisplay, { events: events }));
52
+ // Wait for useEffect to complete
53
+ await vi.waitFor(() => {
54
+ const output = lastFrame() ?? "";
55
+ expect(output).toContain("Updated version");
56
+ });
57
+ const output = lastFrame() ?? "";
58
+ // Should not duplicate the first text
59
+ expect(output.match(/First version/g)?.length).toBe(1);
60
+ });
61
+ it("handles multiple different messages", async () => {
62
+ const events = [
63
+ {
64
+ type: "assistant",
65
+ message: {
66
+ id: "msg_123",
67
+ content: [{ type: "text", text: "Message 1" }],
68
+ },
69
+ },
70
+ {
71
+ type: "assistant",
72
+ message: {
73
+ id: "msg_456",
74
+ content: [{ type: "text", text: "Message 2" }],
75
+ },
76
+ },
77
+ ];
78
+ const { lastFrame } = render(React.createElement(EventDisplay, { events: events }));
79
+ await vi.waitFor(() => {
80
+ const output = lastFrame() ?? "";
81
+ expect(output).toContain("Message 1");
82
+ expect(output).toContain("Message 2");
83
+ });
84
+ });
85
+ it("handles tool use events", async () => {
86
+ const events = [
87
+ {
88
+ type: "assistant",
89
+ message: {
90
+ id: "msg_123",
91
+ content: [
92
+ {
93
+ type: "tool_use",
94
+ name: "Read",
95
+ input: { file_path: "/absolute/path/file.ts" },
96
+ },
97
+ ],
98
+ },
99
+ },
100
+ ];
101
+ const { lastFrame } = render(React.createElement(EventDisplay, { events: events }));
102
+ await vi.waitFor(() => {
103
+ const output = lastFrame() ?? "";
104
+ expect(output).toContain("Read");
105
+ expect(output).toContain("file.ts");
106
+ });
107
+ });
108
+ it("updates display when new events arrive", async () => {
109
+ const events1 = [
110
+ {
111
+ type: "assistant",
112
+ message: {
113
+ id: "msg_123",
114
+ content: [{ type: "text", text: "Initial" }],
115
+ },
116
+ },
117
+ ];
118
+ const { lastFrame, rerender } = render(React.createElement(EventDisplay, { events: events1 }));
119
+ await vi.waitFor(() => {
120
+ expect(lastFrame()).toContain("Initial");
121
+ });
122
+ const events2 = [
123
+ ...events1,
124
+ {
125
+ type: "assistant",
126
+ message: {
127
+ id: "msg_456",
128
+ content: [{ type: "text", text: "New message" }],
129
+ },
130
+ },
131
+ ];
132
+ rerender(React.createElement(EventDisplay, { events: events2 }));
133
+ await vi.waitFor(() => {
134
+ const output = lastFrame() ?? "";
135
+ expect(output).toContain("Initial");
136
+ expect(output).toContain("New message");
137
+ });
138
+ });
139
+ it("handles partial message updates without duplicating keys", async () => {
140
+ // Simulate streaming where the same message gets updated multiple times
141
+ const events = [
142
+ {
143
+ type: "assistant",
144
+ message: {
145
+ id: "msg_123",
146
+ content: [{ type: "text", text: "Thinking..." }],
147
+ },
148
+ },
149
+ {
150
+ type: "assistant",
151
+ message: {
152
+ id: "msg_123",
153
+ content: [
154
+ { type: "text", text: "Thinking..." },
155
+ {
156
+ type: "tool_use",
157
+ id: "toolu_read1",
158
+ name: "Read",
159
+ input: { file_path: "/path/file.ts" },
160
+ },
161
+ ],
162
+ },
163
+ },
164
+ {
165
+ type: "assistant",
166
+ message: {
167
+ id: "msg_123",
168
+ content: [
169
+ { type: "text", text: "Thinking..." },
170
+ {
171
+ type: "tool_use",
172
+ id: "toolu_read1",
173
+ name: "Read",
174
+ input: { file_path: "/path/file.ts" },
175
+ },
176
+ {
177
+ type: "tool_use",
178
+ id: "toolu_edit1",
179
+ name: "Edit",
180
+ input: { file_path: "/path/file.ts" },
181
+ },
182
+ ],
183
+ },
184
+ },
185
+ ];
186
+ const { lastFrame } = render(React.createElement(EventDisplay, { events: events }));
187
+ await vi.waitFor(() => {
188
+ const output = lastFrame() ?? "";
189
+ // Should only see one instance of each tool
190
+ expect(output.match(/Read/g)?.length).toBe(1);
191
+ expect(output.match(/Edit/g)?.length).toBe(1);
192
+ });
193
+ });
194
+ it("merges consecutive text blocks to prevent unwanted gaps", async () => {
195
+ // When Claude outputs text in multiple blocks (e.g., before and after inline code),
196
+ // we should merge them into one StreamingText component to avoid gaps
197
+ const events = [
198
+ {
199
+ type: "assistant",
200
+ message: {
201
+ id: "msg_123",
202
+ content: [
203
+ { type: "text", text: "Use the " },
204
+ { type: "text", text: "`console.log()`" },
205
+ { type: "text", text: " function to debug." },
206
+ ],
207
+ },
208
+ },
209
+ ];
210
+ const { lastFrame } = render(React.createElement(EventDisplay, { events: events }));
211
+ await vi.waitFor(() => {
212
+ const output = lastFrame() ?? "";
213
+ expect(output).toContain("Use the");
214
+ expect(output).toContain("console.log()");
215
+ expect(output).toContain("function to debug");
216
+ });
217
+ // The output should be on one line without extra spacing
218
+ const output = lastFrame() ?? "";
219
+ const lines = output.split("\n").filter(l => l.trim());
220
+ expect(lines.length).toBe(1);
221
+ });
222
+ });
223
+ //# sourceMappingURL=EventDisplay.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventDisplay.test.js","sourceRoot":"","sources":["../../src/components/EventDisplay.test.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ export declare const Header: ({ claudeVersion, ralphVersion }: Props) => React.JSX.Element;
3
+ type Props = {
4
+ claudeVersion: string;
5
+ ralphVersion: string;
6
+ };
7
+ export {};
8
+ //# sourceMappingURL=Header.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../src/components/Header.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,eAAO,MAAM,MAAM,GAAI,iCAAiC,KAAK,sBAiB5D,CAAA;AAED,KAAK,KAAK,GAAG;IACX,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA"}