@opengeni/react 0.45.0 → 0.48.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 (141) hide show
  1. package/README.md +68 -12
  2. package/dist/{chunk-U3CSCMWA.js → chunk-FK6VG4LL.js} +9 -13
  3. package/dist/chunk-FK6VG4LL.js.map +1 -0
  4. package/dist/{chunk-HFO4ERGQ.js → chunk-FWXGSNXT.js} +2 -2
  5. package/dist/{chunk-SRFUT2ZU.js → chunk-I4MPFDRP.js} +119 -63
  6. package/dist/chunk-I4MPFDRP.js.map +1 -0
  7. package/dist/{chunk-EB67J347.js → chunk-KZ73RL76.js} +111 -31
  8. package/dist/chunk-KZ73RL76.js.map +1 -0
  9. package/dist/{chunk-LWR4MXSS.js → chunk-LHLYWG5R.js} +10 -1
  10. package/dist/chunk-LHLYWG5R.js.map +1 -0
  11. package/dist/{chunk-L3EWO3UK.js → chunk-NJ7M2B6Z.js} +445 -84
  12. package/dist/chunk-NJ7M2B6Z.js.map +1 -0
  13. package/dist/{chunk-VCBFUSUZ.js → chunk-O4VXOBGF.js} +3 -3
  14. package/dist/{chunk-VCBFUSUZ.js.map → chunk-O4VXOBGF.js.map} +1 -1
  15. package/dist/{chunk-6EDV6YFE.js → chunk-OL6QVXGF.js} +121 -29
  16. package/dist/chunk-OL6QVXGF.js.map +1 -0
  17. package/dist/chunk-VZTQ73XT.js +86 -0
  18. package/dist/chunk-VZTQ73XT.js.map +1 -0
  19. package/dist/{chunk-EHSYZ4KP.js → chunk-WYA65Y3F.js} +16 -16
  20. package/dist/chunk-WYA65Y3F.js.map +1 -0
  21. package/dist/{chunk-FD72GJMK.js → chunk-XCNTXWBB.js} +274 -125
  22. package/dist/chunk-XCNTXWBB.js.map +1 -0
  23. package/dist/client.d.ts +1 -1
  24. package/dist/components/chat-composer.d.ts +7 -2
  25. package/dist/components/composer-transcription-control.d.ts +2 -0
  26. package/dist/components/composer.d.ts +14 -0
  27. package/dist/components/machines/machine-detail.d.ts +3 -1
  28. package/dist/components/machines-dashboard.d.ts +3 -3
  29. package/dist/components/message-timeline.d.ts +12 -2
  30. package/dist/components/sandbox-files.d.ts +2 -2
  31. package/dist/components/sandbox-terminal.d.ts +29 -0
  32. package/dist/components/sandbox-workspace.d.ts +5 -1
  33. package/dist/components/workspace-dock.d.ts +3 -1
  34. package/dist/composer.d.ts +2 -2
  35. package/dist/composer.js +6 -6
  36. package/dist/hooks/internal.d.ts +6 -0
  37. package/dist/hooks/use-codex-accounts.d.ts +1 -1
  38. package/dist/hooks/use-environments.d.ts +10 -4
  39. package/dist/hooks/use-machines.d.ts +7 -0
  40. package/dist/hooks/use-sandbox-files.d.ts +19 -0
  41. package/dist/hooks/use-sandbox-git.d.ts +7 -0
  42. package/dist/hooks/use-transcription.d.ts +2 -2
  43. package/dist/hooks/use-voice-input.d.ts +13 -4
  44. package/dist/index.d.ts +6 -5
  45. package/dist/index.js +904 -538
  46. package/dist/index.js.map +1 -1
  47. package/dist/lib/composer-responsive-context.d.ts +9 -0
  48. package/dist/lib/use-portal-token-style.d.ts +14 -3
  49. package/dist/machines.js +2 -2
  50. package/dist/{queue-surface-implementation-J4XJFKRW.js → queue-surface-implementation-U5JFG7HT.js} +19 -18
  51. package/dist/queue-surface-implementation-U5JFG7HT.js.map +1 -0
  52. package/dist/realtime/realtime-control.d.ts +9 -0
  53. package/dist/realtime.js +29 -32
  54. package/dist/realtime.js.map +1 -1
  55. package/dist/session-ui.js +5 -5
  56. package/dist/session.js +4 -4
  57. package/dist/timeline/activity-rail.d.ts +3 -2
  58. package/dist/timeline/index.d.ts +2 -2
  59. package/dist/timeline/parsers.d.ts +3 -3
  60. package/dist/timeline/registry.d.ts +3 -0
  61. package/dist/timeline/screenshot-lightbox.d.ts +1 -1
  62. package/dist/timeline/types.d.ts +4 -0
  63. package/dist/voice-recording-store.d.ts +8 -2
  64. package/package.json +20 -4
  65. package/src/client.ts +3 -0
  66. package/src/components/chat-composer.tsx +12 -2
  67. package/src/components/code-editor.tsx +1 -1
  68. package/src/components/command-palette.tsx +1 -1
  69. package/src/components/composer-transcription-control.tsx +41 -16
  70. package/src/components/composer.tsx +52 -26
  71. package/src/components/copy-button.tsx +2 -2
  72. package/src/components/desktop-viewer.tsx +2 -2
  73. package/src/components/file-browser.tsx +39 -17
  74. package/src/components/human-input-form.tsx +2 -2
  75. package/src/components/machine-card.tsx +1 -1
  76. package/src/components/machines/machine-detail.tsx +39 -15
  77. package/src/components/machines-dashboard.tsx +7 -6
  78. package/src/components/message-timeline.tsx +44 -11
  79. package/src/components/model-picker.tsx +2 -2
  80. package/src/components/model-policy-picker.tsx +16 -15
  81. package/src/components/queue-surface-implementation.tsx +20 -16
  82. package/src/components/queue-surface-state.tsx +2 -2
  83. package/src/components/sandbox-files.tsx +140 -60
  84. package/src/components/sandbox-terminal.tsx +24 -5
  85. package/src/components/sandbox-workspace.tsx +180 -142
  86. package/src/components/session-chrome.tsx +14 -14
  87. package/src/components/tooltip.tsx +13 -16
  88. package/src/components/user-message-body.tsx +1 -1
  89. package/src/components/workbench-changes.tsx +4 -4
  90. package/src/components/workspace-dock.tsx +13 -5
  91. package/src/composer.ts +3 -0
  92. package/src/hooks/internal.ts +132 -38
  93. package/src/hooks/use-codex-accounts.ts +4 -4
  94. package/src/hooks/use-environments.ts +24 -5
  95. package/src/hooks/use-file-attachments.ts +70 -32
  96. package/src/hooks/use-goal.ts +17 -5
  97. package/src/hooks/use-machines.ts +47 -1
  98. package/src/hooks/use-sandbox-files.ts +310 -59
  99. package/src/hooks/use-sandbox-git.ts +148 -41
  100. package/src/hooks/use-session-capabilities.ts +35 -24
  101. package/src/hooks/use-session-events.ts +18 -4
  102. package/src/hooks/use-transcription.ts +4 -14
  103. package/src/hooks/use-turn-queue.ts +17 -5
  104. package/src/hooks/use-voice-input.ts +481 -36
  105. package/src/hooks/use-windowed-sections.ts +9 -7
  106. package/src/index.ts +11 -6
  107. package/src/lib/composer-responsive-context.ts +15 -0
  108. package/src/lib/use-portal-token-style.ts +60 -15
  109. package/src/provider.tsx +52 -7
  110. package/src/realtime/dropdown-menu.tsx +15 -19
  111. package/src/realtime/realtime-control.tsx +18 -7
  112. package/src/timeline/activity-rail.tsx +15 -6
  113. package/src/timeline/index.ts +1 -1
  114. package/src/timeline/parsers.ts +33 -20
  115. package/src/timeline/projection.ts +23 -0
  116. package/src/timeline/registry.ts +7 -0
  117. package/src/timeline/screenshot-lightbox.tsx +15 -4
  118. package/src/timeline/shared.tsx +8 -8
  119. package/src/timeline/tool-renderers.tsx +166 -22
  120. package/src/timeline/turn-summary.tsx +6 -6
  121. package/src/timeline/types.ts +4 -0
  122. package/src/voice-recording-store.ts +15 -0
  123. package/styles/compiled.css +5065 -0
  124. package/styles/compiled.d.ts +2 -0
  125. package/styles/effective-tokens.css +27 -0
  126. package/styles/index.css +3 -0
  127. package/styles/responsive.css +196 -0
  128. package/styles/responsive.d.ts +2 -0
  129. package/styles/tokens.css +50 -17
  130. package/dist/chunk-6EDV6YFE.js.map +0 -1
  131. package/dist/chunk-EB67J347.js.map +0 -1
  132. package/dist/chunk-EHSYZ4KP.js.map +0 -1
  133. package/dist/chunk-FD72GJMK.js.map +0 -1
  134. package/dist/chunk-JB5725BI.js +0 -48
  135. package/dist/chunk-JB5725BI.js.map +0 -1
  136. package/dist/chunk-L3EWO3UK.js.map +0 -1
  137. package/dist/chunk-LWR4MXSS.js.map +0 -1
  138. package/dist/chunk-SRFUT2ZU.js.map +0 -1
  139. package/dist/chunk-U3CSCMWA.js.map +0 -1
  140. package/dist/queue-surface-implementation-J4XJFKRW.js.map +0 -1
  141. /package/dist/{chunk-HFO4ERGQ.js.map → chunk-FWXGSNXT.js.map} +0 -0
@@ -68,7 +68,7 @@ function QueueErrorAlert({
68
68
  role: "region",
69
69
  "aria-label": "Queue error details",
70
70
  tabIndex: 0,
71
- className: "max-h-[min(5rem,20dvh)] min-w-0 max-w-full flex-[1_1_5rem] overflow-auto overscroll-contain whitespace-pre-wrap rounded-sm outline-none [overflow-wrap:anywhere] [unicode-bidi:plaintext] focus-visible:ring-2 focus-visible:ring-ring/40",
71
+ className: "max-h-[min(5rem,20dvh)] min-w-0 max-w-full flex-[1_1_5rem] overflow-auto overscroll-contain whitespace-pre-wrap rounded-sm outline-hidden [overflow-wrap:anywhere] [unicode-bidi:plaintext] focus-visible:ring-2 focus-visible:ring-ring/40",
72
72
  "data-testid": "queue-error-message",
73
73
  dir: "auto",
74
74
  children: (queue.mutationError ?? queue.error)?.message
@@ -84,7 +84,7 @@ function QueueErrorAlert({
84
84
  },
85
85
  "aria-label": "Dismiss queue error and retry",
86
86
  title: "Retry loading the queue",
87
- className: "ms-auto inline-flex size-7 shrink-0 items-center justify-center self-start rounded-md outline-none transition-colors hover:bg-surface-3 focus-visible:ring-2 focus-visible:ring-ring/40 motion-reduce:transition-none pointer-coarse:size-[44px]",
87
+ className: "ms-auto inline-flex size-7 shrink-0 items-center justify-center self-start rounded-md outline-hidden transition-colors hover:bg-surface-3 focus-visible:ring-2 focus-visible:ring-ring/40 motion-reduce:transition-none pointer-coarse:size-[44px]",
88
88
  children: /* @__PURE__ */ jsx(RotateCwIcon, { className: "size-3.5" })
89
89
  }
90
90
  )
@@ -99,4 +99,4 @@ export {
99
99
  QueueStoppingStatus,
100
100
  QueueErrorAlert
101
101
  };
102
- //# sourceMappingURL=chunk-VCBFUSUZ.js.map
102
+ //# sourceMappingURL=chunk-O4VXOBGF.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/queue-draft-policy.ts","../src/components/queue-surface-state.tsx"],"sourcesContent":["import type { ComposerState } from \"../hooks/use-composer\";\n\n/**\n * Decide whether checking out a queued prompt would replace current composer\n * content. `hasDraftContent` reads the synchronous draft refs, so this stays\n * correct even when a controlled input update has not rendered yet.\n */\nexport function requestQueueDraftEdit(\n composer: Pick<ComposerState, \"hasDraftContent\">,\n confirmReplacement: () => void,\n editImmediately: () => void,\n): void {\n if (composer.hasDraftContent()) {\n confirmReplacement();\n } else {\n editImmediately();\n }\n}\n","import { Loader2Icon, RotateCwIcon } from \"lucide-react\";\n\nimport type { UseTurnQueueResult } from \"../hooks/use-turn-queue\";\n\ntype QueueStateProps = {\n queue: UseTurnQueueResult;\n};\n\nexport function EmptyQueueStateSurface({ queue }: QueueStateProps) {\n const hasError = Boolean(queue.error || queue.mutationError);\n return (\n <div\n className=\"og-root mx-auto mb-2 w-full max-w-3xl shrink-0 px-4 sm:px-6\"\n data-testid=\"queue-surface\"\n >\n <div className=\"overflow-hidden rounded-lg border border-border bg-surface/80 shadow-sm\">\n {queue.stoppingPreviousAttempt ? (\n <QueueStoppingStatus queue={queue} dividerAfter={hasError} />\n ) : null}\n {hasError ? <QueueErrorAlert queue={queue} /> : null}\n </div>\n </div>\n );\n}\n\nexport function QueueStoppingStatus({\n queue,\n dividerAfter = false,\n}: QueueStateProps & { dividerAfter?: boolean }) {\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className={`flex min-h-11 items-center gap-2.5 bg-status-waiting/[0.07] px-3 py-2 text-og-control text-fg ${\n dividerAfter ? \"border-b border-status-waiting/20\" : \"\"\n }`}\n data-testid=\"stopping-previous-attempt\"\n >\n <Loader2Icon\n aria-hidden=\"true\"\n className=\"size-3.5 shrink-0 animate-spin text-status-waiting motion-reduce:animate-none\"\n />\n <span className=\"min-w-0\">\n <span className=\"font-medium\">\n {queue.effectiveControl?.state === \"paused\"\n ? \"Stopping current attempt…\"\n : \"Stopping previous attempt…\"}\n </span>{\" \"}\n <span className=\"text-fg-muted\">\n {queue.effectiveControl?.state === \"paused\"\n ? \"Queued work stays saved until you resume.\"\n : \"Queued work is saved and starts automatically.\"}\n </span>\n </span>\n </div>\n );\n}\n\nexport function QueueErrorAlert({\n queue,\n dividerBefore = false,\n}: QueueStateProps & { dividerBefore?: boolean }) {\n return (\n <div className={`${dividerBefore ? \"border-t border-border\" : \"\"} p-2`}>\n <div\n role=\"alert\"\n className=\"flex min-w-0 max-w-full flex-wrap items-start gap-2 rounded-md bg-status-failed/10 px-2 py-1.5 text-og-control text-status-failed\"\n >\n <span\n role=\"region\"\n aria-label=\"Queue error details\"\n tabIndex={0}\n className=\"max-h-[min(5rem,20dvh)] min-w-0 max-w-full flex-[1_1_5rem] overflow-auto overscroll-contain whitespace-pre-wrap rounded-sm outline-none [overflow-wrap:anywhere] [unicode-bidi:plaintext] focus-visible:ring-2 focus-visible:ring-ring/40\"\n data-testid=\"queue-error-message\"\n dir=\"auto\"\n >\n {(queue.mutationError ?? queue.error)?.message}\n </span>\n <button\n type=\"button\"\n onClick={() => {\n queue.clearMutationError();\n void queue.refresh();\n }}\n aria-label=\"Dismiss queue error and retry\"\n title=\"Retry loading the queue\"\n className=\"ms-auto inline-flex size-7 shrink-0 items-center justify-center self-start rounded-md outline-none transition-colors hover:bg-surface-3 focus-visible:ring-2 focus-visible:ring-ring/40 motion-reduce:transition-none pointer-coarse:size-[44px]\"\n >\n <RotateCwIcon className=\"size-3.5\" />\n </button>\n </div>\n </div>\n );\n}\n"],"mappings":";AAOO,SAAS,sBACd,UACA,oBACA,iBACM;AACN,MAAI,SAAS,gBAAgB,GAAG;AAC9B,uBAAmB;AAAA,EACrB,OAAO;AACL,oBAAgB;AAAA,EAClB;AACF;;;ACjBA,SAAS,aAAa,oBAAoB;AAepC,SAEI,KAFJ;AAPC,SAAS,uBAAuB,EAAE,MAAM,GAAoB;AACjE,QAAM,WAAW,QAAQ,MAAM,SAAS,MAAM,aAAa;AAC3D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,eAAY;AAAA,MAEZ,+BAAC,SAAI,WAAU,2EACZ;AAAA,cAAM,0BACL,oBAAC,uBAAoB,OAAc,cAAc,UAAU,IACzD;AAAA,QACH,WAAW,oBAAC,mBAAgB,OAAc,IAAK;AAAA,SAClD;AAAA;AAAA,EACF;AAEJ;AAEO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA,eAAe;AACjB,GAAiD;AAC/C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,aAAU;AAAA,MACV,WAAW,iGACT,eAAe,sCAAsC,EACvD;AAAA,MACA,eAAY;AAAA,MAEZ;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,eAAY;AAAA,YACZ,WAAU;AAAA;AAAA,QACZ;AAAA,QACA,qBAAC,UAAK,WAAU,WACd;AAAA,8BAAC,UAAK,WAAU,eACb,gBAAM,kBAAkB,UAAU,WAC/B,mCACA,mCACN;AAAA,UAAQ;AAAA,UACR,oBAAC,UAAK,WAAU,iBACb,gBAAM,kBAAkB,UAAU,WAC/B,8CACA,kDACN;AAAA,WACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAEO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA,gBAAgB;AAClB,GAAkD;AAChD,SACE,oBAAC,SAAI,WAAW,GAAG,gBAAgB,2BAA2B,EAAE,QAC9D;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,WAAU;AAAA,MAEV;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,cAAW;AAAA,YACX,UAAU;AAAA,YACV,WAAU;AAAA,YACV,eAAY;AAAA,YACZ,KAAI;AAAA,YAEF,iBAAM,iBAAiB,MAAM,QAAQ;AAAA;AAAA,QACzC;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS,MAAM;AACb,oBAAM,mBAAmB;AACzB,mBAAK,MAAM,QAAQ;AAAA,YACrB;AAAA,YACA,cAAW;AAAA,YACX,OAAM;AAAA,YACN,WAAU;AAAA,YAEV,8BAAC,gBAAa,WAAU,YAAW;AAAA;AAAA,QACrC;AAAA;AAAA;AAAA,EACF,GACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/components/queue-draft-policy.ts","../src/components/queue-surface-state.tsx"],"sourcesContent":["import type { ComposerState } from \"../hooks/use-composer\";\n\n/**\n * Decide whether checking out a queued prompt would replace current composer\n * content. `hasDraftContent` reads the synchronous draft refs, so this stays\n * correct even when a controlled input update has not rendered yet.\n */\nexport function requestQueueDraftEdit(\n composer: Pick<ComposerState, \"hasDraftContent\">,\n confirmReplacement: () => void,\n editImmediately: () => void,\n): void {\n if (composer.hasDraftContent()) {\n confirmReplacement();\n } else {\n editImmediately();\n }\n}\n","import { Loader2Icon, RotateCwIcon } from \"lucide-react\";\n\nimport type { UseTurnQueueResult } from \"../hooks/use-turn-queue\";\n\ntype QueueStateProps = {\n queue: UseTurnQueueResult;\n};\n\nexport function EmptyQueueStateSurface({ queue }: QueueStateProps) {\n const hasError = Boolean(queue.error || queue.mutationError);\n return (\n <div\n className=\"og-root mx-auto mb-2 w-full max-w-3xl shrink-0 px-4 sm:px-6\"\n data-testid=\"queue-surface\"\n >\n <div className=\"overflow-hidden rounded-lg border border-border bg-surface/80 shadow-sm\">\n {queue.stoppingPreviousAttempt ? (\n <QueueStoppingStatus queue={queue} dividerAfter={hasError} />\n ) : null}\n {hasError ? <QueueErrorAlert queue={queue} /> : null}\n </div>\n </div>\n );\n}\n\nexport function QueueStoppingStatus({\n queue,\n dividerAfter = false,\n}: QueueStateProps & { dividerAfter?: boolean }) {\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className={`flex min-h-11 items-center gap-2.5 bg-status-waiting/[0.07] px-3 py-2 text-og-control text-fg ${\n dividerAfter ? \"border-b border-status-waiting/20\" : \"\"\n }`}\n data-testid=\"stopping-previous-attempt\"\n >\n <Loader2Icon\n aria-hidden=\"true\"\n className=\"size-3.5 shrink-0 animate-spin text-status-waiting motion-reduce:animate-none\"\n />\n <span className=\"min-w-0\">\n <span className=\"font-medium\">\n {queue.effectiveControl?.state === \"paused\"\n ? \"Stopping current attempt…\"\n : \"Stopping previous attempt…\"}\n </span>{\" \"}\n <span className=\"text-fg-muted\">\n {queue.effectiveControl?.state === \"paused\"\n ? \"Queued work stays saved until you resume.\"\n : \"Queued work is saved and starts automatically.\"}\n </span>\n </span>\n </div>\n );\n}\n\nexport function QueueErrorAlert({\n queue,\n dividerBefore = false,\n}: QueueStateProps & { dividerBefore?: boolean }) {\n return (\n <div className={`${dividerBefore ? \"border-t border-border\" : \"\"} p-2`}>\n <div\n role=\"alert\"\n className=\"flex min-w-0 max-w-full flex-wrap items-start gap-2 rounded-md bg-status-failed/10 px-2 py-1.5 text-og-control text-status-failed\"\n >\n <span\n role=\"region\"\n aria-label=\"Queue error details\"\n tabIndex={0}\n className=\"max-h-[min(5rem,20dvh)] min-w-0 max-w-full flex-[1_1_5rem] overflow-auto overscroll-contain whitespace-pre-wrap rounded-sm outline-hidden [overflow-wrap:anywhere] [unicode-bidi:plaintext] focus-visible:ring-2 focus-visible:ring-ring/40\"\n data-testid=\"queue-error-message\"\n dir=\"auto\"\n >\n {(queue.mutationError ?? queue.error)?.message}\n </span>\n <button\n type=\"button\"\n onClick={() => {\n queue.clearMutationError();\n void queue.refresh();\n }}\n aria-label=\"Dismiss queue error and retry\"\n title=\"Retry loading the queue\"\n className=\"ms-auto inline-flex size-7 shrink-0 items-center justify-center self-start rounded-md outline-hidden transition-colors hover:bg-surface-3 focus-visible:ring-2 focus-visible:ring-ring/40 motion-reduce:transition-none pointer-coarse:size-[44px]\"\n >\n <RotateCwIcon className=\"size-3.5\" />\n </button>\n </div>\n </div>\n );\n}\n"],"mappings":";AAOO,SAAS,sBACd,UACA,oBACA,iBACM;AACN,MAAI,SAAS,gBAAgB,GAAG;AAC9B,uBAAmB;AAAA,EACrB,OAAO;AACL,oBAAgB;AAAA,EAClB;AACF;;;ACjBA,SAAS,aAAa,oBAAoB;AAepC,SAEI,KAFJ;AAPC,SAAS,uBAAuB,EAAE,MAAM,GAAoB;AACjE,QAAM,WAAW,QAAQ,MAAM,SAAS,MAAM,aAAa;AAC3D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,eAAY;AAAA,MAEZ,+BAAC,SAAI,WAAU,2EACZ;AAAA,cAAM,0BACL,oBAAC,uBAAoB,OAAc,cAAc,UAAU,IACzD;AAAA,QACH,WAAW,oBAAC,mBAAgB,OAAc,IAAK;AAAA,SAClD;AAAA;AAAA,EACF;AAEJ;AAEO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA,eAAe;AACjB,GAAiD;AAC/C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,aAAU;AAAA,MACV,WAAW,iGACT,eAAe,sCAAsC,EACvD;AAAA,MACA,eAAY;AAAA,MAEZ;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,eAAY;AAAA,YACZ,WAAU;AAAA;AAAA,QACZ;AAAA,QACA,qBAAC,UAAK,WAAU,WACd;AAAA,8BAAC,UAAK,WAAU,eACb,gBAAM,kBAAkB,UAAU,WAC/B,mCACA,mCACN;AAAA,UAAQ;AAAA,UACR,oBAAC,UAAK,WAAU,iBACb,gBAAM,kBAAkB,UAAU,WAC/B,8CACA,kDACN;AAAA,WACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAEO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA,gBAAgB;AAClB,GAAkD;AAChD,SACE,oBAAC,SAAI,WAAW,GAAG,gBAAgB,2BAA2B,EAAE,QAC9D;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,WAAU;AAAA,MAEV;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,cAAW;AAAA,YACX,UAAU;AAAA,YACV,WAAU;AAAA,YACV,eAAY;AAAA,YACZ,KAAI;AAAA,YAEF,iBAAM,iBAAiB,MAAM,QAAQ;AAAA;AAAA,QACzC;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS,MAAM;AACb,oBAAM,mBAAmB;AACzB,mBAAK,MAAM,QAAQ;AAAA,YACrB;AAAA,YACA,cAAW;AAAA,YACX,OAAM;AAAA,YACN,WAAU;AAAA,YAEV,8BAAC,gBAAa,WAAU,YAAW;AAAA;AAAA,QACrC;AAAA;AAAA;AAAA,EACF,GACF;AAEJ;","names":[]}
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  useMutationRunner,
3
+ usePageLiveActivity,
3
4
  usePolledValue
4
- } from "./chunk-EB67J347.js";
5
+ } from "./chunk-KZ73RL76.js";
5
6
  import {
6
7
  OpenGeniContext,
7
8
  useOpenGeni
@@ -533,7 +534,7 @@ function MachineCard({
533
534
  className: cn(
534
535
  "og-root group relative flex flex-col gap-3 overflow-hidden rounded-og-lg border border-og-border",
535
536
  "bg-og-surface-1 p-4 shadow-og-sm transition-colors",
536
- openable && "cursor-pointer hover:border-og-border-strong focus-visible:border-og-accent/60 focus-visible:outline-none",
537
+ openable && "cursor-pointer hover:border-og-border-strong focus-visible:border-og-accent/60 focus-visible:outline-hidden",
537
538
  machine.active && "border-og-accent/40",
538
539
  className
539
540
  ),
@@ -886,7 +887,14 @@ function MetricHistoryChart({
886
887
  }
887
888
 
888
889
  // src/components/machines/machine-detail.tsx
889
- import { ArrowLeftIcon, CpuIcon as CpuIcon2, LaptopIcon as LaptopIcon2, RadioIcon, ServerIcon as ServerIcon2 } from "lucide-react";
890
+ import {
891
+ ArrowLeftIcon,
892
+ CpuIcon as CpuIcon2,
893
+ LaptopIcon as LaptopIcon2,
894
+ RadioIcon,
895
+ ServerIcon as ServerIcon2,
896
+ Trash2Icon
897
+ } from "lucide-react";
890
898
 
891
899
  // src/components/machines/series.ts
892
900
  var METRIC_WINDOWS = ["15m", "1h", "6h", "24h"];
@@ -985,6 +993,7 @@ function MachineDetail({
985
993
  onWindowChange,
986
994
  loadingSeries,
987
995
  onBack,
996
+ onRemove,
988
997
  now = Date.now(),
989
998
  className
990
999
  }) {
@@ -1015,20 +1024,36 @@ function MachineDetail({
1015
1024
  machine.arch
1016
1025
  ] })
1017
1026
  ] }),
1018
- /* @__PURE__ */ jsx7("div", { className: "flex shrink-0 items-center gap-0.5 rounded-og-md border border-og-border bg-og-surface-1 p-0.5", children: METRIC_WINDOWS.map((w) => /* @__PURE__ */ jsx7(
1019
- "button",
1020
- {
1021
- type: "button",
1022
- onClick: () => onWindowChange(w),
1023
- "data-active": w === window2,
1024
- className: cn(
1025
- "rounded-og-sm px-2 py-1 font-og-mono text-og-xs transition-colors",
1026
- w === window2 ? "bg-og-surface-3 text-og-fg shadow-og-sm" : "text-og-fg-subtle hover:text-og-fg-muted"
1027
- ),
1028
- children: w
1029
- },
1030
- w
1031
- )) })
1027
+ /* @__PURE__ */ jsxs7("div", { className: "flex shrink-0 items-center gap-2", children: [
1028
+ onRemove && machine.enrollmentId && !machine.isSessionGroup ? /* @__PURE__ */ jsxs7(
1029
+ "button",
1030
+ {
1031
+ type: "button",
1032
+ "data-remove-machine": true,
1033
+ "aria-label": `Remove machine ${machine.name}`,
1034
+ onClick: () => onRemove(machine),
1035
+ className: "inline-flex min-h-9 items-center gap-1.5 rounded-og-sm border border-og-status-failed/40 px-2.5 py-1 font-medium text-og-xs text-og-status-failed transition-colors hover:bg-og-status-failed/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-og-status-failed/50 pointer-coarse:min-h-11",
1036
+ children: [
1037
+ /* @__PURE__ */ jsx7(Trash2Icon, { className: "size-3.5", "aria-hidden": true }),
1038
+ /* @__PURE__ */ jsx7("span", { className: "hidden sm:inline", children: "Remove machine" })
1039
+ ]
1040
+ }
1041
+ ) : null,
1042
+ /* @__PURE__ */ jsx7("div", { className: "flex items-center gap-0.5 rounded-og-md border border-og-border bg-og-surface-1 p-0.5", children: METRIC_WINDOWS.map((w) => /* @__PURE__ */ jsx7(
1043
+ "button",
1044
+ {
1045
+ type: "button",
1046
+ onClick: () => onWindowChange(w),
1047
+ "data-active": w === window2,
1048
+ className: cn(
1049
+ "rounded-og-sm px-2 py-1 font-og-mono text-og-xs transition-colors",
1050
+ w === window2 ? "bg-og-surface-3 text-og-fg shadow-og-sm" : "text-og-fg-subtle hover:text-og-fg-muted"
1051
+ ),
1052
+ children: w
1053
+ },
1054
+ w
1055
+ )) })
1056
+ ] })
1032
1057
  ] }),
1033
1058
  /* @__PURE__ */ jsxs7(
1034
1059
  "div",
@@ -1144,7 +1169,7 @@ function EmptyState({ onEnroll }) {
1144
1169
  /* @__PURE__ */ jsx8("span", { className: "flex size-10 items-center justify-center rounded-full bg-og-surface-2 text-og-fg-subtle", children: /* @__PURE__ */ jsx8(LaptopIcon3, { className: "size-5", "aria-hidden": true }) }),
1145
1170
  /* @__PURE__ */ jsxs8("div", { className: "space-y-1", children: [
1146
1171
  /* @__PURE__ */ jsx8("p", { className: "text-og-base font-medium text-og-fg", children: "No machines yet" }),
1147
- /* @__PURE__ */ jsx8("p", { className: "max-w-xs text-og-sm text-og-fg-muted", children: "Enroll your own computer to run the agent on it \u2014 your files, your terminal, your desktop." })
1172
+ /* @__PURE__ */ jsx8("p", { className: "max-w-xs text-og-sm text-og-fg-muted", children: "Connect your own computer to run the agent on it \u2014 your files, your terminal, your desktop." })
1148
1173
  ] }),
1149
1174
  onEnroll ? /* @__PURE__ */ jsxs8(
1150
1175
  "button",
@@ -1155,7 +1180,7 @@ function EmptyState({ onEnroll }) {
1155
1180
  className: "inline-flex items-center gap-1.5 rounded-og-sm bg-og-accent px-3 py-1.5 text-og-sm font-medium text-og-accent-fg transition-colors hover:bg-og-accent-strong pointer-coarse:min-h-11",
1156
1181
  children: [
1157
1182
  /* @__PURE__ */ jsx8(PlusIcon, { className: "size-3.5", "aria-hidden": true }),
1158
- "Enroll a machine"
1183
+ "Connect a machine"
1159
1184
  ]
1160
1185
  }
1161
1186
  ) : null
@@ -1195,7 +1220,7 @@ function Header({
1195
1220
  className: "inline-flex items-center gap-1.5 rounded-og-sm border border-og-border px-2.5 py-1 text-og-sm font-medium text-og-fg-muted transition-colors hover:border-og-border-strong hover:text-og-fg pointer-coarse:min-h-11",
1196
1221
  children: [
1197
1222
  /* @__PURE__ */ jsx8(PlusIcon, { className: "size-3.5", "aria-hidden": true }),
1198
- "Enroll machine"
1223
+ "Connect a machine"
1199
1224
  ]
1200
1225
  }
1201
1226
  ) : null
@@ -1724,6 +1749,9 @@ function OpenGeniProvider({
1724
1749
  );
1725
1750
  const callbackRef = useRef2(onWorkspaceControlEvent);
1726
1751
  const reconcilersRef = useRef2(/* @__PURE__ */ new Map());
1752
+ const reconcileInFlightRef = useRef2(/* @__PURE__ */ new Map());
1753
+ const workspaceControlSequencesRef = useRef2(/* @__PURE__ */ new Map());
1754
+ const pageLive = usePageLiveActivity();
1727
1755
  callbackRef.current = onWorkspaceControlEvent;
1728
1756
  const verifyApiContract = useCallback(async () => {
1729
1757
  try {
@@ -1756,28 +1784,54 @@ function OpenGeniProvider({
1756
1784
  []
1757
1785
  );
1758
1786
  const reconcileSession = useMemo(
1759
- () => async (sessionId) => {
1760
- await verifyApiContract();
1761
- const callbacks = [...reconcilersRef.current.get(sessionId)?.values() ?? []];
1762
- await Promise.all(callbacks.map((reconcile) => reconcile()));
1787
+ () => (sessionId) => {
1788
+ const existing = reconcileInFlightRef.current.get(sessionId);
1789
+ if (existing) return existing;
1790
+ const promise = (async () => {
1791
+ await withTimeout(verifyApiContract(), 1e4, "API contract reconciliation");
1792
+ const callbacks = [...reconcilersRef.current.get(sessionId)?.values() ?? []];
1793
+ await withTimeout(
1794
+ Promise.all(callbacks.map((reconcile) => reconcile())).then(() => void 0),
1795
+ 15e3,
1796
+ "session reconciliation"
1797
+ );
1798
+ })().finally(() => {
1799
+ if (reconcileInFlightRef.current.get(sessionId) === promise) {
1800
+ reconcileInFlightRef.current.delete(sessionId);
1801
+ }
1802
+ });
1803
+ reconcileInFlightRef.current.set(sessionId, promise);
1804
+ return promise;
1763
1805
  },
1764
1806
  [verifyApiContract]
1765
1807
  );
1766
1808
  useEffect(() => {
1809
+ if (!pageLive) {
1810
+ setWorkspaceControlConnectionState("idle");
1811
+ return;
1812
+ }
1767
1813
  const controller = new AbortController();
1768
- setWorkspaceControlEvent(null);
1769
1814
  setWorkspaceControlConnectionState("connecting");
1770
1815
  void (async () => {
1771
1816
  try {
1772
1817
  await verifyApiContract();
1773
1818
  const workspace = await client.getWorkspace(workspaceId);
1819
+ const resumeAfter = Math.max(
1820
+ workspaceControlSequencesRef.current.get(workspaceId) ?? 0,
1821
+ workspace.inferenceControl.revision
1822
+ );
1823
+ workspaceControlSequencesRef.current.set(workspaceId, resumeAfter);
1774
1824
  const stream = client.streamWorkspaceControlEvents(workspaceId, {
1775
- after: workspace.inferenceControl.revision,
1825
+ after: resumeAfter,
1776
1826
  signal: controller.signal,
1777
1827
  onStateChange: setWorkspaceControlConnectionState
1778
1828
  });
1779
1829
  for await (const event of stream) {
1780
1830
  if (controller.signal.aborted) return;
1831
+ workspaceControlSequencesRef.current.set(
1832
+ workspaceId,
1833
+ Math.max(workspaceControlSequencesRef.current.get(workspaceId) ?? 0, event.sequence)
1834
+ );
1781
1835
  setWorkspaceControlEvent(
1782
1836
  (current) => !current || event.sequence > current.sequence ? event : current
1783
1837
  );
@@ -1792,7 +1846,7 @@ function OpenGeniProvider({
1792
1846
  }
1793
1847
  })();
1794
1848
  return () => controller.abort();
1795
- }, [client, verifyApiContract, workspaceId]);
1849
+ }, [client, pageLive, verifyApiContract, workspaceId]);
1796
1850
  const value = useMemo(
1797
1851
  () => ({
1798
1852
  client,
@@ -1816,6 +1870,20 @@ function OpenGeniProvider({
1816
1870
  contractMismatch ? /* @__PURE__ */ jsx12(ApiContractMismatchScreen, { mismatch: contractMismatch }) : null
1817
1871
  ] });
1818
1872
  }
1873
+ function withTimeout(promise, timeoutMs, label) {
1874
+ let timer;
1875
+ return Promise.race([
1876
+ promise,
1877
+ new Promise((_resolve, reject) => {
1878
+ timer = setTimeout(
1879
+ () => reject(new Error(`${label} timed out after ${timeoutMs}ms`)),
1880
+ timeoutMs
1881
+ );
1882
+ })
1883
+ ]).finally(() => {
1884
+ if (timer !== void 0) clearTimeout(timer);
1885
+ });
1886
+ }
1819
1887
  function ApiContractMismatchScreen({ mismatch }) {
1820
1888
  return /* @__PURE__ */ jsx12(
1821
1889
  "div",
@@ -1884,8 +1952,11 @@ function useMachines(options = {}) {
1884
1952
  const { run, mutating, mutationError, clearMutationError } = useMutationRunner(identityKey);
1885
1953
  const [attachState, setAttachState] = useState4(() => ({ identity: identityKey, sandboxId: null }));
1886
1954
  const attachingSandboxId = attachState.identity === identityKey ? attachState.sandboxId : null;
1955
+ const [removeState, setRemoveState] = useState4(() => ({ identity: identityKey, enrollmentId: null }));
1956
+ const removingEnrollmentId = removeState.identity === identityKey ? removeState.enrollmentId : null;
1887
1957
  const data = loadedData ?? EMPTY;
1888
1958
  const canAttach = sessionId !== void 0 && (typeof machinesClient.attachMachine === "function" || typeof machinesClient.swapActiveSandbox === "function");
1959
+ const canRemove = typeof machinesClient.removeEnrollment === "function";
1889
1960
  const attach = useCallback2(
1890
1961
  async (sandboxId) => {
1891
1962
  if (sessionId === void 0) return false;
@@ -1912,6 +1983,24 @@ function useMachines(options = {}) {
1912
1983
  },
1913
1984
  [machinesClient, workspaceId]
1914
1985
  );
1986
+ const remove = useCallback2(
1987
+ async (enrollmentId, request = {}) => {
1988
+ if (!machinesClient.removeEnrollment) return null;
1989
+ const ownedIdentity = identityKey;
1990
+ setRemoveState({ identity: ownedIdentity, enrollmentId });
1991
+ const result = await run(
1992
+ () => machinesClient.removeEnrollment(workspaceId, enrollmentId, request)
1993
+ );
1994
+ if (identityRef.current === ownedIdentity) {
1995
+ setRemoveState({ identity: ownedIdentity, enrollmentId: null });
1996
+ if (result?.outcome === "removed" || result?.outcome === "already_removed") {
1997
+ await refresh();
1998
+ }
1999
+ }
2000
+ return result;
2001
+ },
2002
+ [machinesClient, workspaceId, identityKey, run, refresh]
2003
+ );
1915
2004
  return {
1916
2005
  machines: data.machines,
1917
2006
  activeSandboxId: data.activeSandboxId,
@@ -1922,8 +2011,11 @@ function useMachines(options = {}) {
1922
2011
  attach,
1923
2012
  canAttach,
1924
2013
  fetchSeries,
1925
- attaching: mutating,
2014
+ attaching: mutating && attachingSandboxId !== null,
1926
2015
  attachingSandboxId,
2016
+ remove,
2017
+ canRemove,
2018
+ removingEnrollmentId,
1927
2019
  mutationError,
1928
2020
  clearMutationError
1929
2021
  };
@@ -1957,4 +2049,4 @@ export {
1957
2049
  OpenGeniProvider,
1958
2050
  useMachines
1959
2051
  };
1960
- //# sourceMappingURL=chunk-6EDV6YFE.js.map
2052
+ //# sourceMappingURL=chunk-OL6QVXGF.js.map