repoburg 1.3.201 → 1.3.202

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 (86) 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 +478 -250
  4. package/agent-pane/backend/src/db/index.ts +6 -0
  5. package/agent-pane/backend/src/providers/runtime-provider.ts +6 -0
  6. package/agent-pane/backend/src/repoburg/action-mapping.test.ts +122 -0
  7. package/agent-pane/backend/src/repoburg/action-mapping.ts +89 -11
  8. package/agent-pane/backend/src/repoburg/agent-runtime-client.ts +23 -0
  9. package/agent-pane/backend/src/repoburg/backend-resolver.test.ts +85 -0
  10. package/agent-pane/backend/src/repoburg/backend-resolver.ts +28 -13
  11. package/agent-pane/backend/src/repoburg/repoburg-client.test.ts +21 -0
  12. package/agent-pane/backend/src/repoburg/repoburg-client.ts +13 -0
  13. package/agent-pane/backend/src/repoburg/repoburg-provider.test.ts +57 -0
  14. package/agent-pane/backend/src/repoburg/repoburg-provider.ts +49 -0
  15. package/agent-pane/backend/src/repoburg/turn-projector.test.ts +147 -1
  16. package/agent-pane/backend/src/repoburg/turn-projector.ts +101 -1
  17. package/agent-pane/backend/src/routes/sessions.test.ts +215 -1
  18. package/agent-pane/backend/src/routes/sessions.ts +70 -9
  19. package/agent-pane/frontend/dist/assets/index-CJxD4YmJ.js +370 -0
  20. package/agent-pane/frontend/dist/assets/{index-34WaZYsW.css → index-r-xwfOKQ.css} +1 -1
  21. package/agent-pane/frontend/dist/index.html +2 -2
  22. package/agent-pane/frontend/src/api/sessions.test.ts +1 -0
  23. package/agent-pane/frontend/src/api/websocket.test.ts +2 -2
  24. package/agent-pane/frontend/src/api/websocket.ts +3 -1
  25. package/agent-pane/frontend/src/components/AskUserItem.test.tsx +143 -0
  26. package/agent-pane/frontend/src/components/AskUserItem.tsx +207 -0
  27. package/agent-pane/frontend/src/components/TurnContent.test.tsx +79 -0
  28. package/agent-pane/frontend/src/components/TurnContent.tsx +49 -3
  29. package/agent-pane/frontend/src/components/panels/TurnsPanel.test.tsx +48 -0
  30. package/agent-pane/frontend/src/components/panels/TurnsPanel.tsx +7 -2
  31. package/agent-pane/frontend/src/store/store.test.ts +19 -0
  32. package/agent-pane/frontend/src/store/wsSlice.ts +10 -3
  33. package/agent-pane/frontend/src/styles/app.css +16 -0
  34. package/agent-pane/frontend/src/test/fixtures.ts +1 -0
  35. package/agent-pane/frontend/src/types/index.ts +2 -0
  36. package/agent-pane/frontend/src/utils/duration.test.ts +1 -0
  37. package/agent-pane/shared/types.ts +17 -0
  38. package/askuser-after-step5-postgres-selected.png +0 -0
  39. package/askuser-after-step7-answer-sent.png +0 -0
  40. package/askuser-card-visible.png +0 -0
  41. package/backend/dist/src/agent-runtime/agent-runtime-event-emitter.d.ts +16 -0
  42. package/backend/dist/src/agent-runtime/agent-runtime-event-emitter.js +87 -0
  43. package/backend/dist/src/agent-runtime/agent-runtime-event-emitter.js.map +1 -1
  44. package/backend/dist/src/agent-runtime/agent-runtime.types.d.ts +16 -1
  45. package/backend/dist/src/app.controller.d.ts +1 -0
  46. package/backend/dist/src/app.service.d.ts +1 -0
  47. package/backend/dist/src/app.service.js +4 -1
  48. package/backend/dist/src/app.service.js.map +1 -1
  49. package/backend/dist/src/interactive-chat/chat.service.d.ts +4 -0
  50. package/backend/dist/src/interactive-chat/chat.service.js +21 -1
  51. package/backend/dist/src/interactive-chat/chat.service.js.map +1 -1
  52. package/backend/dist/src/llm-orchestration/action-handlers/invoke-subagent.handler.js +12 -1
  53. package/backend/dist/src/llm-orchestration/action-handlers/invoke-subagent.handler.js.map +1 -1
  54. package/backend/dist/src/llm-orchestration/llm-orchestration.interfaces.d.ts +1 -0
  55. package/backend/dist/src/llm-orchestration/llm-orchestration.interfaces.js +1 -0
  56. package/backend/dist/src/llm-orchestration/llm-orchestration.interfaces.js.map +1 -1
  57. package/backend/dist/src/llm-orchestration/llm-turn-processor.service.js +2 -0
  58. package/backend/dist/src/llm-orchestration/llm-turn-processor.service.js.map +1 -1
  59. package/backend/dist/tsconfig.build.tsbuildinfo +1 -1
  60. package/daemon/dist/api/services.js +4 -0
  61. package/daemon/dist/serviceManager.js +30 -11
  62. package/daemon/dist/serviceManager.spec.js +26 -0
  63. package/daemon/dist/workspace-validation.js +63 -0
  64. package/daemon/dist/workspace-validation.spec.js +63 -0
  65. package/package.json +1 -1
  66. package/r2-step4-apple-banana.png +0 -0
  67. package/r2-step5-after-rewind-apple-last.png +0 -0
  68. package/r2-step7-apple-cherry.png +0 -0
  69. package/r2-step8-cherry-menu-no-restore.png +0 -0
  70. package/r3-step3-live-task-card-running.png +0 -0
  71. package/r3-step4-after-completion.png +0 -0
  72. package/r3-step5-persistence-after-reload.png +0 -0
  73. package/r3-step6-tasks-tab-card.png +0 -0
  74. package/reverify-answered-state-answer-sent.png +0 -0
  75. package/reverify-card-visible-after-completion.png +0 -0
  76. package/rewind-step3-apple-banana-turns.png +0 -0
  77. package/rewind-step5-ui-unchanged-after-confirmed-rewind.png +0 -0
  78. package/rewind-step6-apple-menu-no-restore.png +0 -0
  79. package/rewind-step7-final-turnlist-unchanged.png +0 -0
  80. package/rewind-step7-negative-error-toast.png +0 -0
  81. package/rewind-step7-negative-error-toast2.png +0 -0
  82. package/subagent-r2-step5-turn-after-reload-no-card.png +0 -0
  83. package/subagent-r2-step6-tasks-panel-card.png +0 -0
  84. package/subagent-step3-tasks-tab-done-card.png +0 -0
  85. package/subagent-step4-turn-stuck-no-cards.png +0 -0
  86. package/agent-pane/frontend/dist/assets/index-y7xlT86e.js +0 -362
