zidane-ui 9.1.6 → 9.1.9

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 (224) hide show
  1. package/dist/adapters/run-host.js +17 -20
  2. package/dist/adapters/server-files-host.js +3 -1
  3. package/dist/adapters/server-host.js +18 -11
  4. package/dist/adapters/server-machines-host.js +3 -1
  5. package/dist/adapters/server-session-host.js +2 -1
  6. package/dist/adapters/server-settings-accounts.js +2 -1
  7. package/dist/adapters/server-settings-host.js +3 -3
  8. package/dist/adapters/sse-host.js +9 -7
  9. package/dist/chat/SessionGroupHeader.js +2 -2
  10. package/dist/chat/SessionHostHeader.js +1 -1
  11. package/dist/chat/StatusDot.js +24 -20
  12. package/dist/chat/composer/Composer.d.ts +13 -8
  13. package/dist/chat/composer/Composer.js +14 -10
  14. package/dist/chat/composer/ComposerEditor.js +1 -1
  15. package/dist/chat/composer/HostComposer.d.ts +1 -1
  16. package/dist/chat/composer/HostComposer.js +7 -10
  17. package/dist/chat/composer/RunStatusChip.js +13 -1
  18. package/dist/chat/composer/attachment-ingest.d.ts +4 -1
  19. package/dist/chat/composer/attachment-ingest.js +27 -10
  20. package/dist/chat/composer/composer-bus.d.ts +9 -1
  21. package/dist/chat/composer/composer-bus.js +49 -6
  22. package/dist/chat/composer/index.d.ts +2 -2
  23. package/dist/chat/composer/index.js +2 -2
  24. package/dist/chat/composer/use-draft-target.d.ts +4 -0
  25. package/dist/chat/composer/use-draft-target.js +15 -4
  26. package/dist/chat/composer/use-send-prompt.d.ts +5 -1
  27. package/dist/chat/composer/use-send-prompt.js +2 -12
  28. package/dist/chat/headless/chip-labels.d.ts +2 -0
  29. package/dist/chat/headless/chip-labels.js +3 -1
  30. package/dist/chat/headless/composer/labels-editor.d.ts +2 -0
  31. package/dist/chat/headless/composer/labels-editor.js +2 -0
  32. package/dist/chat/headless/file-chip.d.ts +12 -13
  33. package/dist/chat/headless/file-chip.js +40 -2
  34. package/dist/chat/headless/fixture-host.js +14 -17
  35. package/dist/chat/headless/host.d.ts +24 -6
  36. package/dist/chat/headless/index.d.ts +4 -4
  37. package/dist/chat/headless/index.js +4 -4
  38. package/dist/chat/headless/labels.d.ts +16 -0
  39. package/dist/chat/headless/labels.js +15 -2
  40. package/dist/chat/headless/send-flow.d.ts +21 -4
  41. package/dist/chat/headless/send-flow.js +25 -6
  42. package/dist/chat/headless/session-list.d.ts +11 -0
  43. package/dist/chat/headless/sidebar/index.js +1 -1
  44. package/dist/chat/headless/sidebar/labels.d.ts +12 -1
  45. package/dist/chat/headless/transcript-host.d.ts +8 -1
  46. package/dist/chat/headless/transcript-labels.d.ts +2 -0
  47. package/dist/chat/index.d.ts +3 -3
  48. package/dist/chat/index.js +2 -2
  49. package/dist/chat/interactions/InboxPanel.js +2 -2
  50. package/dist/chat/interactions/QuestionField.js +2 -2
  51. package/dist/chat/rich-composer/RichComposer.d.ts +9 -2
  52. package/dist/chat/rich-composer/RichComposer.js +28 -7
  53. package/dist/chat/rich-composer/composer-extensions.d.ts +2 -0
  54. package/dist/chat/rich-composer/composer-extensions.js +2 -2
  55. package/dist/chat/rich-composer/composer-keys.js +1 -1
  56. package/dist/chat/rich-composer/use-composer-bus.js +2 -1
  57. package/dist/chat/rich-composer/use-composer-editor.d.ts +4 -1
  58. package/dist/chat/rich-composer/use-composer-editor.js +2 -1
  59. package/dist/chat/sidebar/SessionSidebar.js +1 -2
  60. package/dist/chat/sidebar/SidebarSearchRow.js +1 -1
  61. package/dist/chat/sidebar/useSidebarKeyboardNav.d.ts +0 -2
  62. package/dist/chat/sidebar/useSidebarKeyboardNav.js +7 -13
  63. package/dist/chat/testing/contract.d.ts +1 -1
  64. package/dist/chat/testing/contract.js +8 -7
  65. package/dist/chat/transcript/BadgeMenu.d.ts +12 -3
  66. package/dist/chat/transcript/BadgeMenu.js +20 -3
  67. package/dist/chat/transcript/CodemodeScript.js +147 -44
  68. package/dist/chat/transcript/EditDiffBlock.js +1 -4
  69. package/dist/chat/transcript/FileChip.js +60 -14
  70. package/dist/chat/transcript/LiveOutput.js +7 -3
  71. package/dist/chat/transcript/badges.js +2 -2
  72. package/dist/chat/transcript/index.d.ts +2 -2
  73. package/dist/chat/transcript/markdown-context.d.ts +4 -1
  74. package/dist/chat/transcript/rolling.d.ts +12 -0
  75. package/dist/chat/transcript/rolling.js +22 -0
  76. package/dist/chat/transcript/script-input.d.ts +1 -1
  77. package/dist/chat/transcript/shell-block.js +70 -60
  78. package/dist/chat/transcript/tool-row.js +21 -5
  79. package/dist/code/editor/FileTree.d.ts +3 -1
  80. package/dist/code/editor/FileTree.js +29 -1
  81. package/dist/components/Restricted.d.ts +25 -0
  82. package/dist/components/Restricted.js +32 -0
  83. package/dist/components/StepFrame.d.ts +1 -1
  84. package/dist/components/ZidaneMark.d.ts +28 -0
  85. package/dist/components/ZidaneMark.js +114 -0
  86. package/dist/components/palette/PalettePanel.d.ts +7 -1
  87. package/dist/components/palette/PalettePanel.js +37 -11
  88. package/dist/components/zidane-mark.d.ts +52 -0
  89. package/dist/components/zidane-mark.js +94 -0
  90. package/dist/core.css +59 -6
  91. package/dist/dist/{index-DqCio7Nd.d.ts → index-Bq87OcGy.d.ts} +19 -12
  92. package/dist/dist/index.d.ts +1 -1
  93. package/dist/extensions/ExtensionSettingsSection.d.ts +18 -0
  94. package/dist/extensions/ExtensionSettingsSection.js +227 -0
  95. package/dist/extensions/headless/host.d.ts +1 -1
  96. package/dist/extensions/headless/labels.d.ts +41 -1
  97. package/dist/extensions/headless/labels.js +57 -0
  98. package/dist/extensions/headless/select.js +1 -2
  99. package/dist/extensions/index.d.ts +2 -1
  100. package/dist/extensions/index.js +2 -1
  101. package/dist/files/FilesTab.js +2 -0
  102. package/dist/files/TreeColumn.d.ts +5 -1
  103. package/dist/files/TreeColumn.js +6 -0
  104. package/dist/files/headless/fixture-host.js +5 -3
  105. package/dist/files/headless/host.d.ts +24 -6
  106. package/dist/files/headless/index.d.ts +2 -2
  107. package/dist/files/headless/labels.d.ts +1 -0
  108. package/dist/files/headless/labels.js +1 -0
  109. package/dist/files/testing/contract.js +9 -2
  110. package/dist/files/useWorkspace.d.ts +14 -2
  111. package/dist/files/useWorkspace.js +87 -9
  112. package/dist/git/BranchMenu.js +1 -1
  113. package/dist/git/MoveSessionDialog.js +1 -1
  114. package/dist/git/RemoteFolderPicker.js +1 -1
  115. package/dist/git/WherePicker.js +1 -1
  116. package/dist/git/headless/index.js +1 -1
  117. package/dist/git/useEnvironmentChoices.js +1 -1
  118. package/dist/index.d.ts +4 -2
  119. package/dist/index.js +4 -2
  120. package/dist/keybindings/headless/catalog.js +1 -1
  121. package/dist/labels.d.ts +1 -0
  122. package/dist/labels.js +1 -0
  123. package/dist/machines/DaemonMenu.js +1 -1
  124. package/dist/machines/HostCapabilities.d.ts +23 -1
  125. package/dist/machines/HostCapabilities.js +149 -65
  126. package/dist/machines/HostSyncPanel.js +129 -123
  127. package/dist/machines/HostsSection.js +5 -1
  128. package/dist/machines/ServerCard.d.ts +4 -2
  129. package/dist/machines/ServerCard.js +222 -99
  130. package/dist/machines/ServerMachinesPanel.js +16 -13
  131. package/dist/machines/ServerUpdatePanel.js +31 -21
  132. package/dist/machines/TokensPanel.js +75 -53
  133. package/dist/machines/headless/fixture-host.d.ts +5 -0
  134. package/dist/machines/headless/fixture-host.js +13 -4
  135. package/dist/machines/headless/fixtures.js +1 -1
  136. package/dist/machines/headless/host.d.ts +22 -2
  137. package/dist/machines/headless/index.d.ts +2 -2
  138. package/dist/machines/headless/labels.d.ts +22 -1
  139. package/dist/machines/headless/labels.js +22 -2
  140. package/dist/machines/testing/contract.d.ts +3 -1
  141. package/dist/machines/testing/contract.js +9 -0
  142. package/dist/motion/size.d.ts +22 -1
  143. package/dist/motion/size.js +82 -4
  144. package/dist/onboarding/demos/delivery.d.ts +16 -0
  145. package/dist/onboarding/demos/delivery.js +132 -0
  146. package/dist/onboarding/demos/index.d.ts +2 -1
  147. package/dist/onboarding/demos/index.js +2 -1
  148. package/dist/onboarding/headless/labels.d.ts +8 -0
  149. package/dist/onboarding/headless/labels.js +7 -0
  150. package/dist/onboarding/index.d.ts +2 -1
  151. package/dist/onboarding/index.js +2 -1
  152. package/dist/onboarding/steps/ConversationStep.js +46 -4
  153. package/dist/palette/CommandPalette.js +3 -0
  154. package/dist/palette/PaletteDialog.js +7 -3
  155. package/dist/palette/usePaletteController.d.ts +10 -0
  156. package/dist/palette/usePaletteController.js +25 -3
  157. package/dist/server/sse-handler.js +6 -1
  158. package/dist/session/ArtifactsPanel.js +1 -1
  159. package/dist/session/SideChat.js +1 -2
  160. package/dist/session/UsagePanel.js +1 -1
  161. package/dist/session/headless/host.d.ts +3 -1
  162. package/dist/session/headless/index.js +2 -2
  163. package/dist/settings/SettingsRestricted.d.ts +25 -0
  164. package/dist/settings/SettingsRestricted.js +44 -0
  165. package/dist/settings/SettingsRowsPage.js +31 -37
  166. package/dist/settings/headless/catalog.js +7 -6
  167. package/dist/settings/headless/labels.d.ts +4 -2
  168. package/dist/settings/headless/labels.js +4 -2
  169. package/dist/settings/headless/layout.js +1 -1
  170. package/dist/settings/headless/providers.d.ts +2 -0
  171. package/dist/settings/headless/search.d.ts +1 -1
  172. package/dist/settings/index.d.ts +2 -2
  173. package/dist/settings/index.js +2 -2
  174. package/dist/settings/rows.d.ts +51 -8
  175. package/dist/settings/rows.js +81 -26
  176. package/dist/settings/sections/enabled-list/EnabledListSection.js +3 -2
  177. package/dist/settings/sections/environments/EnvironmentsSection.js +4 -3
  178. package/dist/settings/sections/extensions/ExtensionConfigRows.d.ts +2 -2
  179. package/dist/settings/sections/extensions/ExtensionConfigRows.js +22 -25
  180. package/dist/settings/sections/extensions/ExtensionOptionsSection.js +3 -2
  181. package/dist/settings/sections/extensions/options-labels.d.ts +2 -2
  182. package/dist/settings/sections/extensions/options-labels.js +2 -2
  183. package/dist/settings/sections/host-catalog/HostCatalogSection.d.ts +5 -3
  184. package/dist/settings/sections/host-catalog/HostCatalogSection.js +7 -4
  185. package/dist/settings/sections/instructions/InstructionsSection.js +24 -17
  186. package/dist/settings/sections/logs/LogsSection.d.ts +2 -1
  187. package/dist/settings/sections/logs/LogsSection.js +64 -56
  188. package/dist/settings/sections/mcp/McpSection.d.ts +1 -1
  189. package/dist/settings/sections/mcp/McpSection.js +18 -17
  190. package/dist/settings/sections/models/ModelRows.d.ts +3 -3
  191. package/dist/settings/sections/models/ModelRows.js +8 -7
  192. package/dist/settings/sections/performance/PerformanceSection.js +13 -4
  193. package/dist/settings/sections/performance/labels.d.ts +0 -1
  194. package/dist/settings/sections/performance/labels.js +0 -1
  195. package/dist/settings/sections/providers/CredentialSources.js +18 -8
  196. package/dist/settings/sections/providers/ProvidersSection.d.ts +2 -2
  197. package/dist/settings/sections/providers/ProvidersSection.js +20 -17
  198. package/dist/settings/sections/providers/ServerProvidersSection.d.ts +1 -1
  199. package/dist/settings/sections/providers/ServerProvidersSection.js +10 -14
  200. package/dist/settings/sections/shared/catalog.js +3 -2
  201. package/dist/settings/sections/skills/SkillList.js +3 -2
  202. package/dist/settings/testing/accounts-demo.js +1 -0
  203. package/dist/settings/testing/accounts.contract.js +2 -0
  204. package/dist/styles.css +160 -24
  205. package/dist/terminal/HostTerminalSurface.js +1 -1
  206. package/dist/terminal/headless/links.d.ts +19 -1
  207. package/dist/terminal/headless/links.js +26 -2
  208. package/dist/theme/css-vars.js +1 -0
  209. package/dist/theme/derive.d.ts +4 -0
  210. package/dist/theme/derive.js +2 -0
  211. package/dist/workspace/PanelContentView.js +1 -1
  212. package/dist/workspace/PanelHome.d.ts +3 -1
  213. package/dist/workspace/PanelHome.js +4 -3
  214. package/dist/workspace/SidePanel.d.ts +3 -1
  215. package/dist/workspace/SidePanel.js +3 -2
  216. package/dist/workspace/headless/open-target.d.ts +1 -1
  217. package/dist/workspace/headless/open-target.js +2 -2
  218. package/package.json +2 -2
  219. package/src/styles/chat.css +10 -10
  220. package/src/styles/motion.css +37 -0
  221. package/src/styles/primitives.css +11 -3
  222. package/src/styles/sidebar.css +12 -0
  223. package/src/styles/tokens.css +6 -0
  224. package/src/styles/transcript.css +69 -5
