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
@@ -1,3 +1,4 @@
1
+ import { displayedPlan } from "../headless/plans.js";
1
2
  import { createSessionActions } from "../headless/session-actions.js";
2
3
  import { afterEach, describe, expect, it, vi } from "vitest";
3
4
  //#region src/session/testing/contract.ts
@@ -6,29 +7,34 @@ import { afterEach, describe, expect, it, vi } from "vitest";
6
7
  * (`createFixtureSessionHost`), zidane-server (`createServerSessionHost`), the desktop app's IPC host.
7
8
  *
8
9
  * An implementation's test calls {@link describeSessionHostContract} with a harness factory. The
9
- * contract hands it a {@link SessionHostContractBackend}: the todo lists, queues and artifacts the
10
+ * contract hands it a {@link SessionHostContractBackend}: the plans, queues and artifacts the
10
11
  * backend holds. The harness builds the host over a backend that holds them and behaves as below, and
11
12
  * returns a {@link SessionHostContractControl} that changes the backend from outside (the agent wrote
12
13
  * its todos, another window queued a message, an artifact landed). The capabilities list says which
13
14
  * optional members the host offers: the suite checks the others are left out (undefined, never a
14
15
  * throwing stub) and skips the behaviours that need them.
15
16
  *
16
- * The backend: `todos.set` replaces the list and announces the new snapshot; every session is mid-run,
17
+ * The backend: plans change through zidane's plan gate (`applyPlanEvent`; `createFixturePlansBackend` is one):
18
+ * `plans.edit` and `plans.control` apply the user's change, answer the snapshot and announce it, and reject
19
+ * with the gate's reason; every session is mid-run,
17
20
  * so a message added to the queue waits there (delivered `queued`); removing, editing or pushing an
18
21
  * entry announces the queue; pushing an entry that is gone answers `missing`; removing an artifact
19
22
  * announces the change; cancelling work removes it (`all`: every item) and announces the session's work;
20
23
  * a fork answers a new session id; editing a turn's text replaces its text blocks; deleting a turn removes
21
24
  * it; generating a title answers a non-empty title, an export a path; the usage summary of a range covers
22
- * that range. The session actions over the host (`createSessionActions`) offer what it offers and run.
25
+ * that range; saving a secret stores its entry (name, expiry, the saving session; never the value) and
26
+ * announces a change, revoking one removes it and announces a change; the reminders are served as
27
+ * `createFixtureScheduleBackend` does (the setting on, a create validated, a pause clears the next time). The session actions over the host (`createSessionActions`) offer what it offers and run.
23
28
  *
24
29
  * describeSessionHostContract('createFixtureSessionHost', (backend) => ({ host, control }), [
25
- * 'todos', 'todos.set', 'queue', 'queue.add', 'artifacts',
30
+ * 'plans', 'plans.edit', 'plans.control', 'queue', 'queue.add', 'artifacts',
26
31
  * ]);
27
32
  */
28
33
  const CAPABILITIES = [
29
- "todos",
30
- "todos.set",
31
- "todos.retry",
34
+ "plans",
35
+ "plans.edit",
36
+ "plans.control",
37
+ "plans.retry",
32
38
  "queue",
33
39
  "queue.add",
34
40
  "queue.remove",
@@ -58,7 +64,16 @@ const CAPABILITIES = [
58
64
  "usage.github",
59
65
  "usage.redeemReset",
60
66
  "side",
61
- "side.subscribe"
67
+ "side.subscribe",
68
+ "secrets",
69
+ "secrets.save",
70
+ "secrets.revoke",
71
+ "schedules",
72
+ "schedules.create",
73
+ "schedules.update",
74
+ "schedules.remove",
75
+ "schedules.runNow",
76
+ "schedules.fires"
62
77
  ];
63
78
  const artifact = (id, kind, label) => ({
64
79
  id,
@@ -129,9 +144,81 @@ function contractBackend() {
129
144
  }],
130
145
  createdAt: 2
131
146
  }] },
132
- sides: { "s-1": "side-1" }
147
+ sides: { "s-1": "side-1" },
148
+ secrets: { "s-1": [{
149
+ name: "GITHUB_TOKEN",
150
+ createdAt: 1,
151
+ expiresAt: null,
152
+ sessionId: "s-1"
153
+ }, {
154
+ name: "API_KEY",
155
+ createdAt: 2,
156
+ expiresAt: 41024448e5,
157
+ sessionId: "s-2"
158
+ }] },
159
+ schedules: [
160
+ schedule("sch-1", {
161
+ kind: "at",
162
+ at: FAR
163
+ }, {
164
+ kind: "prompt",
165
+ sessionId: "s-1",
166
+ text: "Check the CI"
167
+ }, { kind: "user" }),
168
+ {
169
+ ...schedule("sch-2", {
170
+ kind: "every",
171
+ everyMs: 36e5,
172
+ anchor: 1
173
+ }, {
174
+ kind: "prompt",
175
+ sessionId: "s-1",
176
+ text: "Look at the queue"
177
+ }, {
178
+ kind: "agent",
179
+ sessionId: "s-1"
180
+ }),
181
+ expiresAt: FAR + 6e4
182
+ },
183
+ schedule("sch-3", {
184
+ kind: "at",
185
+ at: FAR
186
+ }, {
187
+ kind: "prompt",
188
+ sessionId: "s-2",
189
+ text: "Ship it"
190
+ }, { kind: "user" })
191
+ ],
192
+ scheduleFires: { "sch-2": [{
193
+ id: "f2",
194
+ scheduleId: "sch-2",
195
+ dueAt: 20,
196
+ firedAt: 20,
197
+ outcome: "queued",
198
+ sessionId: "s-1"
199
+ }, {
200
+ id: "f1",
201
+ scheduleId: "sch-2",
202
+ dueAt: 10,
203
+ firedAt: 11,
204
+ outcome: "sent",
205
+ sessionId: "s-1"
206
+ }] }
133
207
  };
