@oar-sh/oar 0.9.21 → 0.9.22

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 (69) hide show
  1. package/CHANGELOG.md +113 -0
  2. package/README.md +9 -9
  3. package/package.json +1 -1
  4. package/server/claude-cloud-worker/claude-cloud-session-worker.mjs +9 -1
  5. package/server/claude-worker/claude-sdk-adapter.mjs +149 -4
  6. package/server/claude-worker/claude-session-process.mjs +9 -4
  7. package/server/claude-worker/claude-session-worker-main.mjs +10 -1
  8. package/server/copilot-worker/copilot-sdk-session-process.mjs +1 -0
  9. package/server/copilot-worker/copilot-sdk-session-worker.mjs +10 -1
  10. package/server/cursor-worker/cursor-session-worker.mjs +9 -1
  11. package/server/db-schema.mjs +19 -0
  12. package/server/grok-worker/grok-background-tasks.mjs +1 -0
  13. package/server/grok-worker/grok-session-worker.mjs +10 -1
  14. package/server/grok-worker/grok-turn-runner.mjs +1 -0
  15. package/server/migrations/0037-relay-asks-queue-id.mjs +66 -0
  16. package/server/migrations/0038-turn-seq.mjs +92 -0
  17. package/server/public/app/activity-replay-state.mjs +160 -42
  18. package/server/public/app/api-client.js +7 -0
  19. package/server/public/app/ask-user-view.js +4 -3
  20. package/server/public/app/bootstrap.js +62 -4
  21. package/server/public/app/chat-actions-menu-state.mjs +2 -0
  22. package/server/public/app/context-usage-view.mjs +68 -0
  23. package/server/public/app/conversation-view.js +306 -49
  24. package/server/public/app/header-priority-actions.mjs +5 -1
  25. package/server/public/app/held-details.mjs +202 -0
  26. package/server/public/app/inbox-ui.js +70 -79
  27. package/server/public/app/inbox-view.mjs +35 -19
  28. package/server/public/app/journal-view.js +17 -0
  29. package/server/public/app/live-activity-cap.mjs +103 -0
  30. package/server/public/app/questions-panel-ui.js +634 -0
  31. package/server/public/app/questions-stub-view.mjs +40 -0
  32. package/server/public/app/questions-view.mjs +89 -0
  33. package/server/public/app/relay-board-view.js +12 -2
  34. package/server/public/app/relay-thoughts.mjs +15 -1
  35. package/server/public/app/session-history-ui.js +1 -0
  36. package/server/public/app/settings-modal.js +6 -0
  37. package/server/public/app/socket-handlers.js +42 -11
  38. package/server/public/app/stream-view-preference.mjs +60 -0
  39. package/server/public/app/subagent-fold.mjs +6 -3
  40. package/server/public/app/subagent-timeline-view.mjs +12 -5
  41. package/server/public/app/subagent-viewer.mjs +8 -6
  42. package/server/public/app/thoughts-preference.mjs +79 -0
  43. package/server/public/app/turn-stream-view.mjs +124 -0
  44. package/server/public/index.html +391 -214
  45. package/server/repositories/message-repository.mjs +10 -0
  46. package/server/repositories/question-repository.mjs +51 -7
  47. package/server/repositories/relay-turn-rows.mjs +56 -0
  48. package/server/routes/ask-user-routes.mjs +34 -5
  49. package/server/routes/messages-routes.mjs +35 -14
  50. package/server/routes/relay-ask-routes.mjs +15 -5
  51. package/server/routes/sessions-routes.mjs +76 -5
  52. package/server/server-runtime.mjs +178 -131
  53. package/server/services/cloudflared-tunnel-service.mjs +7 -0
  54. package/server/services/idle-timers.mjs +184 -0
  55. package/server/services/queue-wake-hook.mjs +145 -0
  56. package/server/services/queue-waker.mjs +127 -0
  57. package/server/services/relay-ask-service.mjs +64 -5
  58. package/server/services/relay-event-service.mjs +4 -1
  59. package/server/services/remote-relay-dispatcher.mjs +23 -4
  60. package/server/services/session-history-refresh-service.mjs +4 -0
  61. package/server/services/session-worker-supervisor-service.mjs +36 -0
  62. package/server/services/session-worker-websocket-service.mjs +143 -15
  63. package/server/services/ssh-tunnel-manager-service.mjs +7 -0
  64. package/shared/ask-user-bridge.mjs +9 -6
  65. package/shared/relay-asks.mjs +10 -0
  66. package/shared/relay-events.mjs +1 -0
  67. package/shared/worker-runtime/heartbeat.mjs +26 -0
  68. package/shared/worker-runtime/worker-keepalive.mjs +108 -0
  69. package/shared/worker-runtime/worker-websocket-link.mjs +21 -10