@@ -1,5 +1,7 @@
1
1
  import { iconButtonClass } from "../../components/IconButton.js";
2
2
  import { CopyButton } from "../../components/CopyButton.js";
3
+ import { Grow, GrowPresence } from "../../motion/grow.js";
4
+ import { SmoothHeight } from "../../motion/size.js";
3
5
  import { constant, useReadable } from "../headless/store.js";
4
6
  import "../headless/block-runs.js";
5
7
  import { useOptionalChatHost } from "../ChatProvider.js";
@@ -68,6 +70,8 @@ function RunnableCodeBlock({ code, language, scope, CodeBlock }) {
68
70
  const live = useReadable(blocks ? blocks.live(scope.sessionId) : NO_LIVE)[key];
69
71
  const caretRef = useRef(null);
70
72
  const [menuOpen, setMenuOpen] = useState(false);
73
+ const [shownAtMount] = useState(() => live !== void 0 || saved !== void 0);
74
+ const [removed, setRemoved] = useState(false);
71
75
  const [menuArmed, setMenuArmed] = useState(false);
72
76
  if (!plan || !blocks && !runInTerminal) return /* @__PURE__ */ jsx(CodeBlock, {
73
77
  code,
@@ -153,16 +157,23 @@ function RunnableCodeBlock({ code, language, scope, CodeBlock }) {
153
157
  items: menu
154
158
  })
155
159
  }),