134
208
  }
209
+ /** A time far ahead (2100), so a reminder never fires during a test. */
210
+ const FAR = 41024448e5;
211
+ const schedule = (id, trigger, action, createdBy) => ({
212
+ id,
213
+ trigger,
214
+ action,
215
+ catchUp: trigger.kind === "at" ? "once" : "skip",
216
+ enabled: true,
217
+ createdBy,
218
+ createdAt: 1,
219
+ updatedAt: 1,
220
+ nextFireAt: FAR
221
+ });
135
222
  function member(host, capability) {
136
223
  const [head, tail] = capability.split(".");
137
224
  const value = host[head];
@@ -175,7 +262,7 @@ function describeSessionHostContract(name, makeHarness, capabilities) {
175
262
  }
176
263
  expect(typeof value, capability).toBe(capability.includes(".") ? "function" : "object");
177
264
  }
178
- if (has("todos")) expect(typeof host.todos?.snapshot).toBe("function");
265
+ if (has("plans")) expect(typeof host.plans?.snapshot).toBe("function");
179
266
  if (has("queue")) expect(typeof host.queue?.items).toBe("function");
180
267
  if (has("artifacts")) expect(typeof host.artifacts?.groups).toBe("function");
181
268
  if (has("runningWork")) {
@@ -203,51 +290,113 @@ function describeSessionHostContract(name, makeHarness, capabilities) {
203
290
  if (actions.fork) expect(await actions.fork("s-1", "u1")).not.toBe("s-1");
204
291
  expect(onError).not.toHaveBeenCalled();
205
292
  });