@@ -21,6 +21,44 @@ function turnWithToolItem(item: Item): Turn {
21
21
  return turnWithItems([agentMsg, item], { status: 'completed', agent_response: 'Done' });
22
22
  }
23
23
 
24
+ describe('TurnContent — sub-agent cards + response fallback', () => {
25
+ it('renders the agent_response fallback when no agent_message item exists (final-action turns)', () => {
26
+ const turn = turnWithItems([], { status: 'completed', agent_response: 'Confirmed: the answer.' });
27
+ render(<TurnContent turn={turn} />);
28
+ expect(screen.getByText(/Confirmed: the answer\./)).toBeInTheDocument();
29
+ });
30
+
31
+ it('renders no fallback while running or when an agent_message item exists', () => {
32
+ const { rerender } = render(
33
+ <TurnContent turn={turnWithItems([], { status: 'running', agent_response: 'partial' })} />,
34
+ );
35
+ expect(screen.queryByText('partial')).not.toBeInTheDocument();
36
+
37
+ const agentMsg = makeItem('i-agent', 't1', 'agent_message');
38
+ agentMsg.data = { text: 'Item text wins' };
39
+ rerender(<TurnContent turn={turnWithItems([agentMsg], { status: 'completed', agent_response: 'stale fallback' })} />);
40
+ expect(screen.getByText('Item text wins')).toBeInTheDocument();
41
+ expect(screen.queryByText('stale fallback')).not.toBeInTheDocument();
42
+ });
43
+
44
+ it('renders a background_task card in the turn flow (running and completed)', () => {
45
+ const runningTask = makeItem('i-task', 't1', 'background_task');
46
+ runningTask.data = { description: 'run_command: npm test', task_type: 'subagent', status: 'running', token_count: 42, last_tool_name: 'run_command' };
47
+ const { rerender } = render(
48
+ <TurnContent turn={turnWithItems([runningTask], { status: 'running' })} />,
49
+ );
50
+ expect(screen.getByText('run_command: npm test')).toBeInTheDocument();
51
+
52
+ const doneTask = { ...runningTask, status: 'completed' as const, data: { ...runningTask.data, status: 'completed', summary: 'Task finished' } };
53
+ rerender(<TurnContent turn={turnWithItems([doneTask], { status: 'completed' })} />);
54
+ // Card stays visible with the done status; the summary lives in the
55
+ // Tasks panel (Claude-parity compact card).
56
+ expect(screen.getByText('run_command: npm test')).toBeInTheDocument();
57
+ expect(screen.getByText('done')).toBeInTheDocument();
58
+ expect(screen.queryByText('last tool: run_command')).not.toBeInTheDocument();
59
+ });
60
+ });
61
+
24
62
  describe('TurnContent', () => {
25
63
  afterEach(() => {
26
64
  cleanup();
@@ -283,6 +321,47 @@ describe('TurnContent', () => {
283
321
  expect(screen.getByText('Post-error')).toBeInTheDocument();
284
322
  });
285
323
 
324
+ it('renders ask_user item after the final agent_message (question card)', () => {
325
+ const agentMsg = makeItem('i1', 't1', 'agent_message');
326
+ agentMsg.data = { text: 'Need your input' };
327
+ const askItem = makeItem('i2', 't1', 'ask_user');
328
+ askItem.data = {
329
+ question: '',
330
+ groups: [{ question: 'Which one?', selections: ['A', 'B'] }],
331
+ };
332
+ const turn = turnWithItems([agentMsg, askItem], {
333
+ status: 'completed',
334
+ agent_response: 'Need your input',
335
+ });
336
+ render(<TurnContent turn={turn} />);
337
+ expect(screen.getByText('Which one?')).toBeInTheDocument();
338
+ expect(screen.getByText('A')).toBeInTheDocument();
339
+ expect(screen.getByText('B')).toBeInTheDocument();
340
+ });
341
+
342
+ it('renders the ask_user card for an ask_user-ONLY turn after completion (always-visible section)', () => {
343
+ const askItem = makeItem('i1', 't1', 'ask_user');
344
+ askItem.data = {
345
+ question: '',
346
+ groups: [{ question: 'Proceed?', selections: ['yes', 'no'] }],
347
+ };
348
+ const turn = turnWithItems([askItem], { status: 'completed' });
349
+ render(<TurnContent turn={turn} />);
350
+ expect(screen.getByText('Proceed?')).toBeInTheDocument();
351
+ expect(screen.getByText('yes')).toBeInTheDocument();
352
+ });
353
+
354
+ it('renders the ask_user card even while the turn is running (disabled by the store state)', () => {
355
+ const askItem = makeItem('i1', 't1', 'ask_user');
356
+ askItem.data = {
357
+ question: '',
358
+ groups: [{ question: 'Proceed?', selections: ['yes', 'no'] }],
359
+ };
360
+ const turn = turnWithItems([askItem], { status: 'running' });
361
+ render(<TurnContent turn={turn} />);
362
+ expect(screen.getByText('Proceed?')).toBeInTheDocument();
363
+ });
364
+
286
365
  it('unknown item type renders null (default case)', () => {
287
366
  const item = makeItem('i1', 't1', 'unknown_type' as never);
288
367
  item.data = {};
@@ -9,6 +9,7 @@ import type { Turn, Item, DiscussionThread, Attachment } from '../types/index.ts
9
9
  import { runtimeIcon } from '../types/index.ts';
10
10
  import CollapsibleToolCalls, { isToolItem } from './CollapsibleToolCalls.tsx';
11
11
  import CommentableText from './CommentableText.tsx';
12
+ import AskUserItem from './AskUserItem.tsx';
12
13
 
13
14
  marked.setOptions({ breaks: true, gfm: true });
14
15
 
@@ -306,6 +307,10 @@ function ItemCard({ item, runtimeType, turn, threads }: { item: Item; runtimeTyp
306
307
  );
307
308
  }
308
309
 
310
+ case 'ask_user': {
311
+ return <AskUserItem item={item} turn={turn} />;
312
+ }
313
+
309
314
  case 'background_task': {
310
315
  const data = item.data || {};
311
316
  const taskType = (data.task_type as string) || 'unknown';
@@ -427,15 +432,35 @@ function TurnContentBase({ turn, runtimeType, threads = [] }: Props) {
427
432
  // Intermediate = everything before final agent_message (or ALL items if running)
428
433
  const intermediateItems = hasFinalResponse ? turn.items.slice(0, lastAgentIdx) : turn.items;
429
434
 
435
+ // Fallback final response — some runtime turns (repoburg final-action
436
+ // rounds) never produce an agent_message item; their final text lives on
437
+ // turn.agent_response instead. Synthesize the final card from it.
438
+ const responseFallback: Item | null =
439
+ !hasFinalResponse && turn.status === 'completed' && turn.agent_response
440
+ ? {
441
+ id: `response-${turn.id}`,
442
+ turn_id: turn.id,
443
+ external_item_id: `response-${turn.id}`,
444
+ type: 'agent_message',
445
+ data: { text: turn.agent_response },
446
+ status: 'completed',
447
+ created_at: turn.created_at,
448
+ updated_at: turn.updated_at,
449
+ }
450
+ : null;
451
+
430
452
  // Filter out empty reasoning items (text is "" — signed-empty thinking blocks from Claude SDK).
431
453
  // These inflate the intermediate step count and render as empty cards.
432
454
  const visibleIntermediate = intermediateItems.filter(
433
455
  (item) => !(item.type === 'reasoning' && (!item.data?.text || item.data.text === '')),
434
456
  );
435
457
 
436
- // Filter main flow: remove background_task items (they belong in Tasks panel).
458
+ // Filter main flow: remove background_task items (they belong in Tasks panel)
459
+ // and ask_user items (always-visible section below — the answer flow must
460
+ // never hide behind the collapsed intermediate section).
437
461
  const mainIntermediate = visibleIntermediate.filter((item) => {
438
462
  if (item.type === 'background_task') return false;
463
+ if (item.type === 'ask_user') return false;
439
464
  return true;
440
465
  });
441
466
 
@@ -517,11 +542,32 @@ function TurnContentBase({ turn, runtimeType, threads = [] }: Props) {
517
542
  </div>
518
543
  )}
519
544
 
545
+ {/* background_task cards — always visible in the turn flow (live sub-agent
546
+ / monitor lifecycle), outside the collapsible intermediate section.
547
+ Rendered before the final answer to match the chronological flow
548
+ (task ran, then the agent responded). Mirrors the Tasks panel entries
549
+ but inline with the conversation. */}
550
+ {turn.items.filter((i) => i.type === 'background_task').map((item) => (
551
+ <MemoItemCard key={`task-${item.id}`} item={item} runtimeType={runtimeType} turn={turn} threads={threads} />
552
+ ))}
553
+
520
554
  {/* Final agent message — always visible */}
521
555
  {hasFinalResponse && <MemoItemCard key={turn.items[lastAgentIdx].id} item={turn.items[lastAgentIdx]} runtimeType={runtimeType} turn={turn} threads={threads} />}
522
556
 
523
- {/* Items after final agent message (rare — errors, etc.) */}
524
- {hasFinalResponse && turn.items.slice(lastAgentIdx + 1).map((item) => <MemoItemCard key={item.id} item={item} runtimeType={runtimeType} turn={turn} threads={threads} />)}
557
+ {/* Fallback final response (turn.agent_response with no agent_message item). */}
558
+ {responseFallback && (
559
+ <MemoItemCard key={responseFallback.id} item={responseFallback} runtimeType={runtimeType} turn={turn} threads={threads} />
560
+ )}
561
+
562
+ {/* Items after final agent message (rare — errors, etc.; ask_user and
563
+ background_task render in the dedicated always-visible sections below). */}
564
+ {hasFinalResponse && turn.items.slice(lastAgentIdx + 1).filter((i) => i.type !== 'ask_user' && i.type !== 'background_task').map((item) => <MemoItemCard key={item.id} item={item} runtimeType={runtimeType} turn={turn} threads={threads} />)}
565
+
566
+ {/* ask_user cards — always visible + interactive, outside the collapsible
567
+ intermediate section (works even for ask_user-only turns). */}
568
+ {turn.items.filter((i) => i.type === 'ask_user').map((item) => (
569
+ <MemoItemCard key={`ask-${item.id}`} item={item} runtimeType={runtimeType} turn={turn} threads={threads} />
570
+ ))}
525
571
 
526
572
  {/* Pending state (no items at all) */}
527
573
  {turn.items.length === 0 && !turn.error && (turn.status === 'pending' || turn.status === 'running') && (
@@ -80,4 +80,52 @@ describe('TurnsPanel', () => {
80
80
  fireEvent.click(screen.getByText('Branch from Here'));
81
81
  expect(branchFromTurn).toHaveBeenCalledWith('s1', 't1');
82
82
  });
83
+
84
+ it('shows Restore Rewind for rewound non-repoburg sessions', () => {
85
+ const detail = makeDetail('s1', [makeTurn('t1', 's1'), makeTurn('t2', 's1')], {
86
+ runtime_type: 'codex',
87
+ rewound_at_turn_id: 't1',
88
+ });
89
+ resetStore({ activeSessionId: 's1', sessionDetails: { s1: detail } });
90
+ render(<TurnsPanel />);
91
+ fireEvent.contextMenu(document.querySelector('.turn-item')!);
92
+ expect(screen.getByText('Restore Rewind')).toBeInTheDocument();
93
+ });
94
+
95
+ it('hides Restore Rewind for rewound repoburg sessions (hard delete — no restore)', () => {
96
+ const detail = makeDetail('s1', [makeTurn('t1', 's1'), makeTurn('t2', 's1')], {
97
+ runtime_type: 'repoburg',
98
+ rewound_at_turn_id: 't1',
99
+ });
100
+ resetStore({ activeSessionId: 's1', sessionDetails: { s1: detail } });
101
+ render(<TurnsPanel />);
102
+ fireEvent.contextMenu(document.querySelector('.turn-item')!);
103
+ expect(screen.queryByText('Restore Rewind')).not.toBeInTheDocument();
104
+ });
105
+
106
+ it('repoburg rewind confirm says the runtime history is permanently deleted', () => {
107
+ const confirmSpy = vi.spyOn(window, 'confirm').mockReturnValue(false);
108
+ const rewindToTurn = vi.fn();
109
+ const detail = makeDetail('s1', [makeTurn('t1', 's1'), makeTurn('t2', 's1')], {
110
+ runtime_type: 'repoburg',
111
+ });
112
+ resetStore({ activeSessionId: 's1', sessionDetails: { s1: detail }, rewindToTurn });
113
+ render(<TurnsPanel />);
114
+ fireEvent.contextMenu(document.querySelectorAll('.turn-item')[0]);
115
+ fireEvent.click(screen.getByText('Rewind to Here'));
116
+ expect(confirmSpy).toHaveBeenCalledWith(
117
+ 'Rewind to this turn? Runtime history after this point is PERMANENTLY deleted and cannot be restored.',
118
+ );
119
+ expect(rewindToTurn).not.toHaveBeenCalled();
120
+ });
121
+
122
+ it('non-repoburg rewind confirm keeps the restore-later copy', () => {
123
+ const confirmSpy = vi.spyOn(window, 'confirm').mockReturnValue(false);
124
+ const detail = makeDetail('s1', [makeTurn('t1', 's1'), makeTurn('t2', 's1')]);
125
+ resetStore({ activeSessionId: 's1', sessionDetails: { s1: detail } });
126
+ render(<TurnsPanel />);
127
+ fireEvent.contextMenu(document.querySelectorAll('.turn-item')[0]);
128
+ fireEvent.click(screen.getByText('Rewind to Here'));
129
+ expect(confirmSpy).toHaveBeenCalledWith('Rewind to this turn? Hidden turns can be restored later.');
130
+ });
83
131
  });
@@ -26,6 +26,11 @@ export default function TurnsPanel() {
26
26
  const turns = detail?.turns ?? [];
27
27
  const isRunning = detail?.is_running === 1;
28
28
  const isRewound = !!detail?.rewound_at_turn_id;
29
+ // Repoburg rewind = platform-parity hard delete — no restore, permanent copy.
30
+ const isRepoburg = detail?.runtime_type === 'repoburg';
31
+ const rewindConfirm = isRepoburg
32
+ ? 'Rewind to this turn? Runtime history after this point is PERMANENTLY deleted and cannot be restored.'
33
+ : 'Rewind to this turn? Hidden turns can be restored later.';
29
34
 
30
35
  const [ctxMenu, setCtxMenu] = useState<TurnContextMenu | null>(null);
31
36
  const ctxRef = useRef<HTMLDivElement>(null);
@@ -91,7 +96,7 @@ export default function TurnsPanel() {
91
96
  className={`ctx-menu-item ${ctxMenu.isLast || isRunning || ctxMenu.isSlashCommand ? 'ctx-disabled' : ''}`}
92
97
  onClick={() => {
93
98
  if (ctxMenu.isLast || isRunning || ctxMenu.isSlashCommand) return;
94
- if (window.confirm('Rewind to this turn? Hidden turns can be restored later.')) {
99
+ if (window.confirm(rewindConfirm)) {
95
100
  rewindToTurn(activeSessionId!, ctxMenu.turnId);
96
101
  }
97
102
  setCtxMenu(null);
@@ -99,7 +104,7 @@ export default function TurnsPanel() {
99
104
  >
100
105
  <Rewind size={12} /> Rewind to Here{ctxMenu.isSlashCommand ? ' (slash command)' : ''}
101
106
  </div>
102
- {isRewound && (
107
+ {isRewound && !isRepoburg && (
103
108
  <div
104
109
  className="ctx-menu-item"
105
110
  onClick={() => {
@@ -438,6 +438,25 @@ describe('onTurnCompleted', () => {
438
438
  expect(useStore.getState().sessionDetails['s1'].has_unreviewed).toBe(1);
439
439
  expect(useStore.getState().sessions[0].has_unreviewed).toBe(1);
440
440
  });
441
+ it('stores the response text when provided and not already streamed', () => {
442
+ const turn = makeTurn('t1', 's1', { status: 'running' });
443
+ const detail = makeDetail('s1', [turn], { is_running: 1 });
444
+ resetStore({ sessionDetails: { s1: detail }, sessions: [makeSession('s1', { is_running: 1 })] });
445
+
446
+ useStore.getState().onTurnCompleted('s1', 't1', makeUsage(), true, 'Confirmed: done.');
447
+
448
+ expect(useStore.getState().sessionDetails['s1'].turns[0].agent_response).toBe('Confirmed: done.');
449
+ });
450
+
451
+ it('keeps streamed agent_response over the event response', () => {
452
+ const turn = makeTurn('t1', 's1', { status: 'running', agent_response: 'streamed text' });
453
+ const detail = makeDetail('s1', [turn], { is_running: 1 });
454
+ resetStore({ sessionDetails: { s1: detail }, sessions: [makeSession('s1', { is_running: 1 })] });
455
+
456
+ useStore.getState().onTurnCompleted('s1', 't1', makeUsage(), true, 'event text');
457
+
458
+ expect(useStore.getState().sessionDetails['s1'].turns[0].agent_response).toBe('streamed text');
459
+ });
441
460
 
442
461
  it('does not change has_unreviewed when hasUnreviewed is falsy', () => {
443
462
  const turn = makeTurn('t1', 's1', { status: 'running' });
@@ -16,7 +16,7 @@ export type WsSlice = {
16
16
  onItemUpdated: (sessionId: string, turnId: string, item: Item) => void;
17
17
  onItemCompleted: (sessionId: string, turnId: string, item: Item) => void;
18
18
  onItemDelta: (sessionId: string, turnId: string, itemId: string, delta: string) => void;
19
- onTurnCompleted: (sessionId: string, turnId: string, usage?: TokenUsage | null, hasUnreviewed?: boolean) => void;
19
+ onTurnCompleted: (sessionId: string, turnId: string, usage?: TokenUsage | null, hasUnreviewed?: boolean, response?: string) => void;
20
20
  onTokenUsageUpdated: (sessionId: string, turnId: string, usage: TokenUsage) => void;
21
21
  onContextUsageUpdated: (sessionId: string, ctx: ContextUsage) => void;
22
22
  onTurnFailed: (sessionId: string, turnId: string, error: string) => void;
@@ -141,7 +141,7 @@ export const createWsSlice: StateCreator<StoreState, [], [], WsSlice> = (set, ge
141
141
  });
142
142
  },
143
143
 
144
- onTurnCompleted: (sessionId, turnId, usage, hasUnreviewed) => {
144
+ onTurnCompleted: (sessionId, turnId, usage, hasUnreviewed, response) => {
145
145
  const inTok = usage?.input_tokens ?? 0;
146
146
  const outTok = usage?.output_tokens ?? 0;
147
147
  get().addLogEntry('INFO', `turn:completed — ${inTok} in / ${outTok} out`);
@@ -160,7 +160,14 @@ export const createWsSlice: StateCreator<StoreState, [], [], WsSlice> = (set, ge
160
160
  has_unreviewed: hasUnreviewed ? 1 : detail.has_unreviewed,
161
161
  turns: detail.turns.map((t) =>
162
162
  t.id === turnId
163
- ? { ...t, status: 'completed', token_usage: usage ?? t.token_usage ?? null }
163
+ ? {
164
+ ...t,
165
+ status: 'completed',
166
+ token_usage: usage ?? t.token_usage ?? null,
167
+ // Final text for turns that produce no agent_message item
168
+ // (repoburg final-action rounds) — keep any streamed text.
169
+ ...(response && !t.agent_response ? { agent_response: response } : {}),
170
+ }
164
171
  : t,
165
172
  ),
166
173
  },
@@ -609,3 +609,19 @@ mark[data-thread-id].thread-mark-resolved { background: transparent; border-bott
609
609
  .agent-call-status.running { color: var(--accent); background: var(--accent-soft); }
610
610
  .agent-call-status.done { color: var(--green); background: rgba(34,197,94,0.08); }
611
611
  .agent-call-status.failed { color: var(--red); background: rgba(239,68,68,0.08); }
612
+
613
+ /* === Ask-user selection buttons (platform parity) === */
614
+ .ask-user-card { border-left: 3px solid var(--accent); }
615
+ .ask-user-groups { display: flex; flex-direction: column; gap: 10px; margin-top: 6px; }
616
+ .ask-user-group { display: flex; flex-direction: column; gap: 6px; }
617
+ .ask-user-question { font-size: 12px; font-weight: 600; color: var(--text-2); }
618
+ .ask-user-options { display: flex; flex-wrap: wrap; gap: 6px; }
619
+ .ask-user-option { padding: 4px 10px; font-size: 12px; font-family: var(--font-sans); color: var(--text-2); background: var(--canvas); border: 1px solid var(--border); border-radius: var(--r-sm); cursor: pointer; transition: all var(--dur-fast) var(--ease); }
620
+ .ask-user-option:not(:disabled):hover { border-color: var(--accent); color: var(--accent); }
621
+ .ask-user-option.selected { background: var(--accent); border-color: var(--accent); color: #fff; }
622
+ .ask-user-option:disabled { opacity: 0.55; cursor: default; }
623
+ .ask-user-option.selected:disabled { opacity: 0.8; }
624
+ .ask-user-send { display: inline-flex; align-items: center; gap: 5px; padding: 4px 12px; font-size: 12px; font-family: var(--font-sans); color: #fff; background: var(--accent); border: none; border-radius: var(--r-sm); cursor: pointer; align-self: flex-start; transition: background var(--dur-fast) var(--ease); }
625
+ .ask-user-send:disabled { opacity: 0.4; cursor: default; }
626
+ .ask-user-send:not(:disabled):hover { background: var(--accent-hover); }
627
+ .ask-user-submitted { font-size: 11px; color: var(--text-muted); font-style: italic; }
@@ -54,6 +54,7 @@ export function makeTurn(id: string, sessionId: string, overrides: Partial<Turn>
54
54
  error: null,
55
55
  thread_id: null,
56
56
  attachments: null,
57
+ runtime_input_ids: null,
57
58
  created_at: NOW,
58
59
  updated_at: NOW,
59
60
  items: [],
@@ -15,6 +15,8 @@ export type {
15
15
  DiscussionThread,
16
16
  Attachment,
17
17
  ContextUsage,
18
+ AskUserItemData,
19
+ AskUserSelectionGroup,
18
20
  } from '@agentpane/shared';
19
21
 
20
22
  export type { ProviderDefinition, ProviderCapabilities, ProviderSlashCommand, SessionRuntimeConfig, ModelInfo, Extension } from '@agentpane/shared';
@@ -32,6 +32,7 @@ function makeDetail(turns: { created_at: string; updated_at: string }[]): Sessio
32
32
  error: null,
33
33
  thread_id: null,
34
34
  attachments: null,
35
+ runtime_input_ids: null,
35
36
  created_at: t.created_at,
36
37
  updated_at: t.updated_at,
37
38
  items: [],
@@ -22,10 +22,24 @@ export type ItemType =
22
22
  | 'todo_list'
23
23
  | 'context_compaction'
24
24
  | 'background_task'
25
+ | 'ask_user'
25
26
  | 'error';
26
27
  /** Item processing state. */
27
28
  export type ItemStatus = 'in_progress' | 'completed' | 'failed';
28
29
 
30
+ /** One ask_user selection group — a question with clickable options. */
31
+ export interface AskUserSelectionGroup {
32
+ question: string;
33
+ selections: string[];
34
+ }
35
+
36
+ /** ask_user item data — the runtime's ask_user action payload. */
37
+ export interface AskUserItemData {
38
+ /** Fallback plain text when the selections payload is malformed. */
39
+ question: string;
40
+ groups: AskUserSelectionGroup[];
41
+ }
42
+
29
43
  /** A session row — maps directly to the `sessions` SQLite table. */
30
44
  export interface Session {
31
45
  id: string;
@@ -90,6 +104,9 @@ export interface TurnBase {
90
104
  thread_id: string | null;
91
105
  /** Attachments sent with the user prompt (images, PDFs, text files). Null = no attachments. */
92
106
  attachments: Attachment[] | null;
107
+ /** Runtime input ids composing this turn (rewind anchor mapping — repoburg;
108
+ * JSON array in the DB). Null = not recorded (turn predates the mapping). */
109
+ runtime_input_ids: string[] | null;
93
110
  created_at: string;
94
111
  updated_at: string;
95
112
  }
Binary file
@@ -3,6 +3,7 @@ export declare class AgentRuntimeEventEmitter {
3
3
  private readonly logger;
4
4
  private readonly clients;
5
5
  private readonly turnStates;
6
+ private readonly subagents;
6
7
  hasSubscribers(sessionId: string): boolean;
7
8
  subscribe(sessionId: string, listener: (message: AgentRuntimeMessage) => void, opts?: {
8
9
  deltas?: boolean;
@@ -17,4 +18,19 @@ export declare class AgentRuntimeEventEmitter {
17
18
  result: string;
18
19
  errors?: string[];
19
20
  }): void;
21
+ registerSubagent(childSessionId: string, meta: {
22
+ parentId: string;
23
+ inputId: string;
24
+ actionId: string;
25
+ agentName: string;
26
+ description: string;
27
+ }): void;
28
+ unregisterSubagent(childSessionId: string): void;
29
+ emitSubagentStarted(childSessionId: string): void;
30
+ emitSubagentSettled(childSessionId: string, settlement: {
31
+ success: boolean;
32
+ summary: string;
33
+ }): void;
34
+ private emitSubagentEvent;
35
+ private resolveDeliveryParent;
20
36
  }
@@ -20,6 +20,7 @@ let AgentRuntimeEventEmitter = AgentRuntimeEventEmitter_1 = class AgentRuntimeEv
20
20
  this.logger = new common_1.Logger(AgentRuntimeEventEmitter_1.name);
21
21
  this.clients = new Map();
22
22
  this.turnStates = new Map();
23
+ this.subagents = new Map();
23
24
  }
24
25
  hasSubscribers(sessionId) {
25
26
  return (this.clients.get(sessionId)?.size ?? 0) > 0;
@@ -58,6 +59,20 @@ let AgentRuntimeEventEmitter = AgentRuntimeEventEmitter_1 = class AgentRuntimeEv
58
59
  this.emit({ type: 'stream_event', sessionId, inputId, delta });
59
60
  }
60
61
  emitAssistant(sessionId, inputId, content, usage) {
62
+ const sub = this.subagents.get(sessionId);
63
+ if (sub) {
64
+ if (usage) {
65
+ sub.usage.input_tokens += usage.input_tokens ?? 0;
66
+ sub.usage.output_tokens += usage.output_tokens ?? 0;
67
+ sub.usage.cache_read_input_tokens += usage.cache_read_input_tokens ?? 0;
68
+ sub.usage.cache_creation_input_tokens +=
69
+ usage.cache_creation_input_tokens ?? 0;
70
+ sub.tokenCount +=
71
+ (usage.input_tokens ?? 0) + (usage.output_tokens ?? 0);
72
+ }
73
+ this.emitSubagentEvent(sessionId, sub, 'progress');
74
+ return;
75
+ }
61
76
  const state = this.turnStates.get(sessionId) ?? {
62
77
  rounds: 0,
63
78
  usage: emptyUsage(),
@@ -81,6 +96,20 @@ let AgentRuntimeEventEmitter = AgentRuntimeEventEmitter_1 = class AgentRuntimeEv
81
96
  this.emit(message);
82
97
  }
83
98
  emitToolResult(sessionId, inputId, toolResult) {
99
+ const sub = this.subagents.get(sessionId);
100
+ if (sub) {
101
+ const action = toolResult.action;
102
+ if (action.action_type !== 'final' &&
103
+ action.action_type !== 'html_final') {
104
+ const detail = action.file_path ?? action.command_string ?? action.tool_name ?? '';
105
+ sub.description = detail
106
+ ? `${action.action_type}: ${detail}`
107
+ : action.action_type;
108
+ sub.lastToolName = action.action_type;
109
+ }
110
+ this.emitSubagentEvent(sessionId, sub, 'progress');
111
+ return;
112
+ }
84
113
  const message = {
85
114
  type: 'user',
86
115
  sessionId,
@@ -90,6 +119,8 @@ let AgentRuntimeEventEmitter = AgentRuntimeEventEmitter_1 = class AgentRuntimeEv
90
119
  this.emit(message);
91
120
  }
92
121
  emitResult(sessionId, partial) {
122
+ if (this.subagents.has(sessionId))
123
+ return;
93
124
  const state = this.turnStates.get(sessionId);
94
125
  const message = {
95
126
  type: 'result',
@@ -104,6 +135,62 @@ let AgentRuntimeEventEmitter = AgentRuntimeEventEmitter_1 = class AgentRuntimeEv
104
135
  this.turnStates.delete(sessionId);
105
136
  this.emit(message);
106
137
  }
138
+ registerSubagent(childSessionId, meta) {
139
+ this.subagents.set(childSessionId, {
140
+ parentId: meta.parentId,
141
+ inputId: meta.inputId,
142
+ actionId: meta.actionId,
143
+ agentName: meta.agentName,
144
+ description: meta.description,
145
+ lastToolName: null,
146
+ tokenCount: 0,
147
+ usage: emptyUsage(),
148
+ });
149
+ }
150
+ unregisterSubagent(childSessionId) {
151
+ this.subagents.delete(childSessionId);
152
+ }
153
+ emitSubagentStarted(childSessionId) {
154
+ const sub = this.subagents.get(childSessionId);
155
+ if (sub)
156
+ this.emitSubagentEvent(childSessionId, sub, 'started');
157
+ }
158
+ emitSubagentSettled(childSessionId, settlement) {
159
+ const sub = this.subagents.get(childSessionId);
160
+ if (!sub)
161
+ return;
162
+ this.emitSubagentEvent(childSessionId, sub, settlement.success ? 'completed' : 'failed', { summary: settlement.summary });
163
+ this.subagents.delete(childSessionId);
164
+ }
165
+ emitSubagentEvent(childSessionId, sub, event, extra = {}) {
166
+ const message = {
167
+ type: 'subagent',
168
+ sessionId: this.resolveDeliveryParent(sub),
169
+ event,
170
+ task_id: childSessionId,
171
+ agent_name: sub.agentName,
172
+ description: sub.description,
173
+ input_id: sub.inputId,
174
+ action_id: sub.actionId,
175
+ ...(sub.lastToolName !== null || event !== 'started'
176
+ ? { last_tool_name: sub.lastToolName }
177
+ : {}),
178
+ ...(sub.tokenCount > 0 ? { token_count: sub.tokenCount } : {}),
179
+ ...(event === 'completed' || event === 'failed'
180
+ ? { summary: extra.summary ?? '', usage: sub.usage }
181
+ : {}),
182
+ };
183
+ this.emit(message);
184
+ }
185
+ resolveDeliveryParent(sub) {
186
+ let parentId = sub.parentId;
187
+ let guard = 0;
188
+ while (this.subagents.has(parentId) && guard < 100) {
189
+ parentId = this.subagents.get(parentId).parentId;
190
+ guard += 1;
191
+ }
192
+ return parentId;
193
+ }
107
194
  };
108
195
  exports.AgentRuntimeEventEmitter = AgentRuntimeEventEmitter;
109
196
  exports.AgentRuntimeEventEmitter = AgentRuntimeEventEmitter = AgentRuntimeEventEmitter_1 = __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"agent-runtime-event-emitter.js","sourceRoot":"","sources":["../../../src/agent-runtime/agent-runtime-event-emitter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-runtime-event-emitter.js","sourceRoot":"","sources":["../../../src/agent-runtime/agent-runtime-event-emitter.ts"],"names":[],"mappings":"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"}
@@ -26,6 +26,7 @@ export interface AgentRuntimeActionInfo {
26
26
  tool_name: string | null;
27
27
  arguments: string | null;
28
28
  plain: string | null;
29
+ selections: string | null;
29
30
  order_of_execution: number;
30
31
  }
31
32
  export interface AgentRuntimeToolResultBlock {
@@ -63,6 +64,20 @@ export interface UserMessage {
63
64
  inputId: string;
64
65
  content: AgentRuntimeToolResultBlock[];
65
66
  }
67
+ export interface SubagentMessage {
68
+ type: 'subagent';
69
+ sessionId: string;
70
+ event: 'started' | 'progress' | 'completed' | 'failed';
71
+ task_id: string;
72
+ agent_name: string;
73
+ description: string;
74
+ input_id: string;
75
+ action_id: string;
76
+ last_tool_name?: string | null;
77
+ token_count?: number;
78
+ summary?: string;
79
+ usage?: AgentRuntimeUsage;
80
+ }
66
81
  export type AgentRuntimeResultSubtype = 'success' | 'error_during_execution' | 'aborted';
67
82
  export interface ResultMessage {
68
83
  type: 'result';
@@ -74,4 +89,4 @@ export interface ResultMessage {
74
89
  num_rounds: number;
75
90
  errors?: string[];
76
91
  }
77
- export type AgentRuntimeMessage = SystemInitMessage | StreamEventMessage | AssistantMessage | UserMessage | ResultMessage;
92
+ export type AgentRuntimeMessage = SystemInitMessage | StreamEventMessage | AssistantMessage | UserMessage | SubagentMessage | ResultMessage;
@@ -5,6 +5,7 @@ export declare class AppController {
5
5
  getHello(): string;
6
6
  getHealth(): {
7
7
  status: string;
8
+ projectPath: string;
8
9
  };
9
10
  getInfo(): {
10
11
  project_path: string;
@@ -3,6 +3,7 @@ export declare class AppService {
3
3
  getHello(): string;
4
4
  getHealth(): {
5
5
  status: string;
6
+ projectPath: string;
6
7
  };
7
8
  setPort(port: number): void;
8
9
  getPort(): number;