156
- (live ?? saved) && /* @__PURE__ */ jsx(RunPanel, {
157
- code,
158
- live,
159
- saved,
160
- onAgain: runHere,
161
- onTerminal: inTerminal,
162
- onRemove: () => {
163
- if (live?.error !== void 0) stop();
164
- else if (blocks && saved) blocks.remove(scope.sessionId, key);
165
- }
160
+ /* @__PURE__ */ jsx(GrowPresence, {
161
+ initial: false,
162
+ children: (live ?? saved) && /* @__PURE__ */ jsx(Grow, {
163
+ appear: !shownAtMount || removed,
164
+ children: /* @__PURE__ */ jsx(RunPanel, {
165
+ code,
166
+ live,
167
+ saved,
168
+ onAgain: runHere,
169
+ onTerminal: inTerminal,
170
+ onRemove: () => {
171
+ setRemoved(true);
172
+ if (live?.error !== void 0) stop();
173
+ else if (blocks && saved) blocks.remove(scope.sessionId, key);
174
+ }
175
+ })
176
+ }, "run")
166
177
  })
167
178
  ]
168
179
  });
@@ -222,58 +233,57 @@ function RunPanel({ code, live, saved, onAgain, onTerminal, onRemove }) {
222
233
  className: "zg-run-panel group",
223
234
  "aria-label": labels.blockRunOutput,
224
235
  "data-failed": failed ? "" : void 0,
225
- children: [
226
- /* @__PURE__ */ jsxs("header", {
227
- className: "zg-meta flex items-center gap-2 min-h-6",
228
- children: [status, /* @__PURE__ */ jsx("span", {
229
- className: "ml-auto flex items-center gap-0.5",
230
- children: !running && /* @__PURE__ */ jsxs(Fragment, { children: [
231
- saved && text !== "" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(CopyButton, {
232
- text,
233
- label: labels.blockRunCopy,
234
- reveal: true
235
- }), /* @__PURE__ */ jsx("button", {
236
- type: "button",
237
- "aria-label": labels.blockRunAttach,
238
- title: labels.blockRunAttach,
239
- onClick: attach,
240
- className: `zg-reveal ${button}`,
241
- children: /* @__PURE__ */ jsx("span", {
242
- "aria-hidden": true,
243
- className: "i-ph-paperclip text-zg-label"
244
- })
245
- })] }),
246
- onAgain && /* @__PURE__ */ jsx("button", {
247
- type: "button",
248
- "aria-label": labels.blockRunAgain,
249
- title: labels.blockRunAgain,
250
- onClick: onAgain,
251
- className: `zg-reveal ${button}`,
252
- children: /* @__PURE__ */ jsx("span", {
253
- "aria-hidden": true,
254
- className: "i-ph-arrow-clockwise text-zg-label"
255
- })
256
- }),
257
- /* @__PURE__ */ jsx("button", {
258
- type: "button",
259
- "aria-label": labels.blockRunRemove,
260
- title: labels.blockRunRemove,
261
- onClick: onRemove,
262
- className: `zg-reveal ${button}`,
263
- children: /* @__PURE__ */ jsx("span", {
264
- "aria-hidden": true,
265
- className: "i-ph-x text-zg-label"
266
- })
236
+ children: [/* @__PURE__ */ jsxs("header", {
237
+ className: "zg-meta flex items-center gap-2 min-h-6",
238
+ children: [status, /* @__PURE__ */ jsx("span", {
239
+ className: "ml-auto flex items-center gap-0.5",
240
+ children: !running && /* @__PURE__ */ jsxs(Fragment, { children: [
241
+ saved && text !== "" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(CopyButton, {
242
+ text,
243
+ label: labels.blockRunCopy,
244
+ reveal: true
245
+ }), /* @__PURE__ */ jsx("button", {
246
+ type: "button",
247
+ "aria-label": labels.blockRunAttach,
248
+ title: labels.blockRunAttach,
249
+ onClick: attach,
250
+ className: `zg-reveal ${button}`,
251
+ children: /* @__PURE__ */ jsx("span", {
252
+ "aria-hidden": true,
253
+ className: "i-ph-paperclip text-zg-label"
267
254
  })
268
- ] })
269
- })]
270
- }),
271
- live ? live.lines.length > 0 && /* @__PURE__ */ jsx(LiveOutput, {
255
+ })] }),
256
+ onAgain && /* @__PURE__ */ jsx("button", {
257
+ type: "button",
258
+ "aria-label": labels.blockRunAgain,
259
+ title: labels.blockRunAgain,
260
+ onClick: onAgain,
261
+ className: `zg-reveal ${button}`,
262
+ children: /* @__PURE__ */ jsx("span", {
263
+ "aria-hidden": true,
264
+ className: "i-ph-arrow-clockwise text-zg-label"
265
+ })
266
+ }),
267
+ /* @__PURE__ */ jsx("button", {
268
+ type: "button",
269
+ "aria-label": labels.blockRunRemove,
270
+ title: labels.blockRunRemove,
271
+ onClick: onRemove,
272
+ className: `zg-reveal ${button}`,
273
+ children: /* @__PURE__ */ jsx("span", {
274
+ "aria-hidden": true,
275
+ className: "i-ph-x text-zg-label"
276
+ })
277
+ })
278
+ ] })
279
+ })]
280
+ }), /* @__PURE__ */ jsxs(SmoothHeight, {
281
+ swapKey: running ? live.lines.length > 0 ? "live" : "starting" : live ? "failed" : "saved",
282
+ children: [live ? live.lines.length > 0 && /* @__PURE__ */ jsx(LiveOutput, {
272
283
  lines: live.lines,
273
284
  window: 15,
274
285
  label: labels.blockRunOutput
275
- }) : saved && saved.output !== "" && /* @__PURE__ */ jsx(RunOutput, { run: saved }),
276
- failed && !running && onTerminal && /* @__PURE__ */ jsxs("button", {
286
+ }) : saved && saved.output !== "" && /* @__PURE__ */ jsx(RunOutput, { run: saved }), failed && !running && onTerminal && /* @__PURE__ */ jsxs("button", {
277
287
  type: "button",
278
288
  onClick: onTerminal,
279
289
  className: "zg-run-terminal zg-meta",
@@ -281,8 +291,8 @@ function RunPanel({ code, live, saved, onAgain, onTerminal, onRemove }) {
281
291
  "aria-hidden": true,
282
292
  className: "i-ph-terminal-window"
283
293
  }), labels.blockRunNeedsTerminal]
284
- })
285
- ]
294
+ })]
295
+ })]
286
296
  });
