repoburg 1.3.196 → 1.3.197

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 (71) hide show
  1. package/agent-pane/backend/data.db-shm +0 -0
  2. package/agent-pane/backend/data.db-wal +0 -0
  3. package/agent-pane/backend/dist/index.js +13399 -10390
  4. package/agent-pane/backend/package-lock.json +162 -92
  5. package/agent-pane/backend/scripts/backfill-from-jsonl.ts +206 -0
  6. package/agent-pane/backend/scripts/import-session-from-jsonl.ts +264 -0
  7. package/agent-pane/backend/src/claude/claude-message-mapper.test.ts +116 -8
  8. package/agent-pane/backend/src/claude/claude-message-mapper.ts +114 -9
  9. package/agent-pane/backend/src/claude/claude-provider.ts +918 -84
  10. package/agent-pane/backend/src/claude/claude-types.ts +16 -4
  11. package/agent-pane/backend/src/codex/app-server-client.ts +22 -0
  12. package/agent-pane/backend/src/db/index.ts +102 -0
  13. package/agent-pane/backend/src/db/schema.ts +4 -0
  14. package/agent-pane/backend/src/index.ts +3 -1
  15. package/agent-pane/backend/src/integration/helpers/test-app.ts +2 -0
  16. package/agent-pane/backend/src/integration/session-operations.test.ts +18 -11
  17. package/agent-pane/backend/src/integration/threads.test.ts +309 -0
  18. package/agent-pane/backend/src/providers/runtime-provider.ts +19 -1
  19. package/agent-pane/backend/src/routes/providers.ts +11 -0
  20. package/agent-pane/backend/src/routes/sessions.test.ts +143 -9
  21. package/agent-pane/backend/src/routes/sessions.ts +133 -28
  22. package/agent-pane/backend/src/routes/threads.ts +308 -0
  23. package/agent-pane/backend/src/routes/turns.ts +32 -9
  24. package/agent-pane/frontend/dist/assets/index-BYo-lnxm.js +362 -0
  25. package/agent-pane/frontend/dist/assets/index-Dwwhx7YN.css +1 -0
  26. package/agent-pane/frontend/dist/index.html +2 -2
  27. package/agent-pane/frontend/package-lock.json +51 -9
  28. package/agent-pane/frontend/src/__tests__/ThreadsPanel.test.tsx +192 -0
  29. package/agent-pane/frontend/src/api/providers.ts +6 -1
  30. package/agent-pane/frontend/src/api/sessions.test.ts +4 -0
  31. package/agent-pane/frontend/src/api/sessions.ts +13 -5
  32. package/agent-pane/frontend/src/api/websocket.ts +65 -1
  33. package/agent-pane/frontend/src/components/CollapsibleToolCalls.test.tsx +4 -4
  34. package/agent-pane/frontend/src/components/CollapsibleToolCalls.tsx +13 -4
  35. package/agent-pane/frontend/src/components/CommandInputBar.test.tsx +2 -2
  36. package/agent-pane/frontend/src/components/CommandInputBar.tsx +292 -29
  37. package/agent-pane/frontend/src/components/CommandPalette.test.tsx +0 -4
  38. package/agent-pane/frontend/src/components/CommandPalette.tsx +1 -17
  39. package/agent-pane/frontend/src/components/CommentableText.tsx +291 -0
  40. package/agent-pane/frontend/src/components/RenderArea.tsx +9 -2
  41. package/agent-pane/frontend/src/components/RightPanel.test.tsx +5 -5
  42. package/agent-pane/frontend/src/components/RightPanel.tsx +20 -14
  43. package/agent-pane/frontend/src/components/SessionTabs.tsx +7 -2
  44. package/agent-pane/frontend/src/components/StatusBar.tsx +68 -1
  45. package/agent-pane/frontend/src/components/TurnContent.test.tsx +29 -18
  46. package/agent-pane/frontend/src/components/TurnContent.tsx +199 -28
  47. package/agent-pane/frontend/src/components/input/SlashPopup.tsx +24 -5
  48. package/agent-pane/frontend/src/components/panels/TasksPanel.test.tsx +97 -0
  49. package/agent-pane/frontend/src/components/panels/TasksPanel.tsx +208 -0
  50. package/agent-pane/frontend/src/components/panels/ThreadsPanel.tsx +350 -0
  51. package/agent-pane/frontend/src/components/panels/TurnsPanel.tsx +47 -25
  52. package/agent-pane/frontend/src/hooks/useSessionStatus.test.ts +2 -0
  53. package/agent-pane/frontend/src/store/sessionSlice.ts +29 -6
  54. package/agent-pane/frontend/src/store/store.test.ts +5 -5
  55. package/agent-pane/frontend/src/store/store.ts +4 -1
  56. package/agent-pane/frontend/src/store/threadSlice.ts +136 -0
  57. package/agent-pane/frontend/src/store/wsSlice.ts +72 -3
  58. package/agent-pane/frontend/src/styles/app.css +150 -19
  59. package/agent-pane/frontend/src/test/fixtures.ts +4 -0
  60. package/agent-pane/frontend/src/types/index.ts +5 -2
  61. package/agent-pane/frontend/src/utils/duration.test.ts +4 -0
  62. package/agent-pane/frontend/vite.config.ts +2 -2
  63. package/agent-pane/shared/provider-types.ts +14 -0
  64. package/agent-pane/shared/types.ts +60 -0
  65. package/package.json +1 -1
  66. package/agent-pane/frontend/dist/assets/index-Bg0PF2aV.css +0 -1
  67. package/agent-pane/frontend/dist/assets/index-BlybeX5e.js +0 -281
  68. package/agent-pane/frontend/src/components/panels/LogsPanel.test.tsx +0 -58
  69. package/agent-pane/frontend/src/components/panels/LogsPanel.tsx +0 -25
  70. package/agent-pane/frontend/src/components/panels/MetricsPanel.test.tsx +0 -71
  71. package/agent-pane/frontend/src/components/panels/MetricsPanel.tsx +0 -114
