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
@@ -0,0 +1,241 @@
1
+ import { IconButton } from "../components/IconButton.js";
2
+ import { PanelEmpty, PanelLoading } from "../components/PanelEmpty.js";
3
+ import { PANEL_ROW, PANEL_ROW_HOVER } from "../components/PanelRows.js";
4
+ import { useMinuteTick } from "../hooks/useMinuteTick.js";
5
+ import { useSessionHost, useSessionSecrets } from "./SessionProvider.js";
6
+ import { useSessionLabels } from "./useSessionLabels.js";
7
+ import { BTN_GHOST, BTN_PRIMARY, CardError, INPUT } from "../chat/interactions/card-ui.js";
8
+ import { secretTimeLeft } from "../chat/headless/secrets.js";
9
+ import { SecretInput } from "../chat/interactions/SecretInput.js";
10
+ import { Tutorial } from "../onboarding/tutorials.js";
11
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
+ import { useEffect, useId, useRef, useState } from "react";
13
+ import { DEFAULT_SECRET_TTL, isSecretName } from "zidane/chat/pure";
14
+ //#region src/session/SecretsPanel.tsx
15
+ /**
16
+ * The Secrets panel body: the saved secrets of a session's project (API keys,
17
+ * tokens), by name, with when each expires and whether this session saved
18
+ * it. Values never come back: a row can be revoked or replaced, and a secret
19
+ * can be added by hand (name, password field, TTL). The list follows the
20
+ * host's change signal (`secrets:changed`); a refused save (the setting is
21
+ * off, a plain-text link from another machine) shows the host's reason.
22
+ *
23
+ * The app offers the tab only while `Settings.secrets` is on
24
+ * (`SECRETS_PANEL_ID`, core's `buildPanelCatalog({ showSecrets })`), and
25
+ * `SecretsAttention` opens it the first time the session saves a secret.
26
+ */
27
+ /**
28
+ * Renders a session project's saved secrets, with revoke, replace and add.
29
+ *
30
+ * @param props - The `sessionId`, `className` and `style`.
31
+ */
32
+ function SecretsPanel({ sessionId, className = "", style }) {
33
+ const labels = useSessionLabels();
34
+ const entries = useSessionSecrets(sessionId);
35
+ const host = useSessionHost().secrets;
36
+ const refresh = host?.refresh;
37
+ const revoke = host?.revoke;
38
+ const canSave = Boolean(host?.save);
39
+ const [error, setError] = useState(null);
40
+ const [editing, setEditing] = useState(null);
41
+ useMinuteTick();
42
+ const empty = entries !== null && entries.length === 0 && editing === null;
43
+ const addButton = /* @__PURE__ */ jsxs("button", {
44
+ type: "button",
45
+ className: BTN_GHOST,
46
+ onClick: () => setEditing(""),
47
+ children: [/* @__PURE__ */ jsx("span", {
48
+ "aria-hidden": true,
49
+ className: "i-ph-plus"
50
+ }), labels.secretsAdd]
51
+ });
52
+ useEffect(() => {
53
+ refresh?.(sessionId).catch((err) => setError(err.message));
54
+ }, [refresh, sessionId]);
55
+ const onRevoke = revoke ? (name) => {
56
+ setError(null);
57
+ revoke(sessionId, name).catch((err) => setError(err.message));
58
+ } : void 0;
59
+ return /* @__PURE__ */ jsxs("div", {
60
+ className: `flex-1 min-h-0 flex flex-col ${className}`,
61
+ style,
62
+ "aria-label": labels.secretsLabel,
63
+ children: [/* @__PURE__ */ jsxs("div", {
64
+ className: "flex-1 min-h-0 flex flex-col overflow-y-auto px-3 pt-3 pb-3",
65
+ children: [
66
+ error && /* @__PURE__ */ jsx("div", {
67
+ className: "text-xs text-[var(--zg-warn)] mb-2",
68
+ role: "alert",
69
+ children: error
70
+ }),
71
+ entries === null ? /* @__PURE__ */ jsx(PanelLoading, {}) : empty ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(PanelEmpty, {
72
+ icon: "i-ph-key",
73
+ title: labels.secretsEmpty,
74
+ hint: labels.secretsEmptyHint
75
+ }), /* @__PURE__ */ jsx(Tutorial, {
76
+ topic: "secrets",
77
+ surface: "raised",
78
+ className: "mt-4",
79
+ ...canSave ? { actions: addButton } : {}
80
+ })] }) : /* @__PURE__ */ jsxs("div", {
81
+ className: "flex flex-col gap-2",
82
+ children: [/* @__PURE__ */ jsx("p", {
83
+ className: "m-0 text-zg-meta leading-4 text-[var(--zg-text-muted)] zg-pretty",
84
+ children: labels.secretsNote
85
+ }), /* @__PURE__ */ jsx("ul", {
86
+ className: "m-0 p-0 list-none flex flex-col",
87
+ "aria-label": labels.secretsListLabel,
88
+ children: entries.map((entry) => /* @__PURE__ */ jsx(SecretRow, {
89
+ entry,
90
+ sessionId,
91
+ onRevoke: onRevoke ? () => onRevoke(entry.name) : void 0,
92
+ onReplace: canSave ? () => setEditing(entry.name) : void 0
93
+ }, entry.name))
94
+ })]
95
+ }),
96
+ canSave && editing !== null && /* @__PURE__ */ jsx(AddSecretForm, {
97
+ sessionId,
98
+ initialName: editing,
99
+ saved: entries ?? [],
100
+ onDone: () => setEditing(null)
101
+ }, editing)
102
+ ]
103
+ }), canSave && editing === null && !empty && /* @__PURE__ */ jsx("div", {
104
+ className: "shrink-0 flex px-3 py-2",
105
+ children: addButton
106
+ })]
107
+ });
108
+ }
109
+ function SecretRow({ entry, sessionId, onRevoke, onReplace }) {
110
+ const labels = useSessionLabels();
111
+ const left = secretTimeLeft(entry.expiresAt, Date.now());
112
+ return /* @__PURE__ */ jsxs("li", {
113
+ className: `${PANEL_ROW} ${PANEL_ROW_HOVER} items-center`,
114
+ "data-secret-name": entry.name,
115
+ children: [
116
+ /* @__PURE__ */ jsx("span", {
117
+ "aria-hidden": true,
118
+ className: "i-ph-key shrink-0 text-[var(--zg-text-muted)]"
119
+ }),
120
+ /* @__PURE__ */ jsxs("div", {
121
+ className: "flex-1 min-w-0 flex flex-col",
122
+ children: [/* @__PURE__ */ jsx("span", {
123
+ className: "truncate font-mono text-zg-ui text-[var(--zg-text)]",
124
+ children: entry.name
125
+ }), /* @__PURE__ */ jsxs("span", {
126
+ className: "flex flex-col zg-meta",
127
+ children: [/* @__PURE__ */ jsx("span", {
128
+ className: left.kind === "expired" ? "text-[var(--zg-warn)]" : void 0,
129
+ children: labels.secretExpiry(left)
130
+ }), entry.sessionId !== void 0 && /* @__PURE__ */ jsx("span", { children: entry.sessionId === sessionId ? labels.secretSavedHere : labels.secretSavedElsewhere })]
131
+ })]
132
+ }),
133
+ onReplace && /* @__PURE__ */ jsx(IconButton, {
134
+ icon: "i-ph-pencil-simple",
135
+ label: labels.secretReplace(entry.name),
136
+ onClick: onReplace
137
+ }),
138
+ onRevoke && /* @__PURE__ */ jsx(IconButton, {
139
+ icon: "i-ph-trash",
140
+ label: labels.secretRevoke(entry.name),
141
+ onClick: onRevoke
142
+ })
143
+ ]
144
+ });
145
+ }
146
+ function AddSecretForm({ sessionId, initialName, saved, onDone }) {
147
+ const labels = useSessionLabels();
148
+ const save = useSessionHost().secrets?.save;
149
+ const id = useId();
150
+ const [name, setName] = useState(initialName);
151
+ const [ttl, setTtl] = useState(DEFAULT_SECRET_TTL);
152
+ const value = useRef("");
153
+ const [filled, setFilled] = useState(false);
154
+ const [busy, setBusy] = useState(false);
155
+ const [error, setError] = useState(null);
156
+ const nameOk = isSecretName(name);
157
+ const replaces = saved.some((entry) => entry.name === name);
158
+ const submit = async (event) => {
159
+ event?.preventDefault();
160
+ if (!save || busy || !nameOk || !filled) return;
161
+ setBusy(true);
162
+ setError(null);
163
+ try {
164
+ await save(sessionId, {
165
+ name,
166
+ value: value.current,
167
+ ttl
168
+ });
169
+ value.current = "";
170
+ onDone();
171
+ } catch (err) {
172
+ setError(err instanceof Error ? err.message : String(err));
173
+ setBusy(false);
174
+ }
175
+ };
176
+ return /* @__PURE__ */ jsxs("form", {
177
+ className: "zg-raised border mt-3 flex flex-col gap-2 rounded-zg-xl px-3 py-2.5",
178
+ onSubmit: (e) => void submit(e),
179
+ children: [
180
+ /* @__PURE__ */ jsx("label", {
181
+ htmlFor: `${id}-name`,
182
+ className: "text-zg-label font-medium text-[var(--zg-text-muted)]",
183
+ children: labels.secretNameLabel
184
+ }),
185
+ /* @__PURE__ */ jsx("input", {
186
+ id: `${id}-name`,
187
+ value: name,
188
+ onChange: (e) => setName(e.target.value.toUpperCase()),
189
+ placeholder: labels.secretNamePlaceholder,
190
+ autoComplete: "off",
191
+ spellCheck: false,
192
+ "aria-invalid": name !== "" && !nameOk ? true : void 0,
193
+ "aria-describedby": `${id}-name-hint`,
194
+ className: `${INPUT} h-8 font-mono`
195
+ }),
196
+ /* @__PURE__ */ jsx("span", {
197
+ id: `${id}-name-hint`,
198
+ className: "text-zg-meta leading-4 text-[var(--zg-text-muted)]",
199
+ children: name !== "" && !nameOk ? labels.secretNameInvalid : replaces ? labels.secretReplacesSaved(name) : null
200
+ }),
201
+ /* @__PURE__ */ jsx("label", {
202
+ htmlFor: `${id}-value`,
203
+ className: "text-zg-label font-medium text-[var(--zg-text-muted)]",
204
+ children: labels.secretValueLabel
205
+ }),
206
+ /* @__PURE__ */ jsx(SecretInput, {
207
+ id: `${id}-value`,
208
+ ttl,
209
+ required: true,
210
+ onChange: (typed, picked) => {
211
+ value.current = typed;
212
+ setFilled(typed.trim() !== "");
213
+ setTtl(picked);
214
+ },
215
+ onSubmit: () => void submit()
216
+ }),
217
+ /* @__PURE__ */ jsxs("div", {
218
+ className: "flex items-center gap-2 pt-1",
219
+ children: [
220
+ /* @__PURE__ */ jsx("button", {
221
+ type: "button",
222
+ className: BTN_GHOST,
223
+ onClick: onDone,
224
+ disabled: busy,
225
+ children: labels.secretCancel
226
+ }),
227
+ /* @__PURE__ */ jsx(CardError, { error }),
228
+ /* @__PURE__ */ jsx("span", { className: "flex-1" }),
229
+ /* @__PURE__ */ jsx("button", {
230
+ type: "submit",
231
+ className: BTN_PRIMARY,
232
+ disabled: busy || !nameOk || !filled,
233
+ children: labels.secretSave
234
+ })
235
+ ]
236
+ })
237
+ ]
238
+ });
239
+ }
240
+ //#endregion
241
+ export { SecretsPanel };
@@ -1,10 +1,10 @@
1
- import { QueuedMessage, RunningWorkItem, SessionArtifactGroup, SessionHost, TodosSnapshot } from "./headless/host.js";
1
+ import { PlansSnapshot, QueuedMessage, RunningWorkItem, Schedule, SchedulesStatus, SessionArtifactGroup, SessionHost, SessionSecretEntry } from "./headless/host.js";
2
2
  import { SessionLabels } from "./headless/labels.js";
