@yadsh/dsh-qa-surface 0.13.0 → 0.15.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 (339) 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 +293 -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 +77 -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 +98 -7
  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 +145 -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 +7307 -4010
  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/provenance/host-store.js +8 -5
  252. package/lib/provenance/host-store.js.map +1 -1
  253. package/lib/qa-tools/docs-tools.js +1 -1
  254. package/lib/qa-tools/docs-tools.js.map +1 -1
  255. package/lib/qa-tools/lifecycle.js +6 -3
  256. package/lib/qa-tools/lifecycle.js.map +1 -1
  257. package/lib/request-queue.js +32 -0
  258. package/lib/request-queue.js.map +1 -0
  259. package/lib/resolve-config.js +2 -0
  260. package/lib/resolve-config.js.map +1 -1
  261. package/lib/secure-session.js +7 -2
  262. package/lib/secure-session.js.map +1 -1
  263. package/lib/shared/settings.js +19 -2
  264. package/lib/shared/settings.js.map +1 -1
  265. package/lib/turn-failure-log.js +67 -0
  266. package/lib/turn-failure-log.js.map +1 -0
  267. package/lib/typert.host.js +1398 -651
  268. package/lib/typert.remote-client.d.ts +15 -1
  269. package/lib/typert.remote-client.js +1315 -645
  270. package/lib/types/access/capability-catalog.d.ts +20 -4
  271. package/lib/types/access/model.d.ts +23 -0
  272. package/lib/types/access/service.d.ts +2 -3
  273. package/lib/types/account-remotes.d.ts +8 -1
  274. package/lib/types/accounts/database.d.ts +13 -3
  275. package/lib/types/accounts/errors.d.ts +9 -1
  276. package/lib/types/accounts/file.d.ts +12 -0
  277. package/lib/types/accounts/store.d.ts +30 -2
  278. package/lib/types/admin/quality-store.d.ts +33 -0
  279. package/lib/types/admin/service.d.ts +60 -1
  280. package/lib/types/client/QaAccountsController.d.ts +25 -2
  281. package/lib/types/client/QaConfigController.d.ts +2 -2
  282. package/lib/types/client/QaSessionController.d.ts +199 -6
  283. package/lib/types/client/QaSurface.d.ts +6 -1
  284. package/lib/types/client/admin/pages/ExpertMemory.d.ts +19 -0
  285. package/lib/types/client/admin/routes.d.ts +3 -1
  286. package/lib/types/client/admin/shared.d.ts +4 -0
  287. package/lib/types/client/components/Markdown.d.ts +8 -1
  288. package/lib/types/client/components/QaHeader.d.ts +18 -4
  289. package/lib/types/client/components/QaModal.d.ts +7 -0
  290. package/lib/types/client/components/QaQueueDock.d.ts +27 -0
  291. package/lib/types/client/components/QaRequestQueue.d.ts +20 -0
  292. package/lib/types/client/components/QaSidebar.d.ts +14 -0
  293. package/lib/types/client/components/QaThemeSwitcher.d.ts +14 -0
  294. package/lib/types/client/components/QaTurnNotice.d.ts +55 -0
  295. package/lib/types/client/focus-ring.d.ts +65 -0
  296. package/lib/types/client/lineage.d.ts +3 -13
  297. package/lib/types/client/markdown/blocks.d.ts +30 -2
  298. package/lib/types/client/markdown/render.d.ts +4 -1
  299. package/lib/types/client/notifications/notification-dispatcher.d.ts +68 -0
  300. package/lib/types/client/notifications/preferences.d.ts +44 -0
  301. package/lib/types/client/notifications/turn-completion-source.d.ts +114 -0
  302. package/lib/types/client/notifications/use-turn-notifications.d.ts +51 -0
  303. package/lib/types/client/project-session-state.d.ts +35 -1
  304. package/lib/types/client/role/RoleSelector.d.ts +7 -1
  305. package/lib/types/client/settings/card.d.ts +36 -5
  306. package/lib/types/client/settings/fields.d.ts +24 -0
  307. package/lib/types/client/settings/format.d.ts +0 -5
  308. package/lib/types/client/settings/sections/common.d.ts +3 -1
  309. package/lib/types/client/settings/sections/session.d.ts +2 -1
  310. package/lib/types/client/settings/styles.d.ts +9 -4
  311. package/lib/types/client/settings-extensions/user-session.d.ts +1 -1
  312. package/lib/types/client/theme-preference.d.ts +69 -0
  313. package/lib/types/client/types.d.ts +25 -1
  314. package/lib/types/client/use-session-ui-state.d.ts +6 -4
  315. package/lib/types/client/user-settings/GeneralSettingsPage.d.ts +5 -5
  316. package/lib/types/client/user-settings/NotificationSettingsPage.d.ts +40 -0
  317. package/lib/types/client/user-settings/UserSettingsDialog.d.ts +12 -2
  318. package/lib/types/client/user-settings/draft.d.ts +4 -1
  319. package/lib/types/client/user-settings/fields.d.ts +7 -0
  320. package/lib/types/config-resolvers/notifications.d.ts +10 -0
  321. package/lib/types/config-resolvers/session.d.ts +6 -0
  322. package/lib/types/config.d.ts +20 -1
  323. package/lib/types/index.d.ts +53 -5
  324. package/lib/types/integration/answer.d.ts +27 -0
  325. package/lib/types/integration/expert-memory.d.ts +49 -0
  326. package/lib/types/notifications.d.ts +32 -0
  327. package/lib/types/personal-skills/errors.d.ts +1 -1
  328. package/lib/types/personal-skills/service.d.ts +6 -0
  329. package/lib/types/prompt-notes.d.ts +17 -4
  330. package/lib/types/request-queue.d.ts +32 -0
  331. package/lib/types/shared/settings.d.ts +19 -2
  332. package/lib/types/turn-failure-log.d.ts +18 -0
  333. package/lib/types/types.d.ts +180 -4
  334. package/package.json +64 -63
  335. package/scripts/attach-workspace-sessions.mjs +24 -5
  336. package/scripts/repair-session-events.mjs +25 -5
  337. package/lib/client/markdown/MermaidBlock.js +0 -80
  338. package/lib/client/markdown/MermaidBlock.js.map +0 -1
  339. package/lib/types/client/markdown/MermaidBlock.d.ts +0 -6
