@positronic/cli 0.0.77 → 0.0.78

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 (49) hide show
  1. package/dist/src/cli.js +298 -196
  2. package/dist/src/commands/server.js +2 -2
  3. package/dist/src/components/event-detail.js +139 -139
  4. package/dist/src/components/events-view.js +60 -63
  5. package/dist/src/components/watch-keyboard.js +1 -1
  6. package/dist/src/components/watch-machine.js +344 -286
  7. package/dist/src/components/watch.js +17 -84
  8. package/dist/types/cli.d.ts.map +1 -1
  9. package/dist/types/components/event-detail.d.ts.map +1 -1
  10. package/dist/types/components/events-view.d.ts.map +1 -1
  11. package/dist/types/components/watch-machine.d.ts +90 -146
  12. package/dist/types/components/watch-machine.d.ts.map +1 -1
  13. package/dist/types/components/watch.d.ts.map +1 -1
  14. package/dist/types/hooks/useBrainMachine.d.ts +0 -3
  15. package/dist/types/hooks/useBrainMachine.d.ts.map +1 -1
  16. package/package.json +4 -4
  17. package/dist/src/commands/auth.js +0 -91
  18. package/dist/src/commands/brain.js +0 -139
  19. package/dist/src/commands/pages.js +0 -47
  20. package/dist/src/commands/project.js +0 -130
  21. package/dist/src/commands/resources.js +0 -272
  22. package/dist/src/commands/schedule.js +0 -91
  23. package/dist/src/commands/secrets.js +0 -67
  24. package/dist/src/commands/store.js +0 -36
  25. package/dist/src/commands/users.js +0 -92
  26. package/dist/src/components/agent-chat-view.js +0 -125
  27. package/dist/src/utils/agent-utils.js +0 -107
  28. package/dist/types/commands/auth.d.ts +0 -32
  29. package/dist/types/commands/auth.d.ts.map +0 -1
  30. package/dist/types/commands/brain.d.ts +0 -46
  31. package/dist/types/commands/brain.d.ts.map +0 -1
  32. package/dist/types/commands/pages.d.ts +0 -15
  33. package/dist/types/commands/pages.d.ts.map +0 -1
  34. package/dist/types/commands/project.d.ts +0 -55
  35. package/dist/types/commands/project.d.ts.map +0 -1
  36. package/dist/types/commands/resources.d.ts +0 -13
  37. package/dist/types/commands/resources.d.ts.map +0 -1
  38. package/dist/types/commands/schedule.d.ts +0 -33
  39. package/dist/types/commands/schedule.d.ts.map +0 -1
  40. package/dist/types/commands/secrets.d.ts +0 -20
  41. package/dist/types/commands/secrets.d.ts.map +0 -1
  42. package/dist/types/commands/store.d.ts +0 -5
  43. package/dist/types/commands/store.d.ts.map +0 -1
  44. package/dist/types/commands/users.d.ts +0 -34
  45. package/dist/types/commands/users.d.ts.map +0 -1
  46. package/dist/types/components/agent-chat-view.d.ts +0 -12
  47. package/dist/types/components/agent-chat-view.d.ts.map +0 -1
  48. package/dist/types/utils/agent-utils.d.ts +0 -20
  49. package/dist/types/utils/agent-utils.d.ts.map +0 -1
@@ -1,10 +1,18 @@
1
1
  /**
2
- * State machine for the Watch component.
2
+ * State management for the Watch component.
3
3
  *
4
- * This machine handles UI navigation and async operations for the watch view.
5
- * The brain execution tracking (useBrainMachine) and EventSource connection
4
+ * Uses useReducer for UI navigation and async operations.
5
+ * Brain execution tracking (useBrainMachine) and EventSource connection
6
6
  * remain separate concerns.
7
- */ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
7
+ */ function _array_like_to_array(arr, len) {
8
+ if (len == null || len > arr.length) len = arr.length;
9
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
10
+ return arr2;
11
+ }
12
+ function _array_with_holes(arr) {
13
+ if (Array.isArray(arr)) return arr;
14
+ }
15
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
8
16
  try {
9
17
  var info = gen[key](arg);
10
18
  var value = info.value;
@@ -46,6 +54,33 @@ function _define_property(obj, key, value) {
46
54
  }
47
55
  return obj;
48
56
  }
