zidane-ui 9.1.4 → 9.1.6

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 (251) hide show
  1. package/dist/adapters/server-extensions-host.js +1 -1
  2. package/dist/adapters/server-host.js +2 -1
  3. package/dist/adapters/server-machines-host.js +1 -1
  4. package/dist/adapters/server-session-host.js +87 -13
  5. package/dist/adapters/server-settings-host.js +1 -1
  6. package/dist/appearance/AppearanceProvider.js +2 -2
  7. package/dist/appearance/headless/index.js +1 -1
  8. package/dist/approvals/headless/index.js +2 -2
  9. package/dist/chat/HostTranscript.d.ts +5 -1
  10. package/dist/chat/HostTranscript.js +16 -4
  11. package/dist/chat/RunEstimateChip.d.ts +5 -3
  12. package/dist/chat/RunEstimateChip.js +33 -3
  13. package/dist/chat/Transcript.js +1 -1
  14. package/dist/chat/composer/ConversationBadges.js +16 -10
  15. package/dist/chat/composer/composer-bus.d.ts +2 -2
  16. package/dist/chat/composer/composer-bus.js +2 -2
  17. package/dist/chat/composer/use-composer-stores.js +1 -1
  18. package/dist/chat/composer/use-run-meter.js +1 -1
  19. package/dist/chat/headless/composer/conversation-badges.d.ts +8 -3
  20. package/dist/chat/headless/composer/conversation-badges.js +26 -11
  21. package/dist/chat/headless/composer/index.js +2 -2
  22. package/dist/chat/headless/composer/labels-chrome.d.ts +3 -1
  23. package/dist/chat/headless/composer/labels-chrome.js +3 -1
  24. package/dist/chat/headless/index.d.ts +6 -3
  25. package/dist/chat/headless/index.js +16 -13
  26. package/dist/chat/headless/labels.d.ts +54 -1
  27. package/dist/chat/headless/labels.js +62 -2
  28. package/dist/chat/headless/secrets.d.ts +32 -0
  29. package/dist/chat/headless/secrets.js +43 -0
  30. package/dist/chat/headless/session-list.d.ts +45 -0
  31. package/dist/chat/headless/sidebar/estimates.js +13 -1
  32. package/dist/chat/headless/sidebar/history.d.ts +71 -0
  33. package/dist/chat/headless/sidebar/history.js +174 -0
  34. package/dist/chat/headless/sidebar/index.d.ts +3 -2
  35. package/dist/chat/headless/sidebar/index.js +2 -1
  36. package/dist/chat/headless/sidebar/labels.d.ts +50 -0
  37. package/dist/chat/headless/sidebar/labels.js +1 -0
  38. package/dist/chat/headless/sidebar/query.d.ts +2 -2
  39. package/dist/chat/headless/sidebar/query.js +6 -3
  40. package/dist/chat/headless/sidebar/types.d.ts +7 -1
  41. package/dist/chat/headless/sidebar/view.js +2 -0
  42. package/dist/chat/headless/transcript/auth-failure.d.ts +67 -0
  43. package/dist/chat/headless/transcript/auth-failure.js +87 -0
  44. package/dist/chat/headless/transcript/index.d.ts +2 -1
  45. package/dist/chat/headless/transcript/index.js +2 -1
  46. package/dist/chat/headless/transcript/nesting.d.ts +3 -3
  47. package/dist/chat/headless/transcript/nesting.js +12 -4
  48. package/dist/chat/index.d.ts +4 -2
  49. package/dist/chat/index.js +3 -1
  50. package/dist/chat/interactions/InboxPanel.d.ts +6 -2
  51. package/dist/chat/interactions/InboxPanel.js +82 -44
  52. package/dist/chat/interactions/PlanCard.d.ts +2 -2
  53. package/dist/chat/interactions/PlanCard.js +1 -1
  54. package/dist/chat/interactions/QuestionField.d.ts +8 -3
  55. package/dist/chat/interactions/QuestionField.js +89 -8
  56. package/dist/chat/interactions/QuestionForm.d.ts +3 -1
  57. package/dist/chat/interactions/QuestionForm.js +48 -10
  58. package/dist/chat/interactions/SecretInput.d.ts +32 -0
  59. package/dist/chat/interactions/SecretInput.js +72 -0
  60. package/dist/chat/interactions/card-ui.d.ts +5 -3
  61. package/dist/chat/interactions/card-ui.js +5 -3
  62. package/dist/chat/interactions/index.d.ts +2 -1
  63. package/dist/chat/interactions/index.js +2 -1
  64. package/dist/chat/sidebar/SessionSidebar.js +2 -0
  65. package/dist/chat/sidebar/SidebarFilterMenu.d.ts +7 -2
  66. package/dist/chat/sidebar/SidebarFilterMenu.js +26 -2
  67. package/dist/chat/sidebar/SidebarSessionRow.d.ts +3 -1
  68. package/dist/chat/sidebar/SidebarSessionRow.js +8 -3
  69. package/dist/chat/sidebar/sidebar-live.js +8 -4
  70. package/dist/chat/transcript/AuthFailureCard.d.ts +34 -0
  71. package/dist/chat/transcript/AuthFailureCard.js +358 -0
  72. package/dist/chat/transcript/InteractionToolBody.js +12 -2
  73. package/dist/chat/transcript/actions.d.ts +24 -1
  74. package/dist/chat/transcript/index.d.ts +3 -2
  75. package/dist/chat/transcript/index.js +2 -1
  76. package/dist/chat/transcript/notices.d.ts +2 -1
  77. package/dist/chat/transcript/notices.js +13 -1
  78. package/dist/chat/transcript/script-input.d.ts +1 -1
  79. package/dist/chat/transcript/shell-block.js +1 -1
  80. package/dist/components/HowItWorks.d.ts +8 -1
  81. package/dist/components/HowItWorks.js +2 -2
  82. package/dist/components/RowActionsMenu.d.ts +6 -1
  83. package/dist/components/RowActionsMenu.js +4 -0
  84. package/dist/core.css +24 -0
  85. package/dist/dist/{index-WlE93Q6d.d.ts → index-DqCio7Nd.d.ts} +36 -3
  86. package/dist/dist/index-f-XWIoYo.d.ts +1 -0
  87. package/dist/dist/index.d.ts +6 -0
  88. package/dist/dist/sandbox-B4OW6oNx.d.ts +2 -0
  89. package/dist/dist/timeout-B5pO5I5a.d.ts +30 -0
  90. package/dist/extensions/ExtensionSettingsPage.js +1 -1
  91. package/dist/extensions/ExtensionSettingsSidebar.js +1 -1
  92. package/dist/extensions/headless/fixture-host.js +1 -1
  93. package/dist/extensions/headless/index.js +4 -4
  94. package/dist/extensions/hooks.js +1 -1
  95. package/dist/files/DiffsTab.js +1 -1
  96. package/dist/files/EditorColumn.js +1 -1
  97. package/dist/files/MediaDiff.js +1 -1
  98. package/dist/files/SearchPanel.js +121 -53
  99. package/dist/files/headless/name-match.js +29 -14
  100. package/dist/files/useEntryActions.js +1 -1
  101. package/dist/files/useOpenFiles.js +1 -1
  102. package/dist/git/WherePicker.js +2 -2
  103. package/dist/git/headless/environment.d.ts +6 -1
  104. package/dist/git/headless/environment.js +5 -2
  105. package/dist/git/headless/labels.d.ts +2 -0
  106. package/dist/git/headless/labels.js +2 -0
  107. package/dist/git/index.d.ts +2 -1
  108. package/dist/git/index.js +2 -1
  109. package/dist/git/useStartFromPanel.d.ts +22 -0
  110. package/dist/git/useStartFromPanel.js +91 -0
  111. package/dist/keybindings/KeyCommands.js +1 -1
  112. package/dist/keybindings/KeybindingsProvider.js +1 -1
  113. package/dist/keybindings/headless/catalog.d.ts +1 -1
  114. package/dist/keybindings/headless/catalog.js +14 -2
  115. package/dist/keybindings/headless/index.js +2 -2
  116. package/dist/keybindings/headless/key-scope.d.ts +4 -2
  117. package/dist/keybindings/headless/key-scope.js +17 -2
  118. package/dist/keybindings/headless/overrides.js +1 -1
  119. package/dist/machines/HostSyncPanel.js +1 -1
  120. package/dist/machines/SyncOutcomeBadge.js +1 -1
  121. package/dist/machines/headless/index.js +1 -1
  122. package/dist/onboarding/demos/features.d.ts +9 -1
  123. package/dist/onboarding/demos/features.js +107 -2
  124. package/dist/onboarding/demos/how-it-works.d.ts +5 -1
  125. package/dist/onboarding/demos/how-it-works.js +120 -2
  126. package/dist/onboarding/demos/index.js +1 -1
  127. package/dist/onboarding/headless/labels.d.ts +17 -0
  128. package/dist/onboarding/headless/labels.js +17 -0
  129. package/dist/onboarding/index.js +4 -4
  130. package/dist/onboarding/marks.d.ts +1 -2
  131. package/dist/onboarding/marks.js +4 -12
  132. package/dist/onboarding/steps/ConnectorsStep.js +1 -1
  133. package/dist/onboarding/steps/ReadyStep.js +1 -1
  134. package/dist/onboarding/steps/SkillsStep.js +1 -1
  135. package/dist/onboarding/steps/connect/ProviderPanel.js +1 -1
  136. package/dist/onboarding/tutorials.d.ts +3 -1
  137. package/dist/onboarding/tutorials.js +2 -1
  138. package/dist/palette/app-sources.js +1 -1
  139. package/dist/palette/headless/app-sources.js +10 -0
  140. package/dist/palette/headless/labels.js +2 -0
  141. package/dist/session/ArtifactsPanel.js +1 -1
  142. package/dist/session/PanelAttention.d.ts +14 -6
  143. package/dist/session/PanelAttention.js +35 -24
  144. package/dist/session/PlanTracker.d.ts +54 -0
  145. package/dist/session/PlanTracker.js +413 -0
  146. package/dist/session/ProjectHome.d.ts +15 -2
  147. package/dist/session/ProjectHome.js +158 -85
  148. package/dist/session/RemindersPanel.d.ts +25 -0
  149. package/dist/session/RemindersPanel.js +526 -0
  150. package/dist/session/SecretsPanel.d.ts +19 -0
  151. package/dist/session/SecretsPanel.js +241 -0
  152. package/dist/session/SessionProvider.d.ts +26 -5
  153. package/dist/session/SessionProvider.js +51 -6
  154. package/dist/session/StepStatusIcon.d.ts +24 -0
  155. package/dist/session/StepStatusIcon.js +50 -0
  156. package/dist/session/TodoList.d.ts +4 -3
  157. package/dist/session/TodoList.js +6 -5
  158. package/dist/session/headless/fixture-host.d.ts +32 -22
  159. package/dist/session/headless/fixture-host.js +86 -51
  160. package/dist/session/headless/fixture-plans.d.ts +57 -0
  161. package/dist/session/headless/fixture-plans.js +141 -0
  162. package/dist/session/headless/fixture-schedules.d.ts +49 -0
  163. package/dist/session/headless/fixture-schedules.js +133 -0
  164. package/dist/session/headless/home-layout.d.ts +10 -2
  165. package/dist/session/headless/home-layout.js +7 -2
  166. package/dist/session/headless/host.d.ts +85 -13
  167. package/dist/session/headless/index.d.ts +5 -3
  168. package/dist/session/headless/index.js +5 -3
  169. package/dist/session/headless/labels.d.ts +95 -12
  170. package/dist/session/headless/labels.js +67 -18
  171. package/dist/session/headless/plans.d.ts +53 -0
  172. package/dist/session/headless/plans.js +78 -0
  173. package/dist/session/headless/reminder-labels.d.ts +63 -0
  174. package/dist/session/headless/reminder-labels.js +84 -0
  175. package/dist/session/headless/schedules.d.ts +93 -0
  176. package/dist/session/headless/schedules.js +190 -0
  177. package/dist/session/headless/secrets.d.ts +28 -0
  178. package/dist/session/headless/secrets.js +48 -0
  179. package/dist/session/index.d.ts +7 -5
  180. package/dist/session/index.js +6 -4
  181. package/dist/session/testing/contract.d.ts +18 -5
  182. package/dist/session/testing/contract.js +351 -43
  183. package/dist/session/testing/index.d.ts +4 -2
  184. package/dist/session/testing/index.js +4 -2
  185. package/dist/settings/headless/catalog.js +17 -1
  186. package/dist/settings/headless/index.d.ts +2 -2
  187. package/dist/settings/headless/index.js +3 -3
  188. package/dist/settings/headless/labels.d.ts +0 -2
  189. package/dist/settings/headless/labels.js +0 -2
  190. package/dist/settings/headless/layout.js +7 -1
  191. package/dist/settings/headless/providers.d.ts +17 -1
  192. package/dist/settings/headless/providers.js +19 -1
  193. package/dist/settings/headless/search.d.ts +1 -1
  194. package/dist/settings/rows.d.ts +1 -1
  195. package/dist/settings/rows.js +2 -2
  196. package/dist/settings/sections/appearance/AppearanceSection.js +2 -2
  197. package/dist/settings/sections/claude-import/ClaudeImportDialog.js +1 -1
  198. package/dist/settings/sections/editor/EditorSection.js +1 -1
  199. package/dist/settings/sections/environments/EnvironmentsSection.js +1 -1
  200. package/dist/settings/sections/extensions/ChangeOriginDialog.js +1 -1
  201. package/dist/settings/sections/extensions/CreateExtensionDialog.js +1 -1
  202. package/dist/settings/sections/extensions/ExtensionsSection.js +1 -1
  203. package/dist/settings/sections/host-catalog/HostCatalogSection.js +1 -1
  204. package/dist/settings/sections/instructions/InstructionsSection.js +1 -1
  205. package/dist/settings/sections/keybindings/labels.d.ts +2 -0
  206. package/dist/settings/sections/keybindings/labels.js +2 -0
  207. package/dist/settings/sections/keybindings/rows.js +8 -0
  208. package/dist/settings/sections/mcp/McpSection.js +1 -1
  209. package/dist/settings/sections/mcp/McpServerRow.js +1 -1
  210. package/dist/settings/sections/models/ModelRows.js +2 -2
  211. package/dist/settings/sections/providers/ProvidersSection.js +209 -201
  212. package/dist/settings/sections/providers/ServerProvidersSection.js +1 -1
  213. package/dist/settings/sections/shared/catalog.js +1 -1
  214. package/dist/settings/sections/skills/SkillList.js +1 -1
  215. package/dist/settings/sections/skills/SkillsSection.js +2 -2
  216. package/dist/styles.css +59 -1
  217. package/dist/terminal/HostTerminalSurface.js +2 -2
  218. package/dist/workspace/PanelContentView.d.ts +22 -4
  219. package/dist/workspace/PanelContentView.js +112 -16
  220. package/dist/workspace/PanelGlyph.d.ts +21 -0
  221. package/dist/workspace/PanelGlyph.js +33 -0
  222. package/dist/workspace/PanelHome.js +5 -3
  223. package/dist/workspace/PanelStrip.js +11 -4
  224. package/dist/workspace/PanelToolbar.d.ts +32 -0
  225. package/dist/workspace/PanelToolbar.js +194 -0
  226. package/dist/workspace/WorkspaceProvider.d.ts +3 -1
  227. package/dist/workspace/WorkspaceProvider.js +6 -2
  228. package/dist/workspace/extension-tabs.js +5 -2
  229. package/dist/workspace/headless/host.d.ts +4 -0
  230. package/dist/workspace/headless/index.d.ts +3 -1
  231. package/dist/workspace/headless/index.js +4 -2
  232. package/dist/workspace/headless/labels.d.ts +10 -0
  233. package/dist/workspace/headless/labels.js +11 -1
  234. package/dist/workspace/headless/pages.d.ts +15 -0
  235. package/dist/workspace/headless/pages.js +49 -0
  236. package/dist/workspace/headless/tab-mark.d.ts +14 -0
  237. package/dist/workspace/headless/tab-mark.js +27 -0
  238. package/dist/workspace/headless/view.d.ts +7 -1
  239. package/dist/workspace/index.d.ts +3 -2
  240. package/dist/workspace/index.js +3 -2
  241. package/dist/workspace/testing/index.js +6 -0
  242. package/dist/workspace/workspace-key-commands.js +3 -3
  243. package/package.json +2 -2
  244. package/src/styles/motion.css +13 -0
  245. package/src/styles/onboarding.css +0 -1
  246. package/src/styles/primitives.css +10 -0
  247. package/src/styles/workspace.css +17 -0
  248. package/dist/session/TodosPanel.d.ts +0 -19
  249. package/dist/session/TodosPanel.js +0 -251
  250. package/dist/session/headless/todos.d.ts +0 -22
  251. package/dist/session/headless/todos.js +0 -38
