@yadsh/dsh-qa-surface 0.13.0 → 0.14.0

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 (336) hide show
  1. package/README.md +148 -22
  2. package/compatibility.json +7 -3
  3. package/lib/access/capability-catalog.js +22 -6
  4. package/lib/access/capability-catalog.js.map +1 -1
  5. package/lib/access/model.js +36 -2
  6. package/lib/access/model.js.map +1 -1
  7. package/lib/access/service.js +19 -4
  8. package/lib/access/service.js.map +1 -1
  9. package/lib/account-remotes.js +4 -0
  10. package/lib/account-remotes.js.map +1 -1
  11. package/lib/accounts/database.js +49 -9
  12. package/lib/accounts/database.js.map +1 -1
  13. package/lib/accounts/errors.js.map +1 -1
  14. package/lib/accounts/file.js.map +1 -1
  15. package/lib/accounts/store.js +53 -8
  16. package/lib/accounts/store.js.map +1 -1
  17. package/lib/admin/permissions.js +6 -0
  18. package/lib/admin/permissions.js.map +1 -1
  19. package/lib/admin/quality-store.js +95 -19
  20. package/lib/admin/quality-store.js.map +1 -1
  21. package/lib/admin/service.js +178 -0
  22. package/lib/admin/service.js.map +1 -1
  23. package/lib/cli.js +24 -4
  24. package/lib/cli.js.map +1 -1
  25. package/lib/client/QaAccountsController.js +52 -5
  26. package/lib/client/QaAccountsController.js.map +1 -1
  27. package/lib/client/QaConfigController.js.map +1 -1
  28. package/lib/client/QaSessionController.js +626 -63
  29. package/lib/client/QaSessionController.js.map +1 -1
  30. package/lib/client/QaSurface.js +279 -43
  31. package/lib/client/QaSurface.js.map +1 -1
  32. package/lib/client/QaSurfaceGuard.js +2 -2
  33. package/lib/client/QaSurfaceGuard.js.map +1 -1
  34. package/lib/client/QaTranscriptAdapter.js +4 -2
  35. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  36. package/lib/client/admin/QaAdmin.js +59 -34
  37. package/lib/client/admin/QaAdmin.js.map +1 -1
  38. package/lib/client/admin/pages/Conversations.js +12 -12
  39. package/lib/client/admin/pages/Conversations.js.map +1 -1
  40. package/lib/client/admin/pages/ExpertMemory.js +210 -0
  41. package/lib/client/admin/pages/ExpertMemory.js.map +1 -0
  42. package/lib/client/admin/pages/Overview.js +4 -4
  43. package/lib/client/admin/pages/Overview.js.map +1 -1
  44. package/lib/client/admin/pages/Quality.js +5 -5
  45. package/lib/client/admin/pages/Quality.js.map +1 -1
  46. package/lib/client/admin/pages/Review.js +5 -5
  47. package/lib/client/admin/pages/Review.js.map +1 -1
  48. package/lib/client/admin/pages/SkillFiles.js +3 -3
  49. package/lib/client/admin/pages/SkillFiles.js.map +1 -1
  50. package/lib/client/admin/pages/Users.js +12 -12
  51. package/lib/client/admin/pages/Users.js.map +1 -1
  52. package/lib/client/admin/routes.js +4 -0
  53. package/lib/client/admin/routes.js.map +1 -1
  54. package/lib/client/admin/shared.js +15 -6
  55. package/lib/client/admin/shared.js.map +1 -1
  56. package/lib/client/admin/styles.js +3 -0
  57. package/lib/client/admin/styles.js.map +1 -1
  58. package/lib/client/attestation.js +11 -2
  59. package/lib/client/attestation.js.map +1 -1
  60. package/lib/client/audit/QaAuditDialog.js +2 -2
  61. package/lib/client/audit/QaAuditDialog.js.map +1 -1
  62. package/lib/client/audit/QaAuditRowBadge.js +1 -1
  63. package/lib/client/audit/QaAuditRowBadge.js.map +1 -1
  64. package/lib/client/components/Markdown.js +7 -2
  65. package/lib/client/components/Markdown.js.map +1 -1
  66. package/lib/client/components/QaAgentsDrawer.js +7 -5
  67. package/lib/client/components/QaAgentsDrawer.js.map +1 -1
  68. package/lib/client/components/QaApproval.js +2 -2
  69. package/lib/client/components/QaApproval.js.map +1 -1
  70. package/lib/client/components/QaAuthGate.js +6 -6
  71. package/lib/client/components/QaAuthGate.js.map +1 -1
  72. package/lib/client/components/QaChangelog.js +64 -0
  73. package/lib/client/components/QaChangelog.js.map +1 -1
  74. package/lib/client/components/QaComposer.js +9 -6
  75. package/lib/client/components/QaComposer.js.map +1 -1
  76. package/lib/client/components/QaFileAttachment.js +1 -1
  77. package/lib/client/components/QaFileAttachment.js.map +1 -1
  78. package/lib/client/components/QaFilesPanel.js +7 -7
  79. package/lib/client/components/QaFilesPanel.js.map +1 -1
  80. package/lib/client/components/QaHeader.js +4 -4
  81. package/lib/client/components/QaHeader.js.map +1 -1
  82. package/lib/client/components/QaMessage.js +12 -12
  83. package/lib/client/components/QaMessage.js.map +1 -1
  84. package/lib/client/components/QaModal.js +11 -2
  85. package/lib/client/components/QaModal.js.map +1 -1
  86. package/lib/client/components/QaQuestions.js +4 -4
  87. package/lib/client/components/QaQuestions.js.map +1 -1
  88. package/lib/client/components/QaQueueDock.js +137 -0
  89. package/lib/client/components/QaQueueDock.js.map +1 -0
  90. package/lib/client/components/QaRequestQueue.js +22 -0
  91. package/lib/client/components/QaRequestQueue.js.map +1 -0
  92. package/lib/client/components/QaRightRail.js +2 -2
  93. package/lib/client/components/QaRightRail.js.map +1 -1
  94. package/lib/client/components/QaSidebar.js +66 -6
  95. package/lib/client/components/QaSidebar.js.map +1 -1
  96. package/lib/client/components/QaSourcesPanel.js +10 -8
  97. package/lib/client/components/QaSourcesPanel.js.map +1 -1
  98. package/lib/client/components/QaThemeSwitcher.js +19 -0
  99. package/lib/client/components/QaThemeSwitcher.js.map +1 -0
  100. package/lib/client/components/QaTurnNotice.js +40 -0
  101. package/lib/client/components/QaTurnNotice.js.map +1 -0
  102. package/lib/client/components/QaTurnRail.js +3 -3
  103. package/lib/client/components/QaTurnRail.js.map +1 -1
  104. package/lib/client/components/QaWelcomeNotice.js +2 -6
  105. package/lib/client/components/QaWelcomeNotice.js.map +1 -1
  106. package/lib/client/components/QaWidthHandle.js +2 -2
  107. package/lib/client/components/QaWidthHandle.js.map +1 -1
  108. package/lib/client/components/QaWorkGroup.js +5 -5
  109. package/lib/client/components/QaWorkGroup.js.map +1 -1
  110. package/lib/client/components/QaWorkspaceBrowser.js +10 -10
  111. package/lib/client/components/QaWorkspaceBrowser.js.map +1 -1
  112. package/lib/client/components/VariantSwitcher.js +1 -1
  113. package/lib/client/components/VariantSwitcher.js.map +1 -1
  114. package/lib/client/failure-copy.js +26 -8
  115. package/lib/client/failure-copy.js.map +1 -1
  116. package/lib/client/focus-ring.js +193 -0
  117. package/lib/client/focus-ring.js.map +1 -0
  118. package/lib/client/index.js +40 -20
  119. package/lib/client/index.js.map +1 -1
  120. package/lib/client/lineage.js +3 -16
  121. package/lib/client/lineage.js.map +1 -1
  122. package/lib/client/markdown/CodeBlock.js +2 -2
  123. package/lib/client/markdown/CodeBlock.js.map +1 -1
  124. package/lib/client/markdown/blocks.js +118 -31
  125. package/lib/client/markdown/blocks.js.map +1 -1
  126. package/lib/client/markdown/math.js +1 -1
  127. package/lib/client/markdown/math.js.map +1 -1
  128. package/lib/client/markdown/render.js +32 -16
  129. package/lib/client/markdown/render.js.map +1 -1
  130. package/lib/client/markdown/source-chip.js +3 -3
  131. package/lib/client/markdown/source-chip.js.map +1 -1
  132. package/lib/client/notifications/notification-dispatcher.js +90 -0
  133. package/lib/client/notifications/notification-dispatcher.js.map +1 -0
  134. package/lib/client/notifications/preferences.js +61 -0
  135. package/lib/client/notifications/preferences.js.map +1 -0
  136. package/lib/client/notifications/turn-completion-source.js +82 -0
  137. package/lib/client/notifications/turn-completion-source.js.map +1 -0
  138. package/lib/client/notifications/use-turn-notifications.js +108 -0
  139. package/lib/client/notifications/use-turn-notifications.js.map +1 -0
  140. package/lib/client/panels/PanelHost.js +5 -5
  141. package/lib/client/panels/PanelHost.js.map +1 -1
  142. package/lib/client/panels/PanelLauncher.js +2 -2
  143. package/lib/client/panels/PanelLauncher.js.map +1 -1
  144. package/lib/client/project-session-state.js +156 -4
  145. package/lib/client/project-session-state.js.map +1 -1
  146. package/lib/client/role/RoleSelector.js +9 -4
  147. package/lib/client/role/RoleSelector.js.map +1 -1
  148. package/lib/client/settings/card.js +58 -17
  149. package/lib/client/settings/card.js.map +1 -1
  150. package/lib/client/settings/fields.js +11 -10
  151. package/lib/client/settings/fields.js.map +1 -1
  152. package/lib/client/settings/format.js +0 -9
  153. package/lib/client/settings/format.js.map +1 -1
  154. package/lib/client/settings/sections/access.js +5 -5
  155. package/lib/client/settings/sections/access.js.map +1 -1
  156. package/lib/client/settings/sections/accounts.js +10 -10
  157. package/lib/client/settings/sections/accounts.js.map +1 -1
  158. package/lib/client/settings/sections/attachments.js +6 -6
  159. package/lib/client/settings/sections/attachments.js.map +1 -1
  160. package/lib/client/settings/sections/branding.js +7 -7
  161. package/lib/client/settings/sections/branding.js.map +1 -1
  162. package/lib/client/settings/sections/common.js +4 -2
  163. package/lib/client/settings/sections/common.js.map +1 -1
  164. package/lib/client/settings/sections/docs.js +4 -3
  165. package/lib/client/settings/sections/docs.js.map +1 -1
  166. package/lib/client/settings/sections/embedding.js +2 -2
  167. package/lib/client/settings/sections/embedding.js.map +1 -1
  168. package/lib/client/settings/sections/interface.js +12 -12
  169. package/lib/client/settings/sections/interface.js.map +1 -1
  170. package/lib/client/settings/sections/lockdown.js +9 -9
  171. package/lib/client/settings/sections/lockdown.js.map +1 -1
  172. package/lib/client/settings/sections/notes.js +12 -12
  173. package/lib/client/settings/sections/notes.js.map +1 -1
  174. package/lib/client/settings/sections/session.js +15 -12
  175. package/lib/client/settings/sections/session.js.map +1 -1
  176. package/lib/client/settings/sections/slash.js +9 -9
  177. package/lib/client/settings/sections/slash.js.map +1 -1
  178. package/lib/client/settings/sections/sources.js +26 -26
  179. package/lib/client/settings/sections/sources.js.map +1 -1
  180. package/lib/client/settings/sections/status.js +2 -2
  181. package/lib/client/settings/sections/status.js.map +1 -1
  182. package/lib/client/settings/styles.js +15 -9
  183. package/lib/client/settings/styles.js.map +1 -1
  184. package/lib/client/slash/SlashPalette.js +4 -4
  185. package/lib/client/slash/SlashPalette.js.map +1 -1
  186. package/lib/client/styles.js +133 -83
  187. package/lib/client/styles.js.map +1 -1
  188. package/lib/client/theme-preference.js +162 -0
  189. package/lib/client/theme-preference.js.map +1 -0
  190. package/lib/client/types.js +8 -0
  191. package/lib/client/types.js.map +1 -1
  192. package/lib/client/use-session-ui-state.js +7 -5
  193. package/lib/client/use-session-ui-state.js.map +1 -1
  194. package/lib/client/user-settings/GeneralSettingsPage.js +6 -6
  195. package/lib/client/user-settings/GeneralSettingsPage.js.map +1 -1
  196. package/lib/client/user-settings/IntegrationTokensPage.js +6 -6
  197. package/lib/client/user-settings/IntegrationTokensPage.js.map +1 -1
  198. package/lib/client/user-settings/NotificationSettingsPage.js +107 -0
  199. package/lib/client/user-settings/NotificationSettingsPage.js.map +1 -0
  200. package/lib/client/user-settings/PasswordSettingsPage.js +1 -1
  201. package/lib/client/user-settings/PasswordSettingsPage.js.map +1 -1
  202. package/lib/client/user-settings/ProfileSettingsPage.js +2 -2
  203. package/lib/client/user-settings/ProfileSettingsPage.js.map +1 -1
  204. package/lib/client/user-settings/SkillCatalog.js +3 -3
  205. package/lib/client/user-settings/SkillCatalog.js.map +1 -1
  206. package/lib/client/user-settings/SkillEditor.js +26 -8
  207. package/lib/client/user-settings/SkillEditor.js.map +1 -1
  208. package/lib/client/user-settings/SkillToolPicker.js +3 -3
  209. package/lib/client/user-settings/SkillToolPicker.js.map +1 -1
  210. package/lib/client/user-settings/SkillsSettingsPage.js +1 -1
  211. package/lib/client/user-settings/SkillsSettingsPage.js.map +1 -1
  212. package/lib/client/user-settings/StartersSettingsPage.js +6 -6
  213. package/lib/client/user-settings/StartersSettingsPage.js.map +1 -1
  214. package/lib/client/user-settings/UserSettingsDialog.js +7 -2
  215. package/lib/client/user-settings/UserSettingsDialog.js.map +1 -1
  216. package/lib/client/user-settings/copy.js +2 -0
  217. package/lib/client/user-settings/copy.js.map +1 -1
  218. package/lib/client/user-settings/draft.js +4 -1
  219. package/lib/client/user-settings/draft.js.map +1 -1
  220. package/lib/client/user-settings/fields.js +5 -5
  221. package/lib/client/user-settings/fields.js.map +1 -1
  222. package/lib/client.js +7228 -4002
  223. package/lib/client.js.map +1 -1
  224. package/lib/config-resolvers/defaults.js +7 -0
  225. package/lib/config-resolvers/defaults.js.map +1 -1
  226. package/lib/config-resolvers/lockdown.js +7 -0
  227. package/lib/config-resolvers/lockdown.js.map +1 -1
  228. package/lib/config-resolvers/notifications.js +15 -0
  229. package/lib/config-resolvers/notifications.js.map +1 -0
  230. package/lib/config-resolvers/session.js +11 -1
  231. package/lib/config-resolvers/session.js.map +1 -1
  232. package/lib/config.js +67 -18
  233. package/lib/config.js.map +1 -1
  234. package/lib/enforcement/tool-grants.js +6 -6
  235. package/lib/enforcement/tool-grants.js.map +1 -1
  236. package/lib/index.js +145 -30
  237. package/lib/index.js.map +1 -1
  238. package/lib/integration/answer.js +74 -8
  239. package/lib/integration/answer.js.map +1 -1
  240. package/lib/integration/expert-memory.js +39 -0
  241. package/lib/integration/expert-memory.js.map +1 -0
  242. package/lib/integration/host-runner.js +26 -14
  243. package/lib/integration/host-runner.js.map +1 -1
  244. package/lib/notifications.js +66 -0
  245. package/lib/notifications.js.map +1 -0
  246. package/lib/personal-skills/errors.js.map +1 -1
  247. package/lib/personal-skills/service.js +81 -7
  248. package/lib/personal-skills/service.js.map +1 -1
  249. package/lib/prompt-notes.js +2 -10
  250. package/lib/prompt-notes.js.map +1 -1
  251. package/lib/qa-tools/docs-tools.js +1 -1
  252. package/lib/qa-tools/docs-tools.js.map +1 -1
  253. package/lib/qa-tools/lifecycle.js +6 -3
  254. package/lib/qa-tools/lifecycle.js.map +1 -1
  255. package/lib/request-queue.js +32 -0
  256. package/lib/request-queue.js.map +1 -0
  257. package/lib/resolve-config.js +2 -0
  258. package/lib/resolve-config.js.map +1 -1
  259. package/lib/secure-session.js +7 -2
  260. package/lib/secure-session.js.map +1 -1
  261. package/lib/shared/settings.js +19 -2
  262. package/lib/shared/settings.js.map +1 -1
  263. package/lib/turn-failure-log.js +67 -0
  264. package/lib/turn-failure-log.js.map +1 -0
  265. package/lib/typert.host.js +1398 -651
  266. package/lib/typert.remote-client.d.ts +15 -1
  267. package/lib/typert.remote-client.js +1315 -645
  268. package/lib/types/access/capability-catalog.d.ts +20 -4
  269. package/lib/types/access/model.d.ts +23 -0
  270. package/lib/types/access/service.d.ts +2 -3
  271. package/lib/types/account-remotes.d.ts +8 -1
  272. package/lib/types/accounts/database.d.ts +13 -3
  273. package/lib/types/accounts/errors.d.ts +9 -1
  274. package/lib/types/accounts/file.d.ts +12 -0
  275. package/lib/types/accounts/store.d.ts +30 -2
  276. package/lib/types/admin/quality-store.d.ts +33 -0
  277. package/lib/types/admin/service.d.ts +60 -1
  278. package/lib/types/client/QaAccountsController.d.ts +25 -2
  279. package/lib/types/client/QaConfigController.d.ts +2 -2
  280. package/lib/types/client/QaSessionController.d.ts +199 -6
  281. package/lib/types/client/QaSurface.d.ts +6 -1
  282. package/lib/types/client/admin/pages/ExpertMemory.d.ts +19 -0
  283. package/lib/types/client/admin/routes.d.ts +3 -1
  284. package/lib/types/client/admin/shared.d.ts +4 -0
  285. package/lib/types/client/components/Markdown.d.ts +8 -1
  286. package/lib/types/client/components/QaHeader.d.ts +3 -1
  287. package/lib/types/client/components/QaModal.d.ts +7 -0
  288. package/lib/types/client/components/QaQueueDock.d.ts +27 -0
  289. package/lib/types/client/components/QaRequestQueue.d.ts +20 -0
  290. package/lib/types/client/components/QaThemeSwitcher.d.ts +14 -0
  291. package/lib/types/client/components/QaTurnNotice.d.ts +55 -0
  292. package/lib/types/client/focus-ring.d.ts +65 -0
  293. package/lib/types/client/lineage.d.ts +3 -13
  294. package/lib/types/client/markdown/blocks.d.ts +30 -2
  295. package/lib/types/client/markdown/render.d.ts +4 -1
  296. package/lib/types/client/notifications/notification-dispatcher.d.ts +68 -0
  297. package/lib/types/client/notifications/preferences.d.ts +44 -0
  298. package/lib/types/client/notifications/turn-completion-source.d.ts +114 -0
  299. package/lib/types/client/notifications/use-turn-notifications.d.ts +51 -0
  300. package/lib/types/client/project-session-state.d.ts +35 -1
  301. package/lib/types/client/role/RoleSelector.d.ts +7 -1
  302. package/lib/types/client/settings/card.d.ts +36 -5
  303. package/lib/types/client/settings/fields.d.ts +24 -0
  304. package/lib/types/client/settings/format.d.ts +0 -5
  305. package/lib/types/client/settings/sections/common.d.ts +3 -1
  306. package/lib/types/client/settings/sections/session.d.ts +2 -1
  307. package/lib/types/client/settings/styles.d.ts +9 -4
  308. package/lib/types/client/settings-extensions/user-session.d.ts +1 -1
  309. package/lib/types/client/theme-preference.d.ts +69 -0
  310. package/lib/types/client/types.d.ts +25 -1
  311. package/lib/types/client/use-session-ui-state.d.ts +6 -4
  312. package/lib/types/client/user-settings/GeneralSettingsPage.d.ts +5 -5
  313. package/lib/types/client/user-settings/NotificationSettingsPage.d.ts +40 -0
  314. package/lib/types/client/user-settings/UserSettingsDialog.d.ts +12 -2
  315. package/lib/types/client/user-settings/draft.d.ts +4 -1
  316. package/lib/types/client/user-settings/fields.d.ts +7 -0
  317. package/lib/types/config-resolvers/notifications.d.ts +10 -0
  318. package/lib/types/config-resolvers/session.d.ts +6 -0
  319. package/lib/types/config.d.ts +20 -1
  320. package/lib/types/index.d.ts +53 -5
  321. package/lib/types/integration/answer.d.ts +27 -0
  322. package/lib/types/integration/expert-memory.d.ts +49 -0
  323. package/lib/types/notifications.d.ts +32 -0
  324. package/lib/types/personal-skills/errors.d.ts +1 -1
  325. package/lib/types/personal-skills/service.d.ts +6 -0
  326. package/lib/types/prompt-notes.d.ts +17 -4
  327. package/lib/types/request-queue.d.ts +32 -0
  328. package/lib/types/shared/settings.d.ts +19 -2
  329. package/lib/types/turn-failure-log.d.ts +18 -0
  330. package/lib/types/types.d.ts +180 -4
  331. package/package.json +64 -63
  332. package/scripts/attach-workspace-sessions.mjs +24 -5
  333. package/scripts/repair-session-events.mjs +25 -5
  334. package/lib/client/markdown/MermaidBlock.js +0 -80
  335. package/lib/client/markdown/MermaidBlock.js.map +0 -1
  336. package/lib/types/client/markdown/MermaidBlock.d.ts +0 -6