287
297
  }
288
298
  /** A saved run's output, scrolled to its end: where a command says how it went. */
@@ -3,6 +3,7 @@ import { useDisplayPath } from "../../hooks/useDisplayPath.js";
3
3
  import { useChatLabels } from "../useChatLabels.js";
4
4
  import { useModelName } from "./actions.js";
5
5
  import { Caret, FailedMark } from "./frame.js";
6
+ import { Rolling } from "./rolling.js";
6
7
  import { AnsiText } from "./AnsiText.js";
7
8
  import { CODE_PANEL, LoadFullOutputButton, ReadFileBlock, ToolGlyph, ToolInput, ToolTiming, useFullOutput } from "./tool-parts.js";
8
9
  import { EditDiffBlock } from "./EditDiffBlock.js";
@@ -311,19 +312,34 @@ function ScriptProgressChips({ tool }) {
311
312
  "data-testid": "script-progress",
312
313
  children: [view.total !== void 0 && view.percent !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
313
314
  className: "zg-meta-chip",
314
- children: labels.scriptCallsOf(view.done, view.total)
315
+ children: /* @__PURE__ */ jsx(Rolling, {
316
+ text: labels.scriptCallsOf(view.done, view.total),
317
+ value: view.done
318
+ })
315
319
  }), /* @__PURE__ */ jsx("span", {
316
320
  className: "zg-meta-chip",
317
- children: labels.scriptPercent(view.percent)
321
+ children: /* @__PURE__ */ jsx(Rolling, {
322
+ text: labels.scriptPercent(view.percent),
323
+ value: view.percent
324
+ })
318
325
  })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
319
326
  className: "zg-meta-chip",
