@yadsh/dsh-qa-surface 0.3.0 → 0.5.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 (276) hide show
  1. package/README.md +192 -15
  2. package/cordis.patch.yml +8 -0
  3. package/lib/account-remotes.js +100 -0
  4. package/lib/account-remotes.js.map +1 -0
  5. package/lib/accounts/credentials.js +35 -0
  6. package/lib/accounts/credentials.js.map +1 -0
  7. package/lib/accounts/errors.js +9 -0
  8. package/lib/accounts/errors.js.map +1 -0
  9. package/lib/accounts/file.js +101 -0
  10. package/lib/accounts/file.js.map +1 -0
  11. package/lib/accounts/store.js +159 -161
  12. package/lib/accounts/store.js.map +1 -1
  13. package/lib/accounts/token.js +61 -0
  14. package/lib/accounts/token.js.map +1 -0
  15. package/lib/approvals.js +179 -0
  16. package/lib/approvals.js.map +1 -0
  17. package/lib/attachment-rules.js +111 -0
  18. package/lib/attachment-rules.js.map +1 -0
  19. package/lib/cli.js +132 -9
  20. package/lib/cli.js.map +1 -1
  21. package/lib/client/QaAccountsController.js +32 -2
  22. package/lib/client/QaAccountsController.js.map +1 -1
  23. package/lib/client/QaSessionController.js +140 -65
  24. package/lib/client/QaSessionController.js.map +1 -1
  25. package/lib/client/QaSurface.js +134 -107
  26. package/lib/client/QaSurface.js.map +1 -1
  27. package/lib/client/QaTranscriptAdapter.js +71 -6
  28. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  29. package/lib/client/approvals.js +104 -0
  30. package/lib/client/approvals.js.map +1 -0
  31. package/lib/client/attachments.js +150 -0
  32. package/lib/client/attachments.js.map +1 -0
  33. package/lib/client/attestation.js +4 -1
  34. package/lib/client/attestation.js.map +1 -1
  35. package/lib/client/base64.js +16 -0
  36. package/lib/client/base64.js.map +1 -0
  37. package/lib/client/chat-files.js +48 -0
  38. package/lib/client/chat-files.js.map +1 -0
  39. package/lib/client/components/Markdown.js +1 -1
  40. package/lib/client/components/Markdown.js.map +1 -1
  41. package/lib/client/components/QaApproval.js +23 -0
  42. package/lib/client/components/QaApproval.js.map +1 -0
  43. package/lib/client/components/QaChangelog.js +62 -19
  44. package/lib/client/components/QaChangelog.js.map +1 -1
  45. package/lib/client/components/QaComposer.js +56 -74
  46. package/lib/client/components/QaComposer.js.map +1 -1
  47. package/lib/client/components/QaFileAttachment.js +19 -0
  48. package/lib/client/components/QaFileAttachment.js.map +1 -0
  49. package/lib/client/components/QaFilesPanel.js +45 -0
  50. package/lib/client/components/QaFilesPanel.js.map +1 -0
  51. package/lib/client/components/QaHeader.js +34 -0
  52. package/lib/client/components/QaHeader.js.map +1 -0
  53. package/lib/client/components/QaMessage.js +17 -4
  54. package/lib/client/components/QaMessage.js.map +1 -1
  55. package/lib/client/components/QaModal.js +31 -0
  56. package/lib/client/components/QaModal.js.map +1 -0
  57. package/lib/client/components/QaProfile.js +64 -0
  58. package/lib/client/components/QaProfile.js.map +1 -0
  59. package/lib/client/components/QaQuestions.js +96 -0
  60. package/lib/client/components/QaQuestions.js.map +1 -0
  61. package/lib/client/components/QaRightRail.js +15 -0
  62. package/lib/client/components/QaRightRail.js.map +1 -0
  63. package/lib/client/components/QaSidebar.js +6 -1
  64. package/lib/client/components/QaSidebar.js.map +1 -1
  65. package/lib/client/components/{QaSourcesDrawer.js → QaSourcesPanel.js} +3 -3
  66. package/lib/client/components/QaSourcesPanel.js.map +1 -0
  67. package/lib/client/components/QaTurnRail.js +15 -0
  68. package/lib/client/components/QaTurnRail.js.map +1 -1
  69. package/lib/client/components/QaWidthHandle.js +25 -20
  70. package/lib/client/components/QaWidthHandle.js.map +1 -1
  71. package/lib/client/components/QaWorkGroup.js +19 -20
  72. package/lib/client/components/QaWorkGroup.js.map +1 -1
  73. package/lib/client/components/surface-utils.js +28 -0
  74. package/lib/client/components/surface-utils.js.map +1 -0
  75. package/lib/client/components/thinking-phrases.js +24 -0
  76. package/lib/client/components/thinking-phrases.js.map +1 -0
  77. package/lib/client/create-session.js +7 -32
  78. package/lib/client/create-session.js.map +1 -1
  79. package/lib/client/failure-copy.js +63 -0
  80. package/lib/client/failure-copy.js.map +1 -0
  81. package/lib/client/index.js +49 -7
  82. package/lib/client/index.js.map +1 -1
  83. package/lib/client/project-session-state.js +5 -3
  84. package/lib/client/project-session-state.js.map +1 -1
  85. package/lib/client/prompt-content.js +54 -0
  86. package/lib/client/prompt-content.js.map +1 -0
  87. package/lib/client/questions.js +114 -0
  88. package/lib/client/questions.js.map +1 -0
  89. package/lib/client/settings/card.js +143 -0
  90. package/lib/client/settings/card.js.map +1 -0
  91. package/lib/client/settings/fields.js +145 -0
  92. package/lib/client/settings/fields.js.map +1 -0
  93. package/lib/client/settings/format.js +255 -0
  94. package/lib/client/settings/format.js.map +1 -0
  95. package/lib/client/settings/sections/access.js +25 -0
  96. package/lib/client/settings/sections/access.js.map +1 -0
  97. package/lib/client/settings/sections/accounts.js +47 -0
  98. package/lib/client/settings/sections/accounts.js.map +1 -0
  99. package/lib/client/settings/sections/attachments.js +46 -0
  100. package/lib/client/settings/sections/attachments.js.map +1 -0
  101. package/lib/client/settings/sections/branding.js +28 -0
  102. package/lib/client/settings/sections/branding.js.map +1 -0
  103. package/lib/client/settings/sections/common.js +20 -0
  104. package/lib/client/settings/sections/common.js.map +1 -0
  105. package/lib/client/settings/sections/embedding.js +19 -0
  106. package/lib/client/settings/sections/embedding.js.map +1 -0
  107. package/lib/client/settings/sections/interface.js +60 -0
  108. package/lib/client/settings/sections/interface.js.map +1 -0
  109. package/lib/client/settings/sections/lockdown.js +82 -0
  110. package/lib/client/settings/sections/lockdown.js.map +1 -0
  111. package/lib/client/settings/sections/session.js +53 -0
  112. package/lib/client/settings/sections/session.js.map +1 -0
  113. package/lib/client/settings/sections/sources.js +74 -0
  114. package/lib/client/settings/sections/sources.js.map +1 -0
  115. package/lib/client/settings/sections/status.js +37 -0
  116. package/lib/client/settings/sections/status.js.map +1 -0
  117. package/lib/client/settings/sections.js +23 -0
  118. package/lib/client/settings/sections.js.map +1 -0
  119. package/lib/client/settings/styles.js +57 -0
  120. package/lib/client/settings/styles.js.map +1 -0
  121. package/lib/client/stream-publisher.js +47 -0
  122. package/lib/client/stream-publisher.js.map +1 -0
  123. package/lib/client/styles.js +127 -19
  124. package/lib/client/styles.js.map +1 -1
  125. package/lib/client/types.js +2 -0
  126. package/lib/client/types.js.map +1 -1
  127. package/lib/client/use-right-rail.js +96 -0
  128. package/lib/client/use-right-rail.js.map +1 -0
  129. package/lib/client/use-session-ui-state.js +26 -19
  130. package/lib/client/use-session-ui-state.js.map +1 -1
  131. package/lib/client.js +5694 -813
  132. package/lib/client.js.map +1 -1
  133. package/lib/config-resolvers/accounts.js +60 -0
  134. package/lib/config-resolvers/accounts.js.map +1 -0
  135. package/lib/config-resolvers/attachments.js +28 -0
  136. package/lib/config-resolvers/attachments.js.map +1 -0
  137. package/lib/config-resolvers/basics.js +61 -0
  138. package/lib/config-resolvers/basics.js.map +1 -0
  139. package/lib/config-resolvers/defaults.js +136 -0
  140. package/lib/config-resolvers/defaults.js.map +1 -0
  141. package/lib/config-resolvers/lockdown.js +90 -0
  142. package/lib/config-resolvers/lockdown.js.map +1 -0
  143. package/lib/config-resolvers/session.js +42 -0
  144. package/lib/config-resolvers/session.js.map +1 -0
  145. package/lib/config-resolvers/shared.js +51 -0
  146. package/lib/config-resolvers/shared.js.map +1 -0
  147. package/lib/config-resolvers/sources.js +83 -0
  148. package/lib/config-resolvers/sources.js.map +1 -0
  149. package/lib/config-resolvers/ui.js +20 -0
  150. package/lib/config-resolvers/ui.js.map +1 -0
  151. package/lib/config.js +76 -6
  152. package/lib/config.js.map +1 -1
  153. package/lib/entry-redirect.js +2 -1
  154. package/lib/entry-redirect.js.map +1 -1
  155. package/lib/index.js +198 -79
  156. package/lib/index.js.map +1 -1
  157. package/lib/profile.js +214 -0
  158. package/lib/profile.js.map +1 -0
  159. package/lib/prompt-notes.js +231 -0
  160. package/lib/prompt-notes.js.map +1 -0
  161. package/lib/provenance/host-store.js +25 -9
  162. package/lib/provenance/host-store.js.map +1 -1
  163. package/lib/provenance/reported.js +37 -12
  164. package/lib/provenance/reported.js.map +1 -1
  165. package/lib/questions.js +185 -0
  166. package/lib/questions.js.map +1 -0
  167. package/lib/resolve-config.js +35 -410
  168. package/lib/resolve-config.js.map +1 -1
  169. package/lib/secure-session.js +139 -21
  170. package/lib/secure-session.js.map +1 -1
  171. package/lib/session-ownership.js +55 -0
  172. package/lib/session-ownership.js.map +1 -0
  173. package/lib/shared/session-key.js +18 -0
  174. package/lib/shared/session-key.js.map +1 -0
  175. package/lib/shared/settings.js +10 -0
  176. package/lib/shared/settings.js.map +1 -0
  177. package/lib/thinking-phrases.js +68 -0
  178. package/lib/thinking-phrases.js.map +1 -0
  179. package/lib/typert.host.js +506 -21
  180. package/lib/typert.remote-client.d.ts +15 -1
  181. package/lib/typert.remote-client.js +407 -15
  182. package/lib/types/account-remotes.d.ts +42 -0
  183. package/lib/types/accounts/credentials.d.ts +20 -0
  184. package/lib/types/accounts/errors.d.ts +11 -0
  185. package/lib/types/accounts/file.d.ts +82 -0
  186. package/lib/types/accounts/store.d.ts +74 -43
  187. package/lib/types/accounts/token.d.ts +31 -0
  188. package/lib/types/approvals.d.ts +65 -0
  189. package/lib/types/attachment-rules.d.ts +44 -0
  190. package/lib/types/cli.d.ts +2 -2
  191. package/lib/types/client/QaAccountsController.d.ts +8 -1
  192. package/lib/types/client/QaSessionController.d.ts +53 -16
  193. package/lib/types/client/QaSurface.d.ts +14 -1
  194. package/lib/types/client/approvals.d.ts +39 -0
  195. package/lib/types/client/attachments.d.ts +54 -0
  196. package/lib/types/client/base64.d.ts +10 -0
  197. package/lib/types/client/chat-files.d.ts +30 -0
  198. package/lib/types/client/components/QaApproval.d.ts +13 -0
  199. package/lib/types/client/components/QaChangelog.d.ts +1 -1
  200. package/lib/types/client/components/QaComposer.d.ts +8 -4
  201. package/lib/types/client/components/QaFileAttachment.d.ts +14 -0
  202. package/lib/types/client/components/QaFilesPanel.d.ts +15 -0
  203. package/lib/types/client/components/QaHeader.d.ts +41 -0
  204. package/lib/types/client/components/QaMessage.d.ts +3 -1
  205. package/lib/types/client/components/QaModal.d.ts +26 -0
  206. package/lib/types/client/components/QaProfile.d.ts +25 -0
  207. package/lib/types/client/components/QaQuestions.d.ts +13 -0
  208. package/lib/types/client/components/QaRightRail.d.ts +23 -0
  209. package/lib/types/client/components/QaSidebar.d.ts +14 -0
  210. package/lib/types/client/components/{QaSourcesDrawer.d.ts → QaSourcesPanel.d.ts} +7 -4
  211. package/lib/types/client/components/QaTurnRail.d.ts +6 -0
  212. package/lib/types/client/components/QaWidthHandle.d.ts +14 -7
  213. package/lib/types/client/components/QaWorkGroup.d.ts +5 -3
  214. package/lib/types/client/components/surface-utils.d.ts +11 -0
  215. package/lib/types/client/components/thinking-phrases.d.ts +9 -0
  216. package/lib/types/client/create-session.d.ts +6 -9
  217. package/lib/types/client/failure-copy.d.ts +19 -0
  218. package/lib/types/client/project-session-state.d.ts +8 -1
  219. package/lib/types/client/prompt-content.d.ts +30 -0
  220. package/lib/types/client/questions.d.ts +45 -0
  221. package/lib/types/client/settings/card.d.ts +23 -0
  222. package/lib/types/client/settings/fields.d.ts +139 -0
  223. package/lib/types/client/settings/format.d.ts +108 -0
  224. package/lib/types/client/settings/sections/access.d.ts +9 -0
  225. package/lib/types/client/settings/sections/accounts.d.ts +9 -0
  226. package/lib/types/client/settings/sections/attachments.d.ts +15 -0
  227. package/lib/types/client/settings/sections/branding.d.ts +8 -0
  228. package/lib/types/client/settings/sections/common.d.ts +28 -0
  229. package/lib/types/client/settings/sections/embedding.d.ts +8 -0
  230. package/lib/types/client/settings/sections/interface.d.ts +9 -0
  231. package/lib/types/client/settings/sections/lockdown.d.ts +9 -0
  232. package/lib/types/client/settings/sections/session.d.ts +9 -0
  233. package/lib/types/client/settings/sections/sources.d.ts +9 -0
  234. package/lib/types/client/settings/sections/status.d.ts +22 -0
  235. package/lib/types/client/settings/sections.d.ts +25 -0
  236. package/lib/types/client/settings/styles.d.ts +8 -0
  237. package/lib/types/client/stream-publisher.d.ts +28 -0
  238. package/lib/types/client/types.d.ts +76 -1
  239. package/lib/types/client/use-right-rail.d.ts +56 -0
  240. package/lib/types/client/use-session-ui-state.d.ts +13 -7
  241. package/lib/types/config-resolvers/accounts.d.ts +15 -0
  242. package/lib/types/config-resolvers/attachments.d.ts +6 -0
  243. package/lib/types/config-resolvers/basics.d.ts +8 -0
  244. package/lib/types/config-resolvers/defaults.d.ts +4 -0
  245. package/lib/types/config-resolvers/lockdown.d.ts +10 -0
  246. package/lib/types/config-resolvers/session.d.ts +6 -0
  247. package/lib/types/config-resolvers/shared.d.ts +23 -0
  248. package/lib/types/config-resolvers/sources.d.ts +6 -0
  249. package/lib/types/config-resolvers/ui.d.ts +6 -0
  250. package/lib/types/index.d.ts +48 -15
  251. package/lib/types/profile.d.ts +76 -0
  252. package/lib/types/prompt-notes.d.ts +110 -0
  253. package/lib/types/provenance/reported.d.ts +9 -1
  254. package/lib/types/questions.d.ts +83 -0
  255. package/lib/types/resolve-config.d.ts +8 -3
  256. package/lib/types/secure-session.d.ts +46 -2
  257. package/lib/types/session-ownership.d.ts +30 -0
  258. package/lib/types/shared/session-key.d.ts +23 -0
  259. package/lib/types/shared/settings.d.ts +10 -0
  260. package/lib/types/thinking-phrases.d.ts +17 -0
  261. package/lib/types/types.d.ts +203 -9
  262. package/lib/types/user-workspace.d.ts +42 -0
  263. package/lib/user-workspace.js +246 -0
  264. package/lib/user-workspace.js.map +1 -0
  265. package/package.json +15 -8
  266. package/CHANGELOG.md +0 -176
  267. package/SPEC-dsh-qa-surface.md +0 -2425
  268. package/docs/ARCHITECTURE.md +0 -66
  269. package/docs/COMPATIBILITY.md +0 -14
  270. package/docs/CONFIGURATION.md +0 -199
  271. package/docs/EMBEDDING.md +0 -13
  272. package/docs/SOURCES-MIGRATION.md +0 -28
  273. package/docs/SOURCES-PROVENANCE-AUDIT.md +0 -88
  274. package/docs/SPEC-dsh-qa-surface-accounts.md +0 -219
  275. package/docs/SPEC-dsh-qa-surface-sources-provenance.md +0 -1692
  276. package/lib/client/components/QaSourcesDrawer.js.map +0 -1
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Coarse, wire-safe account failure codes. They ride the `(reason: <code>)`
3
+ * marker pattern the attestation path established; the browser maps them to
4
+ * audience-safe copy and the precise cause stays in the Host logs.
5
+ */
6
+ export type QaAccountsErrorReason = "auth-required" | "admin-required" | "invalid-credentials" | "account-disabled" | "email-taken" | "invalid-email" | "invalid-display-name" | "invalid-profile" | "profile-disabled" | "invalid-role" | "weak-password" | "registration-disabled" | "rate-limited" | "session-owned-elsewhere";
7
+ export declare class QaAccountsError extends Error {
8
+ readonly reason: QaAccountsErrorReason;
9
+ constructor(reason: QaAccountsErrorReason, message: string);
10
+ }
11
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1,82 @@
1
+ import type { Stats } from "node:fs";
2
+ import type { QaAccountRole } from "../types.js";
3
+ /** One account's self-declared profile as it rests in the accounts file. */
4
+ export interface StoredProfile {
5
+ fullName?: string;
6
+ identities?: Record<string, string>;
7
+ instructions?: string;
8
+ updatedAt?: string;
9
+ }
10
+ export interface StoredUser {
11
+ readonly id: string;
12
+ readonly email: string;
13
+ readonly displayName: string;
14
+ readonly role: QaAccountRole;
15
+ /** scrypt material: hex salt + hex hash. */
16
+ readonly passwordHash: {
17
+ readonly salt: string;
18
+ readonly hash: string;
19
+ };
20
+ readonly createdAt: string;
21
+ lastLoginAt: string | null;
22
+ /** Disabled accounts are refused at login and lose their live tokens. */
23
+ disabled?: boolean;
24
+ /**
25
+ * Bumped to invalidate every token ever issued to the account: the value
26
+ * rides the token payload and must match at verification time.
27
+ */
28
+ tokenVersion?: number;
29
+ /** Absent until the owner fills the profile form for the first time. */
30
+ profile?: StoredProfile;
31
+ }
32
+ export interface AccountsFile {
33
+ readonly version: 1;
34
+ /** HMAC key for account tokens; rotated on password change by rewriting it. */
35
+ readonly secret: string;
36
+ readonly users: StoredUser[];
37
+ readonly ownership: Record<string, {
38
+ readonly userId: string;
39
+ readonly claimedAt: string;
40
+ }>;
41
+ }
42
+ /** mtime+size pair identifying one on-disk version of the accounts file. */
43
+ export interface FileStamp {
44
+ readonly mtimeMs: number;
45
+ readonly size: number;
46
+ }
47
+ /**
48
+ * Where the last-seen stamp lives. Load and persist keep it current in place,
49
+ * so a caller holds one mutable ref instead of threading the stamp through
50
+ * every read-modify-write.
51
+ */
52
+ export interface FileStampRef {
53
+ current: FileStamp;
54
+ }
55
+ /** A stamp no real file can match, so the first load always reads the disk. */
56
+ export declare function createFileStampRef(): FileStampRef;
57
+ export declare function stampOf(stat: Stats): FileStamp;
58
+ /** The accounts file lives next to the DSH home the launcher exports. */
59
+ export declare function defaultAccountsFilePath(): string;
60
+ /**
61
+ * Read the accounts file, or create it on first run with a fresh token
62
+ * secret. The stamp ref is left pointing at the version just read.
63
+ */
64
+ export declare function loadAccountsFile(filePath: string, stamp: FileStampRef): AccountsFile;
65
+ /**
66
+ * Persist the accounts file atomically (temp file + rename) and leave the
67
+ * stamp ref pointing at the freshly written version.
68
+ */
69
+ export declare function persistAccountsFile(filePath: string, file: AccountsFile, stamp: FileStampRef): void;
70
+ /**
71
+ * The qa-accounts CLI runs in its own process against the same file. Re-read
72
+ * it whenever it changed on disk, before every read or read-modify-write:
73
+ * without this a running Host would keep honoring tokens the CLI revoked
74
+ * and its next save would resurrect the CLI's change from a stale snapshot.
75
+ * One file, one writer at a time remains the deployment's discipline; LAN
76
+ * scale keeps the stat per operation trivial.
77
+ *
78
+ * Returns the freshly loaded file, or undefined when the caller should keep
79
+ * serving its in-memory state.
80
+ */
81
+ export declare function reloadAccountsFileIfChanged(filePath: string, stamp: FileStampRef): AccountsFile | undefined;
82
+ //# sourceMappingURL=file.d.ts.map
@@ -1,46 +1,30 @@
1
- import type { QaAccountRole, QaAccountSession, QaAccountUserPublic, QaClaimResult, QaOwnershipEntry, QaWhoamiResult } from "../types.js";
2
- /**
3
- * Coarse, wire-safe account failure codes. They ride the `(reason: <code>)`
4
- * marker pattern the attestation path established; the browser maps them to
5
- * audience-safe copy and the precise cause stays in the Host logs.
6
- */
7
- export type QaAccountsErrorReason = "auth-required" | "admin-required" | "invalid-credentials" | "account-disabled" | "email-taken" | "invalid-email" | "invalid-display-name" | "invalid-role" | "weak-password" | "registration-disabled" | "rate-limited" | "session-owned-elsewhere";
8
- export declare class QaAccountsError extends Error {
9
- readonly reason: QaAccountsErrorReason;
10
- constructor(reason: QaAccountsErrorReason, message: string);
11
- }
12
- interface StoredUser {
13
- readonly id: string;
14
- readonly email: string;
15
- readonly displayName: string;
16
- readonly role: QaAccountRole;
17
- /** scrypt material: hex salt + hex hash. */
18
- readonly passwordHash: {
19
- readonly salt: string;
20
- readonly hash: string;
21
- };
22
- readonly createdAt: string;
23
- lastLoginAt: string | null;
24
- /** Disabled accounts are refused at login and lose their live tokens. */
25
- disabled?: boolean;
26
- /**
27
- * Bumped to invalidate every token ever issued to the account: the value
28
- * rides the token payload and must match at verification time.
29
- */
30
- tokenVersion?: number;
31
- }
1
+ import type { QaAccountIdentityField, QaAccountProfile, QaAccountProfileInput, QaAccountRole, QaAccountSession, QaAccountUserPublic, QaClaimResult, QaOwnershipEntry, QaWhoamiResult } from "../types.js";
2
+ import type { StoredUser } from "./file.js";
3
+ export { QaAccountsError } from "./errors.js";
4
+ export type { QaAccountsErrorReason } from "./errors.js";
5
+ export { defaultAccountsFilePath } from "./file.js";
32
6
  export interface QaAccountsOptions {
33
7
  readonly sessionTtlDays: number;
34
8
  readonly allowRegistration: boolean;
35
9
  /** Login/registration attempts accepted per rolling minute, store-wide. */
36
10
  readonly maxAuthAttemptsPerMinute?: number;
11
+ /** Character cap on a stored profile's agent guidance. */
12
+ readonly instructionsMaxLength?: number;
13
+ /**
14
+ * Fields the deployment declares. Self-service writes may name only these;
15
+ * omitting the list (the operator CLI) checks the key shape alone.
16
+ */
17
+ readonly identityFields?: readonly QaAccountIdentityField[];
37
18
  }
