zidane-ui 9.1.13 → 9.1.14

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 (309) hide show
  1. package/dist/adapters/index.d.ts +2 -2
  2. package/dist/adapters/index.js +2 -2
  3. package/dist/adapters/live.d.ts +29 -3
  4. package/dist/adapters/live.js +9 -1
  5. package/dist/adapters/server-composer-host.js +17 -2
  6. package/dist/adapters/server-extensions-host.d.ts +0 -1
  7. package/dist/adapters/server-extensions-host.js +5 -16
  8. package/dist/adapters/server-git-host.js +7 -16
  9. package/dist/adapters/server-host.js +181 -43
  10. package/dist/adapters/server-machines-host.d.ts +2 -0
  11. package/dist/adapters/server-machines-host.js +24 -25
  12. package/dist/adapters/server-onboarding-host.d.ts +1 -1
  13. package/dist/adapters/server-onboarding-host.js +3 -4
  14. package/dist/adapters/server-session-host.js +22 -3
  15. package/dist/adapters/server-settings-accounts.js +2 -2
  16. package/dist/adapters/server-settings-host.js +3 -3
  17. package/dist/adapters/server-settings-performance.js +7 -9
  18. package/dist/adapters/server-settings-sections.js +13 -14
  19. package/dist/adapters/server-sidebar-host.js +2 -2
  20. package/dist/adapters/sse-host.js +68 -3
  21. package/dist/adapters/sse-protocol.d.ts +12 -2
  22. package/dist/adapters/sse-protocol.js +4 -2
  23. package/dist/app/AppHostProvider.js +4 -3
  24. package/dist/app/ModalProvider.d.ts +13 -3
  25. package/dist/app/ModalProvider.js +103 -24
  26. package/dist/app/NoticeStack.d.ts +33 -0
  27. package/dist/app/NoticeStack.js +90 -0
  28. package/dist/app/index.d.ts +3 -2
  29. package/dist/app/index.js +3 -2
  30. package/dist/appearance/AppearanceProvider.js +2 -2
  31. package/dist/appearance/headless/index.js +1 -1
  32. package/dist/approvals/headless/index.js +2 -2
  33. package/dist/chat/SessionFilterMenu.d.ts +1 -1
  34. package/dist/chat/SessionFilterMenu.js +2 -1
  35. package/dist/chat/Transcript.js +1 -1
  36. package/dist/chat/composer/Composer.js +9 -6
  37. package/dist/chat/composer/ComposerEditor.js +1 -1
  38. package/dist/chat/composer/ConversationBadges.js +1 -1
  39. package/dist/chat/composer/ModelChainList.js +17 -8
  40. package/dist/chat/composer/ModelChainTooltip.js +5 -2
  41. package/dist/chat/composer/use-composer-stores.js +1 -1
  42. package/dist/chat/composer/use-draft-target.d.ts +20 -1
  43. package/dist/chat/composer/use-draft-target.js +122 -6
  44. package/dist/chat/composer/use-new-session-defaults.d.ts +5 -1
  45. package/dist/chat/composer/use-new-session-defaults.js +17 -4
  46. package/dist/chat/composer/use-run-meter.js +1 -1
  47. package/dist/chat/composer/use-send-prompt.js +1 -1
  48. package/dist/chat/headless/chip-labels.d.ts +1 -0
  49. package/dist/chat/headless/chip-labels.js +1 -0
  50. package/dist/chat/headless/composer/index.js +2 -2
  51. package/dist/chat/headless/draft-target.d.ts +21 -1
  52. package/dist/chat/headless/fixture-host.js +17 -2
  53. package/dist/chat/headless/host.d.ts +3 -3
  54. package/dist/chat/headless/index.d.ts +9 -9
  55. package/dist/chat/headless/index.js +15 -15
  56. package/dist/chat/headless/labels.d.ts +13 -4
  57. package/dist/chat/headless/labels.js +8 -5
  58. package/dist/chat/headless/session-list.d.ts +20 -6
  59. package/dist/chat/headless/session-list.js +1 -0
  60. package/dist/chat/headless/sidebar/directory.d.ts +56 -14
  61. package/dist/chat/headless/sidebar/directory.js +149 -70
  62. package/dist/chat/headless/sidebar/index.d.ts +3 -3
  63. package/dist/chat/headless/sidebar/index.js +3 -3
  64. package/dist/chat/headless/sidebar/labels.d.ts +15 -6
  65. package/dist/chat/headless/sidebar/types.d.ts +3 -1
  66. package/dist/chat/headless/sidebar/view.d.ts +13 -5
  67. package/dist/chat/headless/sidebar/view.js +31 -11
  68. package/dist/chat/headless/streams/actions.d.ts +5 -3
  69. package/dist/chat/headless/streams/actions.js +3 -2
  70. package/dist/chat/headless/streams/index.d.ts +3 -3
  71. package/dist/chat/headless/streams/merge.d.ts +6 -10
  72. package/dist/chat/headless/streams/merge.js +7 -21
  73. package/dist/chat/headless/streams/session-streams.d.ts +29 -4
  74. package/dist/chat/headless/streams/session-streams.js +86 -0
  75. package/dist/chat/headless/streams/store.d.ts +162 -16
  76. package/dist/chat/headless/streams/store.js +334 -38
  77. package/dist/chat/headless/streams/types.d.ts +10 -7
  78. package/dist/chat/headless/transcript-labels.d.ts +1 -0
  79. package/dist/chat/interactions/PlanCard.js +10 -3
  80. package/dist/chat/interactions/QuestionForm.js +7 -3
  81. package/dist/chat/interactions/card-ui.d.ts +5 -3
  82. package/dist/chat/interactions/card-ui.js +9 -7
  83. package/dist/chat/sidebar/SessionSidebar.js +5 -5
  84. package/dist/chat/sidebar/SidebarFilterMenu.js +3 -1
  85. package/dist/chat/sidebar/SidebarFrame.d.ts +4 -0
  86. package/dist/chat/sidebar/SidebarFrame.js +27 -9
  87. package/dist/chat/sidebar/SidebarGroupHeader.js +1 -1
  88. package/dist/chat/sidebar/SidebarHostProvider.d.ts +8 -5
  89. package/dist/chat/sidebar/SidebarHostProvider.js +13 -9
  90. package/dist/chat/sidebar/SidebarToggleButton.js +7 -3
  91. package/dist/chat/sidebar/index.d.ts +2 -2
  92. package/dist/chat/sidebar/session-menu.js +4 -4
  93. package/dist/chat/sidebar/useSaveViewAsSpace.js +2 -2
  94. package/dist/chat/testing/contract.js +2 -2
  95. package/dist/chat/transcript/AuthFailureCard.js +11 -8
  96. package/dist/chat/transcript/BadgeMenu.js +13 -2
  97. package/dist/chat/transcript/MermaidDiagram.js +7 -3
  98. package/dist/chat/transcript/fold.d.ts +4 -0
  99. package/dist/chat/transcript/fold.js +53 -22
  100. package/dist/chat/transcript/script-input.d.ts +1 -1
  101. package/dist/chat/transcript/shell-block.js +8 -4
  102. package/dist/chat/transcript/useStickToBottom.js +12 -0
  103. package/dist/components/BrowserSignIn.js +23 -21
  104. package/dist/components/Form.d.ts +6 -4
  105. package/dist/components/Form.js +16 -8
  106. package/dist/components/LoadError.d.ts +4 -2
  107. package/dist/components/LoadError.js +13 -9
  108. package/dist/components/Notice.d.ts +29 -0
  109. package/dist/components/Notice.js +63 -0
  110. package/dist/components/PanelEmpty.d.ts +1 -1
  111. package/dist/components/PanelEmpty.js +4 -2
  112. package/dist/components/Restricted.d.ts +1 -1
  113. package/dist/components/palette/PaletteList.js +8 -1
  114. package/dist/components/palette/PalettePanel.js +14 -6
  115. package/dist/core.css +24 -5
  116. package/dist/dist/{index-Bq87OcGy.d.ts → index-C6rzc-tt.d.ts} +28 -3
  117. package/dist/dist/index.d.ts +2 -2
  118. package/dist/dist/{timeout-B5pO5I5a.d.ts → timeout-Cz9dRF8Q.d.ts} +1 -1
  119. package/dist/extensions/ExtensionSettingsPage.js +2 -5
  120. package/dist/extensions/ExtensionSettingsSection.js +5 -4
  121. package/dist/extensions/ExtensionSettingsSidebar.js +3 -7
  122. package/dist/extensions/SettingsWireForm.d.ts +1 -7
  123. package/dist/extensions/SettingsWireForm.js +7 -5
  124. package/dist/extensions/headless/fixture-host.d.ts +1 -5
  125. package/dist/extensions/headless/fixture-host.js +2 -5
  126. package/dist/extensions/headless/host.d.ts +1 -11
  127. package/dist/extensions/headless/index.d.ts +3 -3
  128. package/dist/extensions/headless/index.js +6 -6
  129. package/dist/extensions/headless/select.d.ts +1 -11
  130. package/dist/extensions/headless/select.js +1 -18
  131. package/dist/extensions/hooks.js +1 -1
  132. package/dist/files/EditorColumn.js +13 -2
  133. package/dist/files/MediaDiff.js +1 -1
  134. package/dist/files/TreeColumn.js +13 -20
  135. package/dist/files/useEntryActions.js +1 -1
  136. package/dist/files/useOpenFiles.js +3 -1
  137. package/dist/git/BranchMenu.js +6 -4
  138. package/dist/git/ImportRepoDialog.js +18 -9
  139. package/dist/git/MoveSessionDialog.js +16 -8
  140. package/dist/git/RemoteFolderPicker.js +35 -17
  141. package/dist/git/SyncChip.js +17 -17
  142. package/dist/git/WherePicker.d.ts +16 -1
  143. package/dist/git/WherePicker.js +81 -37
  144. package/dist/git/headless/environment.d.ts +33 -3
  145. package/dist/git/headless/environment.js +33 -5
  146. package/dist/git/headless/index.d.ts +2 -2
  147. package/dist/git/headless/index.js +2 -2
  148. package/dist/git/headless/labels.d.ts +15 -2
  149. package/dist/git/headless/labels.js +17 -4
  150. package/dist/git/useEnvironmentChoices.d.ts +3 -1
  151. package/dist/git/useEnvironmentChoices.js +7 -4
  152. package/dist/index.d.ts +2 -1
  153. package/dist/index.js +2 -1
  154. package/dist/keybindings/KeyCommands.js +1 -1
  155. package/dist/keybindings/KeybindingsProvider.js +1 -1
  156. package/dist/keybindings/headless/index.js +2 -2
  157. package/dist/keybindings/headless/overrides.js +1 -1
  158. package/dist/labels.d.ts +5 -0
  159. package/dist/labels.js +5 -0
  160. package/dist/machines/AddMachineDialog.d.ts +34 -0
  161. package/dist/machines/AddMachineDialog.js +464 -0
  162. package/dist/machines/Banners.d.ts +33 -4
  163. package/dist/machines/Banners.js +64 -3
  164. package/dist/machines/DaemonMenu.js +27 -4
  165. package/dist/machines/HostCapabilities.d.ts +1 -3
  166. package/dist/machines/HostCapabilities.js +24 -45
  167. package/dist/machines/HostSyncPanel.js +124 -130
  168. package/dist/machines/HostsSection.d.ts +4 -1
  169. package/dist/machines/HostsSection.js +30 -7
  170. package/dist/machines/MachinesExplainer.d.ts +17 -0
  171. package/dist/machines/MachinesExplainer.js +71 -0
  172. package/dist/machines/MachinesProvider.d.ts +14 -2
  173. package/dist/machines/MachinesProvider.js +35 -1
  174. package/dist/machines/ServerAddedCard.d.ts +31 -0
  175. package/dist/machines/ServerAddedCard.js +72 -0
  176. package/dist/machines/ServerCard.js +91 -215
  177. package/dist/machines/ServerMachinesPanel.d.ts +2 -2
  178. package/dist/machines/ServerMachinesPanel.js +184 -323
  179. package/dist/machines/ServerUpdatePanel.js +51 -40
  180. package/dist/machines/ShareThisComputerForm.d.ts +19 -0
  181. package/dist/machines/ShareThisComputerForm.js +133 -0
  182. package/dist/machines/SyncOutcomeBadge.js +1 -1
  183. package/dist/machines/TokensPanel.d.ts +5 -3
  184. package/dist/machines/TokensPanel.js +98 -78
  185. package/dist/machines/headless/fixture-host.d.ts +19 -3
  186. package/dist/machines/headless/fixture-host.js +43 -6
  187. package/dist/machines/headless/fixtures.js +4 -6
  188. package/dist/machines/headless/host.d.ts +40 -19
  189. package/dist/machines/headless/index.d.ts +3 -3
  190. package/dist/machines/headless/index.js +3 -3
  191. package/dist/machines/headless/labels.d.ts +63 -20
  192. package/dist/machines/headless/labels.js +88 -25
  193. package/dist/machines/headless/messages.js +8 -0
  194. package/dist/machines/headless/stores.d.ts +9 -2
  195. package/dist/machines/headless/stores.js +28 -1
  196. package/dist/machines/index.d.ts +7 -3
  197. package/dist/machines/index.js +8 -4
  198. package/dist/machines/testing/contract.d.ts +15 -3
  199. package/dist/machines/testing/contract.js +68 -14
  200. package/dist/motion/grow.d.ts +8 -1
  201. package/dist/motion/grow.js +10 -4
  202. package/dist/onboarding/headless/labels.d.ts +13 -0
  203. package/dist/onboarding/headless/labels.js +8 -0
  204. package/dist/onboarding/sources/SourceBrowser.js +11 -7
  205. package/dist/onboarding/steps/ImportStep.js +4 -1
  206. package/dist/onboarding/steps/ReadyStep.js +9 -2
  207. package/dist/onboarding/steps/connect/KeyForm.js +6 -2
  208. package/dist/onboarding/steps/connect/ProviderPanel.js +6 -2
  209. package/dist/onboarding/steps/connect/ProviderReady.js +25 -20
  210. package/dist/onboarding/steps/tasks.js +17 -14
  211. package/dist/palette/app-sources.js +1 -1
  212. package/dist/server/sse-handler.js +141 -19
  213. package/dist/session/ArtifactsPanel.js +40 -18
  214. package/dist/session/PlanTracker.js +13 -8
  215. package/dist/session/ProjectHome.js +13 -11
  216. package/dist/session/RemindersPanel.js +35 -17
  217. package/dist/session/RunningWorkDialog.js +6 -2
  218. package/dist/session/SecretsPanel.js +29 -10
  219. package/dist/session/SessionDetailsDialog.d.ts +1 -1
  220. package/dist/session/SessionDetailsDialog.js +18 -10
  221. package/dist/session/SideChat.js +10 -7
  222. package/dist/session/TurnDetailsDialog.js +19 -5
  223. package/dist/session/UsagePanel.js +10 -4
  224. package/dist/session/headless/host.d.ts +2 -0
  225. package/dist/session/headless/index.js +2 -2
  226. package/dist/session/headless/labels.d.ts +19 -1
  227. package/dist/session/headless/labels.js +15 -1
  228. package/dist/session/headless/queue.js +2 -1
  229. package/dist/session/headless/reminder-labels.d.ts +4 -0
  230. package/dist/session/headless/reminder-labels.js +4 -0
  231. package/dist/settings/SettingsRestricted.d.ts +1 -1
  232. package/dist/settings/SettingsRestricted.js +4 -4
  233. package/dist/settings/SettingsShell.d.ts +7 -0
  234. package/dist/settings/SettingsShell.js +6 -1
  235. package/dist/settings/headless/fixture-performance.d.ts +1 -1
  236. package/dist/settings/headless/host.d.ts +2 -2
  237. package/dist/settings/headless/index.js +1 -1
  238. package/dist/settings/headless/labels.d.ts +3 -3
  239. package/dist/settings/headless/labels.js +3 -3
  240. package/dist/settings/headless/performance.d.ts +3 -4
  241. package/dist/settings/headless/search.d.ts +1 -1
  242. package/dist/settings/index.d.ts +2 -1
  243. package/dist/settings/index.js +2 -1
  244. package/dist/settings/sections/appearance/AppearanceSection.js +2 -2
  245. package/dist/settings/sections/claude-import/ClaudeImportDialog.js +1 -1
  246. package/dist/settings/sections/editor/EditorSection.js +8 -5
  247. package/dist/settings/sections/editor/labels.d.ts +1 -0
  248. package/dist/settings/sections/editor/labels.js +1 -0
  249. package/dist/settings/sections/environments/EnvironmentsSection.js +21 -14
  250. package/dist/settings/sections/environments/labels.d.ts +1 -0
  251. package/dist/settings/sections/environments/labels.js +2 -1
  252. package/dist/settings/sections/extensions/ChangeOriginDialog.js +1 -1
  253. package/dist/settings/sections/extensions/CreateExtensionDialog.js +1 -1
  254. package/dist/settings/sections/extensions/ExtensionConfigRows.d.ts +1 -3
  255. package/dist/settings/sections/extensions/ExtensionConfigRows.js +20 -19
  256. package/dist/settings/sections/extensions/ExtensionOptionsSection.js +2 -1
  257. package/dist/settings/sections/extensions/ExtensionsSection.js +1 -1
  258. package/dist/settings/sections/extensions/options-labels.d.ts +2 -1
  259. package/dist/settings/sections/extensions/options-labels.js +2 -1
  260. package/dist/settings/sections/host-catalog/HostCatalogSection.js +1 -1
  261. package/dist/settings/sections/index.d.ts +2 -1
  262. package/dist/settings/sections/index.js +2 -1
  263. package/dist/settings/sections/instructions/InstructionsSection.js +1 -1
  264. package/dist/settings/sections/logs/LogsSection.d.ts +2 -2
  265. package/dist/settings/sections/logs/LogsSection.js +2 -2
  266. package/dist/settings/sections/mcp/McpSection.d.ts +1 -1
  267. package/dist/settings/sections/mcp/McpSection.js +13 -7
  268. package/dist/settings/sections/mcp/McpServerRow.js +21 -14
  269. package/dist/settings/sections/mcp/labels.d.ts +8 -2
  270. package/dist/settings/sections/mcp/labels.js +8 -2
  271. package/dist/settings/sections/models/ModelRows.js +1 -1
  272. package/dist/settings/sections/models/NewChatPlaceRow.d.ts +26 -0
  273. package/dist/settings/sections/models/NewChatPlaceRow.js +78 -0
  274. package/dist/settings/sections/models/SpacesDefaultsSection.js +15 -3
  275. package/dist/settings/sections/models/labels.d.ts +7 -0
  276. package/dist/settings/sections/models/labels.js +7 -0
  277. package/dist/settings/sections/models/model-test.js +7 -4
  278. package/dist/settings/sections/performance/PerformanceSection.js +16 -6
  279. package/dist/settings/sections/performance/labels.d.ts +1 -1
  280. package/dist/settings/sections/performance/labels.js +1 -1
  281. package/dist/settings/sections/providers/ProvidersSection.d.ts +1 -1
  282. package/dist/settings/sections/providers/ProvidersSection.js +15 -8
  283. package/dist/settings/sections/providers/ServerProvidersSection.d.ts +1 -1
  284. package/dist/settings/sections/providers/ServerProvidersSection.js +12 -6
  285. package/dist/settings/sections/providers/labels.d.ts +2 -2
  286. package/dist/settings/sections/providers/labels.js +2 -2
  287. package/dist/settings/sections/shared/catalog.js +1 -1
  288. package/dist/settings/sections/skills/SkillsSection.js +1 -1
  289. package/dist/settings/testing/performance.contract.js +8 -12
  290. package/dist/styles.css +32 -3
  291. package/dist/terminal/HostTerminalSurface.js +17 -7
  292. package/dist/terminal/TerminalPanel.js +30 -17
  293. package/dist/terminal/TerminalSurface.js +11 -4
  294. package/dist/terminal/headless/labels.d.ts +5 -0
  295. package/dist/terminal/headless/labels.js +5 -0
  296. package/dist/terminal/headless/store.d.ts +1 -1
  297. package/dist/terminal/headless/store.js +6 -3
  298. package/dist/workspace/LayoutBudget.d.ts +5 -1
  299. package/dist/workspace/LayoutBudget.js +14 -1
  300. package/dist/workspace/PanelContentView.d.ts +1 -1
  301. package/dist/workspace/PanelContentView.js +17 -6
  302. package/dist/workspace/WorkspaceProvider.js +4 -3
  303. package/dist/workspace/extension-tabs.js +1 -1
  304. package/dist/workspace/headless/index.js +1 -1
  305. package/dist/workspace/headless/labels.d.ts +1 -0
  306. package/dist/workspace/headless/labels.js +1 -0
  307. package/package.json +3 -3
  308. package/src/styles/motion.css +8 -0
  309. package/src/styles/primitives.css +7 -0