@@ -248,6 +248,10 @@ function ActionRow({ item, divider, expanded, onPoint, onPick }) {
248
248
  role: "menuitem",
249
249
  size: "sm",
250
250
  title: item.label,
251
+ icon: typeof item.icon === "string" ? /* @__PURE__ */ jsx("span", {
252
+ "aria-hidden": true,
253
+ className: item.icon
254
+ }) : item.icon,
251
255
  "data-item": item.id,
252
256
  destructive: item.destructive,
253
257
  disabled: item.disabled || item.items !== void 0 && item.items.length === 0,
package/dist/core.css CHANGED
@@ -24,6 +24,7 @@
24
24
  .i-ph-planet{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 256 256' height='1em' width='1em' display='inline-block' vertical-align='middle' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='currentColor' d='M245.11 60.68c-7.65-13.19-27.84-16.16-58.5-8.66A95.93 95.93 0 0 0 32 128a98 98 0 0 0 .78 12.31C5.09 169 5.49 186 10.9 195.32C16 204.16 26.64 208 40.64 208a124 124 0 0 0 28.79-4A95.93 95.93 0 0 0 224 128a97 97 0 0 0-.77-12.25c12.5-13 20.82-25.35 23.65-35.92c1.95-7.32 1.36-13.76-1.77-19.15M128 48a80.11 80.11 0 0 1 78 62.2c-17.06 16.06-40.15 32.53-62.07 45.13c-27.55 15.81-51.45 25.67-70.51 31.07A79.94 79.94 0 0 1 128 48M24.74 187.29c-1.46-2.51-.65-7.24 2.22-13a79 79 0 0 1 10.29-15.05a96 96 0 0 0 18 31.32c-17.25 2.9-28.01 1.05-30.51-3.27M128 208a79.45 79.45 0 0 1-38.56-9.94a370 370 0 0 0 62.43-28.86c21.58-12.39 40.68-25.82 56.07-39.08A80.07 80.07 0 0 1 128 208M231.42 75.69c-1.7 6.31-6.19 13.53-12.63 21.13a95.7 95.7 0 0 0-18-31.35c14.21-2.35 27.37-2.17 30.5 3.24c.9 1.57.95 3.92.13 6.98'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;height:1em;width:1em;display:inline-block;vertical-align:middle;}
25
25
  .i-ph-sidebar-simple{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 256 256' height='1em' width='1em' display='inline-block' vertical-align='middle' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='currentColor' d='M216 40H40a16 16 0 0 0-16 16v144a16 16 0 0 0 16 16h176a16 16 0 0 0 16-16V56a16 16 0 0 0-16-16M40 56h40v144H40Zm176 144H96V56h120z'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;height:1em;width:1em;display:inline-block;vertical-align:middle;}
26
26
  .i-ph-squares-four{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 256 256' height='1em' width='1em' display='inline-block' vertical-align='middle' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='currentColor' d='M104 40H56a16 16 0 0 0-16 16v48a16 16 0 0 0 16 16h48a16 16 0 0 0 16-16V56a16 16 0 0 0-16-16m0 64H56V56h48zm96-64h-48a16 16 0 0 0-16 16v48a16 16 0 0 0 16 16h48a16 16 0 0 0 16-16V56a16 16 0 0 0-16-16m0 64h-48V56h48zm-96 32H56a16 16 0 0 0-16 16v48a16 16 0 0 0 16 16h48a16 16 0 0 0 16-16v-48a16 16 0 0 0-16-16m0 64H56v-48h48zm96-64h-48a16 16 0 0 0-16 16v48a16 16 0 0 0 16 16h48a16 16 0 0 0 16-16v-48a16 16 0 0 0-16-16m0 64h-48v-48h48z'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;height:1em;width:1em;display:inline-block;vertical-align:middle;}
27
+ .i-ph-terminal-window{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 256 256' height='1em' width='1em' display='inline-block' vertical-align='middle' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='currentColor' d='M128 128a8 8 0 0 1-3 6.25l-40 32a8 8 0 1 1-10-12.5L107.19 128L75 102.25a8 8 0 1 1 10-12.5l40 32a8 8 0 0 1 3 6.25m48 24h-40a8 8 0 0 0 0 16h40a8 8 0 0 0 0-16m56-96v144a16 16 0 0 1-16 16H40a16 16 0 0 1-16-16V56a16 16 0 0 1 16-16h176a16 16 0 0 1 16 16m-16 144V56H40v144z'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;height:1em;width:1em;display:inline-block;vertical-align:middle;}
27
28
  .i-ph-text-align-left{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 256 256' height='1em' width='1em' display='inline-block' vertical-align='middle' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='currentColor' d='M32 64a8 8 0 0 1 8-8h176a8 8 0 0 1 0 16H40a8 8 0 0 1-8-8m8 48h128a8 8 0 0 0 0-16H40a8 8 0 0 0 0 16m176 24H40a8 8 0 0 0 0 16h176a8 8 0 0 0 0-16m-48 40H40a8 8 0 0 0 0 16h128a8 8 0 0 0 0-16'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;height:1em;width:1em;display:inline-block;vertical-align:middle;}
28
29
  .i-ph-warning{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 256 256' height='1em' width='1em' display='inline-block' vertical-align='middle' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='currentColor' d='M236.8 188.09L149.35 36.22a24.76 24.76 0 0 0-42.7 0L19.2 188.09a23.51 23.51 0 0 0 0 23.72A24.35 24.35 0 0 0 40.55 224h174.9a24.35 24.35 0 0 0 21.33-12.19a23.51 23.51 0 0 0 .02-23.72m-13.87 15.71a8.5 8.5 0 0 1-7.48 4.2H40.55a8.5 8.5 0 0 1-7.48-4.2a7.59 7.59 0 0 1 0-7.72l87.45-151.87a8.75 8.75 0 0 1 15 0l87.45 151.87a7.59 7.59 0 0 1-.04 7.72M120 144v-40a8 8 0 0 1 16 0v40a8 8 0 0 1-16 0m20 36a12 12 0 1 1-12-12a12 12 0 0 1 12 12'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;height:1em;width:1em;display:inline-block;vertical-align:middle;}
29
30
  .i-ph-warning-circle{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 256 256' height='1em' width='1em' display='inline-block' vertical-align='middle' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='currentColor' d='M128 24a104 104 0 1 0 104 104A104.11 104.11 0 0 0 128 24m0 192a88 88 0 1 1 88-88a88.1 88.1 0 0 1-88 88m-8-80V80a8 8 0 0 1 16 0v56a8 8 0 0 1-16 0m20 36a12 12 0 1 1-12-12a12 12 0 0 1 12 12'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;height:1em;width:1em;display:inline-block;vertical-align:middle;}
@@ -1142,6 +1143,16 @@ html[data-motion='off'] {
1142
1143
  var(--zg-shadow-well),
1143
1144
  0 0 0 3px color-mix(in oklab, var(--zg-ring) 18%, transparent);
1144
1145
  }
1146
+ /* A well whose value is wrong: the danger edge, focused or not. */
1147
+ .zg-well[aria-invalid='true'] {
1148
+ border-color: color-mix(in oklab, var(--zg-danger) 70%, transparent);
1149
+ }
1150
+ .zg-well[aria-invalid='true']:focus,
1151
+ .zg-well[aria-invalid='true']:focus-within {
1152
+ box-shadow:
1153
+ var(--zg-shadow-well),
1154
+ 0 0 0 3px color-mix(in oklab, var(--zg-danger) 18%, transparent);
1155
+ }
1145
1156
  /* A file dragged over a well that takes it (focused or not). */
1146
1157
  .zg-well[data-drop] {
1147
1158
  border-color: var(--zg-accent);
@@ -1991,6 +2002,19 @@ html[data-motion='reduced'] :is(.animate-spin, .zg-spin-ring, .zg-sendstop-ring)
1991
2002
  animation: zg-sendstop-rotate 800ms linear infinite;
1992
2003
  }
1993
2004
 
2005
+ /* --- Step status icon (`StepStatusIcon`) ----------------------------------
2006
+ * A `.zg-swap` whose layers centre their glyph (the spin ring is a fixed
2007
+ * 12px box, the others are 1em glyphs). The layer that lands after a change
2008
+ * pops in on `snap`, its opacity on the swap's `fade`; the pop sits on the
2009
+ * layer so the ring inside keeps its own rotation. */
2010
+ .zg-step-icon-layer {
2011
+ display: grid;
2012
+ place-items: center;
2013
+ }
2014
+ .zg-step-icon-layer[data-landed] {
2015
+ animation: zg-pop var(--zg-motion-snap) both;
2016
+ }
2017
+
1994
2018
  @keyframes zg-sendstop-rotate {
1995
2019
  to {
1996
2020
  transform: rotate(360deg);
@@ -6,7 +6,7 @@ import "../node_modules/.bun/@earendil-works_pi-ai@1.3.0_bff1df87cb190f90/node_m
6
6
  import "../node_modules/.bun/@anthropic-ai_sdk@0.104.2_fff7ddf946fac095/node_modules/@anthropic-ai/sdk/index.js";
7
7
  import "../node_modules/.bun/@anthropic-ai_sdk@0.104.2_fff7ddf946fac095/node_modules/@anthropic-ai/sdk/resources2.js";
8
8
  import { ReactNode } from "react";
9
- //#region ../dist/index-WlE93Q6d.d.ts
9
+ //#region ../dist/index-DqCio7Nd.d.ts
10
10
  //#endregion
11
11
  //#region src/thinking-levels.d.ts
12
12
  /**
@@ -141,6 +141,20 @@ interface ScriptProgress {
141
141
  ended?: 'ok' | 'error';
142
142
  }
143
143
  //#endregion
144
+ //#region src/chat/secrets/protocol.d.ts
145
+ /**
146
+ * Secret requests: the pure shapes shared by the `ask_user` tool, the host,
147
+ * and every client that renders a `secret` question.
148
+ *
149
+ * The value a person types travels once, from the client to the host, as a
150
+ * {@link SecretAnswer}. The host writes it to the secret store and replaces
151
+ * it with a {@link SecretReference} before the response reaches anything
152
+ * that records it: the tool result, the durable journal, signals, traces.
153
+ * The model only ever reads the reference.
154
+ */
155
+ /** How long a secret stays in the store. `never` keeps it until the user revokes it. */
156
+ type SecretTtl = '1h' | '24h' | '7d' | 'never';
157
+ //#endregion
144
158
  //#region src/chat/session-query/types.d.ts
145
159
  /**
146
160
  * The types of the session query: a declarative filter, sort, grouping
@@ -161,7 +175,7 @@ type QueryBound = number | string;
161
175
  * session without an environment. `projectName` is computed: the folder name
162
176
  * (last path segment) of `projectRoot`, or of `cwd` without one.
163
177
  */
164
- type SessionFieldName = 'id' | 'title' | 'projectRoot' | 'projectName' | 'cwd' | 'agentId' | 'status' | 'createdAt' | 'updatedAt' | 'runStartedAt' | 'archived' | 'favorite' | 'isMain' | 'spaceId' | 'providerKey' | 'modelId' | 'account' | 'effort' | 'hostId' | 'repoKey' | 'environment.kind' | 'environment.state' | 'environment.branch';
178
+ type SessionFieldName = 'id' | 'title' | 'projectRoot' | 'projectName' | 'cwd' | 'agentId' | 'status' | 'createdAt' | 'updatedAt' | 'runStartedAt' | 'archived' | 'favorite' | 'isMain' | 'spaceId' | 'scheduleId' | 'providerKey' | 'modelId' | 'account' | 'effort' | 'hostId' | 'repoKey' | 'environment.kind' | 'environment.state' | 'environment.branch';
165
179
  /**
166
180
  * A facet an extension computes for each session: `facet.<extensionId>.<key>`,
167
181
  * optionally followed by `.<property>` steps into an object value (a number
@@ -464,6 +478,17 @@ interface Settings {
464
478
  * history. Off by default — nothing is created, pinned, or bound until on.
465
479
  */
466
480
  orchestration: boolean;
481
+ /**
482
+ * Schedules: prompts and extension handlers that run at a set time (a
483
+ * reminder fires once). Off by default: no timer runs and nothing is read
484
+ * until on. See docs/SCHEDULES.md.
485
+ */
486
+ schedules: boolean;
487
+ /**
488
+ * The agent's `schedule` tool, while `schedules` is on. On by default, so
489
+ * turning on Schedules gives the agent the tool until you turn this off.
490
+ */
491
+ schedulesAgent: boolean;
467
492
  /**
468
493
  * Run extensions discovered under `<project>/.zidane/extensions`
469
494
  * (project-scoped). Off by default — project extensions execute
@@ -534,6 +559,14 @@ interface Settings {
534
559
  * `/side` sessions; a change rebuilds live agents. Default: on.
535
560
  */
536
561
  webSearch: boolean;
562
+ /**
563
+ * Let the agent ask for secrets (API keys, tokens) with a `secret`
564
+ * question in `ask_user`. The value goes to a private file per project,
565
+ * never into the chat; commands read it at `$ZIDANE_SECRETS/NAME`, and
566
+ * tool output shows it as `[secret:NAME]`. A change rebuilds live agents.
567
+ * See `docs/INTERACTIONS.md` § Secrets. Default: off.
568
+ */
569
+ secrets: boolean;
537
570
  /**
538
571
  * Default model of `generate_image`, as `"providerKey/modelId"`
539
572
  * (e.g. `"openrouter/google/gemini-3-pro-image"`). Empty string = the first
@@ -1449,4 +1482,4 @@ interface Settings {
1449
1482
  activeIcon: string;
1450
1483
  }
1451
1484
  //#endregion
1452
- export { SpaceIcon as Cf, ScriptOutputLine as IC, EnvironmentSettings as IT, ScriptProgress as LC, ScriptCallStatus as MC, ScriptLineProgress as NC, DurabilityMode as OE, Space as Sf, ThinkingLevel as TL, OutputLine as XC, ApprovalMode as Xd, OutputStream as ZC, EditDiffDisplay as Zd, SessionQueryNot as _b, SessionFieldName as ab, OpenInTarget as af, SessionGroupBy as cb, SessionQuery as db, EnvironmentConfigValue as eE, AnsiColor as ew, SessionQueryAll as fb, Settings as ff, TranscriptDensity as gf, ToolCallDisplay as hf, SessionCondition as ib, SessionGroupOrder as lb, QueryBound as nb, InteractionMode as nf, AnsiSpan as nw, SessionFieldPath as ob, SessionQueryAny as pb, QueryValue as rb, AnsiStyle as rw, FacetPath as tb, SessionSort as yb };
1485
+ export { ScriptCallStatus as Bw, Space as Cf, SessionSort as Eb, ThinkingLevel as FR, ScriptProgress as Gw, DurabilityMode as LD, EditDiffDisplay as Qd, ScriptLineProgress as Vw, SecretTtl as WC, EnvironmentSettings as WE, ScriptOutputLine as Ww, ApprovalMode as Zd, TranscriptDensity as _f, OutputStream as aT, SessionQueryAny as bb, AnsiColor as cT, FacetPath as cb, AnsiStyle as dT, SessionCondition as db, SessionFieldName as fb, SessionGroupOrder as gb, ToolCallDisplay as gf, SessionGroupBy as hb, OutputLine as iT, EnvironmentConfigValue as lD, QueryBound as lb, OpenInTarget as of, SessionFieldPath as pb, Settings as pf, InteractionMode as rf, AnsiSpan as uT, QueryValue as ub, SessionQuery as vb, SessionQueryNot as wb, SpaceIcon as wf, SessionQueryAll as yb };
@@ -0,0 +1 @@
1
+ import "./types-2HrgolQz.js";
@@ -0,0 +1,6 @@
1
+ import { d as AuthFailureKind, u as AuthFailure } from "./timeout-B5pO5I5a.js";
2
+ import "./types-2HrgolQz.js";
3
+ import "./oauth-callback-page-DMxIgurj.js";
4
+ import { Eb as SessionSort, FR as ThinkingLevel, bb as SessionQueryAny, cb as FacetPath, db as SessionCondition, fb as SessionFieldName, gb as SessionGroupOrder, hb as SessionGroupBy, lb as QueryBound, pb as SessionFieldPath, ub as QueryValue, vb as SessionQuery, wb as SessionQueryNot, yb as SessionQueryAll } from "./index-DqCio7Nd.js";
5
+ import "./index-f-XWIoYo.js";
6
+ import "./sandbox-B4OW6oNx.js";
@@ -0,0 +1,2 @@
1
+ import "./types-2HrgolQz.js";
2
+ import "node:buffer";
@@ -0,0 +1,30 @@
1
+ //#region ../dist/timeout-B5pO5I5a.d.ts
2
+ /**
3
+ * Why a sign-in stopped working:
4
+ * - `expired`: the refresh failed for a reason that signing in again fixes.
5
+ * - `revoked`: the grant was revoked or rejected (`invalid_grant`).
6
+ * - `missing`: no credential is stored (or the pinned account is gone).
7
+ * - `busy`: another process holds the refresh lock and has not let go.
8
+ * - `network`: the refresh could not reach the provider; retrying may do.
9
+ * - `rejected`: the provider refused the credential it was sent (a 401).
10
+ */
11
+ type AuthFailureKind = 'expired' | 'revoked' | 'missing' | 'busy' | 'network' | 'rejected';
12
+ /** Which sign-in failed, enough for a surface to offer fixing it. JSON-safe: it is persisted with the run. */
13
+ interface AuthFailure {
14
+ /** Why it failed. */
15
+ kind: AuthFailureKind;
16
+ /** What signs in: a model provider, an MCP server, an integration. */
17
+ source: 'provider' | 'mcp' | 'integration';
18
+ /** The provider name as the provider calls itself (`anthropic`, `openai`), or the server / integration name. */
19
+ provider: string;
20
+ /** Credentials key / OAuth flow id (`anthropic`, `openai-codex`), when it differs from nothing else; absent for a 401 the loop classified. */
21
+ providerId?: string;
22
+ /** Stable id of the account that failed, when the credential has one. */
23
+ accountId?: string;
24
+ /** That account's name, when it has one. */
25
+ accountLabel?: string;
26
+ /** `busy`: the pid holding the refresh lock, when it is on this host. */
27
+ holderPid?: number;
28
+ }
29
+ //#endregion
30
+ export { AuthFailureKind as d, AuthFailure as u };
@@ -1,8 +1,8 @@
1
1
  import { constant, useReadable } from "../chat/headless/store.js";
2
+ import { extensionsErrorOf } from "./headless/host.js";
2
3
  import { useExtensionsLabels } from "./useExtensionsLabels.js";
3
4
  import { ExtensionComponent } from "./ExtensionComponent.js";
4
5
  import { useExtensionItems, useExtensionsHost } from "./ExtensionsProvider.js";
5
- import { extensionsErrorOf } from "./headless/host.js";
6
6
  import { settingsValues } from "./headless/select.js";
7
7
  import { SettingsWireForm } from "./SettingsWireForm.js";
8
8
  import { jsx } from "react/jsx-runtime";
@@ -1,9 +1,9 @@
1
1
  import { Tray } from "../components/Surface.js";
2
2
  import { ROW_BUTTON_CLASS, RowText } from "../components/Form.js";
3
3
  import { constant, useReadable } from "../chat/headless/store.js";
4
+ import { extensionsErrorOf } from "./headless/host.js";
4
5
  import { useExtensionsLabels } from "./useExtensionsLabels.js";
5
6
  import { useExtensionsHost } from "./ExtensionsProvider.js";
6
- import { extensionsErrorOf } from "./headless/host.js";
7
7
  import { settingsValues } from "./headless/select.js";
8
8
  import { SettingsPanel, SettingsPanelBody, useSettingsSection } from "../settings/section.js";
9
9
  import { SettingsWireForm } from "./SettingsWireForm.js";
@@ -1,7 +1,7 @@
1
1
  import { writable } from "../../chat/headless/store.js";
2
- import { ExtensionsHostError } from "./host.js";
3
2
  import { createDialogQueue } from "./dialog-queue.js";
4
3
  import { createUiEffectChannel } from "./effect-channel.js";
4
+ import { ExtensionsHostError } from "./host.js";
5
5
  import { EXTENSION_TOKENS } from "./wire.js";
6
6
  //#region src/extensions/headless/fixture-host.ts
7
7
  /**
@@ -1,10 +1,10 @@
1
+ import { createDialogQueue } from "./dialog-queue.js";
2
+ import { createUiEffectChannel } from "./effect-channel.js";
3
+ import { ExtensionsHostError, extensionsErrorOf } from "./host.js";
4
+ import { EXTENSION_TOKENS, SLOT_NAMES } from "./wire.js";
1
5
  import { createEffectRouter } from "./effect-router.js";
2
6
  import { DEFAULT_EXTENSIONS_LABELS } from "./labels.js";
3
- import { ExtensionsHostError, extensionsErrorOf } from "./host.js";
4
7
  import { WEBVIEW_RPC_NOT_ALLOWED, WEBVIEW_RPC_REQUEST, WEBVIEW_RPC_RESULT, WEBVIEW_RPC_UNAVAILABLE, createWebviewRpcBridge, isWebviewRpcRequest } from "./webview-bridge.js";
5
8
  import { openInNewTab, routeLink } from "./links.js";
6
9
  import { TITLEBAR_ITEMS_PER_EXTENSION, clampSettingNumber, filterSelectOptions, groupSelectOptions, isSettingLocked, missingScope, qualifyPanelId, rendererMatches, renderersFor, settingValue, settingsValues, slotIsActionable, slotItems, titlebarItems } from "./select.js";
7
- import { createDialogQueue } from "./dialog-queue.js";
8
- import { createUiEffectChannel } from "./effect-channel.js";
9
- import { EXTENSION_TOKENS, SLOT_NAMES } from "./wire.js";
10
10
  export { DEFAULT_EXTENSIONS_LABELS, EXTENSION_TOKENS, ExtensionsHostError, SLOT_NAMES, TITLEBAR_ITEMS_PER_EXTENSION, WEBVIEW_RPC_NOT_ALLOWED, WEBVIEW_RPC_REQUEST, WEBVIEW_RPC_RESULT, WEBVIEW_RPC_UNAVAILABLE, clampSettingNumber, createDialogQueue, createEffectRouter, createUiEffectChannel, createWebviewRpcBridge, extensionsErrorOf, filterSelectOptions, groupSelectOptions, isSettingLocked, isWebviewRpcRequest, missingScope, openInNewTab, qualifyPanelId, rendererMatches, renderersFor, routeLink, settingValue, settingsValues, slotIsActionable, slotItems, titlebarItems };
@@ -1,7 +1,7 @@
1
1
  import { constant, useReadable } from "../chat/headless/store.js";
2
+ import { ExtensionsHostError } from "./headless/host.js";
2
3
  import { useExtensionScope } from "./ExtensionComponent.js";
3
4
  import { useExtensionEffectRouter, useExtensionsHost } from "./ExtensionsProvider.js";
4
- import { ExtensionsHostError } from "./headless/host.js";
5
5
  import { isSettingLocked, settingValue } from "./headless/select.js";
6
6
  import { useCallback, useEffect, useMemo, useRef } from "react";
7
7
  //#region src/extensions/hooks.ts
@@ -17,8 +17,8 @@ import { DiffFileTree } from "../session/DiffFileTree.js";
17
17
  import { buildDiffTree, fileOrder, relativeTo, visibleRows } from "../session/headless/diff-tree.js";
18
18
  import { collectSessionDiffs, fileDiffCounts, groupByPath } from "../session/headless/session-diffs.js";
19
19
  import { usePanelVisible } from "../workspace/panel-visibility.js";
20
- import { matchRanges } from "./headless/search.js";
21
20
  import { nameMatches } from "./headless/name-match.js";
21
+ import { matchRanges } from "./headless/search.js";
22
22
  import { filesRootOf, steppedIndex } from "./headless/view.js";
23
23
  import { MediaDiff, isMediaDiff } from "./MediaDiff.js";
24
24
  import { parseSessionPatch } from "./session-patch.js";
@@ -1,8 +1,8 @@
1
1
  import { Breadcrumb } from "../components/Breadcrumb.js";
2
2
  import { IconToggle } from "../components/IconToggle.js";
3
3
  import { PanelEmpty, PanelLoading } from "../components/PanelEmpty.js";
4
- import { useFilesHost } from "./FilesProvider.js";
5
4
  import { mediaSiblings, mediaTypeOfPath } from "./headless/media.js";
5
+ import { useFilesHost } from "./FilesProvider.js";
6
6
  import { absolutePath } from "./file-actions.js";
7
7
  import { useFilesLabels } from "./useFilesLabels.js";
8
8
  import { useLsp } from "./useLsp.js";
@@ -1,5 +1,5 @@
1
- import { useFilesHost } from "./FilesProvider.js";
2
1
  import { mediaTypeOfPath } from "./headless/media.js";
2
+ import { useFilesHost } from "./FilesProvider.js";
3
3
  import { useFilesLabels } from "./useFilesLabels.js";
4
4
  import { MediaView } from "./MediaView.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -1,9 +1,10 @@
1
1
  import { IconButton } from "../components/IconButton.js";
2
2
  import { Tooltip } from "../components/Tooltip.js";
3
+ import { useNearViewport } from "../hooks/useNearViewport.js";
3
4
  import { useFilesLabels } from "./useFilesLabels.js";
4
5
  import { FileIcon, TreeChevron } from "../code/editor/FileIcon.js";
5
- import { jsx, jsxs } from "react/jsx-runtime";
6
- import { memo, useEffect, useMemo, useRef, useState } from "react";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ import { memo, startTransition, useCallback, useDeferredValue, useEffect, useMemo, useRef, useState } from "react";
7
8
  //#region src/files/SearchPanel.tsx
8
9
  /**
9
10
  * ⌘⇧F: search across files, shown in place of the Files tree or the Diffs
@@ -12,6 +13,10 @@ import { memo, useEffect, useMemo, useRef, useState } from "react";
12
13
  * lines come from `search` (the host for Files, the diffs for Diffs).
13
14
  *
14
15
  * Keys: ↓ / ↑ move between results, Enter opens, Esc closes.
16
+ *
17
+ * Typing stays ahead of the results: names match on a deferred query, new
18
+ * lines land in a transition, and the lines render a page at a time (the next
19
+ * page once the list's end comes near), so a big result never blocks a keystroke.
15
20
  */
16
21
  function splitPath(path) {
17
22
  const slash = path.lastIndexOf("/");
@@ -27,6 +32,8 @@ const DEBOUNCE_MS = 150;
27
32
  const MAX_NAMES = 50;
28
33
  /** Characters kept before the first match on a long line. */
29
34
  const LEAD = 32;
35
+ /** Result rows (file headers and lines) rendered per page. */
36
+ const PAGE = 200;
30
37
  const SearchPanel = memo(function SearchPanel({ label, asked, names, search, onOpenFile, onOpenLine, onClose, inset }) {
31
38
  const labels = useFilesLabels();
32
39
  const [query, setQuery] = useState("");
@@ -49,12 +56,13 @@ const SearchPanel = memo(function SearchPanel({ label, asked, names, search, onO
49
56
  let live = true;
50
57
  const t = window.setTimeout(() => {
51
58
  latest.current(query, opts).then((r) => {
52
- if (live) setResult({
59
+ if (!live) return;
60
+ startTransition(() => setResult({
53
61
  query,
54
62
  matches: r.matches,
55
63
  capped: r.capped,
56
64
  ...r.unsupported ? { unsupported: r.unsupported } : {}
57
- });
65
+ }));
58
66
  });
59
67
  }, DEBOUNCE_MS);
60
68
  return () => {
@@ -62,16 +70,37 @@ const SearchPanel = memo(function SearchPanel({ label, asked, names, search, onO
62
70
  window.clearTimeout(t);
63
71
  };
64
72
  }, [query, opts]);
65
- const nameHits = useMemo(() => query ? names(query, opts).slice(0, MAX_NAMES) : [], [
73
+ const namesQuery = useDeferredValue(query);
74
+ const nameHits = useMemo(() => namesQuery ? names(namesQuery, opts).slice(0, MAX_NAMES) : [], [
66
75
  names,
67
- query,
76
+ namesQuery,
68
77
  opts
69
78
  ]);
70
79
  const groups = useMemo(() => {
71
80
  const byPath = /* @__PURE__ */ new Map();
72
- for (const m of result?.matches ?? []) byPath.set(m.path, [...byPath.get(m.path) ?? [], m]);
81
+ for (const m of result?.matches ?? []) {
82
+ const lines = byPath.get(m.path);
83
+ if (lines) lines.push(m);
84
+ else byPath.set(m.path, [m]);
85
+ }
73
86
  return [...byPath];
74
87
  }, [result]);
88
+ const [more, setMore] = useState({
89
+ of: null,
90
+ pages: 0
91
+ });
92
+ const budget = PAGE * (1 + (more.of === result ? more.pages : 0));
93
+ const showMore = useCallback(() => {
94
+ startTransition(() => setMore((m) => ({
95
+ of: result,
96
+ pages: (m.of === result ? m.pages : 0) + 1
97
+ })));
98
+ }, [result]);
99
+ const toggleGroup = useCallback((path) => setCollapsed((prev) => {
100
+ const next = new Set(prev);
101
+ if (!next.delete(path)) next.add(path);
102
+ return next;
103
+ }), []);
75
104
  const hitCount = useMemo(() => (result?.matches ?? []).reduce((n, m) => n + m.ranges.length, 0), [result]);
76
105
  const pending = query !== "" && result?.query !== query;
77
106
  const focusResult = (from, direction) => {
@@ -154,6 +183,7 @@ const SearchPanel = memo(function SearchPanel({ label, asked, names, search, onO
154
183
  }),
155
184
  /* @__PURE__ */ jsxs("div", {
156
185
  ref: list,
186
+ "data-scroll-root": "",
157
187
  className: "flex-1 min-h-0 overflow-y-auto px-2 pb-2",
158
188
  children: [nameHits.length > 0 && /* @__PURE__ */ jsx("ul", {
159
189
  "aria-label": labels.filesFileNames,
@@ -167,57 +197,95 @@ const SearchPanel = memo(function SearchPanel({ label, asked, names, search, onO
167
197
  title: path,
168
198
  children: [/* @__PURE__ */ jsx(FileIcon, { path }), /* @__PURE__ */ jsx(PathLabel, { path })]
169
199
  }) }, path))
170
- }), groups.length > 0 && /* @__PURE__ */ jsx("ul", {
171
- "aria-label": labels.filesMatchingLines,
172
- className: `m-0 p-0 list-none flex flex-col ${nameHits.length ? "mt-2" : ""}`,
173
- children: groups.map(([path, lines]) => {
174
- const closed = collapsed.has(path);
175
- return /* @__PURE__ */ jsxs("li", { children: [/* @__PURE__ */ jsxs("button", {
176
- type: "button",
177
- "data-result": "",
178
- "data-size": "sm",
179
- "aria-expanded": !closed,
180
- onClick: () => setCollapsed((prev) => {
181
- const next = new Set(prev);
182
- if (!next.delete(path)) next.add(path);
183
- return next;
184
- }),
185
- className: "zg-menu-row zg-press-subtle",
186
- title: path,
187
- children: [
188
- /* @__PURE__ */ jsx(TreeChevron, {
189
- open: !closed,
190
- className: "text-[var(--zg-text-muted)]"
191
- }),
192
- /* @__PURE__ */ jsx(FileIcon, { path }),
193
- /* @__PURE__ */ jsx(PathLabel, { path }),
194
- /* @__PURE__ */ jsx("span", {
195
- className: "zg-meta shrink-0 tabular-nums",
196
- children: lines.reduce((n, l) => n + l.ranges.length, 0)
197
- })
198
- ]
199
- }), !closed && /* @__PURE__ */ jsx("ul", {
200
- className: "m-0 p-0 list-none flex flex-col",
201
- children: lines.map((m) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("button", {
202
- type: "button",
203
- "data-result": "",
204
- "data-size": "sm",
205
- onClick: () => onOpenLine(m, result.query, opts),
206
- className: "zg-menu-row zg-press-subtle",
207
- style: { paddingLeft: 30 },
208
- "aria-label": labels.filesMatchLine(path, m.line, m.text.trim()),
209
- children: [/* @__PURE__ */ jsxs("span", {
210
- className: "zg-meta shrink-0 w-8 text-right tabular-nums",
211
- children: [m.side === "old" ? "−" : "", m.line]
212
- }), /* @__PURE__ */ jsx(LineText, { match: m })]
213
- }) }, `${m.part ?? ""}:${m.side ?? ""}:${m.line}`))
214
- })] }, path);
215
- })
200
+ }), groups.length > 0 && result && /* @__PURE__ */ jsx(MatchGroups, {
201
+ groups,
202
+ collapsed,
203
+ budget,
204
+ query: result.query,
205
+ opts,
206
+ spaced: nameHits.length > 0,
207
+ onToggle: toggleGroup,
208
+ onOpenLine,
209
+ onMore: showMore
216
210
  })]
217
211
  })
218
212
  ]
219
213
  });
220
214
  });
215
+ /** The matching lines grouped by file, the first `budget` rows of them. Memoized: typing doesn't re-render them. */
216
+ const MatchGroups = memo(function MatchGroups({ groups, collapsed, budget, query, opts, spaced, onToggle, onOpenLine, onMore }) {
217
+ const labels = useFilesLabels();
218
+ let left = budget;
219
+ const shown = [];
220
+ for (const [path, lines] of groups) {
221
+ if (left <= 0) break;
222
+ const closed = collapsed.has(path);
223
+ left -= 1;
224
+ const visible = closed ? [] : lines.slice(0, Math.max(0, left));
225
+ left -= visible.length;
226
+ shown.push({
227
+ path,
228
+ lines: visible,
229
+ closed,
230
+ total: lines.reduce((n, l) => n + l.ranges.length, 0)
231
+ });
232
+ }
233
+ const last = shown[shown.length - 1];
234
+ const truncated = shown.length < groups.length || last !== void 0 && !last.closed && last.lines.length < groups[shown.length - 1][1].length;
235
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("ul", {
236
+ "aria-label": labels.filesMatchingLines,
237
+ className: `m-0 p-0 list-none flex flex-col ${spaced ? "mt-2" : ""}`,
238
+ children: shown.map(({ path, lines, closed, total }) => /* @__PURE__ */ jsxs("li", { children: [/* @__PURE__ */ jsxs("button", {
239
+ type: "button",
240
+ "data-result": "",
241
+ "data-size": "sm",
242
+ "aria-expanded": !closed,
243
+ onClick: () => onToggle(path),
244
+ className: "zg-menu-row zg-press-subtle",
245
+ title: path,
246
+ children: [
247
+ /* @__PURE__ */ jsx(TreeChevron, {
248
+ open: !closed,
249
+ className: "text-[var(--zg-text-muted)]"
250
+ }),
251
+ /* @__PURE__ */ jsx(FileIcon, { path }),
252
+ /* @__PURE__ */ jsx(PathLabel, { path }),
253
+ /* @__PURE__ */ jsx("span", {
254
+ className: "zg-meta shrink-0 tabular-nums",
255
+ children: total
256
+ })
257
+ ]
258
+ }), !closed && lines.length > 0 && /* @__PURE__ */ jsx("ul", {
259
+ className: "m-0 p-0 list-none flex flex-col",
260
+ children: lines.map((m) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("button", {
261
+ type: "button",
262
+ "data-result": "",
263
+ "data-size": "sm",
264
+ onClick: () => onOpenLine(m, query, opts),
265
+ className: "zg-menu-row zg-press-subtle",
266
+ style: { paddingLeft: 30 },
267
+ "aria-label": labels.filesMatchLine(path, m.line, m.text.trim()),
268
+ children: [/* @__PURE__ */ jsxs("span", {
269
+ className: "zg-meta shrink-0 w-8 text-right tabular-nums",
270
+ children: [m.side === "old" ? "−" : "", m.line]
271
+ }), /* @__PURE__ */ jsx(LineText, { match: m })]
272
+ }) }, `${m.part ?? ""}:${m.side ?? ""}:${m.line}`))
273
+ })] }, path))
274
+ }), truncated && /* @__PURE__ */ jsx(MoreRows, { onNear: onMore }, budget)] });
275
+ });
276
+ /** Asks for the next page once the end of the list comes near. One per page (keyed by it). */
277
+ function MoreRows({ onNear }) {
278
+ const ref = useRef(null);
279
+ const near = useNearViewport(ref, "400px 0px");
280
+ useEffect(() => {
281
+ if (near) onNear();
282
+ }, [near, onNear]);
283
+ return /* @__PURE__ */ jsx("div", {
284
+ ref,
285
+ "aria-hidden": true,
286
+ className: "h-px"
287
+ });
288
+ }
221
289
  function PathLabel({ path }) {
222
290
  const { dir, base } = splitPath(path);
223
291
  return /* @__PURE__ */ jsxs("span", {
@@ -1,9 +1,23 @@
1
- import { matchRanges } from "./search.js";
2
1
  //#region src/files/headless/name-match.ts
3
2
  function basename(path) {
4
3
  const trimmed = path.replace(/[/\\]+$/, "");
5
4
  return trimmed.slice(Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\")) + 1);
6
5
  }
6
+ /** Per list of paths: its names split and lowercased once, not on every keystroke. */
7
+ const indexes = /* @__PURE__ */ new WeakMap();
8
+ function indexOf(paths) {
9
+ let index = indexes.get(paths);
10
+ if (!index) {
11
+ const bases = paths.map(basename);
12
+ index = {
13
+ bases,
14
+ lowerBases: bases.map((b) => b.toLowerCase()),
15
+ lowerPaths: paths.map((p) => p.toLowerCase())
16
+ };
17
+ indexes.set(paths, index);
18
+ }
19
+ return index;
20
+ }
7
21
  /**
8
22
  * The paths whose file name (or, ranked after, folders) contain `query`, best first, at most `limit`.
9
23
  *
@@ -14,20 +28,21 @@ function basename(path) {
14
28
  */
15
29
  function nameMatches(paths, query, opts, limit = 50) {
16
30
  if (!query) return [];
31
+ const index = indexOf(paths);
32
+ const needle = opts.caseSensitive ? query : query.toLowerCase();
33
+ const bases = opts.caseSensitive ? index.bases : index.lowerBases;
34
+ const full = opts.caseSensitive ? paths : index.lowerPaths;
17
35
  const scored = [];
18
- for (const path of paths) {
19
- const base = basename(path);
20
- const inBase = matchRanges(base, query, opts)[0];
21
- if (inBase) {
22
- scored.push({
23
- path,
24
- rank: inBase.start,
25
- base: base.length
26
- });
27
- continue;
28
- }
29
- if (matchRanges(path, query, opts).length > 0) scored.push({
30
- path,
36
+ for (let i = 0; i < paths.length; i++) {
37
+ const base = bases[i];
38
+ const inBase = base.indexOf(needle);
39
+ if (inBase !== -1) scored.push({
40
+ path: paths[i],
41
+ rank: inBase,
42
+ base: base.length
43
+ });
44
+ else if (full[i].includes(needle)) scored.push({
45
+ path: paths[i],
31
46
  rank: 1e4,
32
47
  base: base.length
33
48
  });
@@ -1,5 +1,5 @@
1
- import { useOptionalConfirm } from "../app/useConfirm.js";
2
1
  import { droppedItems, entryRefusalText, inFolder, nameOf, parentOf, topLevelPaths } from "./headless/entries.js";
2
+ import { useOptionalConfirm } from "../app/useConfirm.js";
3
3
  import { useCallback, useMemo, useRef, useState } from "react";
4
4
  //#region src/files/useEntryActions.ts
5
5
  /**
@@ -1,5 +1,5 @@
1
- import { useFilesHost } from "./FilesProvider.js";
2
1
  import { isUnder, movedPath } from "./headless/entries.js";
2
+ import { useFilesHost } from "./FilesProvider.js";
3
3
  import { filesRootOf } from "./headless/view.js";
4
4
  import { folderBuffers } from "./drafts-store.js";
5
5
  import { editedPath, sameFile, statusDelta } from "./headless/workspace-diff.js";
@@ -201,9 +201,9 @@ function WhereMenu(props) {
201
201
  })] }),
202
202
  description: descriptor.available ? descriptor.description : descriptor.reason,
203
203
  onClick: () => {
204
- onChange({
204
+ onChange(active && props.draft?.kind === descriptor.kind ? props.draft : {
205
205
  kind: descriptor.kind,
206
- branch: active ? typedBranch : ""
206
+ branch: ""
207
207
  });
208
208
  if (descriptor.takesBranch) requestAnimationFrame(() => branchRef.current?.focus());
209
209
  else close();
@@ -1,4 +1,4 @@
1
- import { EnvironmentDescriptor, EnvironmentRequest } from "zidane/chat";
1
+ import { EnvironmentCheckout, EnvironmentDescriptor, EnvironmentRequest } from "zidane/chat";
2
2
  //#region src/git/headless/environment.d.ts
3
3
  /** What the user picked in a draft; `null` where it is used = the configured default. */
4
4
  interface DraftEnvironment {
@@ -6,6 +6,11 @@ interface DraftEnvironment {
6
6
  kind: string;
7
7
  /** Typed branch; empty = the suggested one. */
8
8
  branch: string;
9
+ /**
10
+ * Work on `branch` as it is (a pull request's or a ticket's branch) rather than cutting it: set by a panel's
11
+ * "Open in worktree". Picking another environment or typing a branch drops it.
12
+ */
13
+ checkout?: EnvironmentCheckout;
9
14
  }
10
15
  /** A machine shared with the draft's host, as an environment descriptor names it. */
11
16
  type EnvironmentMachine = NonNullable<EnvironmentDescriptor['machine']>;