320
- children: labels.scriptCallsDone(view.done)
327
+ children: /* @__PURE__ */ jsx(Rolling, {
328
+ text: labels.scriptCallsDone(view.done),
329
+ value: view.done
330
+ })
321
331
  }), view.running > 0 && /* @__PURE__ */ jsx("span", {
322
332
  className: "zg-meta-chip",
323
- children: labels.scriptCallsRunning(view.running)
333
+ children: /* @__PURE__ */ jsx(Rolling, {
334
+ text: labels.scriptCallsRunning(view.running),
335
+ value: view.running
336
+ })
324
337
  })] }), view.failed > 0 && /* @__PURE__ */ jsx("span", {
325
338
  className: "zg-meta-chip text-zg-danger",
326
- children: labels.scriptCallsFailed(view.failed)
339
+ children: /* @__PURE__ */ jsx(Rolling, {
340
+ text: labels.scriptCallsFailed(view.failed),
341
+ value: view.failed
342
+ })
327
343
  })]
328
344
  });
329
345
  }
@@ -87,6 +87,8 @@ interface FileTreeProps {
87
87
  label?: string;
88
88
  /** Rename, create, drag and drop. Absent: the tree only browses. Read when the tree is created. */
89
89
  editing?: FileTreeEditing;
90
+ /** An ignored folder listed as one node was expanded (its path, without the trailing `/`). */
91
+ onExpandFolder?: (path: string) => void;
90
92
  }
91
93
  /**
92
94
  * The workspace file tree: rows from `entries`, painted with `gitStatus`, reporting selection,
@@ -94,7 +96,7 @@ interface FileTreeProps {
94
96
  *
95
97
  * @param props - The paths, git status and selection to show, and the handlers it reports to.
96
98
  */
97
- declare function FileTree({ controlRef, entries, gitStatus, selectedPath, onSelect, onOpen, onContextMenu, className, style, openPaths, label, editing }: FileTreeProps): import("react").JSX.Element;
99
+ declare function FileTree({ controlRef, entries, gitStatus, selectedPath, onSelect, onOpen, onContextMenu, className, style, openPaths, label, editing, onExpandFolder }: FileTreeProps): import("react").JSX.Element;
98
100
  /**
99
101
  * Every folder holding one of `paths` (`src/`, `src/chat/`), as tree ids.
100
102
  *
@@ -18,6 +18,10 @@ import { FileTree as FileTree$1, useFileTree } from "@pierre/trees/react";
18
18
  * (⌥ held: a copy), and files dragged in from outside the page drop onto a
19
19
  * folder. The tree shows each change at once and reports it; the host does
20
20
  * it, then hands new `entries` (or calls `control.resync` when it failed).
21
+ *
22
+ * An ignored folder listed as one node (`dist/`, `ignored`) is opened like any
23
+ * folder; the tree reports it (`onExpandFolder`) so the host can list what
24
+ * is under it and hand it in with the next `entries`.
21
25
  */
22
26
  /** The drag data type a tree row carries (its path, relative to the tree's root): what an editor takes to open it. */
23
27
  const TREE_PATH_MIME = "application/x-zidane-tree-path";
@@ -27,7 +31,7 @@ const TREE_PATH_MIME = "application/x-zidane-tree-path";
27
31
  *
28
32
  * @param props - The paths, git status and selection to show, and the handlers it reports to.
29
33
  */
30
- function FileTree({ controlRef, entries, gitStatus, selectedPath, onSelect, onOpen, onContextMenu, className, style, openPaths, label, editing }) {
34
+ function FileTree({ controlRef, entries, gitStatus, selectedPath, onSelect, onOpen, onContextMenu, className, style, openPaths, label, editing, onExpandFolder }) {
31
35
  const labels = useLabels();
32
36
  const paths = useMemo(() => entries.map((e) => e.path), [entries]);
33
37
  const editingRef = useRef(editing);
@@ -92,6 +96,30 @@ function FileTree({ controlRef, entries, gitStatus, selectedPath, onSelect, onOp
92
96
  } }
93
97
  } : {}
94
98
  });