@@ -23,14 +23,19 @@ export interface ItemDescriptor {
23
23
  externalId: string; // Claude content block ID (or UUID)
24
24
  }
25
25
 
26
- /** Map assistant content blocks to item descriptors. */
26
+ /** Map assistant content blocks to item descriptors.
27
+ * @param thinkingTexts — Optional map of content-block index → accumulated thinking_delta text.
28
+ * When a `thinking` block has empty `thinking` (signed-empty), the mapper falls back to
29
+ * the accumulated text from stream events. */
27
30
  export function mapAssistantContent(
28
31
  content: BetaContentBlock[],
29
32
  messageId: string,
33
+ thinkingTexts?: Map<number, string>,
30
34
  ): ItemDescriptor[] {
31
35
  const descriptors: ItemDescriptor[] = [];
32
36
 
33
- for (const block of content) {
37
+ for (let i = 0; i < content.length; i++) {
38
+ const block = content[i];
34
39
  switch (block.type) {
35
40
  case 'text': {
36
41
  const tb = block as BetaTextBlock;
@@ -44,9 +49,13 @@ export function mapAssistantContent(
44
49
 
45
50
  case 'thinking': {
46
51
  const tb = block as BetaThinkingBlock;
52
+ let text = tb.thinking;
53
+ if (!text && thinkingTexts) {
54
+ text = thinkingTexts.get(i) ?? '';
55
+ }
47
56
  descriptors.push({
48
57
  type: 'reasoning',
49
- data: { text: tb.thinking },
58
+ data: { text },
50
59
  externalId: messageId,
51
60
  });
52
61
  break;
@@ -92,10 +101,7 @@ function mapToolUse(block: BetaToolUseBlock): ItemDescriptor {
92
101
  if (block.name === 'Edit' || block.name === 'Write' || block.name === 'MultiEdit' || block.name === 'NotebookEdit') {
93
102
  return {
94
103
  type: 'file_change',
95
- data: {
96
- changes: input,
97
- status: 'in_progress',
98
- },
104
+ data: deriveFileChangeData(input, block.name),
99
105
  externalId: block.id,
100
106
  };
101
107
  }
@@ -115,10 +121,109 @@ function mapToolUse(block: BetaToolUseBlock): ItemDescriptor {
115
121
  };
116
122
  }
117
123
 
124
+ // ---------------------------------------------------------------------------
125
+ // Tool-result mapping — pure functions shared by the live provider and the
126
+ // JSONL backfill script. Kept free of DB / SDK-specific types so both callers
127
+ // (which hold different shapes: typed SDK blocks vs parsed JSON) can use them.
128
+ // ---------------------------------------------------------------------------
129
+
130
+ /** Derive the canonical file_change data from a Claude file-edit tool_use input.
131
+ * Each Edit/Write/MultiEdit/NotebookEdit touches a single file → one change.
132
+ * Frontend expects `changes: Array<{ path, kind }>` (matches Codex app-server). */
133
+ export function deriveFileChangeData(
134
+ input: Record<string, unknown>,
135
+ toolName: string,
136
+ ): { changes: Array<{ path: string; kind: string }>; status: string } {
137
+ const path = (input.file_path ?? input.notebook_path ?? '') as string;
138
+ const kind = toolName === 'Write' ? 'add' : 'modify';
139
+ return { changes: [{ path, kind }], status: 'in_progress' };
140
+ }
141
+
142
+ /** Loose shape of a `tool_result` content block — works for SDK blocks and parsed JSONL. */
143
+ export interface ToolResultLike {
144
+ tool_use_id?: string;
145
+ is_error?: boolean;
146
+ content?: unknown;
147
+ }
148
+
149
+ /** Extract concatenated text from a tool_result `content` (string or array of text blocks). */
150
+ export function extractToolResultText(content: unknown): string {
151
+ if (!content) return '';
152
+ if (typeof content === 'string') return content;
153
+ if (Array.isArray(content)) {
154
+ return content
155
+ .map((b) => {
156
+ if (b && typeof b === 'object' && (b as { type?: string }).type === 'text') {
157
+ return String((b as { text?: unknown }).text ?? '');
158
+ }
159
+ return '';
160
+ })
161
+ .filter(Boolean)
162
+ .join('\n');
163
+ }
164
+ return '';
165
+ }
166
+
167
+ /** Build the updated item `data` after a tool_result arrives. Pure; no DB access.
168
+ *
169
+ * - `command_execution`: aggregated_output from the result text (Bash stdout) plus
170
+ * structured stderr when present; exit_code heuristically from is_error (the Claude
171
+ * SDK does not expose a real exit code for Bash).
172
+ * - `mcp_tool_call`: result text from the tool_result content; error when is_error.
173
+ * - `file_change`: the `changes` array was set at tool_use time — just mark status.
174
+ * @param itemType — DB item type ('command_execution' | 'file_change' | 'mcp_tool_call').
175
+ * @param existingData — current `data` object stored on the item.
176
+ * @param toolResult — the tool_result content block (may be null if only structured output exists).
177
+ * @param toolUseResult — the SDK `tool_use_result` structured object (per-tool shape; Bash → {stdout, stderr}).
178
+ * @param isError — whether the tool_result flagged an error. */
179
+ export function applyToolResult(
180
+ itemType: string,
181
+ existingData: Record<string, unknown>,
182
+ toolResult: ToolResultLike | null,
183
+ toolUseResult: unknown,
184
+ isError: boolean,
185
+ ): Record<string, unknown> {
186
+ switch (itemType) {
187
+ case 'command_execution': {
188
+ const text = extractToolResultText(toolResult?.content);
189
+ const tur = (toolUseResult && typeof toolUseResult === 'object' ? toolUseResult : {}) as Record<string, unknown>;
190
+ const stdout = typeof tur.stdout === 'string' ? tur.stdout : '';
191
+ const stderr = typeof tur.stderr === 'string' ? tur.stderr : '';
192
+ let aggregated = text || stdout;
193
+ if (stderr) aggregated = aggregated ? `${aggregated}\n${stderr}` : stderr;
194
+ return {
195
+ ...existingData,
196
+ aggregated_output: aggregated,
197
+ exit_code: isError ? 1 : 0,
198
+ status: isError ? 'failed' : 'completed',
199
+ };
200
+ }
201
+
202
+ case 'mcp_tool_call': {
203
+ const text = extractToolResultText(toolResult?.content);
204
+ return {
205
+ ...existingData,
206
+ result: text ? [{ type: 'text', text }] : (toolUseResult ?? null),
207
+ error: isError ? (text || 'Tool error') : null,
208
+ status: isError ? 'failed' : 'completed',
209
+ };
210
+ }
211
+
212
+ case 'file_change': {
213
+ // `changes` was derived at tool_use time; only flip the inner status.
214
+ return { ...existingData, status: isError ? 'failed' : 'completed' };
215
+ }
216
+
217
+ default:
218
+ return existingData;
219
+ }
220
+ }
221
+
118
222
  /** Result of mapping a partial (streaming) delta event. */
119
223
  export interface DeltaResult {
120
224
  kind: 'text' | 'thinking';
121
225
  text: string;
226
+ index: number;
122
227
  }
123
228
 
124
229
  /** Map a streaming delta event to a text or thinking fragment. Returns null for non-delta events. */
@@ -128,10 +233,10 @@ export function mapPartialDelta(event: unknown): DeltaResult | null {
128
233
 
129
234
  const delta = e.delta as unknown as Record<string, unknown>;
130
235
  if (delta.type === 'text_delta') {
131
- return { kind: 'text', text: delta.text as string };
236
+ return { kind: 'text', text: delta.text as string, index: e.index };
132
237
  }
133
238
  if (delta.type === 'thinking_delta') {
134
- return { kind: 'thinking', text: delta.thinking as string };
239
+ return { kind: 'thinking', text: delta.thinking as string, index: e.index };
135
240
  }
136
241
 
137
242
  return null;