3
3
  import { ReactNode } from "react";
4
4
  //#region src/session/SessionProvider.d.ts
5
5
  /** Props for {@link SessionProvider}. */
6
6
  interface SessionProviderProps {
7
- /** The host the session panels below read todos, queues and artifacts from. */
7
+ /** The host the session panels below read plans, queues and artifacts from. */
8
8
  host: SessionHost;
9
9
  /** Overrides for the built-in strings. Keys you leave out keep the default English label. */
10
10
  labels?: Partial<SessionLabels>;
@@ -20,12 +20,33 @@ declare function SessionProvider({ host, labels, children }: SessionProviderProp
20
20
  /** Returns the {@link SessionHost} from the nearest {@link SessionProvider}. Throws when called outside one. */
21
21
  declare function useSessionHost(): SessionHost;
22
22
  /**
23
- * A session's todo snapshot (`null` until read, or without a session or a `todos` host). Re-renders only when that
23
+ * Whether reminders are on (`null` until read, or without a `schedules` host). The first read asks the host. Nothing
24
+ * about reminders shows unless this is `enabled`.
25
+ */
26
+ declare function useSchedulesStatus(): SchedulesStatus | null;
27
+ /**
28
+ * The reminders whose prompt goes to a session (`null` until read, while off, or without a session or a
29
+ * `schedules` host). Re-renders only when that session's reminders change.
30
+ *
31
+ * @param sessionId - The session, or nothing.
32
+ */
33
+ declare function useSessionSchedules(sessionId: string | null | undefined): readonly Schedule[] | null;
34
+ /** Every reminder of the host (`null` until read, while off, or without a `schedules` host). */
35
+ declare function useAllSchedules(): readonly Schedule[] | null;
36
+ /**
37
+ * A session project's saved secrets, by name (`null` until read, or without a session or a `secrets` host).
38
+ * Re-renders only when that session's list changes.
39
+ *
40
+ * @param sessionId - The session, or nothing.
41
+ */
42
+ declare function useSessionSecrets(sessionId: string | null | undefined): readonly SessionSecretEntry[] | null;
43
+ /**
44
+ * A session's plans snapshot (`null` until read, or without a session or a `plans` host). Re-renders only when that
24
45
  * session's snapshot changes.
25
46
  *
26
47
  * @param sessionId - The session, or nothing.
27
48
  */
28
- declare function useSessionTodos(sessionId: string | null | undefined): TodosSnapshot | null;
49
+ declare function useSessionPlans(sessionId: string | null | undefined): PlansSnapshot | null;
29
50
  /**
30
51
  * A session's queued messages, in delivery order (empty without a session or a `queue` host). Re-renders only when
31
52
  * that session's queue changes.
@@ -48,4 +69,4 @@ declare function useSessionArtifacts(sessionId: string | null | undefined): read
48
69
  */
49
70
  declare function useSessionRunningWork(sessionId: string | null | undefined): readonly RunningWorkItem[];
50
71
  //#endregion
51
- export { SessionProvider, SessionProviderProps, useSessionArtifacts, useSessionHost, useSessionQueue, useSessionRunningWork, useSessionTodos };
72
+ export { SessionProvider, SessionProviderProps, useAllSchedules, useSchedulesStatus, useSessionArtifacts, useSessionHost, useSessionPlans, useSessionQueue, useSessionRunningWork, useSessionSchedules, useSessionSecrets };
@@ -32,19 +32,64 @@ function useSessionHost() {
32
32
  if (!host) throw new Error("zidane-ui/session: wrap the session panels in <SessionProvider host={…}>");
33
33
  return host;
34
34
  }
35
- const NO_TODOS = constant(null);
35
+ const NO_PLANS = constant(null);
36
36
  const NO_QUEUE = constant([]);
37
37
  const NO_ARTIFACTS = constant(null);
38
38
  const NO_WORK = constant([]);
39
+ const NO_SECRETS = constant(null);
40
+ const NO_SCHEDULES = constant(null);
41
+ const NO_SCHEDULES_STATUS = constant(null);
39
42
  /**
40
- * A session's todo snapshot (`null` until read, or without a session or a `todos` host). Re-renders only when that
43
+ * Whether reminders are on (`null` until read, or without a `schedules` host). The first read asks the host. Nothing
44
+ * about reminders shows unless this is `enabled`.
45
+ */
46
+ function useSchedulesStatus() {
47
+ const schedules = useSessionHost().schedules;
48
+ useEffect(() => {
49
+ schedules?.ensure();
50
+ }, [schedules]);
51
+ return useReadable(schedules ? schedules.status : NO_SCHEDULES_STATUS);
52
+ }
53
+ /**
54
+ * The reminders whose prompt goes to a session (`null` until read, while off, or without a session or a
55
+ * `schedules` host). Re-renders only when that session's reminders change.
56
+ *
57
+ * @param sessionId - The session, or nothing.
58
+ */
59
+ function useSessionSchedules(sessionId) {
60
+ const schedules = useSessionHost().schedules;
61
+ useEffect(() => {
62
+ if (sessionId) schedules?.ensure();
63
+ }, [schedules, sessionId]);
64
+ return useReadable(sessionId && schedules ? schedules.forSession(sessionId) : NO_SCHEDULES);
65
+ }
66
+ /** Every reminder of the host (`null` until read, while off, or without a `schedules` host). */
67
+ function useAllSchedules() {
68
+ const schedules = useSessionHost().schedules;
69
+ useEffect(() => {
70
+ schedules?.ensure();
71
+ }, [schedules]);
72
+ return useReadable(schedules ? schedules.all : NO_SCHEDULES);
73
+ }
74
+ /**
75
+ * A session project's saved secrets, by name (`null` until read, or without a session or a `secrets` host).
76
+ * Re-renders only when that session's list changes.
77
+ *
78
+ * @param sessionId - The session, or nothing.
79
+ */
80
+ function useSessionSecrets(sessionId) {
81
+ const secrets = useSessionHost().secrets;
82
+ return useReadable(sessionId && secrets ? secrets.entries(sessionId) : NO_SECRETS);
83
+ }
84
+ /**
85
+ * A session's plans snapshot (`null` until read, or without a session or a `plans` host). Re-renders only when that
41
86
  * session's snapshot changes.
42
87
  *
43
88
  * @param sessionId - The session, or nothing.
44
89
  */
45
- function useSessionTodos(sessionId) {
46
- const todos = useSessionHost().todos;
47
- return useReadable(sessionId && todos ? todos.snapshot(sessionId) : NO_TODOS);
90
+ function useSessionPlans(sessionId) {
91
+ const plans = useSessionHost().plans;
92
+ return useReadable(sessionId && plans ? plans.snapshot(sessionId) : NO_PLANS);
48
93
  }
49
94
  /**
50
95
  * A session's queued messages, in delivery order (empty without a session or a `queue` host). Re-renders only when
@@ -80,4 +125,4 @@ function useSessionRunningWork(sessionId) {
80
125
  return useReadable(sessionId && work ? work.items(sessionId) : NO_WORK);
81
126
  }
82
127
  //#endregion
83
- export { SessionProvider, useSessionArtifacts, useSessionHost, useSessionQueue, useSessionRunningWork, useSessionTodos };
128
+ export { SessionProvider, useAllSchedules, useSchedulesStatus, useSessionArtifacts, useSessionHost, useSessionPlans, useSessionQueue, useSessionRunningWork, useSessionSchedules, useSessionSecrets };
@@ -0,0 +1,24 @@
1
+ import { CSSProperties } from "react";
2
+ import { TodoStatus } from "zidane/chat";
3
+ //#region src/session/StepStatusIcon.d.ts
4
+ /** What a {@link StepStatusIcon} shows: a todo status, or `stopped` for the step a stopped plan halted at. */
5
+ type StepIconState = TodoStatus | 'stopped';
6
+ /** Props for {@link StepStatusIcon}. */
7
+ interface StepStatusIconProps {
8
+ /** The status to show. */
9
+ state: StepIconState;
10
+ /** Accessible name and tooltip. */
11
+ label: string;
12
+ /** Extra classes on the root element, such as a text size. */
13
+ className?: string;
14
+ /** Inline styles on the root element, merged after the component's own. */
15
+ style?: CSSProperties;
16
+ }
17
+ /**
18
+ * Renders a step's status as an icon that cross-fades and pops between states.
19
+ *
20
+ * @param props - The {@link StepStatusIconProps}.
21
+ */
22
+ declare function StepStatusIcon({ state, label, className, style }: StepStatusIconProps): import("react").JSX.Element;
23
+ //#endregion
24
+ export { StepIconState, StepStatusIcon, StepStatusIconProps };
@@ -0,0 +1,50 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ //#region src/session/StepStatusIcon.tsx
4
+ /**
5
+ * A plan step's or todo's status as an icon: an empty circle while pending,
6
+ * the kit's spin ring while in progress, a check when done, a cross when
7
+ * cancelled, a warning on the step a stopped plan halted at. The glyphs
8
+ * stack in one box and cross-fade (`.zg-swap`); a status that changes while
9
+ * shown pops its glyph in (`zg-pop` on `snap`, `.zg-step-icon-layer`
10
+ * in styles/motion.css). The first render never pops, so opening a finished
11
+ * plan reads still.
12
+ */
13
+ const GLYPHS = {
14
+ pending: "i-ph-circle text-[var(--zg-text-subtle)]",
15
+ in_progress: "zg-spin-ring zg-loop text-[var(--zg-accent)]",
16
+ completed: "i-ph-check-circle-fill text-zg-success",
17
+ cancelled: "i-ph-x-circle text-[var(--zg-text-muted)]",
18
+ stopped: "i-ph-warning-circle-fill text-[var(--zg-warn)]"
19
+ };
20
+ const STATES = Object.keys(GLYPHS);
21
+ /**
22
+ * Renders a step's status as an icon that cross-fades and pops between states.
23
+ *
24
+ * @param props - The {@link StepStatusIconProps}.
25
+ */
26
+ function StepStatusIcon({ state, label, className, style }) {
27
+ const [shown, setShown] = useState(state);
28
+ const [moved, setMoved] = useState(false);
29
+ if (shown !== state) {
30
+ setShown(state);
31
+ setMoved(true);
32
+ }
33
+ return /* @__PURE__ */ jsx("span", {
34
+ role: "img",
35
+ "aria-label": label,
36
+ title: label,
37
+ "data-state": state,
38
+ className: ["zg-swap shrink-0", className].filter(Boolean).join(" "),
39
+ style,
40
+ children: STATES.map((k) => /* @__PURE__ */ jsx("span", {
41
+ "aria-hidden": true,
42
+ className: "zg-step-icon-layer",
43
+ "data-on": k === state ? "" : void 0,
44
+ "data-landed": moved && k === state ? "" : void 0,
45
+ children: /* @__PURE__ */ jsx("span", { className: GLYPHS[k] })
46
+ }, k))
47
+ });
48
+ }
49
+ //#endregion
50
+ export { StepStatusIcon };
@@ -1,5 +1,6 @@
1
+ import { TodoTallyCounts } from "./headless/plans.js";
1
2
  import { CSSProperties } from "react";
2
- import { TodoStatus, TodoTally as TodoTally$1 } from "zidane/chat";
3
+ import { TodoStatus } from "zidane/chat";
3
4
  //#region src/session/TodoList.d.ts
4
5
  /** A flat todo row: no box of its own, the hover wash only. */
5
6
  declare const TODO_ROW_CLASS = "flex items-center gap-2.5 px-2 py-1 rounded-zg-md";
@@ -41,8 +42,8 @@ interface TodoListViewProps {
41
42
  declare function TodoListView({ items, className, style }: TodoListViewProps): import("react").JSX.Element;
42
43
  /** Props for {@link TodoTally}. */
43
44
  interface TodoTallyProps {
44
- /** Items per status. */
45
- tally: TodoTally$1;
45
+ /** Items per status (`planTally` of a plan). */
46
+ tally: TodoTallyCounts;
46
47
  /** Extra classes on the root element. */
47
48
  className?: string;
48
49
  /** Inline styles on the root element, merged after the component's own. */
@@ -1,7 +1,7 @@
1
1
  import { MetaChip } from "../components/Form.js";
2
2
  import { useSessionLabels } from "./useSessionLabels.js";
3
+ import { StepStatusIcon } from "./StepStatusIcon.js";
3
4
  import { jsx, jsxs } from "react/jsx-runtime";
4
- import { TODO_STATUS_GLYPHS } from "zidane/chat/pure";
5
5
  //#region src/session/TodoList.tsx
6
6
  /** A flat todo row: no box of its own, the hover wash only. */
7
7
  const TODO_ROW_CLASS = "flex items-center gap-2.5 px-2 py-1 rounded-zg-md";
@@ -27,16 +27,17 @@ function isDoneTodo(status) {
27
27
  * @param props - The {@link TodoListViewProps}.
28
28
  */
29
29
  function TodoListView({ items, className, style }) {
30
+ const labels = useSessionLabels();
30
31
  return /* @__PURE__ */ jsx("ul", {
31
32
  className: ["flex flex-col gap-px m-0 p-0 list-none", className].filter(Boolean).join(" "),
32
33
  style,
33
34
  children: items.map((todo) => /* @__PURE__ */ jsxs("li", {
34
35
  "data-status": todo.status,
35
36
  className: TODO_ROW_CLASS,
36
- children: [/* @__PURE__ */ jsx("span", {
37
- className: `text-zg-ui leading-6 w-4 shrink-0 ${todoGlyphTone(todo.status)}`,
38
- title: todo.status,
39
- children: TODO_STATUS_GLYPHS[todo.status]
37
+ children: [/* @__PURE__ */ jsx(StepStatusIcon, {
38
+ state: todo.status,
39
+ label: labels.todoStatus(todo.status),
40
+ className: "text-zg-ui"
40
41
  }), /* @__PURE__ */ jsx("span", {
41
42
  className: `flex-1 min-w-0 text-zg-ui leading-6 truncate ${isDoneTodo(todo.status) ? "text-[var(--zg-text-muted)] line-through" : "text-[var(--zg-text)]"}`,
42
43
  title: todo.content,
@@ -1,6 +1,7 @@
1
- import { ProviderUsageSnapshot, UsageRange, UsageSummary } from "./usage.js";
2
- import { PromptAttachment as PromptAttachment$1, RunningWorkItem, SessionArtifactRow, SessionHost, SessionTurn, TodosSnapshot as TodosSnapshot$1 } from "./host.js";
3
- import { TodoItem, TodoTally } from "zidane/chat";
1
+ import { ProviderUsageSnapshot as ProviderUsageSnapshot$1, UsageRange, UsageSummary } from "./usage.js";
2
+ import { PromptAttachment as PromptAttachment$1, RunningWorkItem, SessionArtifactRow, SessionHost, SessionSecretEntry, SessionTurn } from "./host.js";
3
+ import { Schedule, ScheduleFire } from "zidane/chat/pure";
4
+ import { PlanView, TodoItem } from "zidane/chat";
4
5
  //#region src/session/headless/fixture-host.d.ts
5
6
  /** A queued entry the fixture holds, with its attachments' bytes. */
6
7
  interface FixtureQueuedEntry {
@@ -13,7 +14,9 @@ interface FixtureQueuedEntry {
13
14
  }
14
15
  /** What a fixture session host starts with, per session id. */
15
16
  interface SessionFixture {
16
- /** The todo list per session. */
17
+ /** The plans per session, oldest first (`possiblyInterrupted` shows an applying plan with no live run). */
18
+ plans?: Readonly<Record<string, readonly PlanView[]>>;
19
+ /** The task list per session as the agent wrote it (`todowrite`), over `plans`: an applying plan. */
17
20
  todos?: Readonly<Record<string, readonly TodoItem[]>>;
18
21
  /** The queued messages per session. */
19
22
  queue?: Readonly<Record<string, readonly FixtureQueuedEntry[]>>;
@@ -28,41 +31,48 @@ interface SessionFixture {
28
31
  /** The usage summary per range. Absent: no `usage.summary`. */
29
32
  usage?: Partial<Record<UsageRange, UsageSummary>>;
30
33
  /** The providers' subscription snapshots. Absent: no `usage.providers`. */
31
- providerUsage?: readonly ProviderUsageSnapshot[];
34
+ providerUsage?: readonly ProviderUsageSnapshot$1[];
32
35
  /** GitHub's API limits. Absent: no `usage.github`. */
33
- githubUsage?: readonly ProviderUsageSnapshot[];
36
+ githubUsage?: readonly ProviderUsageSnapshot$1[];
34
37
  /** Each session's side chat id, by the parent's id. Absent: no `side`. */
35
38
  sides?: Readonly<Record<string, string>>;
39
+ /** The saved secrets per session (as the session's project holds them). Absent: no `secrets`. */
40
+ secrets?: Readonly<Record<string, readonly SessionSecretEntry[]>>;
41
+ /** `secrets.save` rejects with this message (a plain-text remote link refusing values). */
42
+ secretsSaveError?: string;
43
+ /** The stored reminders (zidane's schedules), oldest first. Absent: no `schedules`. */
44
+ schedules?: readonly Schedule[];
45
+ /** Each reminder's fires, newest first, by schedule id. */
46
+ scheduleFires?: Readonly<Record<string, readonly ScheduleFire[]>>;
47
+ /** `Settings.schedules`. @default true */
48
+ schedulesEnabled?: boolean;
36
49
  }
37
50
  /** Changes a fixture's data from outside and announces it, as the agent or another window would. */
38
51
  interface FixtureSessionControl {
39
- /** Replaces a session's todo list. */
40
- setTodos(sessionId: string, items: readonly TodoItem[]): void;
52
+ /** The agent's `todowrite`: updates the applying plan, starts one, or resumes a stopped one with the same step ids. */
53
+ writeTodos(sessionId: string, items: readonly TodoItem[]): void;
54
+ /** The session's run ended: the plan it applied stops. */
55
+ endRun(sessionId: string, outcome?: 'completed' | 'aborted' | 'error'): void;
56
+ /** Replaces a session's plans. */
57
+ setPlans(sessionId: string, plans: readonly PlanView[]): void;
41
58
  /** Replaces a session's queue. */
42
59
  setQueue(sessionId: string, entries: readonly FixtureQueuedEntry[]): void;
43
60
  /** Records an artifact (newest first). */
44
61
  recordArtifact(sessionId: string, row: SessionArtifactRow): void;
45
62
  /** Replaces a session's running work. */
46
63
  setWork(sessionId: string, items: readonly RunningWorkItem[]): void;
64
+ /** Replaces a session's saved secrets (the agent saved one, another window revoked one). */
65
+ setSecrets(sessionId: string, entries: readonly SessionSecretEntry[]): void;
66
+ /** Replaces the stored reminders (the agent set one, one fired) and announces the change. */
67
+ setSchedules(list: readonly Schedule[]): void;
68
+ /** Turns the Reminders setting on or off and announces it. */
69
+ setSchedulesEnabled(enabled: boolean): void;
47
70
  }
48
71
  /** The fixture host: a full `SessionHost` plus its `control`. */
49
72
  interface FixtureSessionHost extends SessionHost {
50
73
  /** Changes the data from outside. */
51
74
  control: FixtureSessionControl;
52
75
  }
53
- /**
54
- * Counts todo items by status.
55
- *
56
- * @param items - The todo list.
57
- */
58
- declare function tallyTodos(items: readonly TodoItem[]): TodoTally;
59
- /**
60
- * A todo snapshot of a list, as a backend broadcasts it.
61
- *
62
- * @param items - The live list.
63
- * @param archive - The last non-empty list (shown read-only when the live one is empty).
64
- */
65
- declare function todosSnapshotOf(items: readonly TodoItem[], archive?: readonly TodoItem[]): TodosSnapshot$1;
66
76
  /**
67
77
  * Creates a {@link FixtureSessionHost} over the fixture's data.
68
78
  *
@@ -70,4 +80,4 @@ declare function todosSnapshotOf(items: readonly TodoItem[], archive?: readonly
70
80
  */
71
81
  declare function createFixtureSessionHost(fixture?: SessionFixture): FixtureSessionHost;
72
82
  //#endregion
73
- export { FixtureQueuedEntry, FixtureSessionControl, FixtureSessionHost, SessionFixture, createFixtureSessionHost, tallyTodos, todosSnapshotOf };
83
+ export { FixtureQueuedEntry, FixtureSessionControl, FixtureSessionHost, SessionFixture, createFixtureSessionHost };