@@ -1,6 +1,8 @@
1
1
  import { buttonClass } from "../../../components/button.js";
2
+ import { Notice } from "../../../components/Notice.js";
2
3
  import { Segmented } from "../../../components/Segmented.js";
3
4
  import "../../../components/Form.js";
5
+ import { errorMessage } from "../../../components/report-error.js";
4
6
  import { SegmentSpinner } from "../../../components/SegmentSpinner.js";
5
7
  import { useOnboarding, useOnboardingLabels } from "../../OnboardingProvider.js";
6
8
  import { providerReadyText } from "./ready-text.js";
@@ -147,7 +149,7 @@ function LiveTest({ provider, model, label }) {
147
149
  result: {
148
150
  ok: false,
149
151
  durationMs: 0,
150
- message: failure instanceof Error ? failure.message : String(failure)
152
+ message: errorMessage(failure)
151
153
  }
152
154
  });
153
155
  });
@@ -166,28 +168,31 @@ function LiveTest({ provider, model, label }) {
166
168
  className: "flex items-center gap-2 text-zg-label text-[var(--zg-text-muted)]",
167
169
  children: [/* @__PURE__ */ jsx(SegmentSpinner, {}), labels.testing]
168
170
  });
171
+ if (!result.ok) return /* @__PURE__ */ jsx(Notice, {
172
+ tone: "error",
173
+ compact: true,
174
+ ...result.message ? { detail: result.message } : {},
175
+ action: /* @__PURE__ */ jsx("button", {
176
+ type: "button",
177
+ onClick: () => setRound((n) => n + 1),
178
+ className: `${buttonClass({
179
+ variant: "ghost",
180
+ size: "sm"
181
+ })} ml-auto`,
182
+ children: labels.testAgain
183
+ }),
184
+ children: labels.testFailed
185
+ });
169
186
  return /* @__PURE__ */ jsxs("div", {
170
187
  role: "status",
171
188
  className: "flex items-center gap-2 min-w-0 text-zg-label",
172
- children: [
173
- /* @__PURE__ */ jsx("span", {
174
- "aria-hidden": true,
175
- className: `${result.ok ? "i-ph-check-circle text-zg-success" : "i-ph-warning-circle text-zg-danger"} text-zg-body shrink-0`
176
- }),
177
- /* @__PURE__ */ jsx("span", {
178
- className: `min-w-0 break-words ${result.ok ? "text-[var(--zg-text-muted)]" : "text-zg-danger"}`,
179
- children: result.ok ? labels.testOk(label ?? result.model ?? provider, (result.durationMs / 1e3).toFixed(1)) : `${labels.testFailed}: ${result.message ?? ""}`
180
- }),
181
- !result.ok && /* @__PURE__ */ jsx("button", {
182
- type: "button",
183
- onClick: () => setRound((n) => n + 1),
184
- className: `${buttonClass({
185
- variant: "ghost",
186
- size: "sm"
187
- })} ml-auto`,
188
- children: labels.testAgain
189
- })
190
- ]
189
+ children: [/* @__PURE__ */ jsx("span", {
190
+ "aria-hidden": true,
191
+ className: "i-ph-check-circle text-zg-success text-zg-body shrink-0"
192
+ }), /* @__PURE__ */ jsx("span", {
193
+ className: "min-w-0 break-words text-[var(--zg-text-muted)]",
194
+ children: labels.testOk(label ?? result.model ?? provider, (result.durationMs / 1e3).toFixed(1))
195
+ })]
191
196
  });