@@ -63,9 +63,13 @@ export function createWorkerWebSocketLink({
63
63
  getDeliveryHeld = null,
64
64
  // Called with the hello's reason once per connection, on the relay's first
65
65
  // server.hello: from then on the relay (possibly a restarted one that knows
66
- // nothing of this worker) has the socket. Later hellos only ack the
67
- // worker.hello every idle readiness refresh re-sends, and are not reported.
66
+ // nothing of this worker) has the socket. Later hellos only ack a later
67
+ // worker.hello, and are not reported.
68
68
  onServerHello = () => {},
69
+ // Called with "server-hello" on every server.hello and with "deliver" on
70
+ // every queue.deliver: the keepalive keeps its busy cadence for a while
71
+ // after either (worker-keepalive.mjs).
72
+ onRelayFrame = () => {},
69
73
  getSessionId = () => null,
70
74
  getPid = () => null,
71
75
  // The kind of worker this is ("claude", "claude-api", ...), stated in
@@ -88,8 +92,12 @@ export function createWorkerWebSocketLink({
88
92
  // Failed attempts after the first few are logged at most once per this
89
93
  // interval, with a count of the ones in between.
90
94
  failureLogIntervalMs = 60_000,
95
+ // The link's own readiness refresh; 0 leaves it to the caller, which then
96
+ // calls refreshReadiness itself (worker-keepalive.mjs does, on its beat).
91
97
  readyRefreshMs = 10_000,
92
- staleConnectionMs = 30_000,
98
+ // Three missed idle beats (30 s each) without any word from the relay: the
99
+ // connection is given up and made again.
100
+ staleConnectionMs = 90_000,
93
101
  WebSocketImpl = globalThis.WebSocket,
94
102
  setTimeoutImpl = setTimeout,
95
103
  clearTimeoutImpl = clearTimeout,
@@ -309,19 +317,17 @@ export function createWorkerWebSocketLink({
309
317
  notifyUnready(reason);
310
318
  return true;
311
319
  }
312
- if (deliveriesInFlight.size) {
313
- // notifyReady gates itself: it only goes through mid-delivery when the
314
- // worker is steering-ready. Hello stays an idle-only affair.
315
- void notifyReady(reason);
316
- return true;
317
- }
318
- notifyHello(reason);
320
+ // notifyReady gates itself: mid-delivery it only goes through when the
321
+ // worker is steering-ready. No hello: the socket's identity, kind and
322
+ // build were bound by the hello at open, and a ready carries them again;
323
+ // a hello would only draw a second server.hello and a second ready.
319
324
  void notifyReady(reason);
320
325
  return true;
321
326
  }
322
327
 
323
328
  function startReadyRefreshTimer() {
324
329
  clearReadyRefreshTimer();
330
+ if (Number(readyRefreshMs) === 0) return;
325
331
  const intervalMs = Math.max(1000, Number(readyRefreshMs) || 10_000);
326
332
  readyRefreshTimer = setIntervalImpl(() => {
327
333
  refreshReadiness("readiness-refresh");
@@ -449,11 +455,13 @@ export function createWorkerWebSocketLink({
449
455
  return;
450
456
  }
451
457
  if (payload?.type === "queue.deliver") {
458
+ try { onRelayFrame("deliver"); } catch {}
452
459
  void deliverPending(payload.pending || null, String(payload.reason || "queue-deliver"))
453
460
  .finally(() => notifyReady("delivery-complete"));
454
461
  return;
455
462
  }
456
463
  if (payload?.type === "server.hello") {
464
+ try { onRelayFrame("server-hello"); } catch {}
457
465
  serverCapabilities = new Set(Array.isArray(payload.capabilities) ? payload.capabilities.map(String) : []);
458
466
  relayBuildId = normalizeText(payload.buildId);
459
467
  // Only a line in the log: the relay decides when to replace this
@@ -565,6 +573,9 @@ export function createWorkerWebSocketLink({
565
573
  return {
566
574
  notifyReady,
567
575
  notifyUnready,
576
+ refreshReadiness,
577
+ // A delivery in flight or a hold: the keepalive beats at its busy cadence.
578
+ isBusy: () => deliveriesInFlight.size > 0 || deliveryHeld(),
568
579
  serverSupports: (capability) => serverCapabilities.has(String(capability || "")),
569
580
  start,
570
581
  stop,