99
+ const lazyDirs = useMemo(() => entries.filter((e) => e.ignored && e.kind === "dir" && e.path.endsWith("/")).map((e) => e.path), [entries]);
100
+ const lazyRef = useRef({
101
+ dirs: lazyDirs,
102
+ onExpandFolder
103
+ });
104
+ lazyRef.current = {
105
+ dirs: lazyDirs,
106
+ onExpandFolder
107
+ };
108
+ useEffect(() => {
109
+ const open = /* @__PURE__ */ new Set();
110
+ return model.subscribe(() => {
111
+ const { dirs, onExpandFolder: report } = lazyRef.current;
112
+ if (!report) return;
113
+ for (const path of dirs) {
114
+ const item = model.getItem(path);
115
+ if (!(item !== null && "isExpanded" in item && item.isExpanded())) open.delete(path);
116
+ else if (!open.has(path)) {
117
+ open.add(path);
118
+ report(bare(path));
119
+ }
120
+ }
121
+ });
122
+ }, [model]);
95
123
  useEffect(() => {
96
124
  if (!editable) return;
97
125
  return model.onMutation("remove", (event) => {
@@ -0,0 +1,25 @@
1
+ import { CSSProperties, ReactNode } from "react";
2
+ //#region src/components/Restricted.d.ts
3
+ /** Props for {@link Restricted}. */
4
+ interface RestrictedProps {
5
+ /** Whether this connection may not change what it wraps. */
6
+ restricted: boolean;
7
+ /** Why, short: the tooltip and the group's accessible name ("Admin only"). */
8
+ reason: string;
9
+ /** What it wraps. */
10
+ children: ReactNode;
11
+ /** Wrap inline content (a button in a row) instead of a block (a section). */
12
+ inline?: boolean;
13
+ /** Classes merged on the root while restricted. */
14
+ className?: string;
15
+ /** Inline styles on the root while restricted. */
16
+ style?: CSSProperties;
17
+ }
18
+ /**
19
+ * Renders `children` dimmed and inert, with `reason` as a tooltip, while `restricted`; else as they are.
20
+ *
21
+ * @param props - {@link RestrictedProps}.
22
+ */
23
+ declare function Restricted({ restricted, reason, children, inline, className, style }: RestrictedProps): import("react").JSX.Element;
24
+ //#endregion
25
+ export { Restricted, RestrictedProps };
@@ -0,0 +1,32 @@
1
+ import { Tooltip } from "./Tooltip.js";
2
+ import { Fragment, jsx } from "react/jsx-runtime";
3
+ //#region src/components/Restricted.tsx
4
+ /**
5
+ * Renders `children` dimmed and inert, with `reason` as a tooltip, while `restricted`; else as they are.
6
+ *
7
+ * @param props - {@link RestrictedProps}.
8
+ */
9
+ function Restricted({ restricted, reason, children, inline = false, className = "", style }) {
10
+ if (!restricted) return /* @__PURE__ */ jsx(Fragment, { children });
11
+ return /* @__PURE__ */ jsx(Tooltip, {
12
+ label: reason,
13
+ portal: true,
14
+ className: `${inline ? "" : "flex w-full"} ${className}`,
15
+ ...style ? { style } : {},
16
+ children: /* @__PURE__ */ jsx("div", {
17
+ role: "group",
18
+ tabIndex: 0,
19
+ "aria-label": reason,
20
+ "aria-disabled": true,
21
+ "data-restricted": "",
22
+ className: `zg-restricted zg-focus-ring rounded-zg-md ${inline ? "inline-flex" : "block w-full"}`,
23
+ children: /* @__PURE__ */ jsx("div", {
24
+ inert: true,
25
+ className: inline ? "inline-flex" : "block",
26
+ children
27
+ })
28
+ })
29
+ });
30
+ }
31
+ //#endregion
32
+ export { Restricted };
@@ -2,7 +2,7 @@ import { CSSProperties, ReactNode } from "react";
2
2
  //#region src/components/StepFrame.d.ts
3
3
  /** Props for {@link StepFrame}. */
4
4
  interface StepFrameProps {
5
- /** Small uppercase label above the title, such as the step's name. */
5
+ /** Small label above the title, such as the step's name. */
6
6
  eyebrow?: ReactNode;
7
7
  /** The step's question or heading. */
8
8
  title: ReactNode;
@@ -0,0 +1,28 @@
1
+ import { CSSProperties } from "react";
2
+ //#region src/components/ZidaneMark.d.ts
3
+ type Tone = 'inherit' | 'accent' | 'warn' | 'muted';
4
+ /** Props for {@link ZidaneMark}. */
5
+ interface ZidaneMarkProps {
6
+ /** Width and height in pixels. Small marks draw fewer, wider bands. @default 16 */
7
+ size?: number;
8
+ /** Loops per second; 0 holds still. @default 1.2 */
9
+ speed?: number;
10
+ /** Colour of the bands. `inherit` follows the surrounding text colour. @default 'accent' */
11
+ tone?: Tone;
12
+ /** Accessible name and tooltip. Defaults to the `working` label from {@link useLabels}. */
13
+ label?: string;
14
+ /** Hidden from assistive tech, for a mark inside an element that names the state itself. */
15
+ decorative?: boolean;
16
+ /** Extra classes on the root. */
17
+ className?: string;
18
+ /** Inline styles on the root element, merged after the component's own. */
19
+ style?: CSSProperties;
20
+ }
21
+ /**
22
+ * Renders the zidane mark, its bands flowing while `speed` is above 0 and motion is on.
23
+ *
24
+ * @param props - Component props.
25
+ */
26
+ declare function ZidaneMark({ size, speed, tone, label: labelProp, decorative, className, style }: ZidaneMarkProps): import("react").JSX.Element;
27
+ //#endregion
28
+ export { ZidaneMark, ZidaneMarkProps };
@@ -0,0 +1,114 @@
1
+ import { useLabels } from "../labels.js";
2
+ import { useReducedMotion } from "../motion/reduced.js";
3
+ import { markDetail, markEase, markFrame, markFrameIndex, markStill } from "./zidane-mark.js";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { useEffect, useMemo, useRef } from "react";
6
+ //#region src/components/ZidaneMark.tsx
7
+ /**
8
+ * The zidane mark as a live indicator: the logo's sphere, its S-shaped bands
9
+ * flowing across it. One shared animation frame loop draws every mounted
10
+ * mark (it writes the paths' `d` straight to the DOM, so nothing
11
+ * re-renders), from frames cached per detail (`zidane-mark.ts`). A mark
12
+ * starts at its full pace; a later change of `speed` eases in rather than
13
+ * jumping. Reduced or off motion shows the still mark. Bands take
14
+ * `currentColor` over a faint disk of the same tone. To spin it in and out
15
+ * with a state, wrap it in a `Presence` with `zg-mark-swap` (styles/motion.css).
16
+ */
17
+ const TONE = {
18
+ inherit: void 0,
19
+ accent: "var(--zg-accent)",
20
+ warn: "var(--zg-warn)",
21
+ muted: "var(--zg-text-muted)"
22
+ };
23
+ const live = /* @__PURE__ */ new Set();
24
+ let raf = 0;
25
+ let last = 0;
26
+ function tick(now) {
27
+ const dt = last ? Math.min(.1, (now - last) / 1e3) : 0;
28
+ last = now;
29
+ for (const mark of live) {
30
+ mark.speed += (mark.target - mark.speed) * Math.min(1, dt * 3);
31
+ mark.phase = (mark.phase + dt * mark.speed / 3) % 1;
32
+ const frame = markFrameIndex(markEase(mark.phase));
33
+ if (frame === mark.drawn) continue;
34
+ mark.drawn = frame;
35
+ const d = markFrame(mark.detail, frame);
36
+ mark.paths.forEach((path, i) => path.setAttribute("d", d[i] ?? ""));
37
+ }
38
+ raf = live.size > 0 ? requestAnimationFrame(tick) : 0;
39
+ if (!raf) last = 0;
40
+ }
41
+ /**
42
+ * Renders the zidane mark, its bands flowing while `speed` is above 0 and motion is on.
43
+ *
44
+ * @param props - Component props.
45
+ */
46
+ function ZidaneMark({ size = 16, speed = 1.2, tone = "accent", label: labelProp, decorative = false, className = "", style }) {
47
+ const labels = useLabels();
48
+ const label = labelProp ?? labels.working;
49
+ const reduced = useReducedMotion();
50
+ const detail = useMemo(() => markDetail(size), [size]);
51
+ const still = markStill(detail);
52
+ const svg = useRef(null);
53
+ const mark = useRef(null);
54
+ const moving = !reduced && speed > 0;
55
+ useEffect(() => {
56
+ const el = svg.current;
57
+ if (!moving || !el || typeof requestAnimationFrame !== "function") return void 0;
58
+ const entry = {
59
+ paths: Array.from(el.querySelectorAll("path")),
60
+ detail,
61
+ phase: 0,
62
+ speed,
63
+ target: speed,
64
+ drawn: 0
65
+ };
66
+ mark.current = entry;
67
+ live.add(entry);
68
+ if (!raf) raf = requestAnimationFrame(tick);
69
+ return () => {
70
+ live.delete(entry);
71
+ mark.current = null;
72
+ if (live.size === 0 && raf) {
73
+ cancelAnimationFrame(raf);
74
+ raf = 0;
75
+ last = 0;
76
+ }
77
+ const d = markStill(detail);
78
+ entry.paths.forEach((path, i) => path.setAttribute("d", d[i] ?? ""));
79
+ };
80
+ }, [moving, detail]);
81
+ useEffect(() => {
82
+ if (mark.current) mark.current.target = speed;
83
+ }, [speed]);
84
+ const color = TONE[tone];
85
+ return /* @__PURE__ */ jsxs("svg", {
86
+ ref: svg,
87
+ viewBox: "-1 -1 2 2",
88
+ width: size,
89
+ height: size,
90
+ ...decorative ? { "aria-hidden": true } : {
91
+ role: "img",
92
+ "aria-label": label
93
+ },
94
+ className: `block shrink-0 ${className}`,
95
+ style: {
96
+ ...color ? { color } : {},
97
+ ...style
98
+ },
99
+ children: [
100
+ !decorative && /* @__PURE__ */ jsx("title", { children: label }),
101
+ /* @__PURE__ */ jsx("circle", {
102
+ r: "1",
103
+ fill: "currentColor",
104
+ opacity: "0.18"
105
+ }),
106
+ still.map((d, i) => /* @__PURE__ */ jsx("path", {
107
+ d,
108
+ fill: "currentColor"
109
+ }, i))
110
+ ]
111
+ });
112
+ }
113
+ //#endregion
114
+ export { ZidaneMark };
@@ -49,6 +49,12 @@ type PalettePanelProps<T extends PaletteEntry = PaletteEntry> = PanelElementProp
49
49
  onBack?: () => void;
50
50
  /** The level's name, as a chip before the query. */
51
51
  title?: string;
52
+ /** The section the root search is scoped to, as a chip before the query. */
53
+ scope?: string;
54
+ /** Shift+Tab at the root: scope the search to the next section (after the last, back to every section). */
55
+ onScopeNext?: () => void;
56
+ /** Backspace on an empty query at the root while scoped: search every section again. */
57
+ onScopeClear?: () => void;
52
58
  /** Defaults to the labels' `paletteFilter`. */
53
59
  placeholder?: string;
54
60
  /** False while the rows are still for an earlier query: Enter waits for them. Default true. */
@@ -82,6 +88,6 @@ type PalettePanelProps<T extends PaletteEntry = PaletteEntry> = PanelElementProp
82
88
  *
83
89
  * @param props - {@link PalettePanelProps}.
84
90
  */
85
- declare function PalettePanel<T extends PaletteEntry>({ groups, query, onQueryChange, cursor, onCursorChange, onRun, onClose, nested, onBack, title, placeholder, settled, loading, running, notice, verb, renderRow, renderIcon, renderKeys, inputRef, className, ...rest }: PalettePanelProps<T>): import("react").JSX.Element;
91
+ declare function PalettePanel<T extends PaletteEntry>({ groups, query, onQueryChange, cursor, onCursorChange, onRun, onClose, nested, onBack, title, scope, onScopeNext, onScopeClear, placeholder, settled, loading, running, notice, verb, renderRow, renderIcon, renderKeys, inputRef, className, ...rest }: PalettePanelProps<T>): import("react").JSX.Element;
86
92
  //#endregion
87
93
  export { PaletteNotice, PalettePanel, PalettePanelProps, paletteVerb };
@@ -11,7 +11,8 @@ import { Fragment as Fragment$1, useEffect, useMemo, useRef, useState } from "re
11
11
  * desktop app's palette runs sources and nested pickers, the website opens
12
12
  * a docs page). The panel owns the keys of its input: arrows, Home / End,
13
13
  * Enter (held until the rows are for the query typed: `settled`), Escape,
14
- * and Backspace on an empty query to leave a nested level.
14
+ * Backspace on an empty query to leave a nested level or drop the section
15
+ * scope, and Shift+Tab to move the scope to the next section.
15
16
  *
16
17
  * Mount it in a layer (an `Overlay`, the app's modal slot): it brings no
17
18
  * scrim or focus trap of its own; its input takes focus on mount.
@@ -56,7 +57,7 @@ function paletteVerb(row, nested, labels) {
56
57
  *
57
58
  * @param props - {@link PalettePanelProps}.
58
59
  */
59
- function PalettePanel({ groups, query, onQueryChange, cursor, onCursorChange, onRun, onClose, nested = false, onBack, title, placeholder, settled = true, loading = false, running = false, notice, verb, renderRow, renderIcon, renderKeys = defaultPaletteKeys, inputRef, className = "zg-modal-panel zg-float w-[40rem] max-w-[92vw] self-start mt-[13vh] flex flex-col overflow-hidden", ...rest }) {
60
+ function PalettePanel({ groups, query, onQueryChange, cursor, onCursorChange, onRun, onClose, nested = false, onBack, title, scope, onScopeNext, onScopeClear, placeholder, settled = true, loading = false, running = false, notice, verb, renderRow, renderIcon, renderKeys = defaultPaletteKeys, inputRef, className = "zg-modal-panel zg-float w-[40rem] max-w-[92vw] self-start mt-[13vh] flex flex-col overflow-hidden", ...rest }) {
60
61
  const labels = useLabels();
61
62
  const flat = useMemo(() => groups.flatMap((g) => g.rows), [groups]);
62
63
  const showLoading = useLasting(loading, LOADING_LINE_AFTER_MS);
@@ -113,10 +114,22 @@ function PalettePanel({ groups, query, onQueryChange, cursor, onCursorChange, on
113
114
  if (row) onRun(row);
114
115
  return;
115
116
  }
117
+ case "Tab":
118
+ if (e.shiftKey && !nested && onScopeNext) {
119
+ e.preventDefault();
120
+ e.stopPropagation();
121
+ onScopeNext();
122
+ onCursorChange(0);
123
+ }
124
+ return;
116
125
  case "Backspace":
117
126
  if (query === "" && nested && onBack) {
118
127
  e.preventDefault();
119
128
  onBack();
129
+ } else if (query === "" && !nested && scope && onScopeClear) {
130
+ e.preventDefault();
131
+ onScopeClear();
132
+ onCursorChange(0);
120
133
  }
121
134
  return;
122
135
  }
@@ -144,6 +157,11 @@ function PalettePanel({ groups, query, onQueryChange, cursor, onCursorChange, on
144
157
  className: "zg-track-chip shrink-0 px-2.5 h-6 inline-flex items-center text-zg-label text-[var(--zg-text-muted)]",
145
158
  children: title
146
159
  }),
160
+ !nested && scope && /* @__PURE__ */ jsx("span", {
161
+ "data-testid": "palette-scope",
162
+ className: "zg-track-chip shrink-0 px-2.5 h-6 inline-flex items-center text-zg-label text-[var(--zg-text)]",
163
+ children: scope
164
+ }),
147
165
  /* @__PURE__ */ jsx("input", {
148
166
  ref: inputRef,
149
167
  autoFocus: true,
@@ -189,15 +207,23 @@ function PalettePanel({ groups, query, onQueryChange, cursor, onCursorChange, on
189
207
  }),
190
208
  /* @__PURE__ */ jsxs("div", {
191
209
  className: "flex items-center gap-4 px-4 h-9 shrink-0 shadow-[inset_0_1px_0_var(--zg-hairline)]",
192
- children: [marked && /* @__PURE__ */ jsx(PaletteHint, {
193
- keys: ["enter"],
194
- label: verb?.(marked, nested) ?? paletteVerb(marked, nested, labels),
195
- renderKeys
196
- }), nested && /* @__PURE__ */ jsx(PaletteHint, {
197
- keys: ["⌫"],
198
- label: labels.paletteBack,
199
- renderKeys
200
- })]
210
+ children: [
211
+ marked && /* @__PURE__ */ jsx(PaletteHint, {
212
+ keys: ["enter"],
213
+ label: verb?.(marked, nested) ?? paletteVerb(marked, nested, labels),
214
+ renderKeys
215
+ }),
216
+ nested && /* @__PURE__ */ jsx(PaletteHint, {
217
+ keys: ["⌫"],
218
+ label: labels.paletteBack,
219
+ renderKeys
220
+ }),
221
+ !nested && onScopeNext && /* @__PURE__ */ jsx(PaletteHint, {
222
+ keys: ["shift+tab"],
223
+ label: labels.paletteScopeHint,
224
+ renderKeys
225
+ })
226
+ ]
201
227
  }),
202
228
  notice && /* @__PURE__ */ jsx("div", {
203
229
  role: "status",
@@ -0,0 +1,52 @@
1
+ //#region src/components/zidane-mark.d.ts
2
+ /**
3
+ * The zidane mark's geometry: flat S-shaped stripes wrapped onto a sphere.
4
+ * In the flat texture a band lies between two curves
5
+ * u = c + amplitude·sin(WAVE·π·v) (v from -1 to 1)
6
+ * one and a half waves top to bottom, so each band reads as an S whose turns
7
+ * hook against the left and right rims, as in the logo (its stripe
8
+ * directions fitted to the app icon). The texture is spherized: a point at texture radius ρ lands at disk
9
+ * radius sin(ρ·π/2), so bands thin out toward the rim, and what lies past
10
+ * ρ = 1 collapses onto it. Shifting every band by one `spacing` gives the
11
+ * same picture, so a phase from 0 to 1 is one seamless loop. Coordinates are
12
+ * in the unit disk (viewBox `-1 -1 2 2`).
13
+ */
14
+ /** How finely a mark is drawn: band pitch, band share, samples per edge. */
15
+ interface MarkDetail {
16
+ /** Texture distance from one band to the next (disk radius = 1). */
17
+ spacing: number;
18
+ /** Share of `spacing` that is band; the rest is gap. */
19
+ duty: number;
20
+ /** Samples along each band edge. */
21
+ steps: number;
22
+ }
23
+ /** The detail for a mark drawn `size` pixels wide: fewer, wider bands when small, so they stay apart. */
24
+ declare function markDetail(size: number): MarkDetail;
25
+ /**
26
+ * The band paths at `phase` (0 to 1, one loop). Always the same number of
27
+ * paths for a detail; a band out of view is an empty path.
28
+ */
29
+ declare function markPaths(detail: MarkDetail, phase: number): string[];
30
+ /** Bands one swell carries: a slow surge, not a throb per band. */
31
+ declare const MARK_SWELL = 3;
32
+ /**
33
+ * Where a swell's time (0 to 1) puts the bands, in loops (0 to
34
+ * {@link MARK_SWELL}): they gather speed, peak mid-swell and settle, a
35
+ * raised-cosine bell of speed. Its mean is one loop per loop of time, so
36
+ * `speed` still counts loops per second, and a swell ends on a whole loop.
37
+ */
38
+ declare function markEase(t: number): number;
39
+ /**
40
+ * Frames kept per loop. At the fastest pace (streaming, mid-swell) a loop
41
+ * takes about a third of a second, so 96 frames is still more than a display shows:
42
+ * snapping to them is invisible, and every mark of a detail shares them.
43
+ */
44
+ declare const MARK_FRAMES = 96;
45
+ /** The frame index (0 to {@link MARK_FRAMES} - 1) a phase snaps to. */
46
+ declare function markFrameIndex(phase: number): number;
47
+ /** The band paths of frame `index` for a detail, computed once and kept. */
48
+ declare function markFrame(detail: MarkDetail, index: number): string[];
49
+ /** The still mark (phase 0) for a detail, computed once and kept. */
50
+ declare function markStill(detail: MarkDetail): string[];
51
+ //#endregion
52
+ export { MARK_FRAMES, MARK_SWELL, MarkDetail, markDetail, markEase, markFrame, markFrameIndex, markPaths, markStill };