206
- describe.skipIf(!has("todos"))("todos", () => {
207
- it("reads a session list and hears the backend replace it", async () => {
293
+ describe.skipIf(!has("plans"))("plans", () => {
294
+ const shown = (host) => {
295
+ const snap = host.plans.snapshot("s-1").get();
296
+ return snap ? displayedPlan(snap.plans) : null;
297
+ };
298
+ const titles = (host) => shown(host)?.steps.map((s) => s.title);
299
+ it("reads a session plan and hears the agent write it again", async () => {
208
300
  const { host, control } = await setup();
209
- const snap = watch(host.todos.snapshot("s-1"));
210
- expect(host.todos.snapshot("s-1")).toBe(snap);
211
- await host.todos.refresh("s-1");
212
- expect(snap.get()?.todos.map((t) => t.content)).toEqual([
301
+ const snap = watch(host.plans.snapshot("s-1"));
302
+ expect(host.plans.snapshot("s-1")).toBe(snap);
303
+ await host.plans.refresh("s-1");
304
+ expect(titles(host)).toEqual([
213
305
  "First",
214
306
  "Second",
215
307
  "Third"
216
308
  ]);
217
- expect(snap.get()?.tally).toEqual({
218
- pending: 1,
219
- in_progress: 1,
220
- completed: 1,
221
- cancelled: 0
309
+ expect(shown(host)?.state).toBe("applying");
310
+ expect(snap.get()?.active).toMatchObject({
311
+ state: "applying",
312
+ progress: {
313
+ completed: 1,
314
+ total: 3
315
+ }
222
316
  });
223
- control.setTodos("s-1", [{
224
- id: "n",
225
- content: "Only",
226
- status: "pending"
227
- }]);
228
- await waitFor(() => expect(snap.get()?.todos.map((t) => t.content)).toEqual(["Only"]));
317
+ control.writeTodos("s-1", [
318
+ {
319
+ id: "t1",
320
+ content: "First",
321
+ status: "completed"
322
+ },
323
+ {
324
+ id: "t2",
325
+ content: "Second",
326
+ status: "completed"
327
+ },
328
+ {
329
+ id: "t3",
330
+ content: "Third",
331
+ status: "in_progress"
332
+ }
333
+ ]);
334
+ await waitFor(() => expect(snap.get()?.active?.progress.completed).toBe(2));
229
335
  });
230
- it("reads null for a session without a list, and never rejects", async () => {
336
+ it("reads null for a session without plans, and never rejects", async () => {
231
337
  const { host } = await setup();
232
- await expect(host.todos.refresh("s-none")).resolves.toBeUndefined();
233
- expect(host.todos.snapshot("s-none").get()).toBeNull();
338
+ await expect(host.plans.refresh("s-none")).resolves.toBeUndefined();
339
+ expect(host.plans.snapshot("s-none").get()).toBeNull();
234
340
  });
235
- it.skipIf(!has("todos.set"))("set replaces the list and the snapshot follows", async () => {
341
+ it.skipIf(!has("plans.edit"))("edit adds, renames and cancels a step; the snapshot follows", async () => {
236
342
  const { host } = await setup();
237
- const snap = watch(host.todos.snapshot("s-1"));
238
- await host.todos.refresh("s-1");
239
- const applied = await host.todos.set("s-1", [{
240
- id: "x",
241
- content: "Edited",
242
- status: "completed"
243
- }]);
244
- expect(applied).toBe(true);
245
- await waitFor(() => expect(snap.get()?.todos.map((t) => t.content)).toEqual(["Edited"]));
246
- expect(snap.get()?.tally.completed).toBe(1);
343
+ watch(host.plans.snapshot("s-1"));
344
+ await host.plans.refresh("s-1");
345
+ const planId = shown(host).id;
346
+ await host.plans.edit("s-1", planId, {
347
+ kind: "add",
348
+ title: "Fourth"
349
+ });
350
+ await waitFor(() => expect(titles(host)).toEqual([
351
+ "First",
352
+ "Second",
353
+ "Third",
354
+ "Fourth"
355
+ ]));
356
+ expect(shown(host)?.steps[3]).toMatchObject({
357
+ status: "pending",
358
+ added: true
359
+ });
360
+ await host.plans.edit("s-1", planId, {
361
+ kind: "rename",
362
+ stepId: "t3",
363
+ title: "Third, renamed"
364
+ });
365
+ await waitFor(() => expect(titles(host)?.[2]).toBe("Third, renamed"));
366
+ await host.plans.edit("s-1", planId, {
367
+ kind: "cancel",
368
+ stepId: "t2"
369
+ });
370
+ await waitFor(() => expect(shown(host)?.steps[1]).toMatchObject({
371
+ status: "cancelled",
372
+ cancelledBy: "user"
373
+ }));
374
+ });
375
+ it.skipIf(!has("plans.edit"))("edit rejects with the backend's reason", async () => {
376
+ const { host } = await setup();
377
+ await host.plans.refresh("s-1");
378
+ await expect(host.plans.edit("s-1", shown(host).id, {
379
+ kind: "cancel",
380
+ stepId: "t1"
381
+ })).rejects.toThrow(/already completed/);
247
382
  });
248
- it.skipIf(!has("todos.retry"))("retry resolves", async () => {
383
+ it.skipIf(!has("plans.control"))("control stops, then drops the plan; the snapshot follows", async () => {
249
384
  const { host } = await setup();
250
- await expect(host.todos.retry("s-1", "Retry: Second")).resolves.toBeUndefined();
385
+ watch(host.plans.snapshot("s-1"));
386
+ await host.plans.refresh("s-1");
387
+ const planId = shown(host).id;
388
+ await host.plans.control("s-1", planId, "stop");
389
+ await waitFor(() => expect(shown(host)).toMatchObject({
390
+ state: "stopped",
391
+ stopReason: "user"
392
+ }));
393
+ await host.plans.control("s-1", planId, "drop");
394
+ await waitFor(() => expect(shown(host)?.state).toBe("dropped"));
395
+ await expect(host.plans.control("s-1", planId, "stop")).rejects.toThrow();
396
+ });
397
+ it.skipIf(!has("plans.retry"))("retry resolves", async () => {
398
+ const { host } = await setup();
399
+ await expect(host.plans.retry("s-1", "Retry step t2")).resolves.toBeUndefined();
251
400
  });
252
401
  });
253
402
  describe.skipIf(!has("queue"))("queue", () => {
@@ -363,6 +512,165 @@ function describeSessionHostContract(name, makeHarness, capabilities) {
363
512
  await expect(host.artifacts.refreshRow("s-1", row.artifact, { force: true })).resolves.toBeUndefined();
364
513
  });
365
514
  });
515
+ describe.skipIf(!has("secrets"))("secrets", () => {
516
+ const names = (host, sessionId = "s-1") => host.secrets.entries(sessionId).get()?.map((e) => e.name) ?? null;
517
+ it("reads the session secrets by name, never a value, and hears a change", async () => {
518
+ const { host, control } = await setup();
519
+ const entries = watch(host.secrets.entries("s-1"));
520
+ expect(entries.get()).toBeNull();
521
+ await host.secrets.refresh("s-1");
522
+ expect(names(host)).toEqual(["API_KEY", "GITHUB_TOKEN"]);
523
+ for (const entry of entries.get()) expect(entry).not.toHaveProperty("value");
524
+ control.setSecrets("s-1", [{
525
+ name: "NPM_TOKEN",
526
+ createdAt: 3,
527
+ expiresAt: null,
528
+ sessionId: "s-1"
529
+ }]);
530
+ await waitFor(() => expect(names(host)).toEqual(["NPM_TOKEN"]));
531
+ });
532
+ it("reads an empty list for a session without secrets", async () => {
533
+ const { host } = await setup();
534
+ await host.secrets.refresh("s-none");
535
+ expect(host.secrets.entries("s-none").get()).toEqual([]);
536
+ });
537
+ it.skipIf(!has("secrets.save"))("save stores a secret for the session and the list follows", async () => {
538
+ const { host } = await setup();
539
+ watch(host.secrets.entries("s-1"));
540
+ await host.secrets.refresh("s-1");
541
+ const entry = await host.secrets.save("s-1", {
542
+ name: "NEW_TOKEN",
543
+ value: "hunter2",
544
+ ttl: "never"
545
+ });
546
+ expect(entry).toMatchObject({
547
+ name: "NEW_TOKEN",
548
+ expiresAt: null
549
+ });
550
+ expect(JSON.stringify(entry)).not.toContain("hunter2");
551
+ await waitFor(() => expect(names(host)).toContain("NEW_TOKEN"));
552
+ expect(JSON.stringify(host.secrets.entries("s-1").get())).not.toContain("hunter2");
553
+ });
554
+ it.skipIf(!has("secrets.revoke"))("revoke removes a secret and the list follows", async () => {
555
+ const { host } = await setup();
556
+ watch(host.secrets.entries("s-1"));
557
+ await host.secrets.refresh("s-1");
558
+ expect(await host.secrets.revoke("s-1", "API_KEY")).toBe(true);
559
+ await waitFor(() => expect(names(host)).toEqual(["GITHUB_TOKEN"]));
560
+ expect(await host.secrets.revoke("s-1", "API_KEY")).toBe(false);
561
+ });
562
+ });
563
+ describe.skipIf(!has("schedules"))("schedules", () => {
564
+ const ids = (list) => list?.map((s) => s.id) ?? null;
565
+ it("reads the status and every schedule, and cuts a session view", async () => {
566
+ const { host } = await setup();
567
+ const schedules = host.schedules;
568
+ const all = watch(schedules.all);
569
+ const mine = watch(schedules.forSession("s-1"));
570
+ expect(schedules.forSession("s-1")).toBe(mine);
571
+ await schedules.refresh();
572
+ expect(schedules.status.get()).toEqual({
573
+ enabled: true,
574
+ supported: true
575
+ });
576
+ expect(ids(all.get())).toEqual([
577
+ "sch-1",
578
+ "sch-2",
579
+ "sch-3"
580
+ ]);
581
+ expect(ids(mine.get())).toEqual(["sch-1", "sch-2"]);
582
+ expect(ids(schedules.forSession("s-none").get())).toEqual([]);
583
+ });
584
+ it("hears the backend change the list", async () => {
585
+ const { host, control } = await setup();
586
+ if (!control.setSchedules) return;
587
+ const all = watch(host.schedules.all);
588
+ await host.schedules.refresh();
589
+ control.setSchedules([contractBackend().schedules[2]]);
590
+ await waitFor(() => expect(ids(all.get())).toEqual(["sch-3"]));
591
+ });
592
+ it.skipIf(!has("schedules.create"))("create stores an exact trigger and the session view follows", async () => {
593
+ const { host } = await setup();
594
+ const mine = watch(host.schedules.forSession("s-1"));
595
+ await host.schedules.refresh();
596
+ const at = Date.now() + 36e5;
597
+ const created = await host.schedules.create({
598
+ trigger: {
599
+ kind: "at",
600
+ at
601
+ },
602
+ action: {
603
+ kind: "prompt",
604
+ sessionId: "s-1",
605
+ text: "Run the tests"
606
+ }
607
+ });
608
+ expect(created).toMatchObject({
609
+ enabled: true,
610
+ nextFireAt: at,
611
+ createdBy: { kind: "user" }
612
+ });
613
+ await waitFor(() => expect(ids(mine.get())).toContain(created.id));
614
+ });
615
+ it.skipIf(!has("schedules.create"))("create rejects a time in the past", async () => {
616
+ const { host } = await setup();
617
+ await expect(host.schedules.create({
618
+ trigger: {
619
+ kind: "at",
620
+ at: 1e3
621
+ },
622
+ action: {
623
+ kind: "prompt",
624
+ sessionId: "s-1",
625
+ text: "Too late"
626
+ }
627
+ })).rejects.toThrow();
628
+ });
629
+ it.skipIf(!has("schedules.update"))("update pauses, resumes and keeps an agent repeat for good", async () => {
630
+ const { host } = await setup();
631
+ const all = watch(host.schedules.all);
632
+ await host.schedules.refresh();
633
+ const paused = await host.schedules.update("sch-2", { enabled: false });
634
+ expect(paused).toMatchObject({
635
+ id: "sch-2",
636
+ enabled: false,
637
+ nextFireAt: null
638
+ });
639
+ await waitFor(() => expect(all.get()?.find((s) => s.id === "sch-2")?.enabled).toBe(false));
640
+ const resumed = await host.schedules.update("sch-2", { enabled: true });
641
+ expect(resumed.enabled).toBe(true);
642
+ expect(resumed.nextFireAt).not.toBeNull();
643
+ const kept = await host.schedules.update("sch-2", { expiresAt: null });
644
+ expect(kept.expiresAt).toBeUndefined();
645
+ });
646
+ it.skipIf(!has("schedules.remove"))("remove deletes a schedule and the list follows", async () => {
647
+ const { host } = await setup();
648
+ const all = watch(host.schedules.all);
649
+ await host.schedules.refresh();
650
+ expect(await host.schedules.remove("sch-1")).toBe(true);
651
+ await waitFor(() => expect(ids(all.get())).toEqual(["sch-2", "sch-3"]));
652
+ expect(await host.schedules.remove("sch-1")).toBe(false);
653
+ });
654
+ it.skipIf(!has("schedules.runNow"))("runNow answers the fire it made", async () => {
655
+ const { host } = await setup();
656
+ const fire = await host.schedules.runNow("sch-1");
657
+ expect(fire).toMatchObject({
658
+ scheduleId: "sch-1",
659
+ sessionId: "s-1"
660
+ });
661
+ expect([
662
+ "sent",
663
+ "queued",
664
+ "merged"
665
+ ]).toContain(fire.outcome);
666
+ if (has("schedules.fires")) expect((await host.schedules.fires("sch-1"))[0]?.id).toBe(fire.id);
667
+ });
668
+ it.skipIf(!has("schedules.fires"))("fires answers the history, newest first", async () => {
669
+ const { host } = await setup();
670
+ expect((await host.schedules.fires("sch-2")).map((f) => f.id)).toEqual(["f2", "f1"]);
671
+ expect(await host.schedules.fires("sch-1")).toEqual([]);
672
+ });
673
+ });
366
674
  describe.skipIf(!has("runningWork"))("runningWork", () => {
367
675
  const work = (host) => host.runningWork.items("s-1").get().map((w) => w.id);
368
676
  it("reads a session work and hears the backend change it; ensure reads once", async () => {
@@ -1,3 +1,5 @@
1
- import { FixtureQueuedEntry, FixtureSessionControl, FixtureSessionHost, SessionFixture, createFixtureSessionHost, tallyTodos, todosSnapshotOf } from "../headless/fixture-host.js";
1
+ import { FixtureQueuedEntry, FixtureSessionControl, FixtureSessionHost, SessionFixture, createFixtureSessionHost } from "../headless/fixture-host.js";
2
+ import { FixturePlansBackend, FixturePlansSeed, createFixturePlansBackend, planOf, plansSnapshotOf, tallyTodos } from "../headless/fixture-plans.js";
3
+ import { FixtureScheduleBackend, FixtureScheduleOptions, SCHEDULES_OFF_MESSAGE, createFixtureScheduleBackend } from "../headless/fixture-schedules.js";
2
4
  import { DEMO_ARTIFACT_KIND_LABELS, DEMO_GITHUB_USAGE, DEMO_PROVIDER_USAGE, DEMO_SESSION_FIXTURE, DEMO_TURNS, demoUsageSummary } from "./demo.js";
3
- export { DEMO_ARTIFACT_KIND_LABELS, DEMO_GITHUB_USAGE, DEMO_PROVIDER_USAGE, DEMO_SESSION_FIXTURE, DEMO_TURNS, FixtureQueuedEntry, FixtureSessionControl, FixtureSessionHost, SessionFixture, createFixtureSessionHost, demoUsageSummary, tallyTodos, todosSnapshotOf };
5
+ export { DEMO_ARTIFACT_KIND_LABELS, DEMO_GITHUB_USAGE, DEMO_PROVIDER_USAGE, DEMO_SESSION_FIXTURE, DEMO_TURNS, FixturePlansBackend, FixturePlansSeed, FixtureQueuedEntry, FixtureScheduleBackend, FixtureScheduleOptions, FixtureSessionControl, FixtureSessionHost, SCHEDULES_OFF_MESSAGE, SessionFixture, createFixturePlansBackend, createFixtureScheduleBackend, createFixtureSessionHost, demoUsageSummary, planOf, plansSnapshotOf, tallyTodos };
@@ -1,3 +1,5 @@
1
- import { createFixtureSessionHost, tallyTodos, todosSnapshotOf } from "../headless/fixture-host.js";
1
+ import { SCHEDULES_OFF_MESSAGE, createFixtureScheduleBackend } from "../headless/fixture-schedules.js";
2
+ import { createFixturePlansBackend, planOf, plansSnapshotOf, tallyTodos } from "../headless/fixture-plans.js";
3
+ import { createFixtureSessionHost } from "../headless/fixture-host.js";
2
4
  import { DEMO_ARTIFACT_KIND_LABELS, DEMO_GITHUB_USAGE, DEMO_PROVIDER_USAGE, DEMO_SESSION_FIXTURE, DEMO_TURNS, demoUsageSummary } from "./demo.js";
3
- export { DEMO_ARTIFACT_KIND_LABELS, DEMO_GITHUB_USAGE, DEMO_PROVIDER_USAGE, DEMO_SESSION_FIXTURE, DEMO_TURNS, createFixtureSessionHost, demoUsageSummary, tallyTodos, todosSnapshotOf };
5
+ export { DEMO_ARTIFACT_KIND_LABELS, DEMO_GITHUB_USAGE, DEMO_PROVIDER_USAGE, DEMO_SESSION_FIXTURE, DEMO_TURNS, SCHEDULES_OFF_MESSAGE, createFixturePlansBackend, createFixtureScheduleBackend, createFixtureSessionHost, demoUsageSummary, planOf, plansSnapshotOf, tallyTodos };
@@ -7,7 +7,8 @@ import { APPROVAL_MODE_OPTIONS, DEFAULT_SETTINGS, DURABILITY_OPTIONS, SETTINGS_T
7
7
  */
8
8
  const GUI_GREYED_BY = {
9
9
  browserAgent: "browser",
10
- browserAutoShow: "browser"
10
+ browserAutoShow: "browser",
11
+ schedulesAgent: "schedules"
11
12
  };
12
13
  /** The GUI's copy and order, gated (`requires`, `killSwitchEnv`) exactly as canonical `SETTINGS_TOGGLES` says. */
13
14
  function withCanonicalGates(rows) {
@@ -65,6 +66,16 @@ const SETTINGS_TOGGLES = withCanonicalGates([
65
66
  label: "Start from last session",
66
67
  description: "Open the last session on launch instead of the sessions list."
67
68
  },
69
+ {
70
+ key: "schedules",
71
+ label: "Reminders",
72
+ description: "Send a prompt to a session at a set time, once or on a repeat. Extensions can schedule their own reminders."
73
+ },
74
+ {
75
+ key: "schedulesAgent",
76
+ label: "Agent can set reminders",
77
+ description: "Give the agent a tool to schedule prompts to its own session, such as \"check the CI in 20 minutes\". Needs Reminders."
78
+ },
68
79
  {
69
80
  key: "hideSubagentOutput",
70
81
  label: "Collapse subagents",
@@ -140,6 +151,11 @@ const SETTINGS_TOGGLES = withCanonicalGates([
140
151
  label: "Web search",
141
152
  description: "Let the agent search the web for docs, errors and recent changes."
142
153
  },
154
+ {
155
+ key: "secrets",
156
+ label: "Secrets",
157
+ description: "Let the agent ask you for an API key or a token. It is kept in a private file for this project, out of the chat, and hidden in tool output."
158
+ },
143
159
  {
144
160
  key: "sandbox",
145
161
  label: "Sandbox shell commands",
@@ -1,5 +1,5 @@
1
1
  import { SettingsCatalogEntries, SettingsCatalogInstallKind, SettingsCatalogKind, SettingsEnvironmentsHost, SettingsExtension, SettingsExtensionAction, SettingsExtensionActionResult, SettingsExtensionActionStatus, SettingsExtensionCreate, SettingsExtensionCreated, SettingsExtensionInstall, SettingsExtensionsHost, SettingsFile, SettingsFileWrite, SettingsHostCatalog, SettingsInstallScope, SettingsInstructionsHost, SettingsLoad, SettingsLogsHost, SettingsPaths, SettingsPlugin, SettingsPluginsHost, SettingsResource, SettingsSkillInstall, SettingsSkillsHost } from "./sections-host.js";
2
- import { SettingsCredential, SettingsPreferredCredential, SettingsProvider, SettingsProviderField, SettingsProvidersHost, SettingsSignInOptions, hasCredentialChoice } from "./providers.js";
2
+ import { SettingsCredential, SettingsPreferredCredential, SettingsProvider, SettingsProviderField, SettingsProvidersHost, SettingsSignInOptions, accountsFocusId, accountsKeyFocusId, hasCredentialChoice } from "./providers.js";
3
3
  import { SettingsMcpAuthState, SettingsMcpBadge, SettingsMcpHost, SettingsMcpInstance, SettingsMcpRunning, SettingsMcpServer, SettingsMcpTest, SettingsMcpTool, enabledMcpTools, enabledMcpsAfterAdd, mcpBadge, mcpRunning, mcpSettingsAfterRemove, mcpShareable, mcpSharedNow, mcpSharingWith, settingsMcpServerOf, toggleMcpTool } from "./mcp.js";
4
4
  import { SettingsDecisionModel, SettingsModelTest, SettingsModelsHost } from "./models.js";
5
5
  import { SettingsClaudeImportCopy, SettingsClaudeImportDetect, SettingsClaudeImportHost, SettingsClaudeImportSelection, SettingsClaudeImportSummary } from "./claude-import.js";
@@ -14,4 +14,4 @@ import { DEFAULT_SETTINGS_LABELS, SettingsLabels } from "./labels.js";
14
14
  import { SettingsResourceOptions, createSettingsResource, keyedSettingsResources } from "./resource.js";
15
15
  import { listLength, settingsPageCounts } from "./page-counts.js";
16
16
  import { LayoutSectionsOptions, layoutSections } from "./layout-sections.js";
17
- export { BooleanSettingKey, DEFAULT_SETTINGS, DEFAULT_SETTINGS_LABELS, HIDDEN_TABLE_KEYS, LayoutSearchContext, LayoutSectionsOptions, PERF_HISTORY, PerfChannel, PerfChannelDirection, PerfGpu, PerfHotFunction, PerfLag, PerfMonitor, PerfMonitorState, PerfOrigin, PerfOsThread, PerfProcess, PerfProcessKind, PerfProcessMcp, PerfProcessNode, PerfProcessRow, PerfProcessSession, PerfProfile, PerfProfileError, PerfProfileOutcome, PerfProfileTarget, PerfSample, PerfSessionGroup, PerfSlowFrame, PerfThread, PerfTotals, PerfWatchError, SETTINGS_CHOICES, SETTINGS_CHOICE_BY_KEY, SETTINGS_PAGES, SETTINGS_TOGGLES, SETTINGS_TOGGLE_BY_KEY, SettingsAction, SettingsActionId, SettingsCatalogEntries, SettingsCatalogInstallKind, SettingsCatalogKind, SettingsChoice, SettingsClaudeImportCopy, SettingsClaudeImportDetect, SettingsClaudeImportHost, SettingsClaudeImportSelection, SettingsClaudeImportSummary, SettingsCredential, SettingsCustomRowId, SettingsDecisionModel, SettingsDocument, SettingsEnabledListKey, SettingsEnvironmentsHost, SettingsError, SettingsErrorKind, SettingsExtension, SettingsExtensionAction, SettingsExtensionActionResult, SettingsExtensionActionStatus, SettingsExtensionCreate, SettingsExtensionCreated, SettingsExtensionInstall, SettingsExtensionsHost, SettingsFile, SettingsFileWrite, SettingsHost, SettingsHostCatalog, SettingsInstallScope, SettingsInstructionsHost, SettingsLabels, SettingsLoad, SettingsLogsHost, SettingsMcpAuthState, SettingsMcpBadge, SettingsMcpHost, SettingsMcpInstance, SettingsMcpRunning, SettingsMcpServer, SettingsMcpTest, SettingsMcpTool, SettingsModelTest, SettingsModelsHost, SettingsPage, SettingsPageSection, SettingsPanelId, SettingsPanelPage, SettingsPaths, SettingsPerformanceHost, SettingsPlugin, SettingsPluginsHost, SettingsPreferredCredential, SettingsProvider, SettingsProviderField, SettingsProvidersHost, SettingsResource, SettingsResourceOptions, SettingsRow, SettingsSearchEntry, SettingsSearchHit, SettingsSection, SettingsSectionNoteId, SettingsSectionsPage, SettingsSectionsPageId, SettingsSignInOptions, SettingsSkillInstall, SettingsSkillsHost, SettingsTabId, SettingsToggle, SettingsTopId, createPerfMonitor, createSettingsResource, describedOn, enabledMcpTools, enabledMcpsAfterAdd, enabledNames, formatDuration, formatMemory, formatPercent, hasCredentialChoice, hasLaunched, isPanelPage, isSettingsError, keyedSettingsResources, layoutSearchEntries, layoutSections, listLength, mcpBadge, mcpRunning, mcpSettingsAfterRemove, mcpShareable, mcpSharedNow, mcpSharingWith, nestProcesses, nextOption, perfSeries, processGroups, processTree, searchSettings, sectionSearchHits, sessionGroups, settingsCount, settingsMcpServerOf, settingsPageCounts, settingsSearchHits, shown, toSettingsError, toggleEnabled, toggleMcpTool, visiblePages };
17
+ export { BooleanSettingKey, DEFAULT_SETTINGS, DEFAULT_SETTINGS_LABELS, HIDDEN_TABLE_KEYS, LayoutSearchContext, LayoutSectionsOptions, PERF_HISTORY, PerfChannel, PerfChannelDirection, PerfGpu, PerfHotFunction, PerfLag, PerfMonitor, PerfMonitorState, PerfOrigin, PerfOsThread, PerfProcess, PerfProcessKind, PerfProcessMcp, PerfProcessNode, PerfProcessRow, PerfProcessSession, PerfProfile, PerfProfileError, PerfProfileOutcome, PerfProfileTarget, PerfSample, PerfSessionGroup, PerfSlowFrame, PerfThread, PerfTotals, PerfWatchError, SETTINGS_CHOICES, SETTINGS_CHOICE_BY_KEY, SETTINGS_PAGES, SETTINGS_TOGGLES, SETTINGS_TOGGLE_BY_KEY, SettingsAction, SettingsActionId, SettingsCatalogEntries, SettingsCatalogInstallKind, SettingsCatalogKind, SettingsChoice, SettingsClaudeImportCopy, SettingsClaudeImportDetect, SettingsClaudeImportHost, SettingsClaudeImportSelection, SettingsClaudeImportSummary, SettingsCredential, SettingsCustomRowId, SettingsDecisionModel, SettingsDocument, SettingsEnabledListKey, SettingsEnvironmentsHost, SettingsError, SettingsErrorKind, SettingsExtension, SettingsExtensionAction, SettingsExtensionActionResult, SettingsExtensionActionStatus, SettingsExtensionCreate, SettingsExtensionCreated, SettingsExtensionInstall, SettingsExtensionsHost, SettingsFile, SettingsFileWrite, SettingsHost, SettingsHostCatalog, SettingsInstallScope, SettingsInstructionsHost, SettingsLabels, SettingsLoad, SettingsLogsHost, SettingsMcpAuthState, SettingsMcpBadge, SettingsMcpHost, SettingsMcpInstance, SettingsMcpRunning, SettingsMcpServer, SettingsMcpTest, SettingsMcpTool, SettingsModelTest, SettingsModelsHost, SettingsPage, SettingsPageSection, SettingsPanelId, SettingsPanelPage, SettingsPaths, SettingsPerformanceHost, SettingsPlugin, SettingsPluginsHost, SettingsPreferredCredential, SettingsProvider, SettingsProviderField, SettingsProvidersHost, SettingsResource, SettingsResourceOptions, SettingsRow, SettingsSearchEntry, SettingsSearchHit, SettingsSection, SettingsSectionNoteId, SettingsSectionsPage, SettingsSectionsPageId, SettingsSignInOptions, SettingsSkillInstall, SettingsSkillsHost, SettingsTabId, SettingsToggle, SettingsTopId, accountsFocusId, accountsKeyFocusId, createPerfMonitor, createSettingsResource, describedOn, enabledMcpTools, enabledMcpsAfterAdd, enabledNames, formatDuration, formatMemory, formatPercent, hasCredentialChoice, hasLaunched, isPanelPage, isSettingsError, keyedSettingsResources, layoutSearchEntries, layoutSections, listLength, mcpBadge, mcpRunning, mcpSettingsAfterRemove, mcpShareable, mcpSharedNow, mcpSharingWith, nestProcesses, nextOption, perfSeries, processGroups, processTree, searchSettings, sectionSearchHits, sessionGroups, settingsCount, settingsMcpServerOf, settingsPageCounts, settingsSearchHits, shown, toSettingsError, toggleEnabled, toggleMcpTool, visiblePages };
@@ -1,13 +1,13 @@
1
1
  import { DEFAULT_SETTINGS, SETTINGS_CHOICES, SETTINGS_TOGGLES, nextOption } from "./catalog.js";
2
- import { DEFAULT_SETTINGS_LABELS } from "./labels.js";
3
2
  import { isSettingsError, toSettingsError } from "./host.js";
4
3
  import { createSettingsResource, keyedSettingsResources } from "./resource.js";
5
4
  import { enabledMcpTools, enabledMcpsAfterAdd, mcpBadge, mcpRunning, mcpSettingsAfterRemove, mcpShareable, mcpSharedNow, mcpSharingWith, settingsMcpServerOf, toggleMcpTool } from "./mcp.js";
6
- import { hasCredentialChoice } from "./providers.js";
5
+ import { DEFAULT_SETTINGS_LABELS } from "./labels.js";
6
+ import { accountsFocusId, accountsKeyFocusId, hasCredentialChoice } from "./providers.js";
7
7
  import { enabledNames, toggleEnabled } from "./enabled.js";
8
8
  import { HIDDEN_TABLE_KEYS, SETTINGS_PAGES, describedOn, isPanelPage, settingsCount, shown, visiblePages } from "./layout.js";
9
9
  import { SETTINGS_CHOICE_BY_KEY, SETTINGS_TOGGLE_BY_KEY, layoutSearchEntries, searchSettings, sectionSearchHits, settingsSearchHits } from "./search.js";
10
10
  import { PERF_HISTORY, createPerfMonitor, formatDuration, formatMemory, formatPercent, hasLaunched, nestProcesses, perfSeries, processGroups, processTree, sessionGroups } from "./performance.js";
11
11
  import { listLength, settingsPageCounts } from "./page-counts.js";
12
12
  import { layoutSections } from "./layout-sections.js";
13
- export { DEFAULT_SETTINGS, DEFAULT_SETTINGS_LABELS, HIDDEN_TABLE_KEYS, PERF_HISTORY, SETTINGS_CHOICES, SETTINGS_CHOICE_BY_KEY, SETTINGS_PAGES, SETTINGS_TOGGLES, SETTINGS_TOGGLE_BY_KEY, createPerfMonitor, createSettingsResource, describedOn, enabledMcpTools, enabledMcpsAfterAdd, enabledNames, formatDuration, formatMemory, formatPercent, hasCredentialChoice, hasLaunched, isPanelPage, isSettingsError, keyedSettingsResources, layoutSearchEntries, layoutSections, listLength, mcpBadge, mcpRunning, mcpSettingsAfterRemove, mcpShareable, mcpSharedNow, mcpSharingWith, nestProcesses, nextOption, perfSeries, processGroups, processTree, searchSettings, sectionSearchHits, sessionGroups, settingsCount, settingsMcpServerOf, settingsPageCounts, settingsSearchHits, shown, toSettingsError, toggleEnabled, toggleMcpTool, visiblePages };
13
+ export { DEFAULT_SETTINGS, DEFAULT_SETTINGS_LABELS, HIDDEN_TABLE_KEYS, PERF_HISTORY, SETTINGS_CHOICES, SETTINGS_CHOICE_BY_KEY, SETTINGS_PAGES, SETTINGS_TOGGLES, SETTINGS_TOGGLE_BY_KEY, accountsFocusId, accountsKeyFocusId, createPerfMonitor, createSettingsResource, describedOn, enabledMcpTools, enabledMcpsAfterAdd, enabledNames, formatDuration, formatMemory, formatPercent, hasCredentialChoice, hasLaunched, isPanelPage, isSettingsError, keyedSettingsResources, layoutSearchEntries, layoutSections, listLength, mcpBadge, mcpRunning, mcpSettingsAfterRemove, mcpShareable, mcpSharedNow, mcpSharingWith, nestProcesses, nextOption, perfSeries, processGroups, processTree, searchSettings, sectionSearchHits, sessionGroups, settingsCount, settingsMcpServerOf, settingsPageCounts, settingsSearchHits, shown, toSettingsError, toggleEnabled, toggleMcpTool, visiblePages };
@@ -18,8 +18,6 @@ declare const DEFAULT_SETTINGS_LABELS: {
18
18
  settingsKilled: (env: string) => string;
19
19
  /** A toggle off because a kill switch is engaged: its tooltip. */
20
20
  settingsKilledTitle: (env: string) => string;
21
- /** A toggle that needs another one on: the note under it. */
22
- settingsBlocked: (requirement: string) => string;
23
21
  /** A toggle that needs another one on: its tooltip. */
24
22
  settingsBlockedTitle: (requirement: string) => string;
25
23
  /** The value a choice row shows while the host can't apply its setting. */
@@ -17,8 +17,6 @@ const DEFAULT_SETTINGS_LABELS = {
17
17
  settingsKilled: (env) => `Turned off by ${env}=1. Unset it to change this.`,
18
18
  /** A toggle off because a kill switch is engaged: its tooltip. */
19
19
  settingsKilledTitle: (env) => `${env}=1`,
20
- /** A toggle that needs another one on: the note under it. */
21
- settingsBlocked: (requirement) => `Turn on "${requirement}" first.`,
22
20
  /** A toggle that needs another one on: its tooltip. */
23
21
  settingsBlockedTitle: (requirement) => `Needs "${requirement}"`,
24
22
  /** The value a choice row shows while the host can't apply its setting. */
@@ -16,7 +16,12 @@ const SETTINGS_PAGES = [
16
16
  sections: [
17
17
  {
18
18
  title: "Sessions",
19
- rows: [{ key: "resumeLastSession" }, { key: "durability" }]
19
+ rows: [
20
+ { key: "resumeLastSession" },
21
+ { key: "schedules" },
22
+ { key: "schedulesAgent" },
23
+ { key: "durability" }
24
+ ]
20
25
  },
21
26
  {
22
27
  title: "Updates",
@@ -128,6 +133,7 @@ const SETTINGS_PAGES = [
128
133
  rows: [
129
134
  { key: "approvalMode" },
130
135
  { action: "safelist" },
136
+ { key: "secrets" },
131
137
  { key: "sandbox" },
132
138
  { key: "sandboxNetwork" },
133
139
  { key: "loadProjectExtensions" },
@@ -13,6 +13,8 @@ interface SettingsCredential {
13
13
  key?: string;
14
14
  /** An OAuth account's name. */
15
15
  label?: string;
16
+ /** Its stable id (it stays put when another account is promoted): what a failed sign-in names. Absent: not stored, or stored before ids. */
17
+ id?: string;
16
18
  }
17
19
  /** A configuration field a provider asks for instead of an API key (an endpoint, a project id). */
18
20
  interface SettingsProviderField {
@@ -91,6 +93,20 @@ interface SettingsProvidersHost {
91
93
  /** Starts a browser sign-in; once it is done, `list` shows the account. Absent: keys only. */
92
94
  signIn?(provider: string, options?: SettingsSignInOptions): SignInFlow;
93
95
  }
96
+ /**
97
+ * A provider's row on Settings › Accounts, as a deep link's focus names it
98
+ * (`SettingsShell`'s `initialFocus`).
99
+ *
100
+ * @param provider - The provider's key.
101
+ */
102
+ declare function accountsFocusId(provider: string): string;
103
+ /**
104
+ * A provider's API key field on Settings › Accounts, as a deep link's focus
105
+ * names it: the row opens on its key form.
106
+ *
107
+ * @param provider - The provider's key.
108
+ */
109
+ declare function accountsKeyFocusId(provider: string): string;
94
110
  /**
95
111
  * Whether a provider holds more than one stored credential, so there is a
96
112
  * choice of which one is in use (the TUI's expandable auth rows).
@@ -99,4 +115,4 @@ interface SettingsProvidersHost {
99
115
  */
100
116
  declare function hasCredentialChoice(provider: Pick<SettingsProvider, 'methods'>): boolean;
101
117
  //#endregion
102
- export { SettingsCredential, SettingsPreferredCredential, SettingsProvider, SettingsProviderField, SettingsProvidersHost, SettingsSignInOptions, hasCredentialChoice };
118
+ export { SettingsCredential, SettingsPreferredCredential, SettingsProvider, SettingsProviderField, SettingsProvidersHost, SettingsSignInOptions, accountsFocusId, accountsKeyFocusId, hasCredentialChoice };