38
- /** The accounts file lives next to the DSH home the launcher exports. */
39
- export declare function defaultAccountsFilePath(): string;
40
19
  /**
41
20
  * Host authority for QA accounts: the file-backed user list, the session
42
21
  * ownership map and the HMAC account tokens. All mutations are synchronous
43
22
  * and persisted atomically (temp file + rename); LAN scale keeps this trivial.
23
+ *
24
+ * The class is the facade: token mechanics live in token.ts, the file format
25
+ * and its atomic persistence plus the external-change probe in file.ts, and
26
+ * the credential rules shared by registration and the operator CLI in
27
+ * credentials.ts.
44
28
  */
45
29
  export declare class QaAccounts {
46
30
  readonly filePath: string;
@@ -49,20 +33,19 @@ export declare class QaAccounts {
49
33
  private readonly maxAuthAttemptsPerMinute;
50
34
  private readonly sessionTtlDays;
51
35
  private readonly allowRegistration;
36
+ /** Character cap on a stored profile's agent guidance. */
37
+ private readonly instructionsMaxLength;
38
+ /** Declared handle fields; undefined lets an operator write any shape-valid key. */
39
+ private readonly identityFields;
52
40
  /** mtime+size of the file as of the last load; the external-change probe. */
53
- private lastLoadStamp;
41
+ private readonly fileStamp;
54
42
  constructor(filePath: string | undefined, options: QaAccountsOptions);
55
43
  /**
56
- * The qa-accounts CLI runs in its own process against the same file. Re-read
57
- * it whenever it changed on disk, before every read or read-modify-write:
58
- * without this a running Host would keep honoring tokens the CLI revoked
59
- * and its next save would resurrect the CLI's change from a stale snapshot.
60
- * One file, one writer at a time remains the deployment's discipline; LAN
61
- * scale keeps the stat per operation trivial.
44
+ * Re-read the accounts file when it changed on disk, before every read or
45
+ * read-modify-write. The probe itself and its cross-process rationale live
46
+ * with the file layer (reloadAccountsFileIfChanged).
62
47
  */
63
48
  private reloadIfChanged;
64
- private load;
65
- private persist;
66
49
  private save;
67
50
  private pruneAuthAttempts;
68
51
  private assertAuthBudget;
@@ -81,6 +64,14 @@ export declare class QaAccounts {
81
64
  * foreign sessions unless the caller administers the deployment.
82
65
  */
83
66
  ensureSessionAccess(token: string, sessionId: string): QaAccountUserPublic;
67
+ /**
68
+ * Atomically reserve a Host-generated session id for the token user before
69
+ * the Session exists. Browser callers therefore never get a race window in
70
+ * which they can claim another user's newly created chat.
71
+ */
72
+ reserveSession(token: string, sessionId: string): QaAccountUserPublic;
73
+ /** Roll back a reservation if Host creation failed before a chat existed. */
74
+ releaseSessionReservation(userId: string, sessionId: string): void;
84
75
  /** Bulk-claim a browser's local chat index; foreign ids come back as conflicts. */
85
76
  claimSessions(token: string, sessionIds: readonly string[]): QaClaimResult;
86
77
  /** Session ids owned by the token's user, most recently claimed first. */
@@ -108,6 +99,14 @@ export declare class QaAccounts {
108
99
  private editUser;
109
100
  /** Grant or revoke the admin role. */
110
101
  setUserRole(email: string, role: QaAccountRole): QaAccountUserPublic;
102
+ /**
103
+ * Replace an account's password, which is what a forgotten one needs. The
104
+ * token version bumps with it, so every token minted under the old password
105
+ * dies server-side: a reset is also the response to a leaked credential.
106
+ * Ownership, profile and the account id survive, so the user's chats are
107
+ * still theirs after signing in again.
108
+ */
109
+ setPassword(email: string, password: string): QaAccountUserPublic;
111
110
  /**
112
111
  * Disable an account: future logins are refused and every live token is
113
112
  * invalidated (the token version bumps). `enable` does not resurrect old
@@ -116,6 +115,38 @@ export declare class QaAccounts {
116
115
  setUserDisabled(email: string, disabled: boolean): QaAccountUserPublic;
117
116
  /** Invalidate every token of the account (password-leak response). */
118
117
  revokeTokens(email: string): QaAccountUserPublic;
118
+ /**
119
+ * The account that owns one session, or undefined while nobody claimed it.
120
+ * The prompt renderer resolves a chat's owner through this map, so a session
121
+ * that predates accounts simply carries no identity.
122
+ */
123
+ ownerIdOf(sessionId: string): string | undefined;
124
+ /**
125
+ * Email plus profile of one account, for the prompt renderer. A disabled
126
+ * account resolves to nothing: its identity leaves the prompt together with
127
+ * its access, so a revoked user is no longer addressed by name.
128
+ */
129
+ identityOf(userId: string): {
130
+ readonly email: string;
131
+ readonly profile: QaAccountProfile;
132
+ } | undefined;
133
+ /** One account in its public shape; undefined when the address is unknown. */
134
+ findUser(email: string): QaAccountUserPublic | undefined;
135
+ /**
136
+ * Operator write: replace one account's profile, addressed by email. The
137
+ * CLI merges field-level flags into a full profile before calling this.
138
+ */
139
+ setProfile(email: string, input: QaAccountProfileInput): QaAccountUserPublic;
140
+ /**
141
+ * Self-service write for the token's own account. The token is verified
142
+ * first, so a browser can only ever edit the profile it is signed in as.
143
+ */
144
+ updateOwnProfile(token: string, input: QaAccountProfileInput): QaAccountUserPublic;
145
+ /**
146
+ * Validate one profile write and stamp it onto the account. Throws before
147
+ * anything is mutated, so a rejected write leaves the stored profile, and
148
+ * the address it is keyed to, exactly as they were.
149
+ */
150
+ private stampedProfile;
119
151
  }
120
- export {};
121
152
  //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1,31 @@
1
+ /** The account facts token verification needs: identity plus token version. */
2
+ interface TokenUser {
3
+ readonly id: string;
4
+ readonly tokenVersion?: number;
5
+ }
6
+ /** The claims carried by a v1 account token payload. */
7
+ export interface TokenPayload {
8
+ readonly uid: string;
9
+ /** Expiry, epoch milliseconds. */
10
+ readonly exp: number;
11
+ /** The account's token version at mint time. */
12
+ readonly ver: number;
13
+ }
14
+ export declare function base64Url(value: Buffer | string): string;
15
+ /**
16
+ * Mint a v1 account token: a base64url JSON payload plus an HMAC-SHA256
17
+ * signature keyed with the accounts file secret.
18
+ */
19
+ export declare function mintToken(secret: string, payload: TokenPayload): string;
20
+ /**
21
+ * Verify a v1 account token against the current secret and account list and
22
+ * return its user id, or null for anything malformed, foreign-signed,
23
+ * expired or superseded. Signature computation, the length check and the
24
+ * payload decode share one try, so a hostile token can only ever resolve to
25
+ * null; the comparison is timing-safe (equal length first, then
26
+ * timingSafeEqual) so a signature guess cannot be accelerated by measuring
27
+ * HMAC rejection time.
28
+ */
29
+ export declare function verifyToken(secret: string, token: string, users: readonly TokenUser[]): string | null;
30
+ export {};
31
+ //# sourceMappingURL=token.d.ts.map
@@ -0,0 +1,65 @@
1
+ import type { Agent } from "@deepseek-ai/dsh-agent";
2
+ import type { Context } from "@deepseek-ai/cordis";
3
+ import type { PluginLogger } from "@yadsh/dsh-plugin-log";
4
+ import type { QaSessionOwnership } from "./session-ownership.js";
5
+ import type { QaApprovalDecision, QaPendingApproval } from "./types.js";
6
+ /**
7
+ * The slice of the `tools/pre-execute` execution record this gate reads. The
8
+ * listener is owned by the plugin context, so it is unfiltered: it also wraps
9
+ * the calls of a delegated child, whose scope chain never reaches the chat's
10
+ * own agent context.
11
+ */
12
+ export interface QaApprovalExecution {
13
+ readonly name: string;
14
+ readonly agent?: Agent;
15
+ readonly signal?: AbortSignal;
16
+ }
17
+ /**
18
+ * Interactive resolution of the tool policy `ask` decision.
19
+ *
20
+ * A composed gate — a content classifier, a hook rule — answers `ask` for a
21
+ * call it will not decide alone. On an attested QA agent that ask resolves
22
+ * against the deployment's pinned `approval=never` policy, so the model is told
23
+ * the user rejected a call the user never saw. This gate sits outside every
24
+ * other `tools/pre-execute` listener and hands the decision to the operator
25
+ * instead: the request is parked here, the QA view lists it over its own
26
+ * remote, and the answer becomes the decision the chain would have produced.
27
+ *
28
+ * `interaction.approvals: blocked` keeps the previous fail-closed behavior —
29
+ * the call is refused with the surface's own reason. Either way nothing is
30
+ * approved automatically, and the allow-list, the workspace fence and the
31
+ * read-only sandbox still run on the resolved call.
32
+ *
33
+ * Only sessions this deployment attested are touched. Any other session's ask
34
+ * is handed back to the chain untouched, so an operator instance that also
35
+ * serves ordinary chats keeps its own approval flow.
36
+ */
37
+ export declare class QaApprovalGate {
38
+ private readonly ctx;
39
+ private readonly interactive;
40
+ private readonly ownership;
41
+ private readonly logger;
42
+ private readonly pending;
43
+ private readonly disposers;
44
+ constructor(ctx: Context, interactive: () => boolean, ownership: QaSessionOwnership, logger: PluginLogger);
45
+ /** Wrap every tool call; other gates compose inside this listener. */
46
+ install(): void;
47
+ /** Approvals of one chat, oldest first: what the QA view lists. */
48
+ list(sessionId: string): readonly QaPendingApproval[];
49
+ /** Apply the operator's answer; an unknown or foreign id is refused. */
50
+ answer(sessionId: string, requestId: string, decision: QaApprovalDecision): boolean;
51
+ /** Detach the listener and fail every parked request. Wired as an effect. */
52
+ dispose(): void;
53
+ private handle;
54
+ /**
55
+ * The chat a call belongs to, when this deployment attested it. A child of an
56
+ * attested chat answers under the chat the operator is looking at.
57
+ */
58
+ private ownerOf;
59
+ /** Park one call until the operator answers, the turn is cancelled, or … */
60
+ private request;
61
+ private resolve;
62
+ /** Fail the requests one session's agent owns; a child never holds the chat. */
63
+ private settleOwner;
64
+ }
65
+ //# sourceMappingURL=approvals.d.ts.map
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Attachment vocabulary shared by the Host configuration and the browser
3
+ * composer. The module stays free of Node and DOM imports: the client bundle
4
+ * imports it directly, and the Host resolver uses it to normalize the
5
+ * operator's configuration.
6
+ */
7
+ /**
8
+ * Text-file extensions the composer accepts out of the box. Compared
9
+ * lowercase and without the leading dot; an entry is a suffix, not a glob.
10
+ */
11
+ export declare const DEFAULT_QA_TEXT_EXTENSIONS: readonly string[];
12
+ /** Bounds the resolver and the settings card agree on. */
13
+ export declare const QA_PASTED_TEXT_LINES_MIN = 0;
14
+ export declare const QA_PASTED_TEXT_LINES_MAX = 10000;
15
+ export declare const QA_MAX_FILE_BYTES_MIN = 1024;
16
+ export declare const QA_MAX_FILE_BYTES_MAX = 52428800;
17
+ export declare const QA_MAX_PENDING_MIN = 1;
18
+ export declare const QA_MAX_PENDING_MAX = 40;
19
+ /**
20
+ * Normalize an operator-authored extension list: lowercase, leading dots
21
+ * stripped, malformed entries and duplicates dropped, order preserved.
22
+ * An empty result means no extension is accepted by name — the composer then
23
+ * still accepts whatever the browser reports as `text/*`.
24
+ * @param values - raw extension tokens from configuration.
25
+ * @returns the normalized token list.
26
+ */
27
+ export declare function normalizeTextExtensions(values: readonly string[]): readonly string[];
28
+ /**
29
+ * Whether one file name carries an accepted text extension. The comparison is
30
+ * case-insensitive; a name without a dot, or with a hidden-file dot only
31
+ * (`.gitignore`), is matched against the whole leaf.
32
+ * @param name - display file name.
33
+ * @param extensions - normalized accepted extensions.
34
+ * @returns whether the name matches one accepted extension.
35
+ */
36
+ export declare function hasTextExtension(name: string, extensions: readonly string[]): boolean;
37
+ /**
38
+ * Count the lines of a pasted blob the way a reader counts them: a single
39
+ * trailing newline does not open a new line, and CRLF counts once.
40
+ * @param text - pasted plain text.
41
+ * @returns the line count, at least 1 for any non-empty text.
42
+ */
43
+ export declare function countTextLines(text: string): number;
44
+ //# sourceMappingURL=attachment-rules.d.ts.map
@@ -4,6 +4,6 @@ export interface CliIo {
4
4
  err(line: string): void;
5
5
  }
6
6
  /** Execute one management command; returns the process exit code. */
7
- export declare function run(argv: readonly string[], io: CliIo, readPassword?: () => string): number;
8
- export declare function main(argv: readonly string[], io?: CliIo, readPassword?: () => string): number;
7
+ export declare function run(argv: readonly string[], io: CliIo, readStdin?: () => string): number;
8
+ export declare function main(argv: readonly string[], io?: CliIo, readStdin?: () => string): number;
9
9
  //# sourceMappingURL=cli.d.ts.map
@@ -1,4 +1,4 @@
1
- import type { QaAccountUserPublic, QaOwnershipEntry, ResolvedQaSurfaceConfig } from "../types.js";
1
+ import type { QaAccountProfileInput, QaAccountUserPublic, QaOwnershipEntry, ResolvedQaSurfaceConfig } from "../types.js";
2
2
  import type { QaAccountsApi, StorageLike } from "./types.js";
3
3
  export type QaAccountsSnapshot = {
4
4
  readonly stage: "checking";
@@ -72,6 +72,13 @@ export declare class QaAccountsController {
72
72
  signOut(): void;
73
73
  /** Claim one freshly created chat so the ownership map stays current. */
74
74
  claimNewSession(sessionId: string): Promise<void>;
75
+ /**
76
+ * Replace the signed-in user's own profile. Resolves to audience-safe
77
+ * refusal copy when the Host rejected the write, and to null once the
78
+ * snapshot carries the stored profile — the form reports the outcome inline
79
+ * rather than through the gate's state machine.
80
+ */
81
+ updateProfile(input: QaAccountProfileInput): Promise<string | null>;
75
82
  private authenticate;
76
83
  /** Own the account, migrate the legacy index, then project authed. */
77
84
  private enterSession;
@@ -1,6 +1,7 @@
1
1
  import type { ConnectionGenerationState } from "@deepseek-ai/dsh-client-connection/client";
2
- import type { QaImageDraft, QaSessionState, ResolvedQaSurfaceConfig } from "../types.js";
3
- import type { QaConversation, QaSecureSession, QaSessions, QaSessionsApi, QaSourceApi, StorageLike } from "./types.js";
2
+ import type { QaAttachmentDraft, QaSessionState, ResolvedQaSurfaceConfig } from "../types.js";
3
+ import type { QaApprovalApi, QaConversation, QaCreateSession, QaFileUpload, QaSecureSession, QaSessions, QaSessionsApi, QaQuestionApi, QaSourceApi, StorageLike } from "./types.js";
4
+ import type { QaApprovalDecision, QaQuestionAnswerItem } from "../types.js";
4
5
  export interface QaAccountsFacade {
5
6
  /** The account bearer token, or null while anonymous. */
6
7
  readonly token: () => string | null;
@@ -19,13 +20,30 @@ export interface QaAccountsFacade {
19
20
  export interface QaSessionControllerOptions {
20
21
  readonly sessions: QaSessions;
21
22
  readonly api: QaSessionsApi;
23
+ readonly createSession: QaCreateSession;
22
24
  /** Conversation assembly feeding the transcript projection. */
23
25
  readonly conversation: QaConversation;
24
26
  readonly connection: ConnectionGenerationState;
25
27
  readonly config: ResolvedQaSurfaceConfig;
26
28
  readonly secureSession: QaSecureSession;
27
29
  readonly sourceApi?: QaSourceApi;
30
+ /**
31
+ * The approval half of the Host namespace. Absent on a page built against a
32
+ * Host that does not answer approvals: the surface then never shows a
33
+ * request and keeps the composer as it is.
34
+ */
35
+ readonly approvalApi?: QaApprovalApi;
36
+ /**
37
+ * The question half of the Host namespace. Absent on a page whose Host build
38
+ * does not answer questions: the surface then only renders what it can.
39
+ */
40
+ readonly questionApi?: QaQuestionApi;
28
41
  readonly storage?: StorageLike;
42
+ /**
43
+ * Browser file-upload service, resolved lazily: the page may not serve the
44
+ * upload plugin, and a deployment without it keeps images and text only.
45
+ */
46
+ readonly fileUpload?: () => QaFileUpload | undefined;
29
47
  /** Present while the deployment gates QA users with accounts. */
30
48
  readonly accounts?: QaAccountsFacade;
31
49
  readonly timeoutMs?: number;
@@ -45,7 +63,7 @@ export interface QaSessionControllerOptions {
45
63
  export declare class QaSessionController {
46
64
  private readonly listeners;
47
65
  private readonly sessions;
48
- private readonly api;
66
+ private readonly createSessionRemote;
49
67
  private readonly conversation;
50
68
  private readonly connection;
51
69
  private readonly config;
@@ -53,10 +71,13 @@ export declare class QaSessionController {
53
71
  private readonly sourceApi;
54
72
  private readonly chats;
55
73
  private readonly accounts;
74
+ /** Resolved per send: a page without the upload plugin has no receipts. */
75
+ private readonly fileUpload;
56
76
  /** Per-chat attachment URL cache; blob URLs die with the chat binding. */
57
77
  private readonly assets;
58
78
  private readonly timeoutMs;
59
- private readonly streamIntervalMs;
79
+ /** Spacing for a running turn's stream frames; the policy lives there. */
80
+ private readonly streamPublisher;
60
81
  private state;
61
82
  private session;
62
83
  private conversationBinding;
@@ -69,7 +90,6 @@ export declare class QaSessionController {
69
90
  private admissionPending;
70
91
  private policyReady;
71
92
  private drafting;
72
- private streamFlushTimer;
73
93
  /** The chat session to return to when a subagent view closes. */
74
94
  private chatSessionId;
75
95
  private viewingSubagent;
@@ -79,11 +99,17 @@ export declare class QaSessionController {
79
99
  private chatsRevision;
80
100
  /** Host-side provenance of the bound chat, merged into the projection. */
81
101
  private readonly hostSources;
102
+ /** Host-side approvals of the bound chat waiting for the operator. */
103
+ private readonly hostApprovals;
104
+ /** Host-side question requests of the bound chat waiting for the operator. */
105
+ private readonly hostQuestions;
106
+ /** Set while a running turn is polled for parked requests. */
107
+ private pendingTimer;
82
108
  constructor(options: QaSessionControllerOptions);
83
109
  getSnapshot: () => QaSessionState;
84
110
  subscribe: (listener: () => void) => (() => void);
85
111
  ensureSession(): Promise<void>;
86
- send(text: string, images?: readonly QaImageDraft[]): Promise<boolean>;
112
+ send(text: string, attachments?: readonly QaAttachmentDraft[]): Promise<boolean>;
87
113
  /**
88
114
  * Ask for a fresh variant of the previous answer. The session has no
89
115
  * truncation seam, so this sends the hidden regeneration instruction as an
@@ -160,17 +186,9 @@ export declare class QaSessionController {
160
186
  private bind;
161
187
  private unbind;
162
188
  private waitForConnection;
163
- /**
164
- * Project one session notification. A running turn's frames arrive at
165
- * animation-frame cadence, so re-projections are spaced at least
166
- * {@link streamIntervalMs} apart: the first frame of a window projects at
167
- * once and further frames are absorbed (the memoized render path replays
168
- * nothing, so absorbing a frame only defers it). Everything outside a
169
- * running turn - phase flips, errors, turn completion - projects
170
- * immediately.
171
- */
189
+ /** Project one session notification; the running-turn spacing policy
190
+ * (first frame at once, further frames absorbed) lives in the publisher. */
172
191
  private publishSessionUpdate;
173
- private clearStreamFlush;
174
192
  private publish;
175
193
  private fail;
176
194
  /**
@@ -181,5 +199,24 @@ export declare class QaSessionController {
181
199
  */
182
200
  private attestPolicy;
183
201
  private emit;
202
+ /**
203
+ * Answer a request the Host parked for this chat. The Host re-checks the
204
+ * request against the chat, so an answer that lost its race is a no-op; the
205
+ * refresh that follows is what the surface renders.
206
+ */
207
+ answerApproval(requestId: string, decision: QaApprovalDecision): Promise<void>;
208
+ /** Send the operator's answers to one parked question request. */
209
+ answerQuestion(requestId: string, answers: readonly QaQuestionAnswerItem[]): Promise<void>;
210
+ /** Close a parked question request without answering it. */
211
+ cancelQuestion(requestId: string): Promise<void>;
212
+ /**
213
+ * Poll the Host for parked requests while a turn runs. A request only exists
214
+ * inside an open turn, and it is Host state: polling is how the page learns
215
+ * about it, and how it reappears after a reload. One timer serves both seams,
216
+ * and each is polled only where the deployment answers it.
217
+ */
218
+ private syncPendingPolling;
219
+ private stopPendingPolling;
220
+ private hostToken;
184
221
  }
185
222
  //# sourceMappingURL=QaSessionController.d.ts.map
@@ -3,7 +3,7 @@ import type { InjectFace, PropsRuntime } from "@deepseek-ai/dsh-client-ui-slots"
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 { QaConversation, QaSecureSession, QaSessions, QaSessionsApi, QaSourceApi } from "./types.js";
6
+ import type { QaApprovalApi, QaConversation, QaCreateSession, QaFileUpload, QaSecureSession, QaSessions, QaSessionsApi, QaQuestionApi, QaSourceApi } from "./types.js";
7
7
  export interface QaSurfaceFace {
8
8
  readonly route: QaRouteController;
9
9
  readonly config: QaConfigController;
@@ -12,7 +12,20 @@ export interface QaSurfaceFace {
12
12
  readonly api: QaSessionsApi;
13
13
  readonly connection: ConnectionGenerationState;
14
14
  readonly secureSession: QaSecureSession;
15
+ readonly createSession: QaCreateSession;
15
16
  readonly sourceApi: QaSourceApi;
17
+ /**
18
+ * Approval half of the plugin's namespace. Absent on a page whose Host build
19
+ * does not answer it; the surface then only blocks sends it cannot attest.
20
+ */
21
+ readonly approvalApi?: QaApprovalApi;
22
+ /** Question half of the plugin's namespace, when the Host answers it. */
23
+ readonly questionApi?: QaQuestionApi;
24
+ /**
25
+ * Browser file-upload service, when the page serves the upload plugin.
26
+ * Resolved per send so a page that loads it later still gets file support.
27
+ */
28
+ readonly fileUpload?: () => QaFileUpload | undefined;
16
29
  /** Present when the deployment mounts the QA account gate. */
17
30
  readonly accounts?: QaAccountsController;
18
31
  }
@@ -0,0 +1,39 @@
1
+ import type { QaApprovalDecision, QaPendingApproval } from "../types.js";
2
+ import type { QaApprovalApi } from "./types.js";
3
+ /**
4
+ * The operator's side of a parked tool call.
5
+ *
6
+ * A composed gate's `ask` is answered on the Host, so the waiting request is
7
+ * Host state: it survives a page reload, and the surface learns about it by
8
+ * asking rather than by receiving an event. The bridge holds the last list it
9
+ * saw, refreshes it while a turn runs, and forwards an answer.
10
+ */
11
+ export declare class QaHostApprovalBridge {
12
+ private readonly approvalApi;
13
+ private approvals;
14
+ private signature;
15
+ private refreshing;
16
+ private answering;
17
+ /** Bumped on reset so a stale in-flight response never lands. */
18
+ private generation;
19
+ constructor(approvalApi: QaApprovalApi | undefined);
20
+ /** Leave the chat: a chat switch drops the previous chat's requests. */
21
+ reset(): void;
22
+ /** The last list this bridge saw; empty when the deployment blocks them. */
23
+ list(): readonly QaPendingApproval[];
24
+ /** Whether this page can ask the Host about approvals at all. */
25
+ get available(): boolean;
26
+ /**
27
+ * Re-read the chat's pending requests; a changed list republishes through the
28
+ * callback. Overlapping calls coalesce, and a response that outlives its chat
29
+ * is dropped.
30
+ */
31
+ refresh(sessionId: string, token: string, onChanged: () => void): Promise<void>;
32
+ /**
33
+ * Answer one request and re-read the list. A refusal is not an error: the
34
+ * request was already settled (the turn was stopped, the call went away), so
35
+ * the refresh — not the answer — is what the surface shows.
36
+ */
37
+ answer(sessionId: string, token: string, requestId: string, decision: QaApprovalDecision): Promise<void>;
38
+ }
39
+ //# sourceMappingURL=approvals.d.ts.map