@@ -1,7 +1,13 @@
1
1
  import type { ConnectionGenerationState } from "@deepseek-ai/dsh-client-connection/client";
2
- import type { QaAttachmentDraft, QaSessionState, ResolvedQaSurfaceConfig } from "../types.js";
3
- import type { QaApprovalApi, QaConversation, QaCreateSession, QaFileUpload, QaSecureSession, QaSessions, QaSessionsApi, QaQuestionApi, QaSlashApi, QaSourceApi, StorageLike } from "./types.js";
2
+ import type { QaAttachmentDraft, QaQueueOperation, QaSessionState, ResolvedQaSurfaceConfig } from "../types.js";
3
+ import type { QaApprovalApi, QaConversation, QaCreateSession, QaFileUpload, QaQueueStatusRemote, QaSecureSession, QaSessions, QaSessionsApi, QaQuestionApi, QaSlashApi, QaSourceApi, StorageLike } from "./types.js";
4
4
  import type { QaApprovalDecision, QaQuestionAnswerItem } from "../types.js";
5
+ declare module "@deepseek-ai/dsh-api-session-controller/client" {
6
+ interface SessionReferenceSourceMap {
7
+ /** The QA surface holds the Session of the chat it is showing. */
8
+ qaSurface: unknown;
9
+ }
10
+ }
5
11
  export interface QaAccountsFacade {
6
12
  /** The account bearer token, or null while anonymous. */
7
13
  readonly token: () => string | null;
@@ -44,6 +50,14 @@ export interface QaSessionControllerOptions {
44
50
  * working, which is exactly the pre-feature behaviour.
45
51
  */
46
52
  readonly slashApi?: QaSlashApi;
53
+ /**
54
+ * The Host's live read of the request ceiling. Absent on a Host build that
55
+ * predates it — and unanswered, or answered by a deployment that sets no
56
+ * ceiling — the surface sends the way it always did: the ceiling is an
57
+ * arrangement between browsers about how much this stand can take, never a
58
+ * reason a question cannot be asked.
59
+ */
60
+ readonly queueStatus?: QaQueueStatusRemote;
47
61
  readonly storage?: StorageLike;
48
62
  /**
49
63
  * Browser file-upload service, resolved lazily: the page may not serve the
@@ -91,8 +105,11 @@ export declare class QaSessionController {
91
105
  private readonly streamPublisher;
92
106
  private state;
93
107
  private session;
108
+ /** The reference that keeps {@link session} alive; released with the binding. */
109
+ private sessionReference;
94
110
  private conversationBinding;
95
111
  private unsubscribeSession;
112
+ private unsubscribeInbox;
96
113
  private unsubscribeChat;
97
114
  private readonly unsubscribeConnection;
98
115
  private ensuring;
@@ -101,6 +118,18 @@ export declare class QaSessionController {
101
118
  private admissionPending;
102
119
  private pendingSubmission;
103
120
  private pendingSequence;
121
+ /**
122
+ * Request ids this binding has seen the Host name — in the Inbox queue or as a
123
+ * durable transcript row. The mask that keeps an echo the session library
124
+ * failed to retire from coming back as a question still crossing the
125
+ * transport: the retirement is `@deepseek-ai/dsh-api-session-controller`'s own
126
+ * contract, deferred to an animation frame that a surface with no frame clock
127
+ * never runs, and `projectQueue` in project-session-state.ts carries the
128
+ * citation, what the substitute costs and does not cost, and the point where
129
+ * this set is dead code. Kept for the whole binding: a request id is minted per
130
+ * submission, so an id the Host has named can never belong to a later send.
131
+ */
132
+ private readonly admittedSubmissions;
104
133
  private policyReady;
105
134
  /** Historical transcript retained after the Host classifies policy drift. */
106
135
  private compatibilityReadOnly;
@@ -111,6 +140,31 @@ export declare class QaSessionController {
111
140
  private connectedOnce;
112
141
  private disposed;
113
142
  private generation;
143
+ /**
144
+ * The session the current chat identity names, or null while the chat it
145
+ * names has no session yet. This is what makes the identity a chat identity
146
+ * rather than a counter: {@link bind} compares the session it is about to
147
+ * adopt against it, so any path that ends up in another session takes another
148
+ * identity — and a draft adopting its first session keeps the one it holds.
149
+ * It only ever names a session this controller holds: {@link bind} hands it
150
+ * out once the adoption has cleared every wait that caller asked it to take —
151
+ * a chat is opened and attested, a subagent transcript is only opened — and
152
+ * both a failed adoption and {@link unbind} take it back. The converse does
153
+ * not hold: a held session may name nothing, which is the transcript of an
154
+ * attestation this chat could not pass and whose caller still reads it. So a
155
+ * chat whose first send fell short keeps its identity while naming no session,
156
+ * and the retry — which brings a fresh id — stays in the composer the question
157
+ * was typed into instead of reading as a move to another chat.
158
+ */
159
+ private namedSession;
160
+ /**
161
+ * Chat identity handed to the surface (`QaSessionState.chatKey`). Taken from
162
+ * the page-wide sequence on every move to another chat, and never when the
163
+ * bound draft merely creates its session: a component that keeps per-chat
164
+ * state in React therefore survives the first prompt of a new chat, while two
165
+ * chats never read the same identity.
166
+ */
167
+ private chatKey;
114
168
  private chatsRevision;
115
169
  private selectedSubrole;
116
170
  private adminPreview;
@@ -120,6 +174,9 @@ export declare class QaSessionController {
120
174
  private readonly hostApprovals;
121
175
  /** Host-side question requests of the bound chat waiting for the operator. */
122
176
  private readonly hostQuestions;
177
+ private readonly queueRemote;
178
+ /** Last send the stand had no room for; drives the request-ceiling dialog. */
179
+ private requestQueueNotice;
123
180
  /** Set while a running turn is polled for parked requests. */
124
181
  private pendingTimer;
125
182
  /**
@@ -165,6 +222,21 @@ export declare class QaSessionController {
165
222
  * runtime and never becomes a model message.
166
223
  */
167
224
  send(text: string, attachments?: readonly QaAttachmentDraft[], pick?: string | null): Promise<boolean>;
225
+ /**
226
+ * What the stand answers about its load, or null when it does not answer.
227
+ *
228
+ * Every failure here sends the question anyway. The ceiling exists to keep a
229
+ * weak model from drowning, not to be a door a browser cannot open: an
230
+ * unreadable count says nothing about the load, and refusing a visitor on
231
+ * that would be a worse answer than the one they would have got.
232
+ */
233
+ private readQueueStatus;
234
+ /**
235
+ * Close the request-ceiling dialog. Nothing is retried and nothing is
236
+ * dropped: the held-back question is still the composer's own text, so asking
237
+ * it again is the visitor's keystroke, taken once the stand has a place free.
238
+ */
239
+ dismissRequestQueueNotice(): void;
168
240
  /**
169
241
  * Run one admitted human command. The Host answers it and writes the
170
242
  * lifecycle into the session log; this method only decides what the composer
@@ -193,6 +265,13 @@ export declare class QaSessionController {
193
265
  private slashCatalogReady;
194
266
  /** The slash view of the current state; assembled where the state is. */
195
267
  private slashView;
268
+ /**
269
+ * Turns the loaded Chat window has recorded as durably finished. The Host
270
+ * writes one per `turn/end`, so the count only moves on a fact the
271
+ * transcript itself carries — unlike the session's running bit, which the
272
+ * list relay can also deliver stale.
273
+ */
274
+ private durableTurnEndCount;
196
275
  /** Publish a browser-only copy before any network or Host admission awaits. */
197
276
  private beginSubmission;
198
277
  /**
@@ -204,11 +283,28 @@ export declare class QaSessionController {
204
283
  */
205
284
  regenerate(): Promise<boolean>;
206
285
  stop(): Promise<void>;
286
+ /**
287
+ * Edit, send now, or drop one message that still waits for its turn. Every
288
+ * operation addresses the occurrence id the Host's queue frame carried, so a
289
+ * row the agent claimed a moment ago is refused by the Host rather than
290
+ * quietly dropped here.
291
+ *
292
+ * The answer is the refusal text rather than a flag, and the strip beside the
293
+ * composer keeps showing it: a session frame follows a refusal within
294
+ * milliseconds, and the shared error line is cleared by exactly that frame.
295
+ */
296
+ queueAction(id: string, action: QaQueueOperation, text?: string): Promise<string | null>;
207
297
  /**
208
298
  * Enter the "new chat" draft: show an empty composer without creating any
209
299
  * session. Nothing appears in the chat list and no Host session is spent
210
300
  * until the first prompt is actually sent, which materializes the session
211
301
  * lazily ({@link materializeDraft}). Fixed-policy deployments cannot draft.
302
+ *
303
+ * A draft is a chat of its own, so entering one takes the screen the way
304
+ * {@link switchTo} does; see the note where the generation moves. Stopping the
305
+ * turn that was running first takes a round-trip, and a chat opened through it
306
+ * keeps the screen: the draft is what the visitor asked for before that click,
307
+ * so this call gives up rather than taking the chat back from under them.
212
308
  */
213
309
  startDraft(policyChange?: boolean): Promise<void>;
214
310
  /**
@@ -278,13 +374,104 @@ export declare class QaSessionController {
278
374
  * attested session id, or null when nothing was attested.
279
375
  */
280
376
  private recoverForSend;
377
+ /**
378
+ * Begin a chat of its own: take a fresh identity from the page-wide sequence,
379
+ * leave it naming no session, and retire the send the ending chat had in
380
+ * flight. Called on every move between chats — reset, switch, subagent view —
381
+ * by {@link bind} when it ends up in a session the identity does not name, and
382
+ * by the bootstrap whose restored chat was refused, for the replacement it is
383
+ * about to open.
384
+ */
385
+ private openChat;
386
+ /**
387
+ * Adopt one Host session as the chat on screen: take its binding, wait for it
388
+ * to open, attest the policy, and only then hand the chat identity to the
389
+ * session, so {@link namedSession} never names one this controller does not
390
+ * hold. A caller that asks for no attestation — the subagent view, whose
391
+ * transcript is read rather than written into — is named once its session is
392
+ * open.
393
+ *
394
+ * Answers whether the adoption happened. `true` is a finished one: this call
395
+ * holds the session and the chat identity names it, so the caller may publish
396
+ * what it kept for that chat — the draft it retired, the id it persisted.
397
+ * `false` is a step back: the chat on screen moved on while this call waited,
398
+ * it undoes nothing of the chat that replaced it and leaves the screen holding
399
+ * nothing of this one ({@link stepBack}), and the caller must keep its own
400
+ * state as unclaimed — a draft that was never materialized stays a draft, and a
401
+ * chat that was never adopted is not persisted as the open one.
402
+ *
403
+ * Any of those waits can outlive the operation it belongs to — the user moves
404
+ * to another chat while a first send is still looking for its session. Two
405
+ * questions decide that at each wait: is this still the generation the caller
406
+ * owns, and is this still the session this call took? The first is the page's
407
+ * own — every path that takes the screen raises the generation. The second is
408
+ * kept beside it because a generation only records who was asked to start, not
409
+ * what the controller holds by the time an adoption resumes: a binding
410
+ * somebody else retired in between is no more this one's to finish.
411
+ */
281
412
  private bind;
413
+ /**
414
+ * Give up on an adoption the chat on screen has outgrown, and answer whether
415
+ * that is what happened (`true` — the caller has nothing left to publish).
416
+ *
417
+ * Past the binding this call installed a session of its own: the retained
418
+ * reference, the three subscriptions beside it, and whatever those
419
+ * subscriptions write on every frame. The path that took the screen usually
420
+ * retired all of that with its own {@link unbind} — but the bootstrap raises the
421
+ * generation while keeping the transcript readable until its own session
422
+ * exists, and an adoption left behind by it would otherwise go on holding a
423
+ * Host session nobody is in and publishing that chat's frames into the surface:
424
+ * each frame clears the error the bootstrap published and answers for a binding
425
+ * the page has given up on. Undoing the install is therefore this call's own
426
+ * hand — and only its own: the chat that already replaced this one holds the
427
+ * name, the subscriptions and the policy proof, and emptying its screen is the
428
+ * failure this method exists to prevent.
429
+ */
430
+ private stepBack;
431
+ /**
432
+ * Is this adoption still the one on screen? The generation says whether the
433
+ * operation that asked for it still owns the page — every path that takes the
434
+ * screen raises it, {@link startDraft} among them — and the session says
435
+ * whether the binding this call took is still the one held, which a generation
436
+ * alone cannot answer: a newer chat raises it before it has taken any name, and
437
+ * a caller can retire the binding it holds inside its own generation.
438
+ */
439
+ private ownsAdoption;
282
440
  private unbind;
283
441
  private waitForConnection;
284
442
  /** Project one session notification; the running-turn spacing policy
285
443
  * (first frame at once, further frames absorbed) lives in the publisher. */
286
444
  private publishSessionUpdate;
287
445
  private publish;
446
+ /**
447
+ * The messages the Host has accepted for the agent's next turn. They arrive
448
+ * through the session's Inbox projection rather than the snapshot the queue
449
+ * strip used to read: `rc.2` moved pending input onto the projection surface,
450
+ * and a key the Host never published reads as no queued work.
451
+ */
452
+ private queuedMessages;
453
+ /**
454
+ * Record the submissions this binding has seen the Host name — the queue rows
455
+ * it holds and the durable input rows it has written. Naming the message is the
456
+ * server's own receipt for it, so from that notification on the row belongs to
457
+ * the chat, not to the transport: an echo the claim leaves behind must not read
458
+ * again as a question still crossing. The scan is only paid for while some
459
+ * queued echo still waits for its name.
460
+ *
461
+ * Both lists are read because neither is reliable alone, and the transcript is
462
+ * the durable one: a send admitted and claimed between two notifications never
463
+ * appears in a queue frame this browser is handed, but its row stays in the
464
+ * transcript, so the next frame names it. And the receipt is never dropped
465
+ * while the binding lives — an id the server has named belongs to the submission
466
+ * that minted it (`beginSubmission` returns a fresh `randomUUID`), so no later
467
+ * send can need the row this hides, whereas forgetting the receipt re-draws the
468
+ * ghost the moment the snapshot registers the echo again.
469
+ *
470
+ * Read from the notification, not from the projected frame: the projection of a
471
+ * running turn is spaced, and an absorbed frame is dropped rather than
472
+ * replayed, so spacing must not decide whether this browser ever saw the name.
473
+ */
474
+ private trackAdmittedSubmissions;
288
475
  /**
289
476
  * The directory the transcript's source paths are anchored on: the chat's
290
477
  * own cwd, never the configured pin while the chat is known.
@@ -319,12 +506,18 @@ export declare class QaSessionController {
319
506
  * deployment without accounts, where the list is the browser's own.
320
507
  */
321
508
  private visibleChatIds;
509
+ /**
510
+ * Tell the user that a submission they pressed did not go. The composer keeps
511
+ * its text through a refused send, so silence here would read as success.
512
+ */
513
+ private refuseSend;
322
514
  private fail;
323
515
  /**
324
- * Attest the currently bound session. `ok` carries the session id the proof
325
- * was issued for; `stale` means the binding changed while the request was
326
- * in flight, so nothing was written — the newer binding manages its own
327
- * attestation; `refused` is a genuine admission refusal of this binding.
516
+ * Attest `session`, which defaults to the one currently bound. `ok` carries
517
+ * the session id the proof was issued for; `stale` means the binding changed
518
+ * while the request was in flight, so nothing was written — the newer binding
519
+ * manages its own attestation; `refused` is a genuine admission refusal of
520
+ * this binding.
328
521
  */
329
522
  private attestPolicy;
330
523
  private emit;
@@ -3,7 +3,7 @@ import type { InjectFace, PropsRenderSlots, PropsRuntime } from "@deepseek-ai/ds
3
3
  import type { QaConfigController } from "./QaConfigController.js";
4
4
  import type { QaRouteController } from "./QaRouteController.js";
5
5
  import type { QaAccountsController } from "./QaAccountsController.js";
6
- import type { QaApprovalApi, QaAccessApi, QaAdminApi, QaConversation, QaCreateSession, QaFileUpload, QaSecureSession, QaSessions, QaSessionsApi, QaQuestionApi, QaSkillApi, QaSlashApi, QaSourceApi } from "./types.js";
6
+ import type { QaApprovalApi, QaAccessApi, QaAdminApi, QaConversation, QaCreateSession, QaFileUpload, QaQueueStatusRemote, QaSecureSession, QaSessions, QaSessionsApi, QaQuestionApi, QaSkillApi, QaSlashApi, QaSourceApi } from "./types.js";
7
7
  import type { QaSurfacePanelRegistry } from "./panels/registry.js";
8
8
  import type { QaUserSettingsSections } from "./settings-extensions/index.js";
9
9
  import type { QaAuditController } from "./audit/controller.js";
@@ -41,6 +41,11 @@ export interface QaSurfaceFace {
41
41
  * untouched.
42
42
  */
43
43
  readonly slashApi?: QaSlashApi;
44
+ /**
45
+ * The Host's live read of the request ceiling. Absent on a Host build that
46
+ * predates it: a deployment with no ceiling never asks, so nothing changes.
47
+ */
48
+ readonly queueStatus?: QaQueueStatusRemote;
44
49
  /**
45
50
  * Browser file-upload service, when the page serves the upload plugin.
46
51
  * Resolved per send so a page that loads it later still gets file support.
@@ -0,0 +1,19 @@
1
+ import type { QaAdminApi } from "../../types.js";
2
+ /**
3
+ * What the domain experts remembered.
4
+ *
5
+ * An expert writes its own notes, and a note that turned out to be wrong keeps
6
+ * being injected into every later answer of that domain until someone deletes
7
+ * it. This page is for that someone. The edit is deliberately narrow — the text
8
+ * and its tags, never the key, which is what the audit trail and the expert's
9
+ * own `forget` calls point at.
10
+ *
11
+ * A reviewer opens the same list read-only: seeing what an expert believes is
12
+ * the half of the job that produces the report "this is wrong".
13
+ */
14
+ export declare function AdminExpertMemory(props: {
15
+ readonly api: QaAdminApi;
16
+ readonly token: string;
17
+ readonly canManage: boolean;
18
+ }): import("react/jsx-runtime").JSX.Element;
19
+ //# sourceMappingURL=ExpertMemory.d.ts.map
@@ -34,6 +34,8 @@ export type QaAdminRoute = {
34
34
  readonly page: "feedback";
35
35
  } | {
36
36
  readonly page: "quality";
37
+ } | {
38
+ readonly page: "memory";
37
39
  } | {
38
40
  readonly page: "audit";
39
41
  };
@@ -58,5 +60,5 @@ export declare function parseAdminRoute(pathname: string, routePath: string): Qa
58
60
  /** The pathname for one console route; the inverse of {@link parseAdminRoute}. */
59
61
  export declare function adminPath(routePath: string, route: QaAdminRoute, search?: string): string;
60
62
  /** Which navigation entry is current for one route. */
61
- export declare function adminSectionOf(route: QaAdminRoute): "overview" | "users" | "access" | "conversations" | "review" | "feedback" | "quality" | "audit";
63
+ export declare function adminSectionOf(route: QaAdminRoute): "overview" | "users" | "access" | "conversations" | "review" | "feedback" | "quality" | "memory" | "audit";
62
64
  //# sourceMappingURL=routes.d.ts.map
@@ -38,9 +38,11 @@ export declare function useAdminResource<T>(load: (signal: AbortSignal) => Promi
38
38
  /** A status chip; the modifier class carries the semantic colour. */
39
39
  export declare function Badge(props: {
40
40
  readonly tone?: "neutral" | "positive" | "negative" | "warning";
41
+ readonly testId?: string;
41
42
  readonly children: React.ReactNode;
42
43
  }): import("react/jsx-runtime").JSX.Element;
43
44
  export declare function Empty(props: {
45
+ readonly testId?: string;
44
46
  readonly children: React.ReactNode;
45
47
  }): import("react/jsx-runtime").JSX.Element;
46
48
  /** A relative timestamp with the exact one available on hover. */
@@ -49,6 +51,7 @@ export declare function Stamp(props: {
49
51
  }): import("react/jsx-runtime").JSX.Element;
50
52
  export declare function ErrorLine(props: {
51
53
  readonly message: string | undefined;
54
+ readonly testId?: string;
52
55
  }): import("react/jsx-runtime").JSX.Element | null;
53
56
  /**
54
57
  * Cursor paging controls. The cursor is opaque to the browser by design: only
@@ -65,6 +68,7 @@ export declare function Pager(props: {
65
68
  /** One labeled filter control in a table toolbar. */
66
69
  export declare function FilterField(props: {
67
70
  readonly label: string;
71
+ readonly testId: string;
68
72
  readonly children: React.ReactNode;
69
73
  }): import("react/jsx-runtime").JSX.Element;
70
74
  //# sourceMappingURL=shared.d.ts.map
@@ -7,11 +7,18 @@ export type { MarkdownSourceContext } from "../markdown/source-chip.js";
7
7
  * or inline-code token that names a source the owning message knows about
8
8
  * renders as a source chip instead of plain text.
9
9
  *
10
+ * `streaming` says the text is a frame of a live answer, so the block the
11
+ * answer stopped inside is held rather than rendered as settled: an open `$$`
12
+ * fence shows the TeX being written instead of its dollars, and a table leaves
13
+ * a half-typed row out until the row is whole.
14
+ *
10
15
  * Memoized on the text value: stream updates re-render only the message whose
11
16
  * text actually changed, so committed history is never re-parsed.
12
17
  */
13
- export declare const Markdown: import("react").MemoExoticComponent<({ text, sourceRefs, onSourceOpen, }: {
18
+ export declare const Markdown: import("react").MemoExoticComponent<({ text, streaming, sourceRefs, onSourceOpen, }: {
14
19
  readonly text: string;
20
+ /** Whether the text is still growing; a settled answer renders in full. */
21
+ readonly streaming?: boolean;
15
22
  readonly sourceRefs?: QaSourceRefs;
16
23
  readonly onSourceOpen?: (source: QaSource) => void;
17
24
  }) => import("react/jsx-runtime").JSX.Element>;
@@ -21,6 +21,8 @@ export interface QaHeaderProps {
21
21
  readonly viewingSubagent: boolean;
22
22
  readonly onCloseSubagent: () => void;
23
23
  readonly roleSelector?: ReactNode;
24
+ /** The palette choice, next to the role it belongs to on screen. */
25
+ readonly themeSwitcher?: ReactNode;
24
26
  readonly administration?: {
25
27
  readonly onOpen: () => void;
26
28
  };
@@ -59,5 +61,5 @@ export interface QaHeaderProps {
59
61
  readonly resetDisabled: boolean;
60
62
  readonly onReset: () => void;
61
63
  }
62
- export declare function QaHeader({ logoUrl, title, viewingSubagent, onCloseSubagent, roleSelector, administration, agentCount, agentsOpen, onToggleAgents, sourcesVisible, sourcesCount, sourcesComplete, sourcesOpen, onOpenSources, fileCount, filesEnabled, filesOpen, onOpenFiles, settings, panelLauncher, showReset, resetDisabled, onReset, }: QaHeaderProps): import("react/jsx-runtime").JSX.Element;
64
+ export declare function QaHeader({ logoUrl, title, viewingSubagent, onCloseSubagent, roleSelector, themeSwitcher, administration, agentCount, agentsOpen, onToggleAgents, sourcesVisible, sourcesCount, sourcesComplete, sourcesOpen, onOpenSources, fileCount, filesEnabled, filesOpen, onOpenFiles, settings, panelLauncher, showReset, resetDisabled, onReset, }: QaHeaderProps): import("react/jsx-runtime").JSX.Element;
63
65
  //# sourceMappingURL=QaHeader.d.ts.map
@@ -1,4 +1,11 @@
1
1
  import { type ReactNode } from "react";
2
+ /**
3
+ * Whether a dialog of this shell is on screen. The keyboard belongs to it: the
4
+ * page under it, and anything painted beside it — the notice stack is such a
5
+ * neighbour — have to stop steering Tab while it holds, or a reader working in
6
+ * the dialog is turned back into a page under the scrim.
7
+ */
8
+ export declare function isQaModalOpen(): boolean;
2
9
  export interface QaModalProps {
3
10
  readonly open: boolean;
4
11
  /** Dialog title; also the dialog's accessible name. */
@@ -0,0 +1,27 @@
1
+ import type { QaQueueRow } from "../../types.js";
2
+ export interface QaQueueDockProps {
3
+ /** Messages waiting for the agent's next turn, oldest first. */
4
+ readonly rows: readonly QaQueueRow[];
5
+ /** Only a running turn can be interrupted, so only then is "send now" live. */
6
+ readonly running: boolean;
7
+ readonly canEdit: boolean;
8
+ /**
9
+ * Each operation answers with its refusal text, or null when the Host took
10
+ * it; the strip is the only place that answer stays readable.
11
+ */
12
+ readonly onEdit: (id: string, text: string) => Promise<string | null>;
13
+ readonly onSendNow: (id: string) => Promise<string | null>;
14
+ readonly onRemove: (id: string) => Promise<string | null>;
15
+ }
16
+ /**
17
+ * The queue strip beside the composer. What the user typed while the agent was
18
+ * answering is not in the transcript yet — the Host keeps it until the next
19
+ * turn claims it — so without this strip those messages simply are not on the
20
+ * screen: they cannot be read back, corrected, sent ahead, or dropped.
21
+ *
22
+ * One row shows directly; several fold behind a count so a long queue does not
23
+ * push the composer off the screen. Editing or an operation in flight forces
24
+ * the list open, because either way the user is looking at the rows.
25
+ */
26
+ export declare const QaQueueDock: import("react").MemoExoticComponent<(props: QaQueueDockProps) => import("react/jsx-runtime").JSX.Element | null>;
27
+ //# sourceMappingURL=QaQueueDock.d.ts.map
@@ -0,0 +1,20 @@
1
+ import type { QaQueueStatus } from "../../types.js";
2
+ /**
3
+ * The dialog a question gets when the stand has no place left for it.
4
+ *
5
+ * Saying where the question is beats saying that the visitor was refused: the
6
+ * send stopped before anything reached the Host, so nothing was created,
7
+ * nothing was answered, and the text is still in the composer. A visitor who
8
+ * cannot tell that asks twice, and a second question is exactly the load the
9
+ * ceiling exists to keep off a model that is already busy.
10
+ *
11
+ * The count names occupied places, not people ahead of the visitor: `active`
12
+ * includes this visitor's own turns, and a stand that cannot tell whose place
13
+ * is whose has no business numbering a queue behind which it claims to wait.
14
+ * @param props - the load read that held the question back, and how to close.
15
+ */
16
+ export declare function QaRequestQueue(props: {
17
+ readonly status: QaQueueStatus | null;
18
+ readonly onClose: () => void;
19
+ }): import("react/jsx-runtime").JSX.Element;
20
+ //# sourceMappingURL=QaRequestQueue.d.ts.map
@@ -0,0 +1,14 @@
1
+ import { type QaThemePreference } from "../theme-preference.js";
2
+ /**
3
+ * The palette choice of the QA surface. Three cubes, like the Host's own
4
+ * Appearance row: the selection is the preference, never the resolved scheme,
5
+ * so «Системная тема» stays pressed while the OS decides which palette that
6
+ * is. Icons only — the row is the header's, and the labels travel as the
7
+ * accessible name and the tooltip instead of eating 200px of it.
8
+ */
9
+ export interface QaThemeSwitcherProps {
10
+ readonly preference: QaThemePreference;
11
+ readonly onSelect: (preference: QaThemePreference) => void;
12
+ }
13
+ export declare function QaThemeSwitcher({ preference, onSelect, }: QaThemeSwitcherProps): import("react/jsx-runtime").JSX.Element;
14
+ //# sourceMappingURL=QaThemeSwitcher.d.ts.map
@@ -0,0 +1,55 @@
1
+ import type { KeyboardEventHandler, RefObject } from "react";
2
+ import type { QaTurnNoticeItem } from "../notifications/notification-dispatcher.js";
3
+ export interface QaTurnNoticeProps {
4
+ /** Newest first; the stack keeps a handful and drops what it cannot show. */
5
+ readonly items: readonly QaTurnNoticeItem[];
6
+ /** Open the chat a notice is about. */
7
+ readonly onOpen: (sessionId: string) => void;
8
+ /** Take one line out of the stack. */
9
+ readonly onDismiss: (key: string) => void;
10
+ /**
11
+ * Offer the desktop channel. Omitted when it is unavailable, refused, or
12
+ * already answered: the offer is a single question per browser, never a
13
+ * fixture of the stack.
14
+ */
15
+ readonly onEnableDesktop?: () => void;
16
+ /**
17
+ * The stack is painted in `document.body`, so the surface that owns it keeps
18
+ * its Tab ring reachable: `rootRef` is the element the ring counts these
19
+ * buttons from, and `onKeyDown` traps the key here, where no ancestor
20
+ * `<main>` can hear it. Both are optional — a stand that reads the stack on
21
+ * its own needs neither.
22
+ */
23
+ readonly rootRef?: RefObject<HTMLDivElement>;
24
+ readonly onKeyDown?: KeyboardEventHandler<HTMLDivElement>;
25
+ }
26
+ export declare const QA_TURN_NOTICE_COPY: Readonly<{
27
+ region: "Уведомления о завершённых ходах";
28
+ finished: "Ход завершён";
29
+ dismiss: "Скрыть уведомление";
30
+ offer: "Системные уведомления приходят, даже когда эта вкладка свёрнута.";
31
+ offerAction: "Включить системные уведомления";
32
+ }>;
33
+ /**
34
+ * The line of the stack, named once so the markup and whatever walks the lines
35
+ * cannot drift apart: the surface hands the keyboard back to a neighbouring line
36
+ * when the one the reader stood on goes away, and it finds its lines by this
37
+ * class.
38
+ */
39
+ export declare const QA_TURN_NOTICE_LINE_CLASS = "dsh-qa-turn-notice__item";
40
+ export declare const QA_TURN_NOTICE_LINE_SELECTOR = ".dsh-qa-turn-notice__item";
41
+ /**
42
+ * The offer block, named the same way. It shares the stack with the lines and is
43
+ * none of them: the surface reads the desktop opt-in by this class, rather than
44
+ * by whatever else the stack happens to hold.
45
+ */
46
+ export declare const QA_TURN_NOTICE_OFFER_CLASS = "dsh-qa-turn-notice__offer";
47
+ export declare const QA_TURN_NOTICE_OFFER_SELECTOR = ".dsh-qa-turn-notice__offer";
48
+ /**
49
+ * The in-app half of a turn-completion notice: one line per chat that settled
50
+ * while the reader was elsewhere, carried by the page until they open the chat
51
+ * or wave it off. It names the chat and the fact — never the answer, which is
52
+ * what the transcript is for.
53
+ */
54
+ export declare function QaTurnNotice(props: QaTurnNoticeProps): import("react").ReactPortal | null;
55
+ //# sourceMappingURL=QaTurnNotice.d.ts.map
@@ -0,0 +1,65 @@
1
+ import type { KeyboardEvent } from "react";
2
+ /**
3
+ * Whether a modal gate has taken this element away from the keyboard: the
4
+ * element itself or an ancestor of it is marked inert.
5
+ *
6
+ * `inert` is read as a property, not looked up as an attribute. The gate marks
7
+ * the page inert from script (`QaWelcomeNotice`), a browser reflects that into
8
+ * the attribute, and jsdom stores nothing but the property on the element it
9
+ * was given — so the property is the one thing the two agree on, and the walk
10
+ * up the parent chain is what stands in for the browser's own inheritance.
11
+ * That a browser additionally refuses focus to everything found here is the
12
+ * browser's doing: what a live stand has to settle is that the ring's edge and
13
+ * the gate's own trap hold the keyboard between them without help from this
14
+ * file.
15
+ */
16
+ export declare function isInert(element: HTMLElement): boolean;
17
+ /**
18
+ * Every control of `root` the keyboard can still reach, in DOM order: what the
19
+ * page has not hidden, in its markup or in its layout, what still carries a
20
+ * place in the tab order, what no `inert` ancestor has handed to a dialog, and
21
+ * what no closed fold keeps out of sight.
22
+ */
23
+ export declare function focusable(root: HTMLElement): HTMLElement[];
24
+ /**
25
+ * Hand the keyboard to the first candidate that takes it.
26
+ *
27
+ * `focusable` reads the layout as well as the markup, so the candidates are
28
+ * already the controls the width leaves in the path. This is the post-condition
29
+ * for a refusal that no read predicts: a page can keep a control from taking
30
+ * focus in ways its own styles do not say, and a test environment applies no CSS
31
+ * at all, so each candidate is checked at the moment it is asked — a control that
32
+ * leaves `document.activeElement` where it was is passed over, instead of leaving
33
+ * the reader on the same control they pressed Tab from.
34
+ */
35
+ export declare function focusFirst(candidates: readonly (HTMLElement | null | undefined)[]): void;
36
+ /**
37
+ * The Tab ring over the roots a surface owns, in the order it walks them.
38
+ *
39
+ * A root under a modal gate contributes nothing: none of its controls can take
40
+ * focus, so an edge of the ring that pointed into one would be a key the page
41
+ * had already swallowed with nowhere to go — a Tab that sticks.
42
+ */
43
+ export declare function focusRing(roots: readonly (HTMLElement | null)[]): HTMLElement[];
44
+ /**
45
+ * Keep Tab inside the ring the surface painted, and let the reader out at
46
+ * neither edge.
47
+ *
48
+ * The ring is wider than `<main>`: a notice stack the surface paints in
49
+ * `document.body` sits after it in the page, so a Tab leaving the composer
50
+ * walks into the stack, and the edge where the key is caught and turned back is
51
+ * the stack's last button — not the last control inside `<main>`, which is where
52
+ * the ring used to stop the reader short of the notice. A key typed inside such
53
+ * a portal is trapped by the handler mounted on the portal: the `<main>` above
54
+ * it is not its ancestor and never hears the key.
55
+ *
56
+ * A ring with no controls in it answers nothing: there is nothing here to keep
57
+ * the reader inside, and a key prevented with nowhere to hand the focus is a key
58
+ * that sticks.
59
+ *
60
+ * The two ends the key is caught at are ends of the *walked* path, so a control
61
+ * the current width has switched off is neither of them: it holds no focus for
62
+ * the reader to stand on, and an edge drawn at it is an edge no Tab arrives at.
63
+ */
64
+ export declare function trapKeys(event: KeyboardEvent<HTMLElement>, roots: readonly (HTMLElement | null)[]): void;
65
+ //# sourceMappingURL=focus-ring.d.ts.map
@@ -31,19 +31,9 @@ export interface SubagentNameCandidate {
31
31
  /** The Host's own wording for the delegation; empty when it listed none. */
32
32
  readonly label: string;
33
33
  }
34
- /** One durable delegation catalog entry, as the Host lists it. */
35
- export interface SubagentCatalogEntry {
36
- readonly kind?: string;
37
- readonly id?: string;
38
- readonly label?: string;
39
- }
40
- /** Direct delegation catalogs keyed by their parent chat. */
41
- export type SubagentCatalogs = Readonly<Record<string, {
42
- readonly entries?: readonly SubagentCatalogEntry[];
43
- } | undefined>>;
44
34
  /**
45
- * Delegated sessions whose names a page may sign its notices with: the
46
- * children of the chats it lists, catalog labels first and list titles after.
35
+ * Delegated sessions whose names a page may sign its notices with: the children
36
+ * of the chats it lists, named by the row title the Host's session list carries.
47
37
  *
48
38
  * `chats` is the visible chat set — the account's own chats while accounts are
49
39
  * on, and `undefined` for a deployment without accounts, where every chat on
@@ -53,5 +43,5 @@ export type SubagentCatalogs = Readonly<Record<string, {
53
43
  * therefore contributes no id and no label — a foreign chat can neither sign
54
44
  * a notice nor be named by one.
55
45
  */
56
- export declare function visibleSubagentCandidates(byId: Readonly<Record<string, SessionSummary>>, catalogs: SubagentCatalogs, chats: ReadonlySet<string> | undefined): readonly SubagentNameCandidate[];
46
+ export declare function visibleSubagentCandidates(byId: Readonly<Record<string, SessionSummary>>, chats: ReadonlySet<string> | undefined): readonly SubagentNameCandidate[];
57
47
  //# sourceMappingURL=lineage.d.ts.map