@@ -20,6 +20,15 @@ export interface QaTurnAnswer {
20
20
  /** Durable seq of the message the answer came from, when there was one. */
21
21
  readonly seq: number | null;
22
22
  }
23
+ /** One request's answer, additionally attributed to the turn it came from. */
24
+ export interface QaRequestAnswer extends QaTurnAnswer {
25
+ /**
26
+ * The harness turn number the answer was read out of, or null when the log
27
+ * named no turn for the request's own row. The provenance bundle of a turn is
28
+ * the evidence of its answer, so the caller cites the same number.
29
+ */
30
+ readonly turn: number | null;
31
+ }
23
32
  /** The empty answer: what a turn that committed nothing readable looks like. */
24
33
  export declare const QA_EMPTY_ANSWER: QaTurnAnswer;
25
34
  /**
@@ -35,6 +44,24 @@ export declare const QA_EMPTY_ANSWER: QaTurnAnswer;
35
44
  * @returns the publishable answer and whether the turn was interrupted.
36
45
  */
37
46
  export declare function answerAfter(events: readonly StoredSessionEvent[], afterSeq: number): QaTurnAnswer;
47
+ /**
48
+ * Project the answer of the turn one request's own prompt opened.
49
+ *
50
+ * The harness stamps the prompt's rpc id onto the durable user row it claims,
51
+ * so the row is found by id rather than guessed from the newest human message:
52
+ * two questions in flight on one chat open two turns, and a selection by
53
+ * "latest" answers each caller with the other's turn. The turn that answers a
54
+ * request is the one its row was claimed into — `turn/start` opens a turn and
55
+ * the claimed rows follow it — so the answer is read out of that turn's
56
+ * assistant messages only, and its number travels with it for the citation.
57
+ *
58
+ * @param events - durable events, in any order.
59
+ * @param requestId - the rpc id the prompt was submitted with.
60
+ * @returns the answer of this request's turn, or `undefined` when the log
61
+ * holds no row for the request (an unflushed prompt, or a harness that does not
62
+ * echo the id), which leaves the choice of cursor to the caller.
63
+ */
64
+ export declare function answerForRequest(events: readonly StoredSessionEvent[], requestId: string): QaRequestAnswer | undefined;
38
65
  /**
39
66
  * Cut an answer down to the size the caller publishes.
40
67
  *
@@ -0,0 +1,49 @@
1
+ import type { QaExpertMemoryRecord, QaExpertMemoryScope } from "../types.js";
2
+ /**
3
+ * The slice of `@yadsh/dsh-domain-experts` the QA console uses.
4
+ *
5
+ * Declared structurally instead of imported, for the same reason the audit
6
+ * remote is: the QA surface has to load on a stand where the experts plugin is
7
+ * not composed at all, and a package dependency would turn "not installed" into
8
+ * "does not boot".
9
+ *
10
+ * What is reached is the plugin's `memoryAdmin` seam — not its `@Remote`
11
+ * methods. A domain-experts remote takes no token and checks no permission,
12
+ * because inside the Harness its caller is already a trusted component; the QA
13
+ * console answers a browser on a LAN port, so it carries the identity itself
14
+ * and goes through the host-plane seam instead.
15
+ */
16
+ export interface QaExpertMemoryAdmin {
17
+ scopes(): Promise<readonly QaExpertMemoryScope[]>;
18
+ search(namespace: string, query: string, limit: number, offset: number): Promise<{
19
+ readonly records: readonly QaExpertMemoryRecord[];
20
+ readonly total: number;
21
+ }>;
22
+ correct(input: QaExpertMemoryRecordInput): Promise<QaExpertMemoryRecord>;
23
+ remove(namespace: string, key: string): Promise<boolean>;
24
+ removeMany(namespace: string, keys: readonly string[]): Promise<number>;
25
+ wipe(namespace: string): Promise<number>;
26
+ }
27
+ /** What a correction says one record should hold. The key is the address. */
28
+ export interface QaExpertMemoryRecordInput {
29
+ readonly namespace: string;
30
+ readonly key: string;
31
+ readonly text: string;
32
+ readonly tags?: readonly string[];
33
+ }
34
+ /** The part of the domain-experts service the console addresses. */
35
+ export interface QaDomainExpertsFace {
36
+ readonly memoryAdmin: QaExpertMemoryAdmin;
37
+ }
38
+ /**
39
+ * Why a memory call failed, in the coarse vocabulary the console's copy table
40
+ * speaks.
41
+ *
42
+ * The refusal is read off the plugin's stable `code` field rather than its
43
+ * message: a message is written for a log and gets reworded, and matching one
44
+ * here would mean a rename in another package silently turns a refusal into an
45
+ * unhandled fault. `cause` is checked too, because the storage seam wraps what
46
+ * the backend threw.
47
+ */
48
+ export declare function expertMemoryReasonOf(error: unknown): "forbidden" | "memory-record-unknown" | "memory-unavailable" | "invalid-memory" | undefined;
49
+ //# sourceMappingURL=expert-memory.d.ts.map
@@ -0,0 +1,32 @@
1
+ import type { QaAccountNotifications, QaAccountNotificationsInput } from "./types.js";
2
+ /**
3
+ * What an account that never opened the notifications form gets.
4
+ *
5
+ * The in-page line is the shipped default of the feature itself, so an
6
+ * untouched account keeps behaving as it did before the form existed. The
7
+ * desktop channel stays off until asked for: raising an operating-system notice
8
+ * is the one choice that leaves the page, and a stand where the browser was
9
+ * never asked must not make it on the account's behalf.
10
+ */
11
+ export declare function emptyNotifications(): QaAccountNotifications;
12
+ /**
13
+ * Read one stored (or wire-delivered) notifications record into its public
14
+ * shape. Unknown or hand-edited input degrades to the readable subset rather
15
+ * than throwing, mirroring the starters read path: a malformed record must
16
+ * never cost the account its session.
17
+ */
18
+ export declare function normalizeNotifications(value: unknown): QaAccountNotifications;
19
+ export type QaNotificationsWriteResult = {
20
+ readonly ok: true;
21
+ readonly value: QaAccountNotificationsInput;
22
+ } | {
23
+ readonly ok: false;
24
+ readonly message: string;
25
+ };
26
+ /**
27
+ * Validate one full-replace notifications write. Both channels are required: a
28
+ * payload that names only one would silently reset the other, and the form
29
+ * always sends the pair it was rendered with.
30
+ */
31
+ export declare function validateNotificationsWrite(input: unknown): QaNotificationsWriteResult;
32
+ //# sourceMappingURL=notifications.d.ts.map
@@ -3,7 +3,7 @@
3
3
  * `(reason: <code>)` marker the account remotes established: the browser maps
