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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zidane-ui",
3
- "version": "9.1.4",
3
+ "version": "9.1.6",
4
4
  "description": "Zidane design system and chat kit: tokens, surface primitives, theme engine, React components, the chat layer (sessions, transcript, composer) and ChatHost adapters.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -536,7 +536,7 @@
536
536
  "react": "^19.3.0",
537
537
  "react-dom": "^19.3.0",
538
538
  "unocss": ">=66.0.0",
539
- "zidane": "^9.1.4",
539
+ "zidane": "^9.1.6",
540
540
  "vitest": ">=3"
541
541
  },
542
542
  "peerDependenciesMeta": {
@@ -611,6 +611,19 @@ html[data-motion='reduced'] :is(.animate-spin, .zg-spin-ring, .zg-sendstop-ring)
611
611
  animation: zg-sendstop-rotate 800ms linear infinite;
612
612
  }
613
613
 
614
+ /* --- Step status icon (`StepStatusIcon`) ----------------------------------
615
+ * A `.zg-swap` whose layers centre their glyph (the spin ring is a fixed
616
+ * 12px box, the others are 1em glyphs). The layer that lands after a change
617
+ * pops in on `snap`, its opacity on the swap's `fade`; the pop sits on the
618
+ * layer so the ring inside keeps its own rotation. */
619
+ .zg-step-icon-layer {
620
+ display: grid;
621
+ place-items: center;
622
+ }
623
+ .zg-step-icon-layer[data-landed] {
624
+ animation: zg-pop var(--zg-motion-snap) both;
625
+ }
626
+
614
627
  @keyframes zg-sendstop-rotate {
615
628
  to {
616
629
  transform: rotate(360deg);
@@ -281,7 +281,6 @@ html[data-motion='off'] .zg-onboarding-step {
281
281
  .zg-demo-fade-y {
282
282
  mask-image: linear-gradient(to bottom, transparent, #000 22%, #000 78%, transparent);
283
283
  }
284
-
285
284
  /* Two states of one scene in the same cell: the before state, then the
286
285
  after state (the rest state). */
287
286
  .zg-demo-stack {
@@ -346,6 +346,16 @@
346
346
  var(--zg-shadow-well),
347
347
  0 0 0 3px color-mix(in oklab, var(--zg-ring) 18%, transparent);
348
348
  }
349
+ /* A well whose value is wrong: the danger edge, focused or not. */
350
+ .zg-well[aria-invalid='true'] {
351
+ border-color: color-mix(in oklab, var(--zg-danger) 70%, transparent);
352
+ }
353
+ .zg-well[aria-invalid='true']:focus,
354
+ .zg-well[aria-invalid='true']:focus-within {
355
+ box-shadow:
356
+ var(--zg-shadow-well),
357
+ 0 0 0 3px color-mix(in oklab, var(--zg-danger) 18%, transparent);
358
+ }
349
359
  /* A file dragged over a well that takes it (focused or not). */
350
360
  .zg-well[data-drop] {
351
361
  border-color: var(--zg-accent);
@@ -63,6 +63,23 @@
63
63
  padding-right: calc(0.5rem + var(--zg-strip-end-inset));
64
64
  }
65
65
 
66
+ /* A panel row's buttons (`PanelRowItem.actions`): shown while the row is hovered or holds focus, or one runs.
67
+ Their place is kept, so the row never shifts. */
68
+ .zg-row-actions {
69
+ opacity: 0;
70
+ transition: opacity var(--zg-motion-hover);
71
+ }
72
+ .group:hover .zg-row-actions,
73
+ .group:focus-within .zg-row-actions,
74
+ .zg-row-actions[data-busy] {
75
+ opacity: 1;
76
+ }
77
+ @media (hover: none) {
78
+ .zg-row-actions {
79
+ opacity: 1;
80
+ }
81
+ }
82
+
66
83
  /* The corner (`PanelCorner`): pop out and full screen fade in left of the toggle while the panel shows. */
67
84
  .zg-panel-corner-extra {
68
85
  transition: opacity var(--zg-motion-fade);
@@ -1,19 +0,0 @@
1
- import { CSSProperties } from "react";
2
- //#region src/session/TodosPanel.d.ts
3
- /** Props for {@link TodosPanel}. */
4
- interface TodosPanelProps {
5
- /** The session whose list the panel shows. */
6
- sessionId: string;
7
- /** Extra classes on the root element. */
8
- className?: string;
9
- /** Inline styles on the root element. */
10
- style?: CSSProperties;
11
- }
12
- /**
13
- * A session's todo list with its edits, retry, add box, tally and "Clear all".
14
- *
15
- * @param props - The {@link TodosPanelProps}.
16
- */
17
- declare function TodosPanel({ sessionId, className, style }: TodosPanelProps): import("react").JSX.Element;
18
- //#endregion
19
- export { TodosPanel, TodosPanelProps };
@@ -1,251 +0,0 @@
1
- import { IconButton } from "../components/IconButton.js";
2
- import { buttonClass } from "../components/button.js";
3
- import { MetaChip } from "../components/Form.js";
4
- import { PanelEmpty } from "../components/PanelEmpty.js";
5
- import { useSessionHost, useSessionTodos } from "./SessionProvider.js";
6
- import { useSessionLabels } from "./useSessionLabels.js";
7
- import { TODO_ROW_CLASS, TodoTally, isDoneTodo, todoGlyphTone } from "./TodoList.js";
8
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
- import { useCallback, useEffect, useRef, useState } from "react";
10
- import { TODO_STATUS_GLYPHS, addTodo, buildTodoRetryMessage, clearTodos, cycleTodoStatus, editTodo, removeTodo } from "zidane/chat/pure";
11
- //#region src/session/TodosPanel.tsx
12
- /**
13
- * The Todos panel: a session's live list, editable at parity with the TUI's
14
- * modal. Shows the live list when non-empty, else the archive (the last
15
- * list, read-only).
16
- *
17
- * Every edit goes through the shared todo transforms (`zidane/chat/pure`)
18
- * and commits through the host's `todos.set`, which lands on the session the
19
- * model reads; the panel follows the host's snapshot, so no shadow list
20
- * lives here. Only "which row is mid-edit" and the add box are local.
21
- *
22
- * Gestures: click the glyph to cycle the status, click the text to edit in
23
- * place (Enter saves, Esc cancels, blur saves), retry asks the agent to redo
24
- * the row, remove drops it, the box at the bottom adds, "Clear all" empties
25
- * after an inline confirm. Without `todos.set` the panel is read-only;
26
- * without `todos.retry` there is no retry.
27
- */
28
- const INPUT_CLS = "zg-well flex-1 min-w-0 font-mono text-zg-label px-2.5 py-1 placeholder:text-[var(--zg-text-subtle)]";
29
- const GHOST_BTN = buttonClass({
30
- variant: "ghost",
31
- size: "xs"
32
- });
33
- /**
34
- * A session's todo list with its edits, retry, add box, tally and "Clear all".
35
- *
36
- * @param props - The {@link TodosPanelProps}.
37
- */
38
- function TodosPanel({ sessionId, className, style }) {
39
- const labels = useSessionLabels();
40
- const host = useSessionHost().todos;
41
- const snap = useSessionTodos(sessionId);
42
- const refresh = host?.refresh;
43
- const set = host?.set;
44
- const retryRun = host?.retry;
45
- useEffect(() => {
46
- refresh?.(sessionId);
47
- }, [sessionId, refresh]);
48
- const list = snap ? snap.todos.length > 0 ? snap.todos : snap.archive : [];
49
- const isArchive = Boolean(snap && snap.todos.length === 0 && snap.archive.length > 0);
50
- const total = list.length;
51
- const done = snap ? snap.tally.completed + snap.tally.cancelled : 0;
52
- const editable = Boolean(set);
53
- const [editingId, setEditingId] = useState(null);
54
- const [draft, setDraft] = useState("");
55
- const [adding, setAdding] = useState("");
56
- const [error, setError] = useState(null);
57
- const [confirmClear, setConfirmClear] = useState(false);
58
- const editRef = useRef(null);
59
- useEffect(() => {
60
- if (editingId) {
61
- editRef.current?.focus();
62
- editRef.current?.select();
63
- }
64
- }, [editingId]);
65
- const base = snap?.todos ?? [];
66
- const saveFailed = labels.todosSaveFailed;
67
- const commit = useCallback((next) => {
68
- if (!set) return;
69
- setError(null);
70
- set(sessionId, next).then((applied) => {
71
- if (!applied) setError(saveFailed);
72
- }, (err) => setError(err instanceof Error ? err.message : String(err)));
73
- }, [
74
- sessionId,
75
- set,
76
- saveFailed
77
- ]);
78
- const startEdit = (todo) => {
79
- if (isArchive || !editable) return;
80
- setEditingId(todo.id);
81
- setDraft(todo.content);
82
- };
83
- const saveEdit = () => {
84
- if (!editingId) return;
85
- const trimmed = draft.trim();
86
- if (trimmed.length > 0) commit(editTodo(base, editingId, trimmed));
87
- setEditingId(null);
88
- };
89
- const submitAdd = () => {
90
- const trimmed = adding.trim();
91
- if (trimmed.length === 0) return;
92
- commit(addTodo(base, trimmed));
93
- setAdding("");
94
- };
95
- /** Steer the run with the shared retry text: mid-run it steers, idle it starts a run. */
96
- const retry = (todo) => {
97
- if (!retryRun) return;
98
- setError(null);
99
- retryRun(sessionId, buildTodoRetryMessage(todo)).catch((err) => setError(err.message));
100
- };
101
- return /* @__PURE__ */ jsxs("div", {
102
- className: ["flex-1 min-h-0 flex flex-col", className].filter(Boolean).join(" "),
103
- style,
104
- children: [/* @__PURE__ */ jsx("div", {
105
- className: "flex-1 min-h-0 overflow-y-auto",
106
- children: list.length === 0 ? /* @__PURE__ */ jsx(PanelEmpty, {
107
- icon: "i-ph-list-checks",
108
- title: labels.todosEmpty,
109
- hint: labels.todosEmptyHint
110
- }) : /* @__PURE__ */ jsxs("div", {
111
- className: "flex flex-col gap-2 p-3",
112
- children: [/* @__PURE__ */ jsxs("div", {
113
- className: "zg-meta flex items-center gap-1 px-2",
114
- "data-testid": "todo-progress",
115
- children: [isArchive && /* @__PURE__ */ jsx("span", {
116
- className: "mr-1",
117
- children: labels.todosLastList
118
- }), /* @__PURE__ */ jsx(MetaChip, { children: labels.todosProgress(done, total) })]
119
- }), /* @__PURE__ */ jsx("ul", {
120
- className: "flex flex-col gap-px m-0 p-0 list-none",
121
- children: list.map((todo) => {
122
- const dim = isDoneTodo(todo.status);
123
- const glyphTone = todoGlyphTone(todo.status);
124
- const rowEditable = editable && !isArchive;
125
- return /* @__PURE__ */ jsxs("li", {
126
- "data-status": todo.status,
127
- className: `group ${TODO_ROW_CLASS} hover:bg-[var(--zg-row-hover)]`,
128
- children: [
129
- /* @__PURE__ */ jsx("button", {
130
- type: "button",
131
- "aria-label": labels.todoChangeStatus(todo.status),
132
- title: rowEditable ? labels.todoChangeStatusHint(todo.status) : labels.todoStatus(todo.status),
133
- disabled: !rowEditable,
134
- onClick: () => commit(cycleTodoStatus(base, todo.id)),
135
- className: `text-zg-ui leading-6 w-4 shrink-0 bg-transparent border-0 p-0 cursor-pointer disabled:cursor-default ${glyphTone}`,
136
- children: TODO_STATUS_GLYPHS[todo.status]
137
- }),
138
- editingId === todo.id ? /* @__PURE__ */ jsx("input", {
139
- ref: editRef,
140
- type: "text",
141
- value: draft,
142
- spellCheck: false,
143
- "aria-label": labels.todoEdit,
144
- onChange: (e) => setDraft(e.target.value),
145
- onBlur: saveEdit,
146
- onKeyDown: (e) => {
147
- if (e.key === "Enter") saveEdit();
148
- if (e.key === "Escape") setEditingId(null);
149
- },
150
- className: INPUT_CLS
151
- }) : /* @__PURE__ */ jsx("button", {
152
- type: "button",
153
- disabled: !rowEditable,
154
- onClick: () => startEdit(todo),
155
- title: rowEditable ? labels.todoEdit : void 0,
156
- className: `flex-1 min-w-0 text-left text-zg-ui leading-6 bg-transparent border-0 p-0 cursor-text disabled:cursor-default truncate ${dim ? "text-[var(--zg-text-muted)] line-through" : "text-[var(--zg-text)]"}`,
157
- children: todo.content
158
- }),
159
- rowEditable && /* @__PURE__ */ jsxs(Fragment, { children: [retryRun && /* @__PURE__ */ jsx(IconButton, {
160
- size: "xs",
161
- icon: "i-ph-arrow-clockwise",
162
- label: labels.todoRetry,
163
- title: labels.todoRetryHint,
164
- onClick: () => retry(todo),
165
- className: "opacity-0 group-hover:opacity-100 focus-visible:opacity-100"
166
- }), /* @__PURE__ */ jsx(IconButton, {
167
- size: "xs",
168
- icon: "i-ph-x",
169
- label: labels.todoRemove,
170
- title: labels.todoRemoveHint,
171
- tone: "danger",
172
- onClick: () => commit(removeTodo(base, todo.id)),
173
- className: "opacity-0 group-hover:opacity-100 focus-visible:opacity-100"
174
- })] })
175
- ]
176
- }, todo.id);
177
- })
178
- })]
179
- })
180
- }), /* @__PURE__ */ jsxs("div", {
181
- className: "shrink-0 px-3 pt-1 pb-3 flex flex-col gap-2",
182
- children: [
183
- error && /* @__PURE__ */ jsx("div", {
184
- className: "text-zg-meta text-[var(--zg-warn)]",
185
- role: "alert",
186
- children: error
187
- }),
188
- editable && /* @__PURE__ */ jsxs("div", {
189
- className: "flex items-center gap-2",
190
- children: [/* @__PURE__ */ jsx("input", {
191
- type: "text",
192
- placeholder: labels.todoAddPlaceholder,
193
- "aria-label": labels.todoAddLabel,
194
- value: adding,
195
- spellCheck: false,
196
- onChange: (e) => setAdding(e.target.value),
197
- onKeyDown: (e) => {
198
- if (e.key === "Enter") submitAdd();
199
- },
200
- className: INPUT_CLS
201
- }), /* @__PURE__ */ jsx("button", {
202
- type: "button",
203
- className: GHOST_BTN,
204
- disabled: adding.trim().length === 0,
205
- onClick: submitAdd,
206
- children: labels.todoAdd
207
- })]
208
- }),
209
- /* @__PURE__ */ jsxs("div", {
210
- className: "flex items-center justify-between gap-3 min-h-6",
211
- children: [snap && /* @__PURE__ */ jsx(TodoTally, {
212
- tally: snap.tally,
213
- className: "ml-2"
214
- }), !editable ? null : confirmClear ? /* @__PURE__ */ jsxs("span", {
215
- className: "flex items-center gap-1.5 text-zg-meta",
216
- children: [
217
- /* @__PURE__ */ jsx("span", {
218
- className: "text-[var(--zg-text-muted)]",
219
- children: labels.todosClearConfirm(base.length)
220
- }),
221
- /* @__PURE__ */ jsx("button", {
222
- type: "button",
223
- className: `${GHOST_BTN} text-[var(--zg-error)]`,
224
- onClick: () => {
225
- commit(clearTodos());
226
- setConfirmClear(false);
227
- },
228
- children: labels.todosClearYes
229
- }),
230
- /* @__PURE__ */ jsx("button", {
231
- type: "button",
232
- className: GHOST_BTN,
233
- onClick: () => setConfirmClear(false),
234
- children: labels.todosClearCancel
235
- })
236
- ]
237
- }) : /* @__PURE__ */ jsx("button", {
238
- type: "button",
239
- className: GHOST_BTN,
240
- disabled: base.length === 0,
241
- onClick: () => setConfirmClear(true),
242
- title: labels.todosClearHint,
243
- children: labels.todosClear
244
- })]
245
- })
246
- ]
247
- })]
248
- });
249
- }
250
- //#endregion
251
- export { TodosPanel };
@@ -1,22 +0,0 @@
1
- import { Readable } from "../../chat/headless/store.js";
2
- import { TodosSnapshot } from "./host.js";
3
- //#region src/session/headless/todos.d.ts
4
- /** The todo snapshots of every session a host has seen. */
5
- interface TodosState {
6
- /** The session's snapshot store (`null` until known). */
7
- snapshot(sessionId: string): Readable<TodosSnapshot | null>;
8
- /** Reads the session from the backend: one request per session at a time, never rejects. */
9
- refresh(sessionId: string): Promise<void>;
10
- /** A snapshot the backend pushed. */
11
- push(sessionId: string, snapshot: TodosSnapshot): void;
12
- /** Forgets a deleted session. */
13
- forget(sessionId: string): void;
14
- }
15
- /**
16
- * Creates a {@link TodosState}.
17
- *
18
- * @param read - Reads one session's snapshot from the backend (`null`: no list yet).
19
- */
20
- declare function createTodosState(read: (sessionId: string) => Promise<TodosSnapshot | null>): TodosState;
21
- //#endregion
22
- export { TodosState, createTodosState };
@@ -1,38 +0,0 @@
1
- import { createKeyedState } from "./keyed.js";
2
- //#region src/session/headless/todos.ts
3
- /**
4
- * Creates a {@link TodosState}.
5
- *
6
- * @param read - Reads one session's snapshot from the backend (`null`: no list yet).
7
- */
8
- function createTodosState(read) {
9
- const state = createKeyedState(null);
10
- const pushes = /* @__PURE__ */ new Map();
11
- const inflight = /* @__PURE__ */ new Map();
12
- return {
13
- snapshot: (sessionId) => state.readable(sessionId),
14
- refresh(sessionId) {
15
- const running = inflight.get(sessionId);
16
- if (running) return running;
17
- const seenPushes = pushes.get(sessionId) ?? 0;
18
- const p = read(sessionId).then((snap) => {
19
- if (!snap || (pushes.get(sessionId) ?? 0) !== seenPushes) return;
20
- state.set(sessionId, snap);
21
- }).catch(() => void 0).finally(() => {
22
- inflight.delete(sessionId);
23
- });
24
- inflight.set(sessionId, p);
25
- return p;
26
- },
27
- push(sessionId, snapshot) {
28
- pushes.set(sessionId, (pushes.get(sessionId) ?? 0) + 1);
29
- state.set(sessionId, snapshot);
30
- },
31
- forget(sessionId) {
32
- pushes.delete(sessionId);
33
- state.delete(sessionId);
34
- }
35
- };
36
- }
37
- //#endregion
38
- export { createTodosState };