192
197
  }
193
198
  //#endregion
@@ -1,4 +1,5 @@
1
1
  import { buttonClass } from "../../components/button.js";
2
+ import { Notice } from "../../components/Notice.js";
2
3
  import { MetaChip } from "../../components/Form.js";
3
4
  import { SegmentSpinner } from "../../components/SegmentSpinner.js";
4
5
  import { useOnboardingLabels } from "../OnboardingProvider.js";
@@ -47,22 +48,24 @@ function TaskChip({ task, className }) {
47
48
  */
48
49
  function TaskFailure({ task, onRetry, className, style }) {
49
50
  const labels = useOnboardingLabels();
50
- return /* @__PURE__ */ jsxs("div", {
51
- className: ["flex items-start gap-2 px-3 pb-2 min-w-0", className].filter(Boolean).join(" "),
51
+ return /* @__PURE__ */ jsx("div", {
52
+ className: ["px-3 pb-2 min-w-0", className].filter(Boolean).join(" "),
52
53
  style,
53
- children: [/* @__PURE__ */ jsx("span", {
54
- role: "alert",
55
- className: "flex-1 min-w-0 text-zg-label text-zg-danger break-words",
56
- children: task.message ?? labels.taskFailed
57
- }), /* @__PURE__ */ jsx("button", {
58
- type: "button",
59
- onClick: onRetry,
60
- className: buttonClass({
61
- variant: "ghost",
62
- size: "xs"
54
+ children: /* @__PURE__ */ jsx(Notice, {
55
+ tone: "error",
56
+ compact: true,
57
+ ...task.message ? { detail: task.message } : {},
58
+ action: /* @__PURE__ */ jsx("button", {
59
+ type: "button",
60
+ onClick: onRetry,
61
+ className: buttonClass({
62
+ variant: "ghost",
63
+ size: "xs"
64
+ }),
65
+ children: labels.retry
63
66
  }),
64
- children: labels.retry
65
- })]
67
+ children: labels.taskFailedNote
68
+ })
66
69
  });
67
70
  }
68
71
  //#endregion
@@ -1,5 +1,5 @@
1
- import { getMergedKeybindings } from "../keybindings/headless/overrides.js";
2
1
  import { usePendingApprovals } from "../approvals/ApprovalsProvider.js";
2
+ import { getMergedKeybindings } from "../keybindings/headless/overrides.js";
3
3
  import { useKeybindingsHost } from "../keybindings/KeybindingsProvider.js";
4
4
  import { useKeyCommandActions, useKeyCommandRegistry } from "../keybindings/KeyCommands.js";
5
5
  import { usePresenceMap } from "../machines/MachinesProvider.js";
@@ -1,5 +1,6 @@
1
1
  import { applyLiveEvent, finishLive } from "../chat/headless/streams/live-events.js";
2
2
  import { SSE_PROTOCOL_HEADER, attachmentsFromPreviews, encodeSseRecord, formatCursor, parseCursor } from "../adapters/sse-protocol.js";
3
+ import { applyHistoryOp } from "zidane/chat/pure";
3
4
  import { createChatHost, eventsFromTurns } from "zidane/chat";
4
5
  import { randomUUID } from "node:crypto";
5
6
  //#region src/server/sse-handler.ts
@@ -24,12 +25,12 @@ const json = (body, status = 200) => new Response(JSON.stringify(body), {
24
25
  status,
25
26
  headers: {
26
27
  "Content-Type": "application/json",
27
- [SSE_PROTOCOL_HEADER]: String(1)
28
+ [SSE_PROTOCOL_HEADER]: String(2)
28
29
  }
29
30
  });
30
31
  const empty = (status) => new Response(null, {
31
32
  status,
32
- headers: { [SSE_PROTOCOL_HEADER]: String(1) }
33
+ headers: { [SSE_PROTOCOL_HEADER]: String(2) }
33
34
  });
34
35
  /**
35
36
  * Creates a Web-standard request handler that runs zidane's chat engine and serves it over HTTP and server-sent events, for {@link createSseHost} to talk to. Every request goes through `authorize` first, and the agent's tools run on this machine.
@@ -93,6 +94,7 @@ function createSseHandler(options) {
93
94
  return;
94
95
  }
95
96
  case "run:start":
97
+ channels.get(sessionId).running = true;
96
98
  record(sessionId, {
97
99
  type: "run",
98
100
  data: { running: true }
@@ -101,7 +103,9 @@ function createSseHandler(options) {
101
103
  return;
102
104
  case "run:end": {
103
105
  const ch = channels.get(sessionId);
106
+ delete ch.running;
104
107
  if (ch.loaded) ch.events = finishLive(ch.events);
108
+ if (ch.loaded && ch.reloadDue) reload(sessionId, ch);
105
109
  const ok = signal.ok !== false;
106
110
  record(sessionId, {
107
111
  type: "run",
@@ -126,9 +130,128 @@ function createSseHandler(options) {
126
130
  data: { requestId: String(signal.requestId) }
127
131
  });
128
132
  return;
129
- case "sessions:changed": if (signal.op === "update") pushSession(sessionId);
133
+ case "sessions:changed":
134
+ if (signal.op === "update") pushSession(sessionId);
135
+ return;
136
+ case "history:changed": {
137
+ const change = signal;
138
+ const ch = channels.get(sessionId);
139
+ if (ch.loaded && ch.reloadDue) {} else if (ch.loaded) {
140
+ const context = ch.pos === void 0 ? {} : {
141
+ pos: ch.pos,
142
+ ...ch.historyId !== void 0 ? { historyId: ch.historyId } : {}
143
+ };
144
+ const applied = applyHistoryOp(ch.events, change, context);
145
+ if ("refetch" in applied) {
146
+ if (ch.running) ch.reloadDue = true;
147
+ else reload(sessionId, ch);
148
+ } else {
149
+ ch.events = applied.rows;
150
+ ch.pos = applied.pos;
151
+ ch.historyId = applied.historyId;
152
+ }
153
+ } else ch.early.push({ change });
154
+ const { kind: _kind, sessionId: _id, ...data } = signal;
155
+ record(sessionId, {
156
+ type: "history",
157
+ data
158
+ });
159
+ }
130
160
  }
131
161
  }
162
+ /**
163
+ * Loads the session's transcript from its store, with its history position.
164
+ * The position is read first, so the turns loaded after it are at that
165
+ * position or past it (a write landed in between). Every history write
166
+ * announced from that position on is held while the transcript loads
167
+ * (`early`). Each one is then applied on top at its position, as a client
168
+ * applies it. A write the turns already hold changes nothing and moves the
169
+ * position on. A rewrite loads again, at the run's end if a run streams. So
170
+ * the position names the rows the channel serves, and every write a client
171
+ * applied is in them.
172
+ *
173
+ * The live events held meanwhile go on top as a client's first read merges
174
+ * its live lane (`mergeLiveTail`). Only the events after the last one whose
175
+ * turn the load holds are applied. A turn that streamed and was saved before
176
+ * the load read it is in the load already.
177
+ */
178
+ const loadChannel = async (sessionId, ch) => {
179
+ const load = ++ch.loads;
180
+ const { env } = await start();
181
+ const position = env.store.getMeta ? await env.store.getMeta(sessionId) : await env.store.historyPosition?.(sessionId);
182
+ const data = await env.store.load(sessionId);
183
+ if (!data) return false;
184
+ if (ch.loads !== load) return true;
185
+ let events = eventsFromTurns(data.turns, data.runs);
186
+ let at = position ? {
187
+ pos: position.pos,
188
+ ...position.historyId !== void 0 ? { historyId: position.historyId } : {}
189
+ } : {};
190
+ const loaded = /* @__PURE__ */ new Set();
191
+ for (const event of events) if (event.turnId) loaded.add(event.turnId);
192
+ let held = -1;
193
+ for (let i = ch.early.length - 1; i >= 0; i--) {
194
+ const item = ch.early[i];
195
+ if ("event" in item && item.event.turnId && loaded.has(item.event.turnId)) {
196
+ held = i;
197
+ break;
198
+ }
199
+ }
200
+ let reloadDue = false;
201
+ for (const [i, item] of ch.early.entries()) {
202
+ if ("event" in item) {
203
+ if (i > held) events = applyLiveEvent(events, item.event);
204
+ continue;
205
+ }
206
+ if (reloadDue) continue;
207
+ const applied = applyHistoryOp(events, item.change, at);
208
+ if ("refetch" in applied) {
209
+ if (!ch.running) {
210
+ reload(sessionId, ch);
211
+ return true;
212
+ }
213
+ reloadDue = true;
214
+ continue;
215
+ }
216
+ events = applied.rows;
217
+ at = {
218
+ pos: applied.pos,
219
+ ...applied.historyId !== void 0 ? { historyId: applied.historyId } : {}
220
+ };
221
+ }
222
+ if (reloadDue) ch.reloadDue = true;
223
+ ch.events = events;
224
+ if (at.pos !== void 0) {
225
+ ch.pos = at.pos;
226
+ if (at.historyId !== void 0) ch.historyId = at.historyId;
227
+ else delete ch.historyId;
228
+ } else {
229
+ delete ch.pos;
230
+ delete ch.historyId;
231
+ }
232
+ ch.early = [];
233
+ ch.loaded = true;
234
+ if (ch.reloadDue && !ch.running) reload(sessionId, ch);
235
+ return true;
236
+ };
237
+ /** Reads the kept transcript again after a write it cannot apply in place (a rewrite). A hydrate waits for the read. */
238
+ const reload = (sessionId, ch) => {
239
+ ch.loaded = false;
240
+ ch.early = [];
241
+ delete ch.reloadDue;
242
+ ch.ready = loadChannel(sessionId, ch).then((found) => {
243
+ if (!found && channels.get(sessionId) === ch) channels.delete(sessionId);
244
+ }, () => {
245
+ if (channels.get(sessionId) === ch) channels.delete(sessionId);
246
+ });
247
+ };
248
+ /** Waits until the channel's latest load is in, because a load may start another. */
249
+ const settled = async (sessionId, ch) => {
250
+ for (let ready = ch.ready;; ready = ch.ready) {
251
+ await ready;
252
+ if (ch.ready === ready || channels.get(sessionId) !== ch) return;
253
+ }
254
+ };
132
255
  const toSession = (engine, row) => {
133
256
  const m = row.metadata ?? {};
134
257
  const stored = row.status ?? "idle";
@@ -163,11 +286,11 @@ function createSseHandler(options) {
163
286
  const channel = async (sessionId) => {
164
287
  let ch = channels.get(sessionId);
165
288
  if (!ch) {
166
- const { env } = await start();
167
289
  const created = {
168
290
  ready: Promise.resolve(),
169
291
  loaded: false,
170
292
  early: [],
293
+ loads: 0,
171
294
  events: [],
172
295
  seq: 0,
173
296
  buffer: [],
@@ -176,28 +299,21 @@ function createSseHandler(options) {
176
299
  };
177
300
  channels.set(sessionId, created);
178
301
  created.ready = (async () => {
179
- const data = await env.store.load(sessionId).catch((error) => {
302
+ if (!await loadChannel(sessionId, created).catch((error) => {
180
303
  if (channels.get(sessionId) === created) channels.delete(sessionId);
181
304
  throw error;
182
- });
183
- if (!data) {
184
- channels.delete(sessionId);
185
- return;
186
- }
187
- let events = eventsFromTurns(data.turns, data.runs);
188
- for (const { event } of created.early) events = applyLiveEvent(events, event);
189
- created.events = events;
190
- created.early = [];
191
- created.loaded = true;
305
+ })) channels.delete(sessionId);
192
306
  })();
193
307
  ch = created;
194
308
  }
195
- await ch.ready;
309
+ await settled(sessionId, ch);
196
310
  return channels.get(sessionId) === ch ? ch : null;
197
311
  };
198
312
  const stream = (request, sessionId, ch) => {
199
313
  const encoder = new TextEncoder();
200
314
  const last = parseCursor(request.headers.get("Last-Event-ID"));
315
+ const version = Number(request.headers.get("X-Zidane-Chat-Protocol")) || 1;
316
+ const known = (rec) => rec.type !== "history" || version >= 2;
201
317
  let cleanup = () => {};
202
318
  const body = new ReadableStream({
203
319
  start(controller) {
@@ -216,9 +332,11 @@ function createSseHandler(options) {
216
332
  }));
217
333
  else {
218
334
  const after = last?.seq ?? ch.seq;
219
- for (const b of ch.buffer) if (b.seq > after) write(encodeSseRecord(formatCursor(epoch, b.seq), b.record));
335
+ for (const b of ch.buffer) if (b.seq > after && known(b.record)) write(encodeSseRecord(formatCursor(epoch, b.seq), b.record));
220
336
  }
221
- const listener = (id, rec) => write(encodeSseRecord(id, rec));
337
+ const listener = (id, rec) => {
338
+ if (known(rec)) write(encodeSseRecord(id, rec));
339
+ };
222
340
  ch.listeners.add(listener);
223
341
  const beat = setInterval(() => write(": keep-alive\n\n"), heartbeatMs);
224
342
  let closed = false;
@@ -247,7 +365,7 @@ function createSseHandler(options) {
247
365
  "Cache-Control": "no-cache, no-transform",
248
366
  Connection: "keep-alive",
249
367
  "X-Accel-Buffering": "no",
250
- [SSE_PROTOCOL_HEADER]: String(1)
368
+ [SSE_PROTOCOL_HEADER]: String(2)
251
369
  } });
252
370
  };
253
371
  const readJson = async (request) => {
@@ -345,6 +463,10 @@ function createSseHandler(options) {
345
463
  events: ch.events,
346
464
  running: engine.isSessionRunning(sessionId),
347
465
  cursor: formatCursor(epoch, ch.seq),
466
+ ...ch.pos !== void 0 ? {
467
+ pos: ch.pos,
468
+ ...ch.historyId !== void 0 ? { historyId: ch.historyId } : {}
469
+ } : {},
348
470
  interactions: engine.interactions.list(sessionId).map((p) => ({
349
471
  requestId: p.request.id,
350
472
  sessionId,
@@ -1,8 +1,9 @@
1
1
  import { IconButton } from "../components/IconButton.js";
2
+ import { Notice } from "../components/Notice.js";
3
+ import { errorMessage } from "../components/report-error.js";
2
4
  import { PanelEmpty, PanelLoading } from "../components/PanelEmpty.js";
3
5
  import { PANEL_ROW, PANEL_ROW_HOVER, RowBadge } from "../components/PanelRows.js";
4
6
  import { RowActionsMenu } from "../components/RowActionsMenu.js";
5
- import { countArtifacts } from "./headless/artifacts.js";
6
7
  import { useExtensionItems } from "../extensions/ExtensionsProvider.js";
7
8
  import { useSessionArtifacts, useSessionHost } from "./SessionProvider.js";
8
9
  import { useLinkRouter } from "../extensions/links.js";
@@ -10,6 +11,7 @@ import { useSessionLabels } from "./useSessionLabels.js";
10
11
  import { ArtifactRowChips, badgeColorStyle, badgeToneClass } from "./ArtifactRowChips.js";
11
12
  import { renderersFor } from "../extensions/headless/select.js";
12
13
  import { ExtensionRenderer } from "../extensions/ExtensionRenderer.js";
14
+ import { countArtifacts } from "./headless/artifacts.js";
13
15
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
14
16
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
15
17
  //#region src/session/ArtifactsPanel.tsx
@@ -45,8 +47,15 @@ function ArtifactsPanel({ sessionId, focus = null, remoteName = null, onOpenPath
45
47
  const removeArtifact = host?.remove;
46
48
  const [error, setError] = useState(null);
47
49
  useEffect(() => {
48
- fetchSession?.(sessionId).catch((err) => setError(err.message));
49
- }, [fetchSession, sessionId]);
50
+ fetchSession?.(sessionId).catch((err) => setError({
51
+ message: labels.artifactsLoadFailed,
52
+ detail: errorMessage(err)
53
+ }));
54
+ }, [
55
+ fetchSession,
56
+ sessionId,
57
+ labels.artifactsLoadFailed
58
+ ]);
50
59
  const total = countArtifacts(groups);
51
60
  const bodyRef = useRef(null);
52
61
  useEffect(() => {
@@ -77,12 +86,16 @@ function ArtifactsPanel({ sessionId, focus = null, remoteName = null, onOpenPath
77
86
  const remove = useMemo(() => removeArtifact ? (row) => {
78
87
  setError(null);
79
88
  removeArtifact(sessionId, row.artifact.id, row.artifact.sessionId).then((ok) => {
80
- if (!ok) setError(labels.artifactsUnsupported);
81
- }).catch((err) => setError(err.message));
89
+ if (!ok) setError({ message: labels.artifactsUnsupported });
90
+ }).catch((err) => setError({
91
+ message: labels.artifactRemoveFailed,
92
+ detail: errorMessage(err)
93
+ }));
82
94
  } : void 0, [
83
95
  removeArtifact,
84
96
  sessionId,
85
- labels.artifactsUnsupported
97
+ labels.artifactsUnsupported,
98
+ labels.artifactRemoveFailed
86
99
  ]);
87
100
  return /* @__PURE__ */ jsxs("div", {
88
101
  className: `flex-1 min-h-0 flex flex-col ${className}`,
@@ -91,10 +104,12 @@ function ArtifactsPanel({ sessionId, focus = null, remoteName = null, onOpenPath
91
104
  children: [/* @__PURE__ */ jsxs("div", {
92
105
  ref: bodyRef,
93
106
  className: "flex-1 min-h-0 flex flex-col overflow-y-auto px-3 pt-3 pb-3",
94
- children: [error && /* @__PURE__ */ jsx("div", {
95
- className: "text-xs text-[var(--zg-warn)] mb-2",
96
- role: "alert",
97
- children: error
107
+ children: [error && /* @__PURE__ */ jsx(Notice, {
108
+ tone: "error",
109
+ compact: true,
110
+ detail: error.detail,
111
+ className: "mb-2",
112
+ children: error.message
98
113
  }), groups === null ? /* @__PURE__ */ jsx(PanelLoading, {}) : total === 0 ? /* @__PURE__ */ jsx(PanelEmpty, {
99
114
  icon: "i-ph-cube-transparent",
100
115
  title: labels.artifactsEmpty,
@@ -144,7 +159,7 @@ function ArtifactRow({ row, focused, remoteName, onOpenPath, onRevealPath, onFoc
144
159
  try {
145
160
  if (!href || !onOpenPath) return;
146
161
  if (remoteName !== null && !isUrl) {
147
- setOpenError(labels.artifactOnRemote(remoteName));
162
+ setOpenError({ message: labels.artifactOnRemote(remoteName) });
148
163
  return;
149
164
  }
150
165
  await links.open(href, {
@@ -152,11 +167,17 @@ function ArtifactRow({ row, focused, remoteName, onOpenPath, onRevealPath, onFoc
152
167
  ...event ? { event } : {}
153
168
  }, () => {
154
169
  onOpenPath(href, event).then((ok) => {
155
- if (!ok) setOpenError(labels.artifactPathUnavailable);
156
- }, (err) => setOpenError(err instanceof Error ? err.message : String(err)));
170
+ if (!ok) setOpenError({ message: labels.artifactPathUnavailable });
171
+ }, (err) => setOpenError({
172
+ message: labels.artifactOpenFailed,
173
+ detail: errorMessage(err)
174
+ }));
157
175
  });
158
176
  } catch (err) {
159
- setOpenError(err instanceof Error ? err.message : String(err));
177
+ setOpenError({
178
+ message: labels.artifactOpenFailed,
179
+ detail: errorMessage(err)
180
+ });
160
181
  }
161
182
  };
162
183
  const menuItems = useMemo(() => [
@@ -242,10 +263,11 @@ function ArtifactRow({ row, focused, remoteName, onOpenPath, onRevealPath, onFoc
242
263
  })
243
264
  ]
244
265
  }),
245
- openError && /* @__PURE__ */ jsx("div", {
246
- role: "alert",
247
- className: "text-xs text-[var(--zg-warn)]",
248
- children: openError
266
+ openError && /* @__PURE__ */ jsx(Notice, {
267
+ tone: "error",
268
+ compact: true,
269
+ detail: openError.detail,
270
+ children: openError.message
249
271
  }),
250
272
  /* @__PURE__ */ jsx(RowFacts, { view }),
251
273
  hasDetail && detailOpen && /* @__PURE__ */ jsx(ExtensionRenderer, {
@@ -1,11 +1,13 @@
1
1
  import { IconButton } from "../components/IconButton.js";
2
2
  import { buttonClass } from "../components/button.js";
3
+ import { Notice } from "../components/Notice.js";
3
4
  import { MetaChip } from "../components/Form.js";
5
+ import { errorMessage } from "../components/report-error.js";
4
6
  import { useMinuteTick } from "../hooks/useMinuteTick.js";
5
- import { inboxPlans } from "./headless/plans.js";
6
7
  import { useSessionHost, useSessionPlans } from "./SessionProvider.js";
7
8
  import { useSessionLabels } from "./useSessionLabels.js";
8
9
  import { ProseMarkdown } from "../chat/transcript/ProseMarkdown.js";
10
+ import { inboxPlans } from "./headless/plans.js";
9
11
  import { StepStatusIcon } from "./StepStatusIcon.js";
10
12
  import { isDoneTodo } from "./TodoList.js";
11
13
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -115,7 +117,7 @@ function PlanTracker({ sessionId, plan, hideHeader = false, className, style })
115
117
  const run = (call) => {
116
118
  if (!call) return;
117
119
  setError(null);
118
- call.catch((err) => setError(err instanceof Error ? err.message : String(err)));
120
+ call.catch((err) => setError(errorMessage(err)));
119
121
  };
120
122
  const startEdit = (step) => {
121
123
  if (!canEdit) return;
@@ -167,8 +169,10 @@ function PlanTracker({ sessionId, plan, hideHeader = false, className, style })
167
169
  })
168
170
  ]
169
171
  }),
170
- stopped && /* @__PURE__ */ jsx("p", {
171
- className: "m-0 px-2 text-zg-meta text-[var(--zg-warn)]",
172
+ stopped && /* @__PURE__ */ jsx(Notice, {
173
+ tone: "warning",
174
+ compact: true,
175
+ className: "mx-2",
172
176
  children: labels.planStopped(stopStep > 0 ? stopStep : null, plan.stopReason)
173
177
  }),
174
178
  applying && plan.possiblyInterrupted && /* @__PURE__ */ jsx("p", {
@@ -271,10 +275,11 @@ function PlanTracker({ sessionId, plan, hideHeader = false, className, style })
271
275
  (error || canEdit || hasActions) && /* @__PURE__ */ jsxs("div", {
272
276
  className: "flex flex-col gap-2 px-2",
273
277
  children: [
274
- error && /* @__PURE__ */ jsx("div", {
275
- className: "text-zg-meta text-[var(--zg-warn)]",
276
- role: "alert",
277
- children: error
278
+ error && /* @__PURE__ */ jsx(Notice, {
279
+ tone: "error",
280
+ compact: true,
281
+ detail: error,
282
+ children: labels.planEditFailed
278
283
  }),
279
284
  canEdit && /* @__PURE__ */ jsxs("div", {
280
285
  className: "flex items-center gap-2",
@@ -1,4 +1,6 @@
1
1
  import { IconButton } from "../components/IconButton.js";
2
+ import { Notice } from "../components/Notice.js";
3
+ import { errorMessage } from "../components/report-error.js";
2
4
  import { RowActionsMenu } from "../components/RowActionsMenu.js";
3
5
  import { useDisplayPath } from "../hooks/useDisplayPath.js";
4
6
  import { readPersisted, writePersisted } from "../hooks/usePersistedState.js";
@@ -343,7 +345,7 @@ function useHomeBlock(panels, cwd, id, view, search) {
343
345
  }, (err) => current && setLoaded((s) => ({
344
346
  key,
345
347
  content: s.content,
346
- error: err instanceof Error ? err.message : String(err)
348
+ error: errorMessage(err)
347
349
  })));
348
350
  return () => {
349
351
  current = false;
@@ -395,7 +397,7 @@ function useHomeBlock(panels, cwd, id, view, search) {
395
397
  });
396
398
  }, (err) => keyRef.current === key && setLoaded((s) => ({
397
399
  ...s,
398
- error: err instanceof Error ? err.message : String(err)
400
+ error: errorMessage(err)
399
401
  }))).finally(() => setLoadingMore(false));
400
402
  }, [
401
403
  panels,
@@ -438,7 +440,7 @@ const HomeBlockCard = memo(function HomeBlockCard({ panels, cwd, block, view, fi
438
440
  setNotice(null);
439
441
  const result = await onStartSession(start).catch((err) => ({
440
442
  ok: false,
441
- message: err instanceof Error ? err.message : String(err)
443
+ message: errorMessage(err)
442
444
  }));
443
445
  if (!result.ok) setNotice(result.message);
444
446
  } : void 0, [onStartSession]);
@@ -555,18 +557,18 @@ const HomeBlockCard = memo(function HomeBlockCard({ panels, cwd, block, view, fi
555
557
  items
556
558
  })] })]
557
559
  }),
558
- notice && /* @__PURE__ */ jsxs("div", {
559
- role: "alert",
560
- className: "mb-3 flex items-start gap-2 text-zg-label text-[var(--zg-warn)]",
561
- children: [/* @__PURE__ */ jsx("span", {
562
- className: "flex-1 min-w-0",
563
- children: notice
564
- }), /* @__PURE__ */ jsx(IconButton, {
560
+ notice && /* @__PURE__ */ jsx(Notice, {
561
+ tone: "error",
562
+ compact: true,
563
+ detail: notice,
564
+ className: "mb-3",
565
+ action: /* @__PURE__ */ jsx(IconButton, {
565
566
  icon: "i-ph-x",
566
567
  size: "xs",
567
568
  label: labels.projectHomeDismiss,
568
569
  onClick: () => setNotice(null)
569
- })]
570
+ }),
571
+ children: labels.projectHomeStartFailed
570
572
  }),
571
573
  /* @__PURE__ */ jsx(PanelContentView, {
572
574
  variant: "block",