@opengeni/react 0.13.0 → 0.20.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 (113) hide show
  1. package/README.md +129 -23
  2. package/dist/chunk-6BXBGJ3B.js +1956 -0
  3. package/dist/chunk-6BXBGJ3B.js.map +1 -0
  4. package/dist/chunk-6UT5OC3P.js +2133 -0
  5. package/dist/chunk-6UT5OC3P.js.map +1 -0
  6. package/dist/chunk-EBTT3MYN.js +92 -0
  7. package/dist/chunk-EBTT3MYN.js.map +1 -0
  8. package/dist/chunk-HHFA4AFX.js +425 -0
  9. package/dist/chunk-HHFA4AFX.js.map +1 -0
  10. package/dist/chunk-LAZ2A743.js +2393 -0
  11. package/dist/chunk-LAZ2A743.js.map +1 -0
  12. package/dist/chunk-MRSECXRP.js +563 -0
  13. package/dist/chunk-MRSECXRP.js.map +1 -0
  14. package/dist/chunk-TK7G6XLT.js +18 -0
  15. package/dist/chunk-TK7G6XLT.js.map +1 -0
  16. package/dist/composer-DvUaa5ki.d.ts +585 -0
  17. package/dist/composer.d.ts +6 -0
  18. package/dist/composer.js +56 -0
  19. package/dist/composer.js.map +1 -0
  20. package/dist/index.d.ts +642 -1080
  21. package/dist/index.js +7672 -8005
  22. package/dist/index.js.map +1 -1
  23. package/dist/machines.d.ts +412 -3
  24. package/dist/machines.js +25 -1
  25. package/dist/noto-sans-arabic-loader-IA2T4X2A.js +21 -0
  26. package/dist/noto-sans-arabic-loader-IA2T4X2A.js.map +1 -0
  27. package/dist/noto-sans-jp-loader.generated-HFGLYBR3.js +292 -0
  28. package/dist/noto-sans-jp-loader.generated-HFGLYBR3.js.map +1 -0
  29. package/dist/queue-surface-implementation-NQMV2ML3.js +890 -0
  30. package/dist/queue-surface-implementation-NQMV2ML3.js.map +1 -0
  31. package/dist/session-Gd4iVPYw.d.ts +425 -0
  32. package/dist/session-context-DIFFlXKc.d.ts +52 -0
  33. package/dist/session.d.ts +4 -0
  34. package/dist/session.js +50 -0
  35. package/dist/session.js.map +1 -0
  36. package/dist/use-composer-BCfm4mzX.d.ts +112 -0
  37. package/package.json +23 -4
  38. package/src/approvals.ts +5 -3
  39. package/src/client.ts +50 -1
  40. package/src/components/approval-surface.tsx +198 -0
  41. package/src/components/chat-composer.tsx +104 -751
  42. package/src/components/code-editor.tsx +104 -26
  43. package/src/components/command-palette.tsx +8 -2
  44. package/src/components/composer-transcription-control.tsx +211 -0
  45. package/src/components/composer.tsx +1536 -0
  46. package/src/components/desktop-viewer.tsx +3 -3
  47. package/src/components/enrollment-consent.tsx +2 -2
  48. package/src/components/file-browser.tsx +367 -29
  49. package/src/components/human-input-form.tsx +417 -0
  50. package/src/components/machine-card.tsx +82 -16
  51. package/src/components/machine-health-pill.tsx +68 -0
  52. package/src/components/machine-metrics.tsx +10 -24
  53. package/src/components/machines/health.ts +146 -0
  54. package/src/components/machines/machine-detail.tsx +220 -0
  55. package/src/components/machines/metric-history-chart.tsx +298 -0
  56. package/src/components/machines/metric-sparkline.tsx +76 -0
  57. package/src/components/machines/series.ts +113 -0
  58. package/src/components/machines-dashboard.tsx +16 -4
  59. package/src/components/message-timeline.tsx +15 -7
  60. package/src/components/model-picker.tsx +12 -3
  61. package/src/components/pierre-diff.tsx +32 -6
  62. package/src/components/queue-surface-implementation.tsx +1041 -0
  63. package/src/components/queue-surface-state.tsx +94 -0
  64. package/src/components/queue-surface.tsx +60 -0
  65. package/src/components/sandbox-files.tsx +230 -21
  66. package/src/components/sandbox-terminal.tsx +8 -2
  67. package/src/components/sandbox-workspace.tsx +489 -135
  68. package/src/components/session-status.tsx +0 -6
  69. package/src/components/workbench-changes.tsx +145 -50
  70. package/src/components/workspace-dock.tsx +329 -68
  71. package/src/composer.ts +60 -0
  72. package/src/hooks/internal.ts +115 -34
  73. package/src/hooks/use-composer.ts +635 -74
  74. package/src/hooks/use-human-input.ts +131 -0
  75. package/src/hooks/use-machine-chip.ts +2 -2
  76. package/src/hooks/use-machines.ts +27 -11
  77. package/src/hooks/use-sandbox-files.ts +310 -62
  78. package/src/hooks/use-sandbox-git.ts +154 -40
  79. package/src/hooks/use-sandbox-terminal.ts +28 -6
  80. package/src/hooks/use-session-capabilities.ts +38 -9
  81. package/src/hooks/use-session-control.ts +43 -15
  82. package/src/hooks/use-session-events.ts +523 -48
  83. package/src/hooks/use-session-lineage.ts +15 -6
  84. package/src/hooks/use-session.ts +10 -2
  85. package/src/hooks/use-slash-commands.ts +38 -38
  86. package/src/hooks/use-transcription.ts +757 -0
  87. package/src/hooks/use-turn-queue.ts +273 -77
  88. package/src/hooks/use-windowed-sections.ts +2 -2
  89. package/src/hooks/use-workspace-capture.ts +146 -40
  90. package/src/hooks/use-workspace-edit.ts +50 -14
  91. package/src/hooks/use-workspace-sessions.ts +3 -0
  92. package/src/human-input.ts +72 -0
  93. package/src/index.ts +88 -12
  94. package/src/lib/noto-sans-arabic-loader.ts +21 -0
  95. package/src/lib/noto-sans-jp-loader.generated.ts +295 -0
  96. package/src/lib/use-portal-token-style.ts +51 -0
  97. package/src/lib/use-unicode-fonts.ts +57 -0
  98. package/src/machines.ts +16 -0
  99. package/src/provider.tsx +163 -41
  100. package/src/session-context.ts +135 -0
  101. package/src/session.ts +79 -0
  102. package/src/timeline/parsers.ts +78 -6
  103. package/src/timeline/projection.ts +36 -6
  104. package/src/timeline/tool-renderers.tsx +41 -0
  105. package/src/timeline/turn-summary.tsx +2 -2
  106. package/src/timeline/types.ts +16 -8
  107. package/styles/index.css +78 -0
  108. package/styles/index.d.ts +2 -0
  109. package/styles/tokens.css +11 -6
  110. package/styles/tokens.d.ts +2 -0
  111. package/dist/chunk-NFYVQWIB.js +0 -1377
  112. package/dist/chunk-NFYVQWIB.js.map +0 -1
  113. package/dist/machines-CnlMb7E-.d.ts +0 -329