57
+ function _iterable_to_array_limit(arr, i) {
58
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
59
+ if (_i == null) return;
60
+ var _arr = [];
61
+ var _n = true;
62
+ var _d = false;
63
+ var _s, _e;
64
+ try {
65
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
66
+ _arr.push(_s.value);
67
+ if (i && _arr.length === i) break;
68
+ }
69
+ } catch (err) {
70
+ _d = true;
71
+ _e = err;
72
+ } finally{
73
+ try {
74
+ if (!_n && _i["return"] != null) _i["return"]();
75
+ } finally{
76
+ if (_d) throw _e;
77
+ }
78
+ }
79
+ return _arr;
80
+ }
81
+ function _non_iterable_rest() {
82
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
83
+ }
49
84
  function _object_spread(target) {
50
85
  for(var i = 1; i < arguments.length; i++){
51
86
  var source = arguments[i] != null ? arguments[i] : {};
@@ -85,6 +120,17 @@ function _object_spread_props(target, source) {
85
120
  }
86
121
  return target;
87
122
  }
123
+ function _sliced_to_array(arr, i) {
124
+ return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
125
+ }
126
+ function _unsupported_iterable_to_array(o, minLen) {
127
+ if (!o) return;
128
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
129
+ var n = Object.prototype.toString.call(o).slice(8, -1);
130
+ if (n === "Object" && o.constructor) n = o.constructor.name;
131
+ if (n === "Map" || n === "Set") return Array.from(n);
132
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
133
+ }
88
134
  function _ts_generator(thisArg, body) {
89
135
  var f, y, t, _ = {
90
136
  label: 0,
@@ -176,138 +222,178 @@ function _ts_generator(thisArg, body) {
176
222
  };
177
223
  }
178
224
  }
179
- import { useMemo } from 'react';
180
- import * as robot3 from 'robot3';
181
- import { useMachine } from 'react-robot';
225
+ import { useReducer, useCallback, useRef, useEffect } from 'react';
182
226
  import { apiClient } from '../commands/helpers.js';
183
- var createMachine = robot3.createMachine, state = robot3.state, transition = robot3.transition, reduce = robot3.reduce, invoke = robot3.invoke, immediate = robot3.immediate, guard = robot3.guard;
184
227
  // ============================================================================
185
- // Reducers
228
+ // Reducer
186
229
  // ============================================================================
187
- var setStateForStateView = reduce(function(ctx, param) {
188
- var stateSnapshot = param.stateSnapshot, stateTitle = param.stateTitle, fromView = param.fromView;
189
- return _object_spread_props(_object_spread({}, ctx), {
190
- stateSnapshot: stateSnapshot,
191
- stateTitle: stateTitle,
192
- stateScrollOffset: 0,
193
- previousView: fromView
194
- });
195
- });
196
- var clearStateSnapshot = reduce(function(ctx) {
197
- return _object_spread_props(_object_spread({}, ctx), {
198
- stateSnapshot: null
199
- });
200
- });
201
- var setAgentForChat = reduce(function(ctx, param) {
202
- var selectedAgentId = param.selectedAgentId, fromView = param.fromView;
203
- return _object_spread_props(_object_spread({}, ctx), {
204
- selectedAgentId: selectedAgentId !== null && selectedAgentId !== void 0 ? selectedAgentId : null,
205
- agentChatScrollOffset: 0,
206
- previousView: fromView
207
- });
208
- });
209
- var clearSelectedAgent = reduce(function(ctx) {
210
- return _object_spread_props(_object_spread({}, ctx), {
211
- selectedAgentId: null
212
- });
213
- });
214
- var setPreviousViewForMessage = reduce(function(ctx, param) {
215
- var fromView = param.fromView;
216
- return _object_spread_props(_object_spread({}, ctx), {
217
- previousView: fromView
218
- });
219
- });
220
- var setEventsSelectedIndex = reduce(function(ctx, param) {
221
- var index = param.index;
222
- return _object_spread_props(_object_spread({}, ctx), {
223
- eventsSelectedIndex: index
224
- });
225
- });
226
- var setStateScrollOffset = reduce(function(ctx, param) {
227
- var offset = param.offset;
228
- return _object_spread_props(_object_spread({}, ctx), {
229
- stateScrollOffset: offset
230
- });
231
- });
232
- var setAgentChatScrollOffset = reduce(function(ctx, param) {
233
- var offset = param.offset;
234
- return _object_spread_props(_object_spread({}, ctx), {
235
- agentChatScrollOffset: offset
236
- });
237
- });
238
- var selectAgentFromPicker = reduce(function(ctx, param) {
239
- var agentId = param.agentId;
240
- return _object_spread_props(_object_spread({}, ctx), {
241
- selectedAgentId: agentId,
242
- agentChatScrollOffset: 0
243
- });
244
- });
245
- var markKilled = reduce(function(ctx) {
246
- return _object_spread_props(_object_spread({}, ctx), {
247
- isKilled: true
248
- });
249
- });
250
- var setKillError = reduce(function(ctx, param) {
251
- var error = param.error;
252
- return _object_spread_props(_object_spread({}, ctx), {
253
- killError: error
254
- });
255
- });
256
- var setPauseMessage = reduce(function(ctx) {
257
- return _object_spread_props(_object_spread({}, ctx), {
258
- pauseResumeMessage: 'Pause signal sent'
259
- });
260
- });
261
- var setResumeMessage = reduce(function(ctx) {
262
- return _object_spread_props(_object_spread({}, ctx), {
263
- pauseResumeMessage: 'Resume signal sent'
264
- });
265
- });
266
- var clearPauseResumeMessage = reduce(function(ctx) {
267
- return _object_spread_props(_object_spread({}, ctx), {
268
- pauseResumeMessage: null
269
- });
270
- });
271
- var setMessageText = reduce(function(ctx, param) {
272
- var text = param.text;
273
- return _object_spread_props(_object_spread({}, ctx), {
274
- messageText: text
275
- });
276
- });
277
- var clearMessageText = reduce(function(ctx) {
278
- return _object_spread_props(_object_spread({}, ctx), {
279
- messageText: ''
280
- });
281
- });
282
- var setMessageSuccess = reduce(function(ctx) {
283
- return _object_spread_props(_object_spread({}, ctx), {
284
- messageFeedback: 'success',
285
- messageText: ''
286
- });
287
- });
288
- var setMessageError = reduce(function(ctx) {
289
- return _object_spread_props(_object_spread({}, ctx), {
290
- messageFeedback: 'error'
291
- });
292
- });
293
- var clearMessageFeedback = reduce(function(ctx) {
294
- return _object_spread_props(_object_spread({}, ctx), {
295
- messageFeedback: null
296
- });
297
- });
298
- // ============================================================================
299
- // Guards
300
- // ============================================================================
301
- var previousViewIsProgress = guard(function(ctx) {
302
- return ctx.previousView === 'progress';
303
- });
304
- var hasSelectedAgent = guard(function(ctx) {
305
- return ctx.selectedAgentId !== null;
306
- });
230
+ function watchReducer(state, action) {
231
+ switch(action.type){
232
+ case 'GO_TO_PROGRESS':
233
+ return _object_spread_props(_object_spread({}, state), {
234
+ viewMode: 'progress'
235
+ });
236
+ case 'GO_TO_EVENTS':
237
+ return _object_spread_props(_object_spread({}, state), {
238
+ viewMode: 'events'
239
+ });
240
+ case 'GO_TO_STATE':
241
+ return _object_spread_props(_object_spread({}, state), {
242
+ viewMode: 'state',
243
+ stateSnapshot: action.stateSnapshot,
244
+ stateTitle: action.stateTitle,
245
+ stateScrollOffset: 0,
246
+ previousView: action.fromView
247
+ });
248
+ case 'GO_TO_AGENTS':
249
+ var _action_selectedAgentId;
250
+ return _object_spread_props(_object_spread({}, state), {
251
+ viewMode: action.selectedAgentId ? 'agent-chat' : 'agent-picker',
252
+ selectedAgentId: (_action_selectedAgentId = action.selectedAgentId) !== null && _action_selectedAgentId !== void 0 ? _action_selectedAgentId : null,
253
+ agentChatScrollOffset: 0,
254
+ previousView: action.fromView
255
+ });
256
+ case 'GO_TO_MESSAGE_INPUT':
257
+ return _object_spread_props(_object_spread({}, state), {
258
+ viewMode: 'message-input',
259
+ previousView: action.fromView
260
+ });
261
+ case 'GO_BACK':
262
+ switch(state.viewMode){
263
+ case 'state':
264
+ return _object_spread_props(_object_spread({}, state), {
265
+ viewMode: state.previousView,
266
+ stateSnapshot: null
267
+ });
268
+ case 'agent-chat':
269
+ return _object_spread_props(_object_spread({}, state), {
270
+ viewMode: state.previousView,
271
+ selectedAgentId: null
272
+ });
273
+ case 'message-input':
274
+ return _object_spread_props(_object_spread({}, state), {
275
+ viewMode: state.previousView,
276
+ messageText: '',
277
+ messageFeedback: null,
278
+ messageStatus: 'idle'
279
+ });
280
+ default:
281
+ return _object_spread_props(_object_spread({}, state), {
282
+ viewMode: state.previousView
283
+ });
284
+ }
285
+ case 'SET_STATE_SCROLL_OFFSET':
286
+ return _object_spread_props(_object_spread({}, state), {
287
+ stateScrollOffset: action.offset
288
+ });
289
+ case 'AGENT_SELECTED':
290
+ return _object_spread_props(_object_spread({}, state), {
291
+ viewMode: 'agent-chat',
292
+ selectedAgentId: action.agentId,
293
+ agentChatScrollOffset: 0
294
+ });
295
+ case 'SET_AGENT_CHAT_SCROLL_OFFSET':
296
+ return _object_spread_props(_object_spread({}, state), {
297
+ agentChatScrollOffset: action.offset
298
+ });
299
+ case 'SET_EVENTS_SELECTED_INDEX':
300
+ return _object_spread_props(_object_spread({}, state), {
301
+ eventsSelectedIndex: action.index
302
+ });
303
+ // Kill flow
304
+ case 'INITIATE_KILL':
305
+ return _object_spread_props(_object_spread({}, state), {
306
+ killStatus: 'confirming'
307
+ });
308
+ case 'CANCEL_KILL':
309
+ return _object_spread_props(_object_spread({}, state), {
310
+ killStatus: 'idle'
311
+ });
312
+ case 'KILL_STARTED':
313
+ return _object_spread_props(_object_spread({}, state), {
314
+ killStatus: 'killing',
315
+ killError: null
316
+ });
317
+ case 'KILL_SUCCESS':
318
+ return _object_spread_props(_object_spread({}, state), {
319
+ killStatus: 'killed'
320
+ });
321
+ case 'KILL_ERROR':
322
+ return _object_spread_props(_object_spread({}, state), {
323
+ killStatus: 'error',
324
+ killError: action.error
325
+ });
326
+ // Pause/Resume
327
+ case 'PAUSE_STARTED':
328
+ return _object_spread_props(_object_spread({}, state), {
329
+ pauseResumeStatus: 'pausing'
330
+ });
331
+ case 'PAUSE_SUCCESS':
332
+ return _object_spread_props(_object_spread({}, state), {
333
+ pauseResumeStatus: 'idle',
334
+ pauseResumeMessage: 'Pause signal sent'
335
+ });
336
+ case 'PAUSE_ERROR':
337
+ return _object_spread_props(_object_spread({}, state), {
338
+ pauseResumeStatus: 'idle'
339
+ });
340
+ case 'RESUME_STARTED':
341
+ return _object_spread_props(_object_spread({}, state), {
342
+ pauseResumeStatus: 'resuming'
343
+ });
344
+ case 'RESUME_SUCCESS':
345
+ return _object_spread_props(_object_spread({}, state), {
346
+ pauseResumeStatus: 'idle',
347
+ pauseResumeMessage: 'Resume signal sent'
348
+ });
349
+ case 'RESUME_ERROR':
350
+ return _object_spread_props(_object_spread({}, state), {
351
+ pauseResumeStatus: 'idle'
352
+ });
353
+ case 'CLEAR_PAUSE_RESUME_MESSAGE':
354
+ return _object_spread_props(_object_spread({}, state), {
355
+ pauseResumeMessage: null
356
+ });
357
+ // Message flow
358
+ case 'SET_MESSAGE_TEXT':
359
+ return _object_spread_props(_object_spread({}, state), {
360
+ messageText: action.text
361
+ });
362
+ case 'SEND_MESSAGE_STARTED':
363
+ return _object_spread_props(_object_spread({}, state), {
364
+ messageStatus: 'sending'
365
+ });
366
+ case 'MESSAGE_SUCCESS':
367
+ return _object_spread_props(_object_spread({}, state), {
368
+ messageText: '',
369
+ messageFeedback: 'success',
370
+ messageStatus: 'idle'
371
+ });
372
+ case 'MESSAGE_ERROR':
373
+ return _object_spread_props(_object_spread({}, state), {
374
+ messageFeedback: 'error',
375
+ messageStatus: 'idle'
376
+ });
377
+ case 'CLEAR_FEEDBACK':
378
+ if (state.messageFeedback === 'success') {
379
+ return _object_spread_props(_object_spread({}, state), {
380
+ viewMode: state.previousView,
381
+ messageFeedback: null
382
+ });
383
+ }
384
+ return _object_spread_props(_object_spread({}, state), {
385
+ messageFeedback: null
386
+ });
387
+ case 'RESET':
388
+ return createInitialState(action.viewMode);
389
+ default:
390
+ return state;
391
+ }
392
+ }
307
393
  // ============================================================================
308
- // Async operation functions
394
+ // Async operations
309
395
  // ============================================================================
310
- var sendKillRequest = function(ctx) {
396
+ function killBrain(runId) {
311
397
  return _async_to_generator(function() {
312
398
  var response;
313
399
  return _ts_generator(this, function(_state) {
@@ -315,7 +401,7 @@ var sendKillRequest = function(ctx) {
315
401
  case 0:
316
402
  return [
317
403
  4,
318
- apiClient.fetch("/brains/runs/".concat(ctx.runId), {
404
+ apiClient.fetch("/brains/runs/".concat(runId), {
319
405
  method: 'DELETE'
320
406
  })
321
407
  ];
@@ -325,14 +411,13 @@ var sendKillRequest = function(ctx) {
325
411
  throw new Error("Failed to kill brain: ".concat(response.status));
326
412
  }
327
413
  return [
328
- 2,
329
- response
414
+ 2
330
415
  ];
331
416
  }
332
417
  });
333
418
  })();
334
- };
335
- var sendPauseSignal = function(ctx) {
419
+ }
420
+ function pauseBrain(runId) {
336
421
  return _async_to_generator(function() {
337
422
  var response;
338
423
  return _ts_generator(this, function(_state) {
@@ -340,7 +425,7 @@ var sendPauseSignal = function(ctx) {
340
425
  case 0:
341
426
  return [
342
427
  4,
343
- apiClient.fetch("/brains/runs/".concat(ctx.runId, "/signals"), {
428
+ apiClient.fetch("/brains/runs/".concat(runId, "/signals"), {
344
429
  method: 'POST',
345
430
  headers: {
346
431
  'Content-Type': 'application/json'
@@ -356,14 +441,13 @@ var sendPauseSignal = function(ctx) {
356
441
  throw new Error("Failed to pause: ".concat(response.status));
357
442
  }
358
443
  return [
359
- 2,
360
- response
444
+ 2
361
445
  ];
362
446
  }
363
447
  });
364
448
  })();
365
- };
366
- var sendResumeSignal = function(ctx) {
449
+ }
450
+ function resumeBrain(runId) {
367
451
  return _async_to_generator(function() {
368
452
  var response;
369
453
  return _ts_generator(this, function(_state) {
@@ -371,7 +455,7 @@ var sendResumeSignal = function(ctx) {
371
455
  case 0:
372
456
  return [
373
457
  4,
374
- apiClient.fetch("/brains/runs/".concat(ctx.runId, "/signals"), {
458
+ apiClient.fetch("/brains/runs/".concat(runId, "/signals"), {
375
459
  method: 'POST',
376
460
  headers: {
377
461
  'Content-Type': 'application/json'
@@ -387,26 +471,21 @@ var sendResumeSignal = function(ctx) {
387
471
  throw new Error("Failed to resume: ".concat(response.status));
388
472
  }
389
473
  return [
390
- 2,
391
- response
474
+ 2
392
475
  ];
393
476
  }
394
477
  });
395
478
  })();
396
- };
397
- var sendUserMessage = function(ctx) {
479
+ }
480
+ function sendUserMessage(runId, text) {
398
481
  return _async_to_generator(function() {
399
- var text, response;
482
+ var response;
400
483
  return _ts_generator(this, function(_state) {
401
484
  switch(_state.label){
402
485
  case 0:
403
- text = ctx.messageText.trim();
404
- if (!text) {
405
- throw new Error('Message is empty');
406
- }
407
486
  return [
408
487
  4,
409
- apiClient.fetch("/brains/runs/".concat(ctx.runId, "/signals"), {
488
+ apiClient.fetch("/brains/runs/".concat(runId, "/signals"), {
410
489
  method: 'POST',
411
490
  headers: {
412
491
  'Content-Type': 'application/json'
@@ -423,151 +502,130 @@ var sendUserMessage = function(ctx) {
423
502
  throw new Error("Failed to send message: ".concat(response.status));
424
503
  }
425
504
  return [
426
- 2,
427
- response
505
+ 2
428
506
  ];
429
507
  }
430
508
  });
431
509
  })();
432
- };
433
- // ============================================================================
434
- // State Machine Definition
435
- // ============================================================================
436
- var createWatchMachine = function(runId) {
437
- var startWithEvents = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false;
438
- return createMachine(startWithEvents ? 'events' : 'progress', {
439
- // Main view states
440
- progress: state(transition('GO_TO_EVENTS', 'events'), transition('GO_TO_STATE', 'state', setStateForStateView), transition('GO_TO_AGENTS', 'route-agents', setAgentForChat), transition('GO_TO_MESSAGE_INPUT', 'message-input', setPreviousViewForMessage), transition('INITIATE_KILL', 'confirming-kill'), transition('PAUSE', 'pausing'), transition('RESUME', 'resuming')),
441
- events: state(transition('GO_TO_PROGRESS', 'progress'), transition('GO_TO_STATE', 'state', setStateForStateView), transition('GO_TO_AGENTS', 'route-agents', setAgentForChat), transition('GO_TO_MESSAGE_INPUT', 'message-input', setPreviousViewForMessage), transition('INITIATE_KILL', 'confirming-kill'), transition('PAUSE', 'pausing'), transition('RESUME', 'resuming'), transition('SET_EVENTS_SELECTED_INDEX', 'events', setEventsSelectedIndex)),
442
- state: state(transition('GO_BACK', 'route-back', clearStateSnapshot), transition('SET_STATE_SCROLL_OFFSET', 'state', setStateScrollOffset)),
443
- // Routing state to determine where to go back
444
- 'route-back': state(immediate('progress', previousViewIsProgress), immediate('events')),
445
- // Routing state to determine if we show picker or go directly to chat
446
- 'route-agents': state(immediate('agent-chat', hasSelectedAgent), immediate('agent-picker')),
447
- 'agent-picker': state(transition('GO_BACK', 'route-back'), transition('AGENT_SELECTED', 'agent-chat', selectAgentFromPicker)),
448
- 'agent-chat': state(transition('GO_BACK', 'route-back', clearSelectedAgent), transition('SET_AGENT_CHAT_SCROLL_OFFSET', 'agent-chat', setAgentChatScrollOffset)),
449
- // Message input and sending
450
- 'message-input': state(transition('GO_BACK', 'route-back', clearMessageText), transition('SET_MESSAGE_TEXT', 'message-input', setMessageText), transition('SEND_MESSAGE', 'sending-message')),
451
- 'sending-message': invoke(sendUserMessage, transition('done', 'message-sent', setMessageSuccess), transition('error', 'message-error', setMessageError)),
452
- 'message-sent': state(transition('CLEAR_FEEDBACK', 'route-back', clearMessageFeedback)),
453
- 'message-error': state(transition('CLEAR_FEEDBACK', 'message-input', clearMessageFeedback), transition('GO_BACK', 'route-back', clearMessageText)),
454
- // Kill flow
455
- 'confirming-kill': state(transition('CONFIRM_KILL', 'killing'), transition('CANCEL_KILL', 'progress')),
456
- killing: invoke(sendKillRequest, transition('done', 'killed', markKilled), transition('error', 'kill-error', setKillError)),
457
- killed: state(// Can still navigate after kill
458
- transition('GO_TO_EVENTS', 'events'), transition('GO_TO_STATE', 'state', setStateForStateView), transition('GO_TO_AGENTS', 'route-agents', setAgentForChat)),
459
- 'kill-error': state(// Can retry kill or navigate
460
- transition('INITIATE_KILL', 'confirming-kill'), transition('GO_TO_EVENTS', 'events'), transition('GO_TO_STATE', 'state', setStateForStateView), transition('GO_TO_AGENTS', 'route-agents', setAgentForChat)),
461
- // Pause flow
462
- pausing: invoke(sendPauseSignal, transition('done', 'pause-sent', setPauseMessage), transition('error', 'progress')),
463
- 'pause-sent': state(transition('CLEAR_PAUSE_RESUME_MESSAGE', 'progress', clearPauseResumeMessage), // Allow navigation while showing message
464
- transition('GO_TO_EVENTS', 'events', clearPauseResumeMessage), transition('GO_TO_STATE', 'state', setStateForStateView), transition('GO_TO_AGENTS', 'route-agents', setAgentForChat)),
465
- // Resume flow
466
- resuming: invoke(sendResumeSignal, transition('done', 'resume-sent', setResumeMessage), transition('error', 'progress')),
467
- 'resume-sent': state(transition('CLEAR_PAUSE_RESUME_MESSAGE', 'progress', clearPauseResumeMessage), // Allow navigation while showing message
468
- transition('GO_TO_EVENTS', 'events', clearPauseResumeMessage), transition('GO_TO_STATE', 'state', setStateForStateView), transition('GO_TO_AGENTS', 'route-agents', setAgentForChat))
469
- }, function() {
470
- return {
471
- runId: runId,
472
- previousView: 'progress',
473
- stateSnapshot: null,
474
- stateTitle: '',
475
- stateScrollOffset: 0,
476
- selectedAgentId: null,
477
- agentChatScrollOffset: 0,
478
- eventsSelectedIndex: null,
479
- killError: null,
480
- isKilled: false,
481
- pauseResumeMessage: null,
482
- messageText: '',
483
- messageFeedback: null
484
- };
485
- });
486
- };
487
- // ============================================================================
488
- // Helper to map machine state to ViewMode
489
- // ============================================================================
490
- /**
491
- * Map machine state name to ViewMode for rendering.
492
- * The machine has routing/async states that need to be mapped to display views.
493
- */ export function machineStateToViewMode(stateName) {
494
- switch(stateName){
495
- case 'progress':
496
- case 'confirming-kill':
497
- case 'killing':
498
- case 'killed':
499
- case 'kill-error':
500
- case 'pausing':
501
- case 'pause-sent':
502
- case 'resuming':
503
- case 'resume-sent':
504
- return 'progress';
505
- case 'events':
506
- return 'events';
507
- case 'state':
508
- return 'state';
509
- case 'agent-picker':
510
- case 'route-agents':
511
- return 'agent-picker';
512
- case 'agent-chat':
513
- return 'agent-chat';
514
- case 'message-input':
515
- case 'sending-message':
516
- case 'message-sent':
517
- case 'message-error':
518
- return 'message-input';
519
- case 'route-back':
520
- // Transient state, treat as progress
521
- return 'progress';
522
- default:
523
- return 'progress';
524
- }
525
- }
526
- /**
527
- * Check if the machine is in a "confirming kill" state.
528
- */ export function isConfirmingKill(stateName) {
529
- return stateName === 'confirming-kill';
530
- }
531
- /**
532
- * Check if the machine is in a "killing" state.
533
- */ export function isKillingState(stateName) {
534
- return stateName === 'killing';
535
- }
536
- /**
537
- * Check if the machine is in a "killed" state.
538
- */ export function isKilledState(stateName) {
539
- return stateName === 'killed' || stateName === 'kill-error';
540
- }
541
- /**
542
- * Check if the machine is in a "pausing" state.
543
- */ export function isPausingState(stateName) {
544
- return stateName === 'pausing';
545
- }
546
- /**
547
- * Check if the machine is in a "resuming" state.
548
- */ export function isResumingState(stateName) {
549
- return stateName === 'resuming';
550
- }
551
- /**
552
- * Check if the machine is in a "sending message" state.
553
- */ export function isSendingMessageState(stateName) {
554
- return stateName === 'sending-message';
555
510
  }
556
511
  // ============================================================================
557
512
  // React Hook
558
513
  // ============================================================================
514
+ function createInitialState(viewMode) {
515
+ return {
516
+ viewMode: viewMode,
517
+ previousView: 'progress',
518
+ stateSnapshot: null,
519
+ stateTitle: '',
520
+ stateScrollOffset: 0,
521
+ selectedAgentId: null,
522
+ agentChatScrollOffset: 0,
523
+ eventsSelectedIndex: null,
524
+ killStatus: 'idle',
525
+ killError: null,
526
+ pauseResumeStatus: 'idle',
527
+ pauseResumeMessage: null,
528
+ messageText: '',
529
+ messageStatus: 'idle',
530
+ messageFeedback: null
531
+ };
532
+ }
559
533
  /**
560
- * React hook for the watch UI state machine.
561
- * Creates a fresh machine when runId changes.
562
- */ export function useWatchMachine(runId) {
534
+ * React hook for the watch UI state.
535
+ * Manages view navigation, async operations (kill/pause/resume/message),
536
+ * and related UI state like scroll offsets and selections.
537
+ */ export function useWatchReducer(runId) {
563
538
  var startWithEvents = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false;
564
- var machine = useMemo(function() {
565
- return createWatchMachine(runId, startWithEvents);
539
+ var initialViewMode = startWithEvents ? 'events' : 'progress';
540
+ var _useReducer = _sliced_to_array(useReducer(watchReducer, initialViewMode, createInitialState), 2), state = _useReducer[0], dispatch = _useReducer[1];
541
+ // Reset when runId changes
542
+ var prevRunIdRef = useRef(runId);
543
+ useEffect(function() {
544
+ if (prevRunIdRef.current !== runId) {
545
+ prevRunIdRef.current = runId;
546
+ dispatch({
547
+ type: 'RESET',
548
+ viewMode: initialViewMode
549
+ });
550
+ }
566
551
  }, [
567
552
  runId,
568
- startWithEvents
553
+ initialViewMode
554
+ ]);
555
+ // Ref for accessing latest state in async callbacks
556
+ var stateRef = useRef(state);
557
+ stateRef.current = state;
558
+ var send = useCallback(function(action) {
559
+ switch(action.type){
560
+ case 'CONFIRM_KILL':
561
+ dispatch({
562
+ type: 'KILL_STARTED'
563
+ });
564
+ killBrain(runId).then(function() {
565
+ return dispatch({
566
+ type: 'KILL_SUCCESS'
567
+ });
568
+ }, function(error) {
569
+ return dispatch({
570
+ type: 'KILL_ERROR',
571
+ error: error
572
+ });
573
+ });
574
+ break;
575
+ case 'PAUSE':
576
+ dispatch({
577
+ type: 'PAUSE_STARTED'
578
+ });
579
+ pauseBrain(runId).then(function() {
580
+ return dispatch({
581
+ type: 'PAUSE_SUCCESS'
582
+ });
583
+ }, function() {
584
+ return dispatch({
585
+ type: 'PAUSE_ERROR'
586
+ });
587
+ });
588
+ break;
589
+ case 'RESUME':
590
+ dispatch({
591
+ type: 'RESUME_STARTED'
592
+ });
593
+ resumeBrain(runId).then(function() {
594
+ return dispatch({
595
+ type: 'RESUME_SUCCESS'
596
+ });
597
+ }, function() {
598
+ return dispatch({
599
+ type: 'RESUME_ERROR'
600
+ });
601
+ });
602
+ break;
603
+ case 'SEND_MESSAGE':
604
+ {
605
+ var text = stateRef.current.messageText.trim();
606
+ if (!text) return;
607
+ dispatch({
608
+ type: 'SEND_MESSAGE_STARTED'
609
+ });
610
+ sendUserMessage(runId, text).then(function() {
611
+ return dispatch({
612
+ type: 'MESSAGE_SUCCESS'
613
+ });
614
+ }, function() {
615
+ return dispatch({
616
+ type: 'MESSAGE_ERROR'
617
+ });
618
+ });
619
+ break;
620
+ }
621
+ default:
622
+ dispatch(action);
623
+ }
624
+ }, [
625
+ runId
569
626
  ]);
570
- return useMachine(machine);
627
+ return [
628
+ state,
629
+ send
630
+ ];
571
631
  }
572
- // Export the machine creator for testing
573
- export { createWatchMachine };