4
4
  * them to audience-safe copy, while the precise cause stays in the Host log.
5
5
  */
6
- export type QaPersonalSkillErrorReason = "skills-disabled" | "workspace-unavailable" | "skill-not-found" | "skill-exists" | "skill-conflict" | "skill-name-invalid" | "skill-invalid" | "storage-unavailable";
6
+ export type QaPersonalSkillErrorReason = "skills-disabled" | "workspace-unavailable" | "skill-not-found" | "skill-exists" | "skill-conflict" | "skill-truncated" | "skill-name-invalid" | "skill-invalid" | "storage-unavailable";
7
7
  export declare class QaPersonalSkillError extends Error {
8
8
  readonly reason: QaPersonalSkillErrorReason;
9
9
  constructor(reason: QaPersonalSkillErrorReason, message: string);
@@ -55,6 +55,12 @@ export interface QaStoredSkill {
55
55
  readonly contents: QaSkillFileContents | undefined;
56
56
  readonly diagnostics: readonly QaSkillDiagnostic[];
57
57
  readonly resourceCount: number;
58
+ /**
59
+ * True when `raw` is only the head of the file: an oversized `SKILL.md` is
60
+ * read up to the ceiling, and what follows it was never loaded. A write must
61
+ * not overwrite such a document without saying so out loud.
62
+ */
63
+ readonly truncated: boolean;
58
64
  }
59
65
  export interface QaPersonalSkillsOptions {
60
66
  readonly getConfig: () => ResolvedQaSurfaceConfig;
@@ -1,13 +1,26 @@
1
1
  import type { Context } from "@deepseek-ai/cordis";
2
+ import type { ContextSnapshotSection } from "@deepseek-ai/dsh-llm";
2
3
  import type { PluginLogger } from "@yadsh/dsh-plugin-log";
3
4
  import type { QaAccounts } from "./accounts/store.js";
4
5
  import type { QaAccountIdentityField, QaAccountProfile, ResolvedQaSurfaceConfig } from "./types.js";
5
6
  /**
6
- * Plugin marker on every injected message. The chat projection turns a
7
- * plugin-sourced user message into injected context rather than a chat
8
- * bubble, and the QA transcript keeps exactly those hidden.
7
+ * This plugin's own producer source kind. The `@deepseek-ai/dsh-llm` source map
8
+ * is merge-extensible and ships no catch-all `plugin` kind, so a producer names
9
+ * itself here. The chat projection turns a `qa-notes`-sourced user message into
10
+ * injected context rather than a chat bubble, and the QA transcript keeps
11
+ * exactly those hidden.
9
12
  */
10
- export declare const QA_NOTES_PLUGIN = "qa-surface";
13
+ export interface QaNotesMessageSource {
14
+ readonly kind: "qa-notes";
15
+ /** Every note is superseded by the next one this plugin injects. */
16
+ readonly form: "snapshot";
17
+ readonly sections: readonly ContextSnapshotSection[];
18
+ }
19
+ declare module "@deepseek-ai/dsh-llm" {
20
+ interface MessageSourceMap {
21
+ "qa-notes": QaNotesMessageSource;
22
+ }
23
+ }
11
24
  /** Note name carrying who the assistant is talking to. */
12
25
  export declare const QA_IDENTITY_NOTE = "dsh-qa-surface:user-identity";
13
26
  /** Note name carrying the deployment's rule about source provenance. */
@@ -0,0 +1,32 @@
1
+ import type { Agent } from "@deepseek-ai/dsh-agent";
2
+ import type { QaQueueStatus } from "./types.js";
3
+ /**
4
+ * Chat turns the stand is answering right now.
5
+ *
6
+ * `running` is the harness's own definition of an active request: an agent
7
+ * enters it when waking input starts the driver and leaves it when the driver
8
+ * retires, which is what `agent/status` reports. Reading the live agents rather
9
+ * than counting the plugin's own sends is what keeps the places honest — a
10
+ * browser that closes mid-answer, an answer started through the HTTP API and a
11
+ * turn resumed by another surface all occupy a place, and none of them has to
12
+ * report it here. Only top-level agents count: a delegated expert's requests
13
+ * belong to the chat turn that delegated them, so charging both would bill one
14
+ * conversation twice.
15
+ *
16
+ * The count is of the model's load, not of this plugin's traffic: a turn the
17
+ * native assistant runs occupies a place exactly like a QA question does,
18
+ * because the ceiling exists for the card that is busy either way.
19
+ */
20
+ export declare function qaActiveRequests(agents: readonly {
21
+ readonly status: Agent["status"];
22
+ }[]): number;
23
+ /**
24
+ * Judge the live count against the deployment's ceiling. A ceiling of 0 sets no
25
+ * limit, so the stand is never full and nobody waits.
26
+ *
27
+ * There is deliberately no "ahead of you" number: `active` includes this
28
+ * visitor's own turns, and a stand that cannot say which place belongs to whom
29
+ * should not pretend to know who is waiting behind whom.
30
+ */
31
+ export declare function qaQueueStatus(limit: number, active: number): QaQueueStatus;
32
+ //# sourceMappingURL=request-queue.d.ts.map
@@ -5,6 +5,23 @@
5
5
  * browser build must not pull the Host config surface (schemastery) into the
6
6
  * page just to learn the namespace name.
7
7
  */
8
- /** Settings namespace the QA surface owns and its card binds to. */
9
- export declare const QA_SURFACE_SETTINGS_NAMESPACE = "qa-surface";
8
+ /**
9
+ * Settings namespace the QA surface owns and its card binds to.
10
+ *
11
+ * The namespace is the profile entry id the bundle declares in
12
+ * `cordis.patch.yml`, not a name this plugin picks: the Host derives the
13
+ * configuration form of every entry from its volatile `Config` fields and serves
14
+ * it under that id.
15
+ */
16
+ export declare const QA_SURFACE_SETTINGS_NAMESPACE = "dsh-qa-surface";
17
+ /**
18
+ * The key of the seat this card takes on the Host's Plugins page.
19
+ *
20
+ * `plugins.row.config` is keyed `<package name>#<row id>`, so the two names the
21
+ * page joins are this bundle's `package.json.name` and the profile entry id
22
+ * above. Neither is a name this plugin picks: a key that drifts from that pair
23
+ * leaves the row without its configure control and the card off the page, with
24
+ * nothing said about it.
25
+ */
26
+ export declare const QA_SURFACE_ROW_CONFIG_KEY = "@yadsh/dsh-qa-surface#dsh-qa-surface";
10
27
  //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1,18 @@
1
+ import type { Context } from "@deepseek-ai/cordis";
2
+ import type { PluginLogger } from "@yadsh/dsh-plugin-log";
3
+ /**
4
+ * Write a failed turn where the operator of the stand reads it.
5
+ *
6
+ * The chat row of a failed turn carries the failure code and nothing else: the
7
+ * provider's own message is deliberately kept out of the browser, and the
8
+ * session journal that holds it is a zstd archive nobody reads over an
9
+ * operator's shoulder. So a stand whose provider adapters never registered —
10
+ * every turn ending `NO_ADAPTER` — shows its tester «Помощнику не удалось
11
+ * завершить ответ.» and stays undiagnosable until someone decodes frames by
12
+ * hand. This listener puts the facts an operator needs — the chat, the session
13
+ * that died inside it, the turn, the code, and the provider the Host was asked
14
+ * to route to — into the plugin's own daily log, which is mirrored to the
15
+ * container's stdout from `warn` up.
16
+ */
17
+ export declare function registerTurnFailureLog(ctx: Context, logger: PluginLogger, resolveChat: (sessionId: string) => string | undefined): () => void;
18
+ //# sourceMappingURL=turn-failure-log.d.ts.map
@@ -44,7 +44,14 @@ export type QaAccountRole = "user" | "reviewer" | "admin";
44
44
  /** Administrative permissions a role grants; see `admin/permissions.ts`. */
45
45
  export type QaPermission = "users.read" | "users.manage" | "roles.read" | "roles.manage" | "conversations.read.all" | "conversations.read.own" | "conversations.delete" | "reviews.read" | "reviews.write" | "analytics.read" | "audit.read" | "settings.manage"
46
46
  /** Write access to skill files, personal and deployment-wide. */
47
- | "skills.manage";
47
+ | "skills.manage"
48
+ /**
49
+ * What the domain experts wrote into their durable memory. Reading is split
50
+ * from correcting because a reviewer is the one who notices a remembered
51
+ * inaccuracy in an answer, and an answer the expert keeps getting wrong is
52
+ * the reviewer's business even though the fix is not.
53
+ */
54
+ | "memory.read" | "memory.manage";
48
55
  /**
49
56
  * Tools split by how they become available. `always` is visible from the first
50
57
  * model step; `skillGrantable` is a ceiling — the tool only appears once an
@@ -217,7 +224,9 @@ export interface QaEffectiveCapabilityPolicy {
217
224
  readonly skills: readonly string[];
218
225
  /**
219
226
  * Visible skills a person may invoke with `/name`, including skills that
220
- * opted out of model invocation and therefore stay out of the catalog.
227
+ * opted out of model invocation and therefore stay out of the catalog. The
228
+ * skills this account owns are here for it without a role grant, unless an
229
+ * administrator has withdrawn the name outright.
221
230
  */
222
231
  readonly userSkills: readonly string[];
223
232
  readonly sources: {
@@ -290,6 +299,8 @@ export interface QaAccountUserPublic {
290
299
  readonly profile: QaAccountProfile;
291
300
  /** The account's own starter buttons; empty until customized. */
292
301
  readonly starters: QaAccountStarters;
302
+ /** Which channels a finished turn may use for this reader. */
303
+ readonly notifications: QaAccountNotifications;
293
304
  }
294
305
  /** One external system the deployment collects a handle for. */
295
306
  export interface QaAccountIdentityField {
@@ -339,6 +350,31 @@ export interface QaAccountStartersInput {
339
350
  readonly items: readonly QaAccountStarter[];
340
351
  readonly hideDefaults: boolean;
341
352
  }
353
+ /**
354
+ * What one account allows a finished turn to do to it. Pure UI preferences:
355
+ * unlike the profile, none of this reaches the agent prompt, and unlike the
356
+ * starter buttons, none of it is content — it is two switches over the
357
+ * channels the plugin already knows how to raise.
358
+ *
359
+ * The deployment's `config.notifications` sits above these: a channel the stand
360
+ * closed stays closed whatever an account asks for, which is the operator's
361
+ * answer to a laptop more than one person signs in on.
362
+ */
363
+ export interface QaAccountNotifications {
364
+ /** Show the in-page line naming the chat whose turn ended. */
365
+ readonly inApp: boolean;
366
+ /**
367
+ * Hand the same fact to the operating system while this page is hidden or
368
+ * behind another window. Needs the browser's permission as well: without it
369
+ * the line stays inside the page and nothing asks a second time.
370
+ */
371
+ readonly desktop: boolean;
372
+ }
373
+ /** Full-replace notifications write: both channels are always sent. */
374
+ export interface QaAccountNotificationsInput {
375
+ readonly inApp: boolean;
376
+ readonly desktop: boolean;
377
+ }
342
378
  /** One successful login/registration: the bearer token plus the user. */
343
379
  export interface QaAccountSession {
344
380
  readonly token: string;
@@ -425,7 +461,7 @@ export interface QaOwnershipEntry {
425
461
  * Why one skill draft cannot be saved, or why it saves with a caveat. Codes
426
462
  * stay stable on the wire; the browser owns the Russian copy.
427
463
  */
428
- export type QaSkillDiagnosticCode = "name-required" | "name-invalid" | "name-mismatch" | "description-required" | "description-too-long" | "when-to-use-too-long" | "field-type-invalid" | "invocation-never" | "invocation-invalid" | "invocation-legacy-key" | "allowed-tools-invalid" | "tool-name-invalid" | "tool-unavailable" | "tools-too-many" | "file-too-large" | "frontmatter-missing" | "skill-file-missing" | "frontmatter-invalid" | "unknown-field" | "resource-unsupported";
464
+ export type QaSkillDiagnosticCode = "name-required" | "name-invalid" | "name-mismatch" | "description-required" | "description-too-long" | "when-to-use-too-long" | "field-type-invalid" | "invocation-never" | "invocation-invalid" | "invocation-legacy-key" | "allowed-tools-invalid" | "tool-name-invalid" | "tool-unavailable" | "tools-too-many" | "file-too-large" | "frontmatter-missing" | "skill-file-missing" | "skill-file-truncated" | "frontmatter-invalid" | "unknown-field" | "resource-unsupported";
429
465
  /** One finding about a skill file or an editor draft. */
430
466
  export interface QaSkillDiagnostic {
431
467
  readonly code: QaSkillDiagnosticCode;
@@ -482,6 +518,40 @@ export interface QaAdminSkillsView {
482
518
  /** Absolute directory this scope reads and writes, rendered read-only. */
483
519
  readonly rootPath: string;
484
520
  }
521
+ /**
522
+ * One memory namespace as the console lists it: which expert it belongs to and
523
+ * whether it takes writes. `access` comes from the expert's own definition, so
524
+ * a shared carrier shows up as what its owner declared rather than as whatever
525
+ * the browser guessed.
526
+ */
527
+ export interface QaExpertMemoryScope {
528
+ readonly domainId: string;
529
+ readonly domainName: string;
530
+ readonly namespace: string;
531
+ readonly access: "read-write" | "read-only";
532
+ readonly records: number;
533
+ }
534
+ /** One line an expert recorded. */
535
+ export interface QaExpertMemoryRecord {
536
+ readonly namespace: string;
537
+ readonly key: string;
538
+ readonly text: string;
539
+ readonly tags: readonly string[];
540
+ readonly createdAt: number;
541
+ readonly updatedAt: number;
542
+ }
543
+ /** One page of a namespace, with the count the filter matched. */
544
+ export interface QaExpertMemoryPage {
545
+ readonly records: readonly QaExpertMemoryRecord[];
546
+ readonly total: number;
547
+ readonly offset: number;
548
+ readonly limit: number;
549
+ }
550
+ /** What an operator says a record should hold. The key never moves. */
551
+ export interface QaExpertMemoryDraft {
552
+ readonly text: string;
553
+ readonly tags: readonly string[];
554
+ }
485
555
  export interface QaSkillSummary {
486
556
  readonly name: string;
487
557
  readonly description: string;
@@ -516,6 +586,12 @@ export interface QaSkillDocument extends QaSkillSummary {
516
586
  readonly sourcePath: string;
517
587
  /** The canonical file the serializer writes, built from the parsed content. */
518
588
  readonly preview: string;
589
+ /**
590
+ * True when the stored file is larger than the Host's read ceiling, so `body`
591
+ * and `preview` describe its head only. A save over such a document erases
592
+ * the unread tail, and the Host refuses it until the client confirms.
593
+ */
594
+ readonly truncated: boolean;
519
595
  }
520
596
  /** One tool the picker can offer, with this deployment's availability. */
521
597
  export interface QaSkillToolDescriptor {
@@ -535,6 +611,13 @@ export interface QaSkillDraftInput {
535
611
  readonly body: string;
536
612
  /** Echo of the revision the editor read; a stale one is refused. */
537
613
  readonly expectedRevision: string | null;
614
+ /**
615
+ * The client's acknowledgement that it is saving from an incomplete copy: the
616
+ * stored `SKILL.md` is over the read ceiling, so the draft carries the head
617
+ * of the file and a save would drop everything the read never loaded. A write
618
+ * without it is refused.
619
+ */
620
+ readonly confirmPartialOverwrite?: boolean;
538
621
  }
539
622
  /**
540
623
  * The Host's answer about one unsaved draft: the file a save would write and
@@ -666,6 +749,14 @@ export interface QaSurfaceConfig {
666
749
  readonly provider?: string | null;
667
750
  readonly model?: string | null;
668
751
  readonly reasoningEffort?: string | null;
752
+ /**
753
+ * How many chat turns the deployment answers at once. A ceiling is what a
754
+ * locally hosted model needs: the card runs out long before the queue does,
755
+ * and a third request makes every answer on the stand slower instead of
756
+ * adding capacity. 0 leaves the count unbounded, which is the default
757
+ * because a hosted model has no such ceiling.
758
+ */
759
+ readonly maxActiveRequests?: number;
669
760
  };
670
761
  readonly ui?: {
671
762
  readonly showHeader?: boolean;
@@ -840,6 +931,17 @@ export interface QaSurfaceConfig {
840
931
  /** Cookie-less /qa navigations go through the one-time ?token= exchange. */
841
932
  readonly cookieBootstrap?: boolean;
842
933
  };
934
+ /** Notices for a turn that ended in one of this browser's own chats. */
935
+ readonly notifications?: {
936
+ /** Master switch: with it off no channel raises anything. */
937
+ readonly enabled?: boolean;
938
+ /**
939
+ * Allow the desktop (operating-system) channel on this stand at all.
940
+ * A reader's own choice only applies while this is on: it is the answer
941
+ * for a shared laptop, where a personal notice is everybody's notice.
942
+ */
943
+ readonly allowOs?: boolean;
944
+ };
843
945
  readonly sources?: QaSourcesConfig;
844
946
  readonly attachments?: QaAttachmentsConfig;
845
947
  readonly notes?: QaNotesConfig;
@@ -923,6 +1025,7 @@ export interface ResolvedQaSurfaceConfig {
923
1025
  readonly provider: string | null;
924
1026
  readonly model: string | null;
925
1027
  readonly reasoningEffort: string | null;
1028
+ readonly maxActiveRequests: number;
926
1029
  };
927
1030
  readonly ui: {
928
1031
  readonly showHeader: boolean;
@@ -1007,6 +1110,11 @@ export interface ResolvedQaSurfaceConfig {
1007
1110
  readonly redirectNonLoopback: boolean;
1008
1111
  readonly cookieBootstrap: boolean;
1009
1112
  };
1113
+ /** Channels a finished turn of this browser's own chats may use. */
1114
+ readonly notifications: {
1115
+ readonly enabled: boolean;
1116
+ readonly allowOs: boolean;
1117
+ };
1010
1118
  readonly tools: {
1011
1119
  readonly dynamicActivation: boolean;
1012
1120
  readonly activationSkill: string;
@@ -1530,9 +1638,55 @@ export interface QaPendingQuestion {
1530
1638
  readonly questions: readonly QaPendingQuestionItem[];
1531
1639
  readonly createdAt: number;
1532
1640
  }
1641
+ /**
1642
+ * One message that waits for the agent's next turn. Rows the Host already
1643
+ * admitted carry their durable occurrence id, which is what a queue operation
1644
+ * addresses; a row still in flight carries a browser id and edits nothing.
1645
+ */
1646
+ export interface QaQueueRow {
1647
+ readonly id: string;
1648
+ /** Short single-line text for the strip; newlines are folded away. */
1649
+ readonly preview: string;
1650
+ /** Full text to edit, or null when the row is not plain text. */
1651
+ readonly text: string | null;
1652
+ /** Attachments the row carries besides its text. */
1653
+ readonly attachments: number;
1654
+ /** Set for a local row the Host queue has not echoed back yet. */
1655
+ readonly sending: boolean;
1656
+ }
1657
+ /** What the queue strip may ask the Host to do with one waiting message. */
1658
+ export type QaQueueOperation = "edit" | "remove" | "steer";
1659
+ /**
1660
+ * What `qaSurface/queueStatus` answers: how much of the deployment's request
1661
+ * ceiling is in use right now. The Host counts the chats whose agent is running
1662
+ * a turn, so the load is read where the whole of it is visible rather than
1663
+ * guessed from one browser's view of the stand.
1664
+ */
1665
+ export interface QaQueueStatus {
1666
+ /** The configured ceiling; 0 means the deployment sets none. */
1667
+ readonly limit: number;
1668
+ /**
1669
+ * Turns answering at the moment of the read, this visitor's own included —
1670
+ * the stand cannot tell a place it owes someone from one it owes you.
1671
+ */
1672
+ readonly active: number;
1673
+ /** Whether one more turn fits; false while no ceiling is set. */
1674
+ readonly full: boolean;
1675
+ }
1533
1676
  export interface QaSessionState {
1534
1677
  readonly phase: QaSessionPhase;
1535
1678
  readonly sessionId: string | null;
1679
+ /**
1680
+ * Identity of the chat the surface is showing. Unique across every chat the
1681
+ * page has opened — a controller that is re-created for a new chat is handed
1682
+ * a new identity, so a component keyed by it cannot carry one chat's composer
1683
+ * text into another. It is taken only when the chat changes: a draft that
1684
+ * creates its session on the first prompt keeps its key, because the composer
1685
+ * holds an unsent question in component state, and remounting it on the new
1686
+ * session id would throw that text away before the Host has accepted
1687
+ * anything. `0` means no chat — see `QA_SESSION_IDLE_STATE`.
1688
+ */
1689
+ readonly chatKey: number;
1536
1690
  readonly messages: readonly QaMessage[];
1537
1691
  /** Immediate send feedback, kept outside the durable transcript. */
1538
1692
  readonly pendingMessage: QaPendingUserMessage | null;
@@ -1545,6 +1699,14 @@ export interface QaSessionState {
1545
1699
  readonly compatibilityReadOnly?: boolean;
1546
1700
  readonly canSend: boolean;
1547
1701
  readonly canStop: boolean;
1702
+ /**
1703
+ * Messages waiting for the next turn, oldest first. Sending while the agent
1704
+ * runs lands here instead of in the transcript, so the strip beside the
1705
+ * composer is the only place the user can still see them.
1706
+ */
1707
+ readonly queue: readonly QaQueueRow[];
1708
+ /** Whether a queue operation may be issued on this binding right now. */
1709
+ readonly canEditQueue: boolean;
1548
1710
  /** Bumped whenever this browser's chat index changes (add/forget). */
1549
1711
  readonly chatsRevision: number;
1550
1712
  /** Tool-derived sources of the current chat (web targets and files read). */
@@ -1557,6 +1719,14 @@ export interface QaSessionState {
1557
1719
  readonly approvals: readonly QaPendingApproval[];
1558
1720
  /** Question requests parked for the operator's answer, oldest first. */
1559
1721
  readonly questions: readonly QaPendingQuestion[];
1722
+ /**
1723
+ * Set when a send was held back because the stand is already answering as
1724
+ * many questions as it allows. The question never left the browser, so this
1725
+ * is the whole of what the visitor is told about it; the surface answers with
1726
+ * the request-ceiling dialog and the composer keeps the draft. Named apart
1727
+ * from `queue`, which is the same chat's list of waiting messages.
1728
+ */
1729
+ readonly requestQueue: QaQueueStatus | null;
1560
1730
  /** Slash palette state, keyed to the chat this snapshot describes. */
1561
1731
  readonly slash: QaSlashView;
1562
1732
  }
@@ -1666,7 +1836,13 @@ export interface QaReviewQueueItem {
1666
1836
  /** Administrative actions recorded in the audit trail. */
1667
1837
  export type QaAdminAuditAction = "user.created" | "user.updated" | "user.enabled" | "user.disabled"
1668
1838
  /** An operator set a new password for an account that had requested one. */
1669
- | "user.password-reset" | "authorization.changed" | "subrole.assignment.changed" | "subrole.created" | "subrole.updated" | "subrole.deleted" | "common_capabilities.updated" | "conversation.reviewed" | "conversation.deleted" | "review.updated" | "review.queued" | "admin.settings.updated" | "skill.created" | "skill.updated" | "skill.deleted";
1839
+ | "user.password-reset" | "authorization.changed" | "subrole.assignment.changed" | "subrole.created" | "subrole.updated" | "subrole.deleted" | "common_capabilities.updated" | "conversation.reviewed" | "conversation.deleted" | "review.updated" | "review.queued" | "admin.settings.updated" | "skill.created" | "skill.updated" | "skill.deleted"
1840
+ /** An operator rewrote a line an expert had remembered. */
1841
+ | "memory.corrected"
1842
+ /** One or several remembered lines were deleted; the count is in the target. */
1843
+ | "memory.deleted"
1844
+ /** A whole namespace was emptied. */
1845
+ | "memory.wiped";
1670
1846
  export interface QaAdminAuditEvent {
1671
1847
  readonly id: string;
1672
1848
  readonly timestamp: string;