@@ -0,0 +1,295 @@
1
+ /* This file is generated by scripts/generate-noto-jp-loader.ts. */
2
+ import unicodeRanges from "@fontsource-variable/noto-sans-jp/unicode.json";
3
+ import font0 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-0-wght-normal.woff2";
4
+ import font1 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-1-wght-normal.woff2";
5
+ import font2 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-2-wght-normal.woff2";
6
+ import font3 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-3-wght-normal.woff2";
7
+ import font4 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-4-wght-normal.woff2";
8
+ import font5 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-5-wght-normal.woff2";
9
+ import font6 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-6-wght-normal.woff2";
10
+ import font7 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-7-wght-normal.woff2";
11
+ import font8 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-8-wght-normal.woff2";
12
+ import font9 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-9-wght-normal.woff2";
13
+ import font10 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-10-wght-normal.woff2";
14
+ import font11 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-11-wght-normal.woff2";
15
+ import font12 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-12-wght-normal.woff2";
16
+ import font13 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-13-wght-normal.woff2";
17
+ import font14 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-14-wght-normal.woff2";
18
+ import font15 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-15-wght-normal.woff2";
19
+ import font16 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-16-wght-normal.woff2";
20
+ import font17 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-17-wght-normal.woff2";
21
+ import font18 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-18-wght-normal.woff2";
22
+ import font19 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-19-wght-normal.woff2";
23
+ import font20 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-20-wght-normal.woff2";
24
+ import font21 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-21-wght-normal.woff2";
25
+ import font22 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-22-wght-normal.woff2";
26
+ import font23 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-23-wght-normal.woff2";
27
+ import font24 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-24-wght-normal.woff2";
28
+ import font25 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-25-wght-normal.woff2";
29
+ import font26 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-26-wght-normal.woff2";
30
+ import font27 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-27-wght-normal.woff2";
31
+ import font28 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-28-wght-normal.woff2";
32
+ import font29 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-29-wght-normal.woff2";
33
+ import font30 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-30-wght-normal.woff2";
34
+ import font31 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-31-wght-normal.woff2";
35
+ import font32 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-32-wght-normal.woff2";
36
+ import font33 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-33-wght-normal.woff2";
37
+ import font34 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-34-wght-normal.woff2";
38
+ import font35 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-35-wght-normal.woff2";
39
+ import font36 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-36-wght-normal.woff2";
40
+ import font37 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-37-wght-normal.woff2";
41
+ import font38 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-38-wght-normal.woff2";
42
+ import font39 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-39-wght-normal.woff2";
43
+ import font40 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-40-wght-normal.woff2";
44
+ import font41 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-41-wght-normal.woff2";
45
+ import font42 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-42-wght-normal.woff2";
46
+ import font43 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-43-wght-normal.woff2";
47
+ import font44 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-44-wght-normal.woff2";
48
+ import font45 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-45-wght-normal.woff2";
49
+ import font46 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-46-wght-normal.woff2";
50
+ import font47 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-47-wght-normal.woff2";
51
+ import font48 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-48-wght-normal.woff2";
52
+ import font49 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-49-wght-normal.woff2";
53
+ import font50 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-50-wght-normal.woff2";
54
+ import font51 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-51-wght-normal.woff2";
55
+ import font52 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-52-wght-normal.woff2";
56
+ import font53 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-53-wght-normal.woff2";
57
+ import font54 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-54-wght-normal.woff2";
58
+ import font55 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-55-wght-normal.woff2";
59
+ import font56 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-56-wght-normal.woff2";
60
+ import font57 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-57-wght-normal.woff2";
61
+ import font58 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-58-wght-normal.woff2";
62
+ import font59 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-59-wght-normal.woff2";
63
+ import font60 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-60-wght-normal.woff2";
64
+ import font61 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-61-wght-normal.woff2";
65
+ import font62 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-62-wght-normal.woff2";
66
+ import font63 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-63-wght-normal.woff2";
67
+ import font64 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-64-wght-normal.woff2";
68
+ import font65 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-65-wght-normal.woff2";
69
+ import font66 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-66-wght-normal.woff2";
70
+ import font67 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-67-wght-normal.woff2";
71
+ import font68 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-68-wght-normal.woff2";
72
+ import font69 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-69-wght-normal.woff2";
73
+ import font70 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-70-wght-normal.woff2";
74
+ import font71 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-71-wght-normal.woff2";
75
+ import font72 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-72-wght-normal.woff2";
76
+ import font73 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-73-wght-normal.woff2";
77
+ import font74 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-74-wght-normal.woff2";
78
+ import font75 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-75-wght-normal.woff2";
79
+ import font76 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-76-wght-normal.woff2";
80
+ import font77 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-77-wght-normal.woff2";
81
+ import font78 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-78-wght-normal.woff2";
82
+ import font79 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-79-wght-normal.woff2";
83
+ import font80 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-80-wght-normal.woff2";
84
+ import font81 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-81-wght-normal.woff2";
85
+ import font82 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-82-wght-normal.woff2";
86
+ import font83 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-83-wght-normal.woff2";
87
+ import font84 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-84-wght-normal.woff2";
88
+ import font85 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-85-wght-normal.woff2";
89
+ import font86 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-86-wght-normal.woff2";
90
+ import font87 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-87-wght-normal.woff2";
91
+ import font88 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-88-wght-normal.woff2";
92
+ import font89 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-89-wght-normal.woff2";
93
+ import font90 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-90-wght-normal.woff2";
94
+ import font91 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-91-wght-normal.woff2";
95
+ import font92 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-92-wght-normal.woff2";
96
+ import font93 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-93-wght-normal.woff2";
97
+ import font94 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-94-wght-normal.woff2";
98
+ import font95 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-95-wght-normal.woff2";
99
+ import font96 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-96-wght-normal.woff2";
100
+ import font97 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-97-wght-normal.woff2";
101
+ import font98 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-98-wght-normal.woff2";
102
+ import font99 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-99-wght-normal.woff2";
103
+ import font100 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-100-wght-normal.woff2";
104
+ import font101 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-101-wght-normal.woff2";
105
+ import font102 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-102-wght-normal.woff2";
106
+ import font103 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-103-wght-normal.woff2";
107
+ import font104 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-104-wght-normal.woff2";
108
+ import font105 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-105-wght-normal.woff2";
109
+ import font106 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-106-wght-normal.woff2";
110
+ import font107 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-107-wght-normal.woff2";
111
+ import font108 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-108-wght-normal.woff2";
112
+ import font109 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-109-wght-normal.woff2";
113
+ import font110 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-110-wght-normal.woff2";
114
+ import font111 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-111-wght-normal.woff2";
115
+ import font112 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-112-wght-normal.woff2";
116
+ import font113 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-113-wght-normal.woff2";
117
+ import font114 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-114-wght-normal.woff2";
118
+ import font115 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-115-wght-normal.woff2";
119
+ import font116 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-116-wght-normal.woff2";
120
+ import font117 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-117-wght-normal.woff2";
121
+ import font118 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-118-wght-normal.woff2";
122
+ import font119 from "@fontsource-variable/noto-sans-jp/files/noto-sans-jp-119-wght-normal.woff2";
123
+
124
+ const fontUrls: Record<string, string> = {
125
+ "[0]": font0,
126
+ "[1]": font1,
127
+ "[2]": font2,
128
+ "[3]": font3,
129
+ "[4]": font4,
130
+ "[5]": font5,
131
+ "[6]": font6,
132
+ "[7]": font7,
133
+ "[8]": font8,
134
+ "[9]": font9,
135
+ "[10]": font10,
136
+ "[11]": font11,
137
+ "[12]": font12,
138
+ "[13]": font13,
139
+ "[14]": font14,
140
+ "[15]": font15,
141
+ "[16]": font16,
142
+ "[17]": font17,
143
+ "[18]": font18,
144
+ "[19]": font19,
145
+ "[20]": font20,
146
+ "[21]": font21,
147
+ "[22]": font22,
148
+ "[23]": font23,
149
+ "[24]": font24,
150
+ "[25]": font25,
151
+ "[26]": font26,
152
+ "[27]": font27,
153
+ "[28]": font28,
154
+ "[29]": font29,
155
+ "[30]": font30,
156
+ "[31]": font31,
157
+ "[32]": font32,
158
+ "[33]": font33,
159
+ "[34]": font34,
160
+ "[35]": font35,
161
+ "[36]": font36,
162
+ "[37]": font37,
163
+ "[38]": font38,
164
+ "[39]": font39,
165
+ "[40]": font40,
166
+ "[41]": font41,
167
+ "[42]": font42,
168
+ "[43]": font43,
169
+ "[44]": font44,
170
+ "[45]": font45,
171
+ "[46]": font46,
172
+ "[47]": font47,
173
+ "[48]": font48,
174
+ "[49]": font49,
175
+ "[50]": font50,
176
+ "[51]": font51,
177
+ "[52]": font52,
178
+ "[53]": font53,
179
+ "[54]": font54,
180
+ "[55]": font55,
181
+ "[56]": font56,
182
+ "[57]": font57,
183
+ "[58]": font58,
184
+ "[59]": font59,
185
+ "[60]": font60,
186
+ "[61]": font61,
187
+ "[62]": font62,
188
+ "[63]": font63,
189
+ "[64]": font64,
190
+ "[65]": font65,
191
+ "[66]": font66,
192
+ "[67]": font67,
193
+ "[68]": font68,
194
+ "[69]": font69,
195
+ "[70]": font70,
196
+ "[71]": font71,
197
+ "[72]": font72,
198
+ "[73]": font73,
199
+ "[74]": font74,
200
+ "[75]": font75,
201
+ "[76]": font76,
202
+ "[77]": font77,
203
+ "[78]": font78,
204
+ "[79]": font79,
205
+ "[80]": font80,
206
+ "[81]": font81,
207
+ "[82]": font82,
208
+ "[83]": font83,
209
+ "[84]": font84,
210
+ "[85]": font85,
211
+ "[86]": font86,
212
+ "[87]": font87,
213
+ "[88]": font88,
214
+ "[89]": font89,
215
+ "[90]": font90,
216
+ "[91]": font91,
217
+ "[92]": font92,
218
+ "[93]": font93,
219
+ "[94]": font94,
220
+ "[95]": font95,
221
+ "[96]": font96,
222
+ "[97]": font97,
223
+ "[98]": font98,
224
+ "[99]": font99,
225
+ "[100]": font100,
226
+ "[101]": font101,
227
+ "[102]": font102,
228
+ "[103]": font103,
229
+ "[104]": font104,
230
+ "[105]": font105,
231
+ "[106]": font106,
232
+ "[107]": font107,
233
+ "[108]": font108,
234
+ "[109]": font109,
235
+ "[110]": font110,
236
+ "[111]": font111,
237
+ "[112]": font112,
238
+ "[113]": font113,
239
+ "[114]": font114,
240
+ "[115]": font115,
241
+ "[116]": font116,
242
+ "[117]": font117,
243
+ "[118]": font118,
244
+ "[119]": font119,
245
+ };
246
+ const loads = new Map<string, Promise<void>>();
247
+
248
+ export async function loadNotoSansJp(text: string): Promise<void> {
249
+ const required = new Set<string>();
250
+ for (const character of text) {
251
+ const codePoint = character.codePointAt(0);
252
+ if (codePoint === undefined) continue;
253
+ for (const [key, range] of Object.entries(unicodeRanges)) {
254
+ if (!fontUrls[key]) continue;
255
+ if (rangeContains(range, codePoint)) {
256
+ required.add(key);
257
+ break;
258
+ }
259
+ }
260
+ }
261
+ await Promise.all([...required].map(loadShard));
262
+ }
263
+
264
+ function loadShard(key: string): Promise<void> {
265
+ const existing = loads.get(key);
266
+ if (existing) return existing;
267
+ const url = fontUrls[key];
268
+ const unicodeRange = (unicodeRanges as Record<string, string>)[key];
269
+ if (!url || !unicodeRange) throw new Error(`Missing Noto Sans JP shard ${key}`);
270
+ const loading = new FontFace(
271
+ "Noto Sans JP Variable",
272
+ `url("${url}") format("woff2-variations")`,
273
+ { style: "normal", weight: "100 900", unicodeRange },
274
+ )
275
+ .load()
276
+ .then((font) => {
277
+ document.fonts.add(font);
278
+ })
279
+ .catch((error: unknown) => {
280
+ loads.delete(key);
281
+ throw error;
282
+ });
283
+ loads.set(key, loading);
284
+ return loading;
285
+ }
286
+
287
+ function rangeContains(range: string, codePoint: number): boolean {
288
+ for (const token of range.split(",")) {
289
+ const [startText, endText = startText] = token.trim().slice(2).split("-");
290
+ const start = Number.parseInt(startText ?? "", 16);
291
+ const end = Number.parseInt(endText ?? "", 16);
292
+ if (Number.isFinite(start) && codePoint >= start && codePoint <= end) return true;
293
+ }
294
+ return false;
295
+ }
@@ -0,0 +1,51 @@
1
+ import { type CSSProperties, type RefObject, useEffect, useState } from "react";
2
+
3
+ export type PortalTokenStyle = CSSProperties & Record<`--${string}`, string>;
4
+
5
+ /**
6
+ * Copy the effective SDK tokens across a portal boundary. A locally themed or
7
+ * rebranded embed cannot rely on CSS inheritance once a portal mounts under
8
+ * `<body>`. Ancestor theme/class/style mutations and OS color-scheme changes
9
+ * keep the copied values live.
10
+ */
11
+ export function usePortalTokenStyle(sourceRef: RefObject<HTMLElement | null>): PortalTokenStyle {
12
+ const [style, setStyle] = useState<PortalTokenStyle>({});
13
+ useEffect(() => {
14
+ const source = sourceRef.current;
15
+ if (!source || typeof MutationObserver === "undefined") return;
16
+ let signature = "";
17
+ const sync = () => {
18
+ const computed = getComputedStyle(source);
19
+ const next: PortalTokenStyle = { colorScheme: computed.colorScheme };
20
+ for (let index = 0; index < computed.length; index += 1) {
21
+ const property = computed.item(index);
22
+ if (!property.startsWith("--og-")) continue;
23
+ next[property as `--${string}`] = computed.getPropertyValue(property);
24
+ }
25
+ const nextSignature = JSON.stringify(next);
26
+ if (nextSignature !== signature) {
27
+ signature = nextSignature;
28
+ setStyle(next);
29
+ }
30
+ };
31
+ const observers: MutationObserver[] = [];
32
+ let ancestor: HTMLElement | null = source;
33
+ while (ancestor) {
34
+ const observer = new MutationObserver(sync);
35
+ observer.observe(ancestor, {
36
+ attributes: true,
37
+ attributeFilter: ["class", "data-og-theme", "style"],
38
+ });
39
+ observers.push(observer);
40
+ ancestor = ancestor.parentElement;
41
+ }
42
+ const colorScheme = window.matchMedia?.("(prefers-color-scheme: dark)");
43
+ colorScheme?.addEventListener?.("change", sync);
44
+ sync();
45
+ return () => {
46
+ for (const observer of observers) observer.disconnect();
47
+ colorScheme?.removeEventListener?.("change", sync);
48
+ };
49
+ }, [sourceRef]);
50
+ return style;
51
+ }
@@ -0,0 +1,57 @@
1
+ import { useEffect, useMemo } from "react";
2
+
3
+ export type UnicodeFontNeeds = {
4
+ japanese: boolean;
5
+ arabic: boolean;
6
+ };
7
+
8
+ const japaneseScript = /[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff]/u;
9
+ const arabicScript = /[\u0600-\u06ff\u0750-\u077f\u0870-\u08ff\ufb50-\ufdff\ufe70-\ufefc]/u;
10
+
11
+ export function detectUnicodeFontNeeds(values: Iterable<string>): UnicodeFontNeeds {
12
+ let japanese = false;
13
+ let arabic = false;
14
+ for (const value of values) {
15
+ japanese ||= japaneseScript.test(value);
16
+ arabic ||= arabicScript.test(value);
17
+ if (japanese && arabic) break;
18
+ }
19
+ return { japanese, arabic };
20
+ }
21
+
22
+ /**
23
+ * Load large script-specific font manifests only when visible workspace content
24
+ * needs them. Fontsource splits the actual glyphs by unicode-range, so Chromium
25
+ * then fetches only the small shards used by the path instead of charging every
26
+ * Latin-only session for the complete font.
27
+ */
28
+ export function useUnicodeFallbackFonts(values: readonly string[]): void {
29
+ const content = useMemo(() => collectUnicodeContent(values), [values]);
30
+ useEffect(() => {
31
+ if (content.japanese) {
32
+ void import("./noto-sans-jp-loader.generated")
33
+ .then(({ loadNotoSansJp }) => loadNotoSansJp(content.japanese))
34
+ .catch(() => undefined);
35
+ }
36
+ if (content.arabic) {
37
+ void import("./noto-sans-arabic-loader")
38
+ .then(({ loadNotoSansArabic }) => loadNotoSansArabic())
39
+ .catch(() => undefined);
40
+ }
41
+ }, [content.arabic, content.japanese]);
42
+ }
43
+
44
+ function collectUnicodeContent(values: Iterable<string>): {
45
+ japanese: string;
46
+ arabic: string;
47
+ } {
48
+ const japanese = new Set<string>();
49
+ const arabic = new Set<string>();
50
+ for (const value of values) {
51
+ for (const character of value) {
52
+ if (japaneseScript.test(character)) japanese.add(character);
53
+ if (arabicScript.test(character)) arabic.add(character);
54
+ }
55
+ }
56
+ return { japanese: [...japanese].join(""), arabic: [...arabic].join("") };
57
+ }
package/src/machines.ts CHANGED
@@ -34,6 +34,22 @@ export { MachineMetrics } from "./components/machine-metrics";
34
34
  export type { MachineMetricsProps } from "./components/machine-metrics";
35
35
  export { MachineCard } from "./components/machine-card";
36
36
  export type { MachineCardProps } from "./components/machine-card";
37
+ export { MachineHealthPill } from "./components/machine-health-pill";
38
+ export type { MachineHealthPillProps } from "./components/machine-health-pill";
39
+ // Telemetry: fused health signal + history charts + the per-machine detail view.
40
+ export { deriveHealth, HEALTH_TOKEN, healthPulses } from "./components/machines/health";
41
+ export type { HealthLevel, HealthVerdict } from "./components/machines/health";
42
+ export { MetricSparkline } from "./components/machines/metric-sparkline";
43
+ export type { MetricSparklineProps } from "./components/machines/metric-sparkline";
44
+ export { MetricHistoryChart } from "./components/machines/metric-history-chart";
45
+ export type {
46
+ MetricHistoryChartProps,
47
+ SeriesPoint,
48
+ } from "./components/machines/metric-history-chart";
49
+ export { MachineDetail } from "./components/machines/machine-detail";
50
+ export type { MachineDetailProps } from "./components/machines/machine-detail";
51
+ export { METRICS, METRIC_WINDOWS, WINDOW_LABEL, pointsFor } from "./components/machines/series";
52
+ export type { MetricDef, MetricKey, MetricWindow } from "./components/machines/series";
37
53
  export { MachinesDashboard } from "./components/machines-dashboard";
38
54
  export type { MachinesDashboardProps } from "./components/machines-dashboard";
39
55
  export { MachineDockBar, SharedMachineDisclosure } from "./components/machine-dock-bar";
package/src/provider.tsx CHANGED
@@ -1,16 +1,21 @@
1
- import { createContext, useContext, useMemo, type ReactNode } from "react";
1
+ import {
2
+ OpenGeniApiContractMismatchError,
3
+ OPENGENI_API_CONTRACT_REVISION,
4
+ type StreamConnectionState,
5
+ type WorkspaceControlEvent,
6
+ } from "@opengeni/sdk";
7
+ import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
2
8
  import type { SessionClientLike } from "./client";
9
+ import { OpenGeniContext } from "./session-context";
3
10
 
4
- export type OpenGeniContextValue = {
5
- client: SessionClientLike;
6
- workspaceId: string;
7
- };
8
-
9
- const OpenGeniContext = createContext<OpenGeniContextValue | null>(null);
11
+ export { useOpenGeni, useOpenGeniClient } from "./session-context";
12
+ export type { ClientOverride, OpenGeniContextValue } from "./session-context";
13
+ const CONTRACT_RELOAD_STORAGE_PREFIX = "opengeni.reloadForApiContract:";
10
14
 
11
15
  export type OpenGeniProviderProps = {
12
16
  client: SessionClientLike;
13
17
  workspaceId: string;
18
+ onWorkspaceControlEvent?: ((event: WorkspaceControlEvent) => void) | undefined;
14
19
  children?: ReactNode;
15
20
  };
16
21
 
@@ -18,42 +23,159 @@ export type OpenGeniProviderProps = {
18
23
  * Supplies the OpenGeni client + workspace to all hooks below it. Hooks also
19
24
  * accept `{ client, workspaceId }` overrides per call for multi-workspace UIs.
20
25
  */
21
- export function OpenGeniProvider({ client, workspaceId, children }: OpenGeniProviderProps) {
22
- const value = useMemo(() => ({ client, workspaceId }), [client, workspaceId]);
23
- return <OpenGeniContext.Provider value={value}>{children}</OpenGeniContext.Provider>;
24
- }
26
+ export function OpenGeniProvider({
27
+ client,
28
+ workspaceId,
29
+ onWorkspaceControlEvent,
30
+ children,
31
+ }: OpenGeniProviderProps) {
32
+ const [workspaceControlEvent, setWorkspaceControlEvent] = useState<WorkspaceControlEvent | null>(
33
+ null,
34
+ );
35
+ const [workspaceControlConnectionState, setWorkspaceControlConnectionState] = useState<
36
+ StreamConnectionState | "idle" | "error"
37
+ >("idle");
38
+ const [contractMismatch, setContractMismatch] = useState<OpenGeniApiContractMismatchError | null>(
39
+ null,
40
+ );
41
+ const callbackRef = useRef(onWorkspaceControlEvent);
42
+ const reconcilersRef = useRef(new Map<string, Map<string, () => Promise<void>>>());
43
+ callbackRef.current = onWorkspaceControlEvent;
25
44
 
26
- export type ClientOverride = {
27
- client?: SessionClientLike | undefined;
28
- workspaceId?: string | undefined;
29
- };
45
+ const verifyApiContract = useCallback(async (): Promise<void> => {
46
+ try {
47
+ const config = await client.getClientConfig();
48
+ if (config.apiContractRevision !== OPENGENI_API_CONTRACT_REVISION) {
49
+ throw new OpenGeniApiContractMismatchError(
50
+ OPENGENI_API_CONTRACT_REVISION,
51
+ String(config.apiContractRevision || "(missing)"),
52
+ );
53
+ }
54
+ } catch (error) {
55
+ if (error instanceof OpenGeniApiContractMismatchError) {
56
+ setContractMismatch(error);
57
+ reloadForContractMismatchOnce(error);
58
+ }
59
+ throw error;
60
+ }
61
+ }, [client]);
30
62
 
31
- /** Resolve client + workspace from explicit overrides or the provider. */
32
- export function useOpenGeni(override: ClientOverride = {}): OpenGeniContextValue {
33
- const context = useContext(OpenGeniContext);
34
- const client = override.client ?? context?.client;
35
- const workspaceId = override.workspaceId ?? context?.workspaceId;
36
- if (!client || !workspaceId) {
37
- throw new Error(
38
- "@opengeni/react: no OpenGeni client/workspace available. Wrap the tree in <OpenGeniProvider> or pass { client, workspaceId } to the hook.",
39
- );
40
- }
41
- return { client, workspaceId };
63
+ const registerSessionReconciler = useMemo(
64
+ () =>
65
+ (sessionId: string, key: string, reconcile: () => Promise<void>): (() => void) => {
66
+ const sessionReconcilers = reconcilersRef.current.get(sessionId) ?? new Map();
67
+ sessionReconcilers.set(key, reconcile);
68
+ reconcilersRef.current.set(sessionId, sessionReconcilers);
69
+ return () => {
70
+ const current = reconcilersRef.current.get(sessionId);
71
+ current?.delete(key);
72
+ if (current?.size === 0) reconcilersRef.current.delete(sessionId);
73
+ };
74
+ },
75
+ [],
76
+ );
77
+ const reconcileSession = useMemo(
78
+ () =>
79
+ async (sessionId: string): Promise<void> => {
80
+ // This read also crosses the exact API-contract handshake before stale
81
+ // state can be presented as live after a deployment.
82
+ await verifyApiContract();
83
+ const callbacks = [...(reconcilersRef.current.get(sessionId)?.values() ?? [])];
84
+ await Promise.all(callbacks.map((reconcile) => reconcile()));
85
+ },
86
+ [verifyApiContract],
87
+ );
88
+
89
+ useEffect(() => {
90
+ const controller = new AbortController();
91
+ setWorkspaceControlEvent(null);
92
+ setWorkspaceControlConnectionState("connecting");
93
+ void (async () => {
94
+ try {
95
+ await verifyApiContract();
96
+ const workspace = await client.getWorkspace(workspaceId);
97
+ const stream = client.streamWorkspaceControlEvents(workspaceId, {
98
+ after: workspace.inferenceControl.revision,
99
+ signal: controller.signal,
100
+ onStateChange: setWorkspaceControlConnectionState,
101
+ });
102
+ for await (const event of stream) {
103
+ if (controller.signal.aborted) return;
104
+ setWorkspaceControlEvent((current) =>
105
+ !current || event.sequence > current.sequence ? event : current,
106
+ );
107
+ callbackRef.current?.(event);
108
+ }
109
+ } catch (error) {
110
+ if (error instanceof OpenGeniApiContractMismatchError) {
111
+ setContractMismatch(error);
112
+ reloadForContractMismatchOnce(error);
113
+ }
114
+ if (!controller.signal.aborted) setWorkspaceControlConnectionState("error");
115
+ }
116
+ })();
117
+ return () => controller.abort();
118
+ }, [client, verifyApiContract, workspaceId]);
119
+
120
+ const value = useMemo(
121
+ () => ({
122
+ client,
123
+ workspaceId,
124
+ workspaceControlEvent,
125
+ workspaceControlConnectionState,
126
+ registerSessionReconciler,
127
+ reconcileSession,
128
+ }),
129
+ [
130
+ client,
131
+ workspaceId,
132
+ workspaceControlEvent,
133
+ workspaceControlConnectionState,
134
+ registerSessionReconciler,
135
+ reconcileSession,
136
+ ],
137
+ );
138
+ return (
139
+ <OpenGeniContext.Provider value={value}>
140
+ {children}
141
+ {contractMismatch ? <ApiContractMismatchScreen mismatch={contractMismatch} /> : null}
142
+ </OpenGeniContext.Provider>
143
+ );
42
144
  }
43
145
 
44
- /**
45
- * Resolve the client only — for hooks that are not workspace-scoped
46
- * (`useWorkspaces`, `useBillingUsage`).
47
- */
48
- export function useOpenGeniClient(
49
- override: Pick<ClientOverride, "client"> = {},
50
- ): SessionClientLike {
51
- const context = useContext(OpenGeniContext);
52
- const client = override.client ?? context?.client;
53
- if (!client) {
54
- throw new Error(
55
- "@opengeni/react: no OpenGeni client available. Wrap the tree in <OpenGeniProvider> or pass { client } to the hook.",
56
- );
57
- }
58
- return client;
146
+ function ApiContractMismatchScreen({ mismatch }: { mismatch: OpenGeniApiContractMismatchError }) {
147
+ return (
148
+ <div
149
+ className="og-root fixed inset-0 z-[2147483647] grid place-items-center bg-og-bg/95 p-6 backdrop-blur-sm"
150
+ role="alert"
151
+ aria-live="assertive"
152
+ data-opengeni-api-contract-mismatch
153
+ >
154
+ <div className="w-full max-w-md rounded-xl border border-og-border bg-og-surface p-6 shadow-2xl">
155
+ <p className="text-sm font-semibold text-og-fg">OpenGeni updated</p>
156
+ <p className="mt-2 text-sm leading-6 text-og-muted">
157
+ This tab cannot safely continue with the new server version. Reload it before sending or
158
+ controlling work.
159
+ </p>
160
+ <p className="mt-3 font-mono text-xs text-og-subtle">
161
+ Client {mismatch.expected} · API {mismatch.actual}
162
+ </p>
163
+ <button
164
+ type="button"
165
+ className="mt-5 inline-flex h-9 items-center rounded-md bg-og-fg px-3 text-sm font-medium text-og-bg"
166
+ onClick={() => window.location.reload()}
167
+ >
168
+ Reload now
169
+ </button>
170
+ </div>
171
+ </div>
172
+ );
173
+ }
174
+
175
+ function reloadForContractMismatchOnce(mismatch: OpenGeniApiContractMismatchError): void {
176
+ if (typeof window === "undefined" || typeof sessionStorage === "undefined") return;
177
+ const key = `${CONTRACT_RELOAD_STORAGE_PREFIX}${mismatch.actual}`;
178
+ if (sessionStorage.getItem(key) === OPENGENI_API_CONTRACT_REVISION) return;
179
+ sessionStorage.setItem(key, OPENGENI_API_CONTRACT_REVISION);
180
+ window.setTimeout(() => window.location.reload(), 150);
59
181
  }