@yadsh/dsh-qa-surface 0.15.6 → 0.16.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 (244) hide show
  1. package/README.md +8 -0
  2. package/lib/access/capability-catalog.js +11 -4
  3. package/lib/access/capability-catalog.js.map +1 -1
  4. package/lib/access/service.js +46 -5
  5. package/lib/access/service.js.map +1 -1
  6. package/lib/accounts/store.js +2 -2
  7. package/lib/accounts/store.js.map +1 -1
  8. package/lib/admin/service.js +4 -2
  9. package/lib/admin/service.js.map +1 -1
  10. package/lib/admin/session-log.js +3 -0
  11. package/lib/admin/session-log.js.map +1 -1
  12. package/lib/agent-scope.js +9 -0
  13. package/lib/agent-scope.js.map +1 -0
  14. package/lib/chat-sharing/native-fence.js +111 -0
  15. package/lib/chat-sharing/native-fence.js.map +1 -0
  16. package/lib/chat-sharing/resources.js +57 -0
  17. package/lib/chat-sharing/resources.js.map +1 -0
  18. package/lib/chat-sharing/store.js +193 -0
  19. package/lib/chat-sharing/store.js.map +1 -0
  20. package/lib/chat-sharing/transport.js +274 -0
  21. package/lib/chat-sharing/transport.js.map +1 -0
  22. package/lib/chat-sharing/turn-guard.js +154 -0
  23. package/lib/chat-sharing/turn-guard.js.map +1 -0
  24. package/lib/chat-sharing/types.js +2 -0
  25. package/lib/chat-sharing/types.js.map +1 -0
  26. package/lib/chat-sharing/uploads.js +55 -0
  27. package/lib/chat-sharing/uploads.js.map +1 -0
  28. package/lib/client/QaAccountsController.js +29 -2
  29. package/lib/client/QaAccountsController.js.map +1 -1
  30. package/lib/client/QaConfigController.js +7 -12
  31. package/lib/client/QaConfigController.js.map +1 -1
  32. package/lib/client/QaSessionController.js +186 -19
  33. package/lib/client/QaSessionController.js.map +1 -1
  34. package/lib/client/QaSurface.js +110 -9
  35. package/lib/client/QaSurface.js.map +1 -1
  36. package/lib/client/QaSurfaceGuard.js +6 -1
  37. package/lib/client/QaSurfaceGuard.js.map +1 -1
  38. package/lib/client/QaTranscriptAdapter.js +13 -3
  39. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  40. package/lib/client/account-conversation.js +33 -0
  41. package/lib/client/account-conversation.js.map +1 -0
  42. package/lib/client/account-sessions.js +106 -0
  43. package/lib/client/account-sessions.js.map +1 -0
  44. package/lib/client/account-upload.js +30 -0
  45. package/lib/client/account-upload.js.map +1 -0
  46. package/lib/client/chat-artifacts.js +17 -3
  47. package/lib/client/chat-artifacts.js.map +1 -1
  48. package/lib/client/chat-sharing-api.js +2 -0
  49. package/lib/client/chat-sharing-api.js.map +1 -0
  50. package/lib/client/components/QaChangelog.js +70 -3
  51. package/lib/client/components/QaChangelog.js.map +1 -1
  52. package/lib/client/components/QaChatSharing.js +92 -0
  53. package/lib/client/components/QaChatSharing.js.map +1 -0
  54. package/lib/client/components/QaComposer.js +8 -4
  55. package/lib/client/components/QaComposer.js.map +1 -1
  56. package/lib/client/components/QaFileAttachment.js +12 -3
  57. package/lib/client/components/QaFileAttachment.js.map +1 -1
  58. package/lib/client/components/QaFilesPanel.js +11 -4
  59. package/lib/client/components/QaFilesPanel.js.map +1 -1
  60. package/lib/client/components/QaHeader.js +3 -3
  61. package/lib/client/components/QaHeader.js.map +1 -1
  62. package/lib/client/components/QaMessage.js +34 -9
  63. package/lib/client/components/QaMessage.js.map +1 -1
  64. package/lib/client/components/QaSidebar.js +1 -1
  65. package/lib/client/components/QaSidebar.js.map +1 -1
  66. package/lib/client/components/QaSourcesPanel.js +12 -4
  67. package/lib/client/components/QaSourcesPanel.js.map +1 -1
  68. package/lib/client/components/QaWorkspaceBrowser.js +28 -7
  69. package/lib/client/components/QaWorkspaceBrowser.js.map +1 -1
  70. package/lib/client/components/source-refs.js +42 -23
  71. package/lib/client/components/source-refs.js.map +1 -1
  72. package/lib/client/index.js +60 -6
  73. package/lib/client/index.js.map +1 -1
  74. package/lib/client/lineage.js +4 -3
  75. package/lib/client/lineage.js.map +1 -1
  76. package/lib/client/markdown/katex-css.js +1 -1
  77. package/lib/client/markdown/render.js +3 -4
  78. package/lib/client/markdown/render.js.map +1 -1
  79. package/lib/client/markdown/source-chip.js +4 -1
  80. package/lib/client/markdown/source-chip.js.map +1 -1
  81. package/lib/client/notifications/notification-dispatcher.js +50 -11
  82. package/lib/client/notifications/notification-dispatcher.js.map +1 -1
  83. package/lib/client/notifications/use-turn-notifications.js +107 -18
  84. package/lib/client/notifications/use-turn-notifications.js.map +1 -1
  85. package/lib/client/project-session-state.js +28 -13
  86. package/lib/client/project-session-state.js.map +1 -1
  87. package/lib/client/session-admission.js +9 -1
  88. package/lib/client/session-admission.js.map +1 -1
  89. package/lib/client/session-sources.js +44 -3
  90. package/lib/client/session-sources.js.map +1 -1
  91. package/lib/client/slash/useSlashNavigation.js +8 -5
  92. package/lib/client/slash/useSlashNavigation.js.map +1 -1
  93. package/lib/client/source-preview.js +1 -1
  94. package/lib/client/source-preview.js.map +1 -1
  95. package/lib/client/styles.js +9 -2
  96. package/lib/client/styles.js.map +1 -1
  97. package/lib/client/turn-sources.js +2 -1
  98. package/lib/client/turn-sources.js.map +1 -1
  99. package/lib/client/types.js.map +1 -1
  100. package/lib/client/workspace-download.js +42 -2
  101. package/lib/client/workspace-download.js.map +1 -1
  102. package/lib/client.js +3337 -947
  103. package/lib/client.js.map +1 -1
  104. package/lib/enforcement/skill-policy.js +29 -4
  105. package/lib/enforcement/skill-policy.js.map +1 -1
  106. package/lib/enforcement/skill-resource-paths.js +32 -0
  107. package/lib/enforcement/skill-resource-paths.js.map +1 -0
  108. package/lib/enforcement/structured-result.js +38 -0
  109. package/lib/enforcement/structured-result.js.map +1 -0
  110. package/lib/enforcement/tool-grants.js +3 -1
  111. package/lib/enforcement/tool-grants.js.map +1 -1
  112. package/lib/index.js +403 -15
  113. package/lib/index.js.map +1 -1
  114. package/lib/prompt-notes.js +18 -1
  115. package/lib/prompt-notes.js.map +1 -1
  116. package/lib/provenance/collector.js +13 -1
  117. package/lib/provenance/collector.js.map +1 -1
  118. package/lib/provenance/connectors.js +32 -8
  119. package/lib/provenance/connectors.js.map +1 -1
  120. package/lib/provenance/dedupe.js +8 -1
  121. package/lib/provenance/dedupe.js.map +1 -1
  122. package/lib/provenance/document-preview.js +19 -1
  123. package/lib/provenance/document-preview.js.map +1 -1
  124. package/lib/provenance/extractors.js +67 -1
  125. package/lib/provenance/extractors.js.map +1 -1
  126. package/lib/provenance/file-download.js +56 -0
  127. package/lib/provenance/file-download.js.map +1 -0
  128. package/lib/provenance/file-preview.js +12 -1
  129. package/lib/provenance/file-preview.js.map +1 -1
  130. package/lib/provenance/host-store.js +59 -10
  131. package/lib/provenance/host-store.js.map +1 -1
  132. package/lib/provenance/integration-extractor.js +63 -0
  133. package/lib/provenance/integration-extractor.js.map +1 -0
  134. package/lib/qa-tools/docs-tools.js +14 -0
  135. package/lib/qa-tools/docs-tools.js.map +1 -1
  136. package/lib/secure-session.js +37 -5
  137. package/lib/secure-session.js.map +1 -1
  138. package/lib/session-fork-host.js +157 -0
  139. package/lib/session-fork-host.js.map +1 -0
  140. package/lib/session-fork.js +34 -0
  141. package/lib/session-fork.js.map +1 -0
  142. package/lib/session-ownership.js +5 -1
  143. package/lib/session-ownership.js.map +1 -1
  144. package/lib/shared/session-lineage.js +6 -0
  145. package/lib/shared/session-lineage.js.map +1 -0
  146. package/lib/slash/draft-target.js +21 -0
  147. package/lib/slash/draft-target.js.map +1 -0
  148. package/lib/slash/remotes.js +39 -4
  149. package/lib/slash/remotes.js.map +1 -1
  150. package/lib/typert.host.js +1628 -231
  151. package/lib/typert.remote-client.d.ts +48 -1
  152. package/lib/typert.remote-client.js +1436 -193
  153. package/lib/types/access/capability-catalog.d.ts +1 -1
  154. package/lib/types/access/service.d.ts +7 -0
  155. package/lib/types/access.js +2 -0
  156. package/lib/types/access.js.map +1 -0
  157. package/lib/types/accounts/store.d.ts +1 -1
  158. package/lib/types/accounts.js +2 -0
  159. package/lib/types/accounts.js.map +1 -0
  160. package/lib/types/admin/session-log.d.ts +2 -0
  161. package/lib/types/admin.js +2 -0
  162. package/lib/types/admin.js.map +1 -0
  163. package/lib/types/agent-scope.d.ts +4 -0
  164. package/lib/types/capability.js +2 -0
  165. package/lib/types/capability.js.map +1 -0
  166. package/lib/types/chat-sharing/native-fence.d.ts +11 -0
  167. package/lib/types/chat-sharing/resources.d.ts +5 -0
  168. package/lib/types/chat-sharing/store.d.ts +28 -0
  169. package/lib/types/chat-sharing/transport.d.ts +31 -0
  170. package/lib/types/chat-sharing/turn-guard.d.ts +21 -0
  171. package/lib/types/chat-sharing/types.d.ts +25 -0
  172. package/lib/types/chat-sharing/uploads.d.ts +5 -0
  173. package/lib/types/client/QaAccountsController.d.ts +3 -0
  174. package/lib/types/client/QaConfigController.d.ts +3 -2
  175. package/lib/types/client/QaSessionController.d.ts +17 -3
  176. package/lib/types/client/QaSurface.d.ts +6 -1
  177. package/lib/types/client/account-conversation.d.ts +6 -0
  178. package/lib/types/client/account-sessions.d.ts +7 -0
  179. package/lib/types/client/account-upload.d.ts +15 -0
  180. package/lib/types/client/chat-sharing-api.d.ts +35 -0
  181. package/lib/types/client/components/QaChatSharing.d.ts +10 -0
  182. package/lib/types/client/components/QaComposer.d.ts +2 -0
  183. package/lib/types/client/components/QaFileAttachment.d.ts +3 -2
  184. package/lib/types/client/components/QaFilesPanel.d.ts +4 -1
  185. package/lib/types/client/components/QaMessage.d.ts +5 -2
  186. package/lib/types/client/components/QaWorkspaceBrowser.d.ts +8 -1
  187. package/lib/types/client/components/source-refs.d.ts +1 -0
  188. package/lib/types/client/lineage.d.ts +2 -2
  189. package/lib/types/client/notifications/notification-dispatcher.d.ts +10 -6
  190. package/lib/types/client/notifications/use-turn-notifications.d.ts +4 -0
  191. package/lib/types/client/project-session-state.d.ts +1 -0
  192. package/lib/types/client/session-admission.d.ts +2 -0
  193. package/lib/types/client/session-sources.d.ts +1 -0
  194. package/lib/types/client/turn-sources.d.ts +1 -1
  195. package/lib/types/client/types.d.ts +8 -1
  196. package/lib/types/client/workspace-download.d.ts +9 -1
  197. package/lib/types/config.js +2 -0
  198. package/lib/types/config.js.map +1 -0
  199. package/lib/types/documents.js +2 -0
  200. package/lib/types/documents.js.map +1 -0
  201. package/lib/types/enforcement/skill-resource-paths.d.ts +5 -0
  202. package/lib/types/enforcement/structured-result.d.ts +11 -0
  203. package/lib/types/expert-memory.js +2 -0
  204. package/lib/types/expert-memory.js.map +1 -0
  205. package/lib/types/index.d.ts +35 -1
  206. package/lib/types/policy.js +2 -0
  207. package/lib/types/policy.js.map +1 -0
  208. package/lib/types/prompt-notes.d.ts +2 -0
  209. package/lib/types/provenance/connectors.d.ts +4 -1
  210. package/lib/types/provenance/document-preview.d.ts +2 -0
  211. package/lib/types/provenance/extractors.d.ts +2 -0
  212. package/lib/types/provenance/file-download.d.ts +10 -0
  213. package/lib/types/provenance/host-store.d.ts +2 -0
  214. package/lib/types/provenance/integration-extractor.d.ts +5 -0
  215. package/lib/types/provenance/types.d.ts +2 -0
  216. package/lib/types/qa-tools/docs-tools.d.ts +2 -0
  217. package/lib/types/quality.js +7 -0
  218. package/lib/types/quality.js.map +1 -0
  219. package/lib/types/secure-session.d.ts +20 -1
  220. package/lib/types/session-fork-host.d.ts +27 -0
  221. package/lib/types/session-fork.d.ts +7 -0
  222. package/lib/types/session.js +2 -0
  223. package/lib/types/session.js.map +1 -0
  224. package/lib/types/shared/session-lineage.d.ts +7 -0
  225. package/lib/types/skills.js +2 -0
  226. package/lib/types/skills.js.map +1 -0
  227. package/lib/types/slash/draft-target.d.ts +7 -0
  228. package/lib/types/slash/remotes.d.ts +7 -0
  229. package/lib/types/slash.js +2 -0
  230. package/lib/types/slash.js.map +1 -0
  231. package/lib/types/types/access.d.ts +43 -0
  232. package/lib/types/types/accounts.d.ts +173 -0
  233. package/lib/types/types/admin.d.ts +286 -0
  234. package/lib/types/types/capability.d.ts +230 -0
  235. package/lib/types/types/config.d.ts +594 -0
  236. package/lib/types/types/documents.d.ts +34 -0
  237. package/lib/types/types/expert-memory.d.ts +35 -0
  238. package/lib/types/types/policy.d.ts +54 -0
  239. package/lib/types/types/quality.d.ts +100 -0
  240. package/lib/types/types/session.d.ts +382 -0
  241. package/lib/types/types/skills.d.ts +143 -0
  242. package/lib/types/types/slash.d.ts +159 -0
  243. package/lib/types/types.d.ts +13 -2180
  244. package/package.json +8 -7
package/lib/index.js CHANGED
@@ -33,6 +33,15 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
33
33
  done = true;
34
34
  };
35
35
  import { randomUUID } from "node:crypto";
36
+ import path from "node:path";
37
+ import { defaultAccountsFilePath } from "./accounts/store.js";
38
+ import { QaChatSharingStore } from "./chat-sharing/store.js";
39
+ import { QaChatTransport } from "./chat-sharing/transport.js";
40
+ import { QaChatTurnGuard } from "./chat-sharing/turn-guard.js";
41
+ import { installQaNativeFence } from "./chat-sharing/native-fence.js";
42
+ import { qaChatPublishedFile, qaChatAttachmentPath, } from "./chat-sharing/resources.js";
43
+ import { installQaChatUploads } from "./chat-sharing/uploads.js";
44
+ import { forkQaSession } from "./session-fork-host.js";
36
45
  import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
37
46
  import { SessionId } from "@deepseek-ai/dsh-session/types";
38
47
  import { WorkspaceId } from "@deepseek-ai/dsh-workspace";
@@ -68,7 +77,8 @@ import { QaTools } from "./qa-tools/index.js";
68
77
  import { docsDefaultVersionOf } from "./config-resolvers/tools.js";
69
78
  import { QaProvenanceHost } from "./provenance/host-store.js";
70
79
  import { defaultLegacyProvenanceFilePath, defaultQaProvenanceDirectoryPath, FileQaProvenanceSnapshotStore, } from "./provenance/snapshot-store.js";
71
- import { previewConvertibleDocument } from "./provenance/document-preview.js";
80
+ import { previewConvertibleDocument, previewSourceDocument, } from "./provenance/document-preview.js";
81
+ import { readWorkspaceFileChunk } from "./provenance/file-download.js";
72
82
  import { listWorkspaceDirectory, readSourceFilePreview, readWorkspaceFile, QaSourcePreviewError, } from "./provenance/file-preview.js";
73
83
  import { existingQaUserWorkspace, prepareQaUserWorkspace, } from "./user-workspace.js";
74
84
  export const name = "qa-surface";
@@ -141,6 +151,7 @@ let QaSurface = (() => {
141
151
  let _describe_decorators;
142
152
  let _queueStatus_decorators;
143
153
  let _createSession_decorators;
154
+ let _forkSession_decorators;
144
155
  let _accessCurrent_decorators;
145
156
  let _accessSession_decorators;
146
157
  let _accessAdminSnapshot_decorators;
@@ -181,6 +192,25 @@ let QaSurface = (() => {
181
192
  let _adminMetrics_decorators;
182
193
  let _adminAudit_decorators;
183
194
  let _secureSession_decorators;
195
+ let _chatVisible_decorators;
196
+ let _chatAccess_decorators;
197
+ let _chatGrants_decorators;
198
+ let _chatSetGrant_decorators;
199
+ let _chatAuthors_decorators;
200
+ let _chatAudit_decorators;
201
+ let _chatAttachmentPath_decorators;
202
+ let _chatList_decorators;
203
+ let _chatSearch_decorators;
204
+ let _chatSelectModel_decorators;
205
+ let _chatPage_decorators;
206
+ let _chatFollow_decorators;
207
+ let _chatControl_decorators;
208
+ let _chatProjections_decorators;
209
+ let _chatPrompt_decorators;
210
+ let _chatAttachment_decorators;
211
+ let _chatRename_decorators;
212
+ let _chatCancel_decorators;
213
+ let _chatUpdateQueue_decorators;
184
214
  let _sources_decorators;
185
215
  let _pendingApprovals_decorators;
186
216
  let _answerApproval_decorators;
@@ -190,6 +220,9 @@ let QaSurface = (() => {
190
220
  let _readSourceFile_decorators;
191
221
  let _listWorkspaceFiles_decorators;
192
222
  let _readWorkspaceFile_decorators;
223
+ let _readWorkspaceFileChunk_decorators;
224
+ let _documentWorkflowStatus_decorators;
225
+ let _approveDocumentWorkflow_decorators;
193
226
  let _previewWorkspaceDocument_decorators;
194
227
  let _skillsList_decorators;
195
228
  let _skillsGet_decorators;
@@ -220,6 +253,7 @@ let QaSurface = (() => {
220
253
  _describe_decorators = [Remote("describe")];
221
254
  _queueStatus_decorators = [Remote("queueStatus")];
222
255
  _createSession_decorators = [Remote("createSession")];
256
+ _forkSession_decorators = [Remote("forkSession")];
223
257
  _accessCurrent_decorators = [Remote("accessCurrent")];
224
258
  _accessSession_decorators = [Remote("accessSession")];
225
259
  _accessAdminSnapshot_decorators = [Remote("accessAdminSnapshot")];
@@ -260,6 +294,25 @@ let QaSurface = (() => {
260
294
  _adminMetrics_decorators = [Remote("adminMetrics")];
261
295
  _adminAudit_decorators = [Remote("adminAudit")];
262
296
  _secureSession_decorators = [Remote("secureSession")];
297
+ _chatVisible_decorators = [Remote("chatVisible")];
298
+ _chatAccess_decorators = [Remote("chatAccess")];
299
+ _chatGrants_decorators = [Remote("chatGrants")];
300
+ _chatSetGrant_decorators = [Remote("chatSetGrant")];
301
+ _chatAuthors_decorators = [Remote("chatAuthors")];
302
+ _chatAudit_decorators = [Remote("chatAudit")];
303
+ _chatAttachmentPath_decorators = [Remote("chatAttachmentPath")];
304
+ _chatList_decorators = [Remote("chatList")];
305
+ _chatSearch_decorators = [Remote("chatSearch")];
306
+ _chatSelectModel_decorators = [Remote("chatSelectModel")];
307
+ _chatPage_decorators = [Remote("chatPage")];
308
+ _chatFollow_decorators = [Remote({ mode: "stream" })];
309
+ _chatControl_decorators = [Remote({ mode: "stream" })];
310
+ _chatProjections_decorators = [Remote("chatProjections")];
311
+ _chatPrompt_decorators = [Remote("chatPrompt")];
312
+ _chatAttachment_decorators = [Remote("chatAttachment")];
313
+ _chatRename_decorators = [Remote("chatRename")];
314
+ _chatCancel_decorators = [Remote("chatCancel")];
315
+ _chatUpdateQueue_decorators = [Remote("chatUpdateQueue")];
263
316
  _sources_decorators = [Remote("sources")];
264
317
  _pendingApprovals_decorators = [Remote("pendingApprovals")];
265
318
  _answerApproval_decorators = [Remote("answerApproval")];
@@ -269,6 +322,9 @@ let QaSurface = (() => {
269
322
  _readSourceFile_decorators = [Remote("readSourceFile")];
270
323
  _listWorkspaceFiles_decorators = [Remote("listWorkspaceFiles")];
271
324
  _readWorkspaceFile_decorators = [Remote("readWorkspaceFile")];
325
+ _readWorkspaceFileChunk_decorators = [Remote("readWorkspaceFileChunk")];
326
+ _documentWorkflowStatus_decorators = [Remote("documentWorkflowStatus")];
327
+ _approveDocumentWorkflow_decorators = [Remote("approveDocumentWorkflow")];
272
328
  _previewWorkspaceDocument_decorators = [Remote("previewWorkspaceDocument")];
273
329
  _skillsList_decorators = [Remote("skillsList")];
274
330
  _skillsGet_decorators = [Remote("skillsGet")];
@@ -296,6 +352,7 @@ let QaSurface = (() => {
296
352
  __esDecorate(this, null, _describe_decorators, { kind: "method", name: "describe", static: false, private: false, access: { has: obj => "describe" in obj, get: obj => obj.describe }, metadata: _metadata }, null, _instanceExtraInitializers);
297
353
  __esDecorate(this, null, _queueStatus_decorators, { kind: "method", name: "queueStatus", static: false, private: false, access: { has: obj => "queueStatus" in obj, get: obj => obj.queueStatus }, metadata: _metadata }, null, _instanceExtraInitializers);
298
354
  __esDecorate(this, null, _createSession_decorators, { kind: "method", name: "createSession", static: false, private: false, access: { has: obj => "createSession" in obj, get: obj => obj.createSession }, metadata: _metadata }, null, _instanceExtraInitializers);
355
+ __esDecorate(this, null, _forkSession_decorators, { kind: "method", name: "forkSession", static: false, private: false, access: { has: obj => "forkSession" in obj, get: obj => obj.forkSession }, metadata: _metadata }, null, _instanceExtraInitializers);
299
356
  __esDecorate(this, null, _accessCurrent_decorators, { kind: "method", name: "accessCurrent", static: false, private: false, access: { has: obj => "accessCurrent" in obj, get: obj => obj.accessCurrent }, metadata: _metadata }, null, _instanceExtraInitializers);
300
357
  __esDecorate(this, null, _accessSession_decorators, { kind: "method", name: "accessSession", static: false, private: false, access: { has: obj => "accessSession" in obj, get: obj => obj.accessSession }, metadata: _metadata }, null, _instanceExtraInitializers);
301
358
  __esDecorate(this, null, _accessAdminSnapshot_decorators, { kind: "method", name: "accessAdminSnapshot", static: false, private: false, access: { has: obj => "accessAdminSnapshot" in obj, get: obj => obj.accessAdminSnapshot }, metadata: _metadata }, null, _instanceExtraInitializers);
@@ -336,6 +393,25 @@ let QaSurface = (() => {
336
393
  __esDecorate(this, null, _adminMetrics_decorators, { kind: "method", name: "adminMetrics", static: false, private: false, access: { has: obj => "adminMetrics" in obj, get: obj => obj.adminMetrics }, metadata: _metadata }, null, _instanceExtraInitializers);
337
394
  __esDecorate(this, null, _adminAudit_decorators, { kind: "method", name: "adminAudit", static: false, private: false, access: { has: obj => "adminAudit" in obj, get: obj => obj.adminAudit }, metadata: _metadata }, null, _instanceExtraInitializers);
338
395
  __esDecorate(this, null, _secureSession_decorators, { kind: "method", name: "secureSession", static: false, private: false, access: { has: obj => "secureSession" in obj, get: obj => obj.secureSession }, metadata: _metadata }, null, _instanceExtraInitializers);
396
+ __esDecorate(this, null, _chatVisible_decorators, { kind: "method", name: "chatVisible", static: false, private: false, access: { has: obj => "chatVisible" in obj, get: obj => obj.chatVisible }, metadata: _metadata }, null, _instanceExtraInitializers);
397
+ __esDecorate(this, null, _chatAccess_decorators, { kind: "method", name: "chatAccess", static: false, private: false, access: { has: obj => "chatAccess" in obj, get: obj => obj.chatAccess }, metadata: _metadata }, null, _instanceExtraInitializers);
398
+ __esDecorate(this, null, _chatGrants_decorators, { kind: "method", name: "chatGrants", static: false, private: false, access: { has: obj => "chatGrants" in obj, get: obj => obj.chatGrants }, metadata: _metadata }, null, _instanceExtraInitializers);
399
+ __esDecorate(this, null, _chatSetGrant_decorators, { kind: "method", name: "chatSetGrant", static: false, private: false, access: { has: obj => "chatSetGrant" in obj, get: obj => obj.chatSetGrant }, metadata: _metadata }, null, _instanceExtraInitializers);
400
+ __esDecorate(this, null, _chatAuthors_decorators, { kind: "method", name: "chatAuthors", static: false, private: false, access: { has: obj => "chatAuthors" in obj, get: obj => obj.chatAuthors }, metadata: _metadata }, null, _instanceExtraInitializers);
401
+ __esDecorate(this, null, _chatAudit_decorators, { kind: "method", name: "chatAudit", static: false, private: false, access: { has: obj => "chatAudit" in obj, get: obj => obj.chatAudit }, metadata: _metadata }, null, _instanceExtraInitializers);
402
+ __esDecorate(this, null, _chatAttachmentPath_decorators, { kind: "method", name: "chatAttachmentPath", static: false, private: false, access: { has: obj => "chatAttachmentPath" in obj, get: obj => obj.chatAttachmentPath }, metadata: _metadata }, null, _instanceExtraInitializers);
403
+ __esDecorate(this, null, _chatList_decorators, { kind: "method", name: "chatList", static: false, private: false, access: { has: obj => "chatList" in obj, get: obj => obj.chatList }, metadata: _metadata }, null, _instanceExtraInitializers);
404
+ __esDecorate(this, null, _chatSearch_decorators, { kind: "method", name: "chatSearch", static: false, private: false, access: { has: obj => "chatSearch" in obj, get: obj => obj.chatSearch }, metadata: _metadata }, null, _instanceExtraInitializers);
405
+ __esDecorate(this, null, _chatSelectModel_decorators, { kind: "method", name: "chatSelectModel", static: false, private: false, access: { has: obj => "chatSelectModel" in obj, get: obj => obj.chatSelectModel }, metadata: _metadata }, null, _instanceExtraInitializers);
406
+ __esDecorate(this, null, _chatPage_decorators, { kind: "method", name: "chatPage", static: false, private: false, access: { has: obj => "chatPage" in obj, get: obj => obj.chatPage }, metadata: _metadata }, null, _instanceExtraInitializers);
407
+ __esDecorate(this, null, _chatFollow_decorators, { kind: "method", name: "chatFollow", static: false, private: false, access: { has: obj => "chatFollow" in obj, get: obj => obj.chatFollow }, metadata: _metadata }, null, _instanceExtraInitializers);
408
+ __esDecorate(this, null, _chatControl_decorators, { kind: "method", name: "chatControl", static: false, private: false, access: { has: obj => "chatControl" in obj, get: obj => obj.chatControl }, metadata: _metadata }, null, _instanceExtraInitializers);
409
+ __esDecorate(this, null, _chatProjections_decorators, { kind: "method", name: "chatProjections", static: false, private: false, access: { has: obj => "chatProjections" in obj, get: obj => obj.chatProjections }, metadata: _metadata }, null, _instanceExtraInitializers);
410
+ __esDecorate(this, null, _chatPrompt_decorators, { kind: "method", name: "chatPrompt", static: false, private: false, access: { has: obj => "chatPrompt" in obj, get: obj => obj.chatPrompt }, metadata: _metadata }, null, _instanceExtraInitializers);
411
+ __esDecorate(this, null, _chatAttachment_decorators, { kind: "method", name: "chatAttachment", static: false, private: false, access: { has: obj => "chatAttachment" in obj, get: obj => obj.chatAttachment }, metadata: _metadata }, null, _instanceExtraInitializers);
412
+ __esDecorate(this, null, _chatRename_decorators, { kind: "method", name: "chatRename", static: false, private: false, access: { has: obj => "chatRename" in obj, get: obj => obj.chatRename }, metadata: _metadata }, null, _instanceExtraInitializers);
413
+ __esDecorate(this, null, _chatCancel_decorators, { kind: "method", name: "chatCancel", static: false, private: false, access: { has: obj => "chatCancel" in obj, get: obj => obj.chatCancel }, metadata: _metadata }, null, _instanceExtraInitializers);
414
+ __esDecorate(this, null, _chatUpdateQueue_decorators, { kind: "method", name: "chatUpdateQueue", static: false, private: false, access: { has: obj => "chatUpdateQueue" in obj, get: obj => obj.chatUpdateQueue }, metadata: _metadata }, null, _instanceExtraInitializers);
339
415
  __esDecorate(this, null, _sources_decorators, { kind: "method", name: "sources", static: false, private: false, access: { has: obj => "sources" in obj, get: obj => obj.sources }, metadata: _metadata }, null, _instanceExtraInitializers);
340
416
  __esDecorate(this, null, _pendingApprovals_decorators, { kind: "method", name: "pendingApprovals", static: false, private: false, access: { has: obj => "pendingApprovals" in obj, get: obj => obj.pendingApprovals }, metadata: _metadata }, null, _instanceExtraInitializers);
341
417
  __esDecorate(this, null, _answerApproval_decorators, { kind: "method", name: "answerApproval", static: false, private: false, access: { has: obj => "answerApproval" in obj, get: obj => obj.answerApproval }, metadata: _metadata }, null, _instanceExtraInitializers);
@@ -345,6 +421,9 @@ let QaSurface = (() => {
345
421
  __esDecorate(this, null, _readSourceFile_decorators, { kind: "method", name: "readSourceFile", static: false, private: false, access: { has: obj => "readSourceFile" in obj, get: obj => obj.readSourceFile }, metadata: _metadata }, null, _instanceExtraInitializers);
346
422
  __esDecorate(this, null, _listWorkspaceFiles_decorators, { kind: "method", name: "listWorkspaceFiles", static: false, private: false, access: { has: obj => "listWorkspaceFiles" in obj, get: obj => obj.listWorkspaceFiles }, metadata: _metadata }, null, _instanceExtraInitializers);
347
423
  __esDecorate(this, null, _readWorkspaceFile_decorators, { kind: "method", name: "readWorkspaceFile", static: false, private: false, access: { has: obj => "readWorkspaceFile" in obj, get: obj => obj.readWorkspaceFile }, metadata: _metadata }, null, _instanceExtraInitializers);
424
+ __esDecorate(this, null, _readWorkspaceFileChunk_decorators, { kind: "method", name: "readWorkspaceFileChunk", static: false, private: false, access: { has: obj => "readWorkspaceFileChunk" in obj, get: obj => obj.readWorkspaceFileChunk }, metadata: _metadata }, null, _instanceExtraInitializers);
425
+ __esDecorate(this, null, _documentWorkflowStatus_decorators, { kind: "method", name: "documentWorkflowStatus", static: false, private: false, access: { has: obj => "documentWorkflowStatus" in obj, get: obj => obj.documentWorkflowStatus }, metadata: _metadata }, null, _instanceExtraInitializers);
426
+ __esDecorate(this, null, _approveDocumentWorkflow_decorators, { kind: "method", name: "approveDocumentWorkflow", static: false, private: false, access: { has: obj => "approveDocumentWorkflow" in obj, get: obj => obj.approveDocumentWorkflow }, metadata: _metadata }, null, _instanceExtraInitializers);
348
427
  __esDecorate(this, null, _previewWorkspaceDocument_decorators, { kind: "method", name: "previewWorkspaceDocument", static: false, private: false, access: { has: obj => "previewWorkspaceDocument" in obj, get: obj => obj.previewWorkspaceDocument }, metadata: _metadata }, null, _instanceExtraInitializers);
349
428
  __esDecorate(this, null, _skillsList_decorators, { kind: "method", name: "skillsList", static: false, private: false, access: { has: obj => "skillsList" in obj, get: obj => obj.skillsList }, metadata: _metadata }, null, _instanceExtraInitializers);
350
429
  __esDecorate(this, null, _skillsGet_decorators, { kind: "method", name: "skillsGet", static: false, private: false, access: { has: obj => "skillsGet" in obj, get: obj => obj.skillsGet }, metadata: _metadata }, null, _instanceExtraInitializers);
@@ -407,6 +486,19 @@ let QaSurface = (() => {
407
486
  * opens the admin console never grows one.
408
487
  */
409
488
  qualityStore;
489
+ chatSharingStore;
490
+ chatTransport;
491
+ chatTurnGuard;
492
+ sharing() {
493
+ const accounts = () => {
494
+ const store = this.accountRemotes.resolve(this.getConfig());
495
+ if (store === undefined)
496
+ throw new Error("QA accounts are required for chat sharing.");
497
+ return store;
498
+ };
499
+ accounts();
500
+ return (this.chatSharingStore ??= new QaChatSharingStore(path.join(path.dirname(defaultAccountsFilePath()), "qa-chat-sharing.db"), accounts));
501
+ }
410
502
  constructor(ctx, entry = {}) {
411
503
  super(ctx, "qaSurface", { namespace: "qaSurface" });
412
504
  // Every Config field is volatile, so the reference the Host hands here is
@@ -453,6 +545,7 @@ let QaSurface = (() => {
453
545
  // Deletion is the console's alone: the sidebar's delete stays a
454
546
  // per-browser row, and only an administrator removes the chat itself.
455
547
  sessionFiles: createSessionEraser(),
548
+ ...(this.getConfig().accounts.enabled ? { sharing: this.sharing() } : {}),
456
549
  dropSources: (sessionId) => this.provenance.dropSession(sessionId),
457
550
  // The console writes skills through the same service the owner's editor
458
551
  // uses, so an administrator's save is path-checked, validated and
@@ -472,6 +565,23 @@ let QaSurface = (() => {
472
565
  });
473
566
  this.slashRemotes = createQaSlashRemotes({
474
567
  ctx,
568
+ draftSkills: async (token, target) => {
569
+ this.accountRemotes.resolve(this.getConfig());
570
+ const preview = await this.access.slashDraftSkills(token, target.subroleId, target.adminPreview);
571
+ return {
572
+ skills: preview.skills.map((skill) => ({
573
+ name: skill.name,
574
+ description: skill.description,
575
+ modelInvocable: skill.invocation.modelInvocable,
576
+ ...(skill.whenToUse === undefined
577
+ ? {}
578
+ : { whenToUse: skill.whenToUse }),
579
+ })),
580
+ grantedSkills: preview.policy === undefined
581
+ ? undefined
582
+ : userInvocableSkillNames(preview.policy),
583
+ };
584
+ },
475
585
  getConfig: () => this.getConfig(),
476
586
  logger: this.logger,
477
587
  sessionGrant: (token, sessionId, agent) => this.slashSessionGrant(token, sessionId, agent),
@@ -493,13 +603,32 @@ let QaSurface = (() => {
493
603
  // Legacy account-free sessions retain the dynamic catalog behavior;
494
604
  // role-managed sessions authorize its known entries through the frozen
495
605
  // capability policy instead.
496
- (agent) => this.tools?.activeToolNames(agent) ?? [], (owner, sessionId, agent) => this.access.policyForSessionOwner(owner, sessionId, agent), () => this.tools?.catalogToolNames() ?? [], (sessionId) => this.access.modelPolicyFor(sessionId));
606
+ (agent) => this.tools?.activeToolNames(agent) ?? [], (owner, sessionId, agent) => this.access.policyForSessionOwner(owner, sessionId, agent), () => this.tools?.catalogToolNames() ?? [], (sessionId) => this.access.modelPolicyFor(sessionId),
607
+ // The integration API's own attestation writes the principal here, because
608
+ // that is where the caller's account has just been matched against the
609
+ // ownership record. The browser's `secureSession` remote keeps its own
610
+ // write: there the compared identity is the token's.
611
+ this.integrationPrincipals);
497
612
  this.provenance = new QaProvenanceHost(ctx, () => this.getConfig(),
498
613
  // Sharded per chat and bounded by the resolved retention policy: the
499
614
  // turn path must never rewrite history it did not touch.
500
615
  new FileQaProvenanceSnapshotStore(defaultQaProvenanceDirectoryPath(), () => this.getConfig().sources.retention, defaultLegacyProvenanceFilePath()), (error) => this.logger.error("sources.persistence-failed", {
501
616
  message: error instanceof Error ? error.message : String(error),
502
617
  }));
618
+ this.chatTransport = new QaChatTransport(ctx, () => this.sharing(), (token, id) => this.secureSession(token, id), (userId, id) => this.access.participantPolicy(userId, id));
619
+ this.chatTurnGuard = new QaChatTurnGuard(ctx, () => this.sharing(), (userId, id) => this.access.participantPolicy(userId, id), () => this.getConfig().accounts.enabled);
620
+ ctx.effect(() => () => {
621
+ this.chatTurnGuard.dispose();
622
+ this.chatSharingStore?.storage.close();
623
+ }, "dsh-qa-surface.chat-sharing");
624
+ ctx.inject(["typertGateway", "connection"], () => {
625
+ const dispose = installQaNativeFence(ctx, () => this.getConfig().accounts.enabled);
626
+ const disposeUploads = installQaChatUploads(ctx, () => this.sharing(), (token, id) => this.secureSession(token, id));
627
+ return async () => {
628
+ dispose();
629
+ await disposeUploads();
630
+ };
631
+ });
503
632
  this.integration = new QaIntegrationService({
504
633
  getConfig: () => this.getConfig(),
505
634
  accounts: () => this.accountRemotes.resolve(this.getConfig()),
@@ -706,6 +835,8 @@ let QaSurface = (() => {
706
835
  }
707
836
  /** Resolve only a directly QA-owned root session; delegated children fail closed. */
708
837
  principalForSession(sessionId) {
838
+ if (this.chatTurnGuard.collaborative(sessionId))
839
+ return undefined;
709
840
  const accounts = this.accountRemotes.resolve(this.getConfig());
710
841
  if (accounts === undefined)
711
842
  return undefined;
@@ -960,6 +1091,20 @@ let QaSurface = (() => {
960
1091
  throw new Error(qaAttestationFailureMessage("Unable to create a QA session.", error), { cause: error });
961
1092
  }
962
1093
  }
1094
+ /** Create an independently admitted ordinary branch of the caller's own chat. */
1095
+ async forkSession(token, sourceId, answerSeq) {
1096
+ return this.accountRemotes.runAsync(() => forkQaSession({
1097
+ ctx: this.ctx,
1098
+ config: this.getConfig(),
1099
+ accounts: this.accountRemotes.resolve(this.getConfig()),
1100
+ access: this.access,
1101
+ admission: this.admission,
1102
+ principals: this.integrationPrincipals,
1103
+ provenance: this.provenance,
1104
+ sessionFiles: createSessionEraser(),
1105
+ logger: this.logger,
1106
+ }, token, sourceId, answerSeq), sourceId);
1107
+ }
963
1108
  /** The selector model for the signed-in user; admin grants are irrelevant. */
964
1109
  accessCurrent(token) {
965
1110
  return this.accountRemotes.run(() => this.access.current(token));
@@ -1120,7 +1265,13 @@ let QaSurface = (() => {
1120
1265
  * stays what it always was, a per-browser row.
1121
1266
  */
1122
1267
  adminDeleteConversation(token, conversationId) {
1123
- return this.accountRemotes.runAsync(() => this.admin.deleteConversation(token, conversationId));
1268
+ return this.accountRemotes.runAsync(async () => {
1269
+ const result = await this.admin.deleteConversation(token, conversationId);
1270
+ if (this.getConfig().accounts.enabled)
1271
+ for (const id of result.sessions)
1272
+ this.sharing().dropSession(id);
1273
+ return result;
1274
+ });
1124
1275
  }
1125
1276
  adminFeedback(token, query, cursor, limit) {
1126
1277
  return this.accountRemotes.runAsync(() => this.admin.feedback(token, query, cursor ?? undefined, limit ?? undefined));
@@ -1158,16 +1309,46 @@ let QaSurface = (() => {
1158
1309
  /** Pin and attest the effective policy. The browser supplies identity only. */
1159
1310
  async secureSession(token, sessionId) {
1160
1311
  try {
1312
+ const accountsForSharing = this.accountRemotes.resolve(this.getConfig());
1313
+ const actor = accountsForSharing?.currentUser(token);
1314
+ const actualOwnerId = accountsForSharing?.ownerIdOf(sessionId);
1315
+ if (actualOwnerId !== undefined && actor?.id !== actualOwnerId) {
1316
+ let shared;
1317
+ try {
1318
+ shared = this.sharing().access(token, sessionId);
1319
+ }
1320
+ catch (error) {
1321
+ if (actor?.role !== "admin" ||
1322
+ !this.getConfig().accounts.showOtherUsersChats)
1323
+ throw error;
1324
+ }
1325
+ if (shared !== undefined) {
1326
+ const proof = await this.admission.secureSessionForUser(shared.ownerId, sessionId);
1327
+ this.sharing().revalidate(token, shared);
1328
+ return { ...proof, chatAccess: shared };
1329
+ }
1330
+ }
1161
1331
  const principal = this.principalForToken(token);
1162
1332
  const proof = await this.admission.secureSession(token, sessionId);
1163
1333
  const accounts = this.accountRemotes.resolve(this.getConfig());
1164
1334
  const ownerId = accounts?.ownerIdOf(sessionId);
1165
1335
  // Admin cross-user viewing is intentionally not credential delegation.
1166
- this.integrationPrincipals.attest(sessionId, principal?.userId, ownerId);
1167
- return proof;
1336
+ if (principal?.userId === ownerId)
1337
+ this.integrationPrincipals.attest(sessionId, principal?.userId, ownerId);
1338
+ const session = this.ctx.sessions.get(SessionId(sessionId));
1339
+ const chatAccess = actualOwnerId === actor?.id && actor !== undefined
1340
+ ? this.sharing().access(token, sessionId)
1341
+ : undefined;
1342
+ return {
1343
+ ...proof,
1344
+ ...(chatAccess === undefined ? {} : { chatAccess }),
1345
+ ...(session?.header.isSeeded === true &&
1346
+ session.header.origin !== "subagent"
1347
+ ? { inheritedThroughSeq: Number(session.inheritedEventCount) - 1 }
1348
+ : {}),
1349
+ };
1168
1350
  }
1169
1351
  catch (error) {
1170
- this.integrationPrincipals.attest(sessionId, undefined, undefined);
1171
1352
  // The carrier empties error.details, so the coarse reason rides the
1172
1353
  // wire message for the browser console; the specific mismatch facts
1173
1354
  // stay in this log only.
@@ -1184,9 +1365,110 @@ let QaSurface = (() => {
1184
1365
  });
1185
1366
  }
1186
1367
  }
1368
+ chatVisible(token) {
1369
+ return this.sharing().visible(token);
1370
+ }
1371
+ chatAccess(token, sessionId) {
1372
+ return this.sharing().access(token, sessionId);
1373
+ }
1374
+ chatGrants(token, sessionId) {
1375
+ return this.sharing().grants(token, sessionId);
1376
+ }
1377
+ chatSetGrant(token, sessionId, email, mode) {
1378
+ if (this.access.isDelegatedChild(sessionId) ||
1379
+ this.getConfig().session.policy === "fixed")
1380
+ throw new Error("Only an ordinary account-owned chat may be shared.");
1381
+ const value = this.sharing().set(token, sessionId, email, mode);
1382
+ this.chatTurnGuard.revoke(sessionId);
1383
+ return value;
1384
+ }
1385
+ chatAuthors(token, sessionId) {
1386
+ return this.sharing().authors(token, sessionId);
1387
+ }
1388
+ async chatAudit(token, sessionId, full) {
1389
+ this.requireChatOwner(token, sessionId);
1390
+ await this.secureSession(token, sessionId);
1391
+ this.requireChatOwner(token, sessionId);
1392
+ const audit = this.ctx.get("sessionAudit");
1393
+ if (audit === undefined)
1394
+ throw new Error("Session audit is unavailable.");
1395
+ const value = full
1396
+ ? await audit.audit(sessionId)
1397
+ : audit.summary(sessionId);
1398
+ this.requireChatOwner(token, sessionId);
1399
+ return value;
1400
+ }
1401
+ async chatAttachmentPath(token, sessionId, attachmentId) {
1402
+ const finish = await this.admitChatRead(token, sessionId);
1403
+ const value = qaChatAttachmentPath(this.ctx, sessionId, attachmentId);
1404
+ finish();
1405
+ return value;
1406
+ }
1407
+ async chatList(token, signal) {
1408
+ return (await this.chatTransport.list(token, signal));
1409
+ }
1410
+ async chatSearch(token, request, signal) {
1411
+ return (await this.chatTransport.search(token, request, signal));
1412
+ }
1413
+ chatSelectModel(token, request) {
1414
+ this.requireChatOwner(token, String(request.sessionId));
1415
+ if (this.getConfig().lockdown.enforceFixedModel)
1416
+ throw new Error("The chat model is fixed by its policy.");
1417
+ return this.chatTransport.selectModel(token, request);
1418
+ }
1419
+ async chatPage(token, request, signal) {
1420
+ return (await this.chatTransport.page(token, request, signal));
1421
+ }
1422
+ async *chatFollow(token, request, signal) {
1423
+ for await (const frame of this.chatTransport.follow(token, request, signal))
1424
+ yield frame;
1425
+ }
1426
+ async *chatControl(token, signal) {
1427
+ for await (const frame of this.chatTransport.control(token, signal))
1428
+ yield frame;
1429
+ }
1430
+ async chatProjections(token, sessionId, signal) {
1431
+ return (await this.chatTransport.projections(token, sessionId, signal));
1432
+ }
1433
+ chatPrompt(token, request, signal) {
1434
+ return this.chatTransport.prompt(token, request, signal);
1435
+ }
1436
+ chatAttachment(token, request) {
1437
+ return this.chatTransport.attachment(token, request);
1438
+ }
1439
+ chatRename(token, request) {
1440
+ return this.chatTransport.rename(token, request);
1441
+ }
1442
+ chatCancel(token, sessionId) {
1443
+ return this.chatTransport.cancel(token, sessionId);
1444
+ }
1445
+ chatUpdateQueue(token, request) {
1446
+ return this.chatTransport.updateQueue(token, request);
1447
+ }
1448
+ async admitChatRead(token, sessionId, filePath) {
1449
+ if (!this.getConfig().accounts.enabled) {
1450
+ await this.admission.secureSession(token, sessionId);
1451
+ return () => undefined;
1452
+ }
1453
+ const access = this.sharing().access(token, sessionId);
1454
+ await this.secureSession(token, sessionId);
1455
+ this.sharing().revalidate(token, access);
1456
+ if (filePath !== undefined &&
1457
+ access.mode !== "owner" &&
1458
+ !qaChatPublishedFile(this.ctx, sessionId, filePath, (id, path) => this.provenance.sourceAllowed(id, path)))
1459
+ throw new Error("This file has not been shared in the chat.");
1460
+ return () => {
1461
+ this.sharing().revalidate(token, access);
1462
+ };
1463
+ }
1464
+ requireChatOwner(token, sessionId) {
1465
+ if (this.getConfig().accounts.enabled)
1466
+ this.sharing().owner(token, sessionId);
1467
+ }
1187
1468
  /** Return canonical Host snapshots from plugin-owned durable provenance. */
1188
1469
  async sources(token, sessionId) {
1189
- await this.admission.secureSession(token, sessionId);
1470
+ const finish = await this.admitChatRead(token, sessionId);
1471
+ finish();
1190
1472
  return this.provenance.bundles(sessionId);
1191
1473
  }
1192
1474
  /**
@@ -1194,7 +1476,10 @@ let QaSurface = (() => {
1194
1476
  * deployment with blocked approvals answers with an empty list.
1195
1477
  */
1196
1478
  async pendingApprovals(token, sessionId) {
1197
- await this.admission.secureSession(token, sessionId);
1479
+ await this.secureSession(token, sessionId);
1480
+ if (this.getConfig().accounts.enabled &&
1481
+ this.sharing().access(token, sessionId).mode !== "owner")
1482
+ return [];
1198
1483
  return this.approvals.list(sessionId);
1199
1484
  }
1200
1485
  /**
@@ -1203,7 +1488,9 @@ let QaSurface = (() => {
1203
1488
  * the agent went away) is refused with `false`.
1204
1489
  */
1205
1490
  async answerApproval(token, sessionId, requestId, decision) {
1491
+ this.requireChatOwner(token, sessionId);
1206
1492
  await this.admission.secureSession(token, sessionId);
1493
+ this.requireChatOwner(token, sessionId);
1207
1494
  return this.approvals.answer(sessionId, requestId, decision);
1208
1495
  }
1209
1496
  /**
@@ -1211,7 +1498,10 @@ let QaSurface = (() => {
1211
1498
  * deployment with unsupported questions answers with an empty list.
1212
1499
  */
1213
1500
  async pendingQuestions(token, sessionId) {
1214
- await this.admission.secureSession(token, sessionId);
1501
+ await this.secureSession(token, sessionId);
1502
+ if (this.getConfig().accounts.enabled &&
1503
+ this.sharing().access(token, sessionId).mode !== "owner")
1504
+ return [];
1215
1505
  return this.userQuestions.list(sessionId);
1216
1506
  }
1217
1507
  /**
@@ -1220,12 +1510,16 @@ let QaSurface = (() => {
1220
1510
  * a skip.
1221
1511
  */
1222
1512
  async answerQuestion(token, sessionId, requestId, answers) {
1513
+ this.requireChatOwner(token, sessionId);
1223
1514
  await this.admission.secureSession(token, sessionId);
1515
+ this.requireChatOwner(token, sessionId);
1224
1516
  return this.userQuestions.answer(sessionId, requestId, answers);
1225
1517
  }
1226
1518
  /** Close a parked question request without answering it. */
1227
1519
  async cancelQuestion(token, sessionId, requestId) {
1520
+ this.requireChatOwner(token, sessionId);
1228
1521
  await this.admission.secureSession(token, sessionId);
1522
+ this.requireChatOwner(token, sessionId);
1229
1523
  return this.userQuestions.cancel(sessionId, requestId);
1230
1524
  }
1231
1525
  /**
@@ -1238,7 +1532,7 @@ let QaSurface = (() => {
1238
1532
  * the per-account scratch directory — could never be opened in the panel.
1239
1533
  */
1240
1534
  async readSourceFile(token, sessionId, sourcePath) {
1241
- await this.admission.secureSession(token, sessionId);
1535
+ const finish = await this.admitChatRead(token, sessionId, sourcePath);
1242
1536
  const config = this.getConfig();
1243
1537
  if (!config.sources.filePreview.enabled) {
1244
1538
  throw sourcePreviewRefusal("unavailable");
@@ -1249,7 +1543,7 @@ let QaSurface = (() => {
1249
1543
  throw sourcePreviewRefusal("unavailable");
1250
1544
  const attachmentRoot = this.admission.attachmentRoot();
1251
1545
  try {
1252
- return await readSourceFilePreview({
1546
+ const value = await readSourceFilePreview({
1253
1547
  sourcePath,
1254
1548
  cwd,
1255
1549
  isEvidence: (canonicalPath) => this.provenance.sourceAllowed(sessionId, canonicalPath),
@@ -1257,7 +1551,32 @@ let QaSurface = (() => {
1257
1551
  ...(attachmentRoot === undefined ? {} : { attachmentRoot }),
1258
1552
  maxBytes: config.sources.filePreview.maxBytes,
1259
1553
  maxMarkdownRenderBytes: config.sources.filePreview.maxMarkdownRenderBytes,
1554
+ }).catch(async (error) => {
1555
+ // Only a format refusal follows successful evidence and root checks.
1556
+ if (!(error instanceof QaSourcePreviewError) ||
1557
+ error.reason !== "unsupported")
1558
+ throw error;
1559
+ const document = await previewSourceDocument({
1560
+ filePath: sourcePath,
1561
+ cwd,
1562
+ sessionId,
1563
+ sharedReadOnlyRoots: config.lockdown.sharedReadOnlyRoots,
1564
+ ...(attachmentRoot === undefined ? {} : { attachmentRoot }),
1565
+ documents: () => this.ctx.get("documents"),
1566
+ maxBytes: config.sources.filePreview.maxBytes,
1567
+ });
1568
+ return {
1569
+ path: sourcePath,
1570
+ content: "",
1571
+ size: document.bytes,
1572
+ truncated: false,
1573
+ markdown: false,
1574
+ renderableMarkdown: false,
1575
+ document,
1576
+ };
1260
1577
  });
1578
+ finish();
1579
+ return value;
1261
1580
  }
1262
1581
  catch (error) {
1263
1582
  this.logger.debug("source.preview-refused", {
@@ -1276,6 +1595,7 @@ let QaSurface = (() => {
1276
1595
  * `readWorkspaceFile` opens one entry of such a listing.
1277
1596
  */
1278
1597
  async listWorkspaceFiles(token, sessionId, path) {
1598
+ this.requireChatOwner(token, sessionId);
1279
1599
  await this.admission.secureSession(token, sessionId);
1280
1600
  const { config, cwd } = await this.browseContext(sessionId);
1281
1601
  try {
@@ -1298,11 +1618,11 @@ let QaSurface = (() => {
1298
1618
  * reopening a cited source.
1299
1619
  */
1300
1620
  async readWorkspaceFile(token, sessionId, path) {
1301
- await this.admission.secureSession(token, sessionId);
1621
+ const finish = await this.admitChatRead(token, sessionId, path);
1302
1622
  const { config, cwd } = await this.browseContext(sessionId);
1303
1623
  const attachmentRoot = this.admission.attachmentRoot();
1304
1624
  try {
1305
- return await readWorkspaceFile({
1625
+ const value = await readWorkspaceFile({
1306
1626
  filePath: path ?? "",
1307
1627
  cwd,
1308
1628
  sharedReadOnlyRoots: config.lockdown.sharedReadOnlyRoots,
@@ -1310,11 +1630,77 @@ let QaSurface = (() => {
1310
1630
  maxBytes: config.sources.filePreview.maxBytes,
1311
1631
  maxMarkdownRenderBytes: config.sources.filePreview.maxMarkdownRenderBytes,
1312
1632
  });
1633
+ finish();
1634
+ return value;
1313
1635
  }
1314
1636
  catch (error) {
1315
1637
  throw this.browseRefusal("workspace.read-refused", sessionId, error);
1316
1638
  }
1317
1639
  }
1640
+ /** Download one bounded chunk after revalidating this chat's ownership. */
1641
+ async readWorkspaceFileChunk(token, sessionId, path, offset, version) {
1642
+ const finish = await this.admitChatRead(token, sessionId, path);
1643
+ const { config, cwd } = await this.browseContext(sessionId);
1644
+ const attachmentRoot = this.admission.attachmentRoot();
1645
+ try {
1646
+ const value = await readWorkspaceFileChunk({
1647
+ filePath: path ?? "",
1648
+ cwd,
1649
+ sharedReadOnlyRoots: config.lockdown.sharedReadOnlyRoots,
1650
+ ...(attachmentRoot === undefined ? {} : { attachmentRoot }),
1651
+ offset,
1652
+ version,
1653
+ });
1654
+ finish();
1655
+ return value;
1656
+ }
1657
+ catch (error) {
1658
+ throw this.browseRefusal("workspace.download-refused", sessionId, error);
1659
+ }
1660
+ }
1661
+ async documentWorkflowStatus(token, sessionId, workflowId) {
1662
+ const finish = await this.admitChatRead(token, sessionId);
1663
+ const { cwd } = await this.browseContext(sessionId);
1664
+ const workflow = this.ctx.get("documents")
1665
+ ?.workflow;
1666
+ if (workflow === undefined)
1667
+ throw new Error("Document workflow is unavailable.");
1668
+ const view = await workflow.read({ workspaceRoot: cwd, sessionId }, workflowId);
1669
+ finish();
1670
+ return {
1671
+ id: view.id,
1672
+ revision: view.revision,
1673
+ status: view.status,
1674
+ sha256: view.draft?.sha256 ?? null,
1675
+ blockers: view.blockers,
1676
+ };
1677
+ }
1678
+ /** Browser-authenticated human consent; intentionally absent from the agent's tool registry. */
1679
+ async approveDocumentWorkflow(token, sessionId, workflowId, revision, sha256) {
1680
+ this.requireChatOwner(token, sessionId);
1681
+ await this.admission.secureSession(token, sessionId);
1682
+ this.requireChatOwner(token, sessionId);
1683
+ const caller = this.principalForToken(token);
1684
+ const ownerId = this.accountRemotes.resolve(this.getConfig())?.ownerIdOf(sessionId) ??
1685
+ (this.getConfig().accounts.enabled
1686
+ ? undefined
1687
+ : this.principalForSession(sessionId)?.userId);
1688
+ if (caller === undefined || ownerId !== caller.userId)
1689
+ throw new Error("Document approval requires the chat owner's account.");
1690
+ const { cwd } = await this.browseContext(sessionId);
1691
+ const workflow = this.ctx.get("documents")
1692
+ ?.workflow;
1693
+ if (workflow === undefined)
1694
+ throw new Error("Document workflow is unavailable.");
1695
+ const view = await workflow.approve({ workspaceRoot: cwd, sessionId }, workflowId, revision, sha256, caller.userId);
1696
+ return {
1697
+ id: view.id,
1698
+ revision: view.revision,
1699
+ status: view.status,
1700
+ sha256: view.draft?.sha256 ?? null,
1701
+ blockers: view.blockers,
1702
+ };
1703
+ }
1318
1704
  /**
1319
1705
  * Render one Word document of the chat's workspace as a PDF for the panel.
1320
1706
  *
@@ -1326,11 +1712,11 @@ let QaSurface = (() => {
1326
1712
  * reaches an unfenced byte route.
1327
1713
  */
1328
1714
  async previewWorkspaceDocument(token, sessionId, path) {
1329
- await this.admission.secureSession(token, sessionId);
1715
+ const finish = await this.admitChatRead(token, sessionId, path);
1330
1716
  const { config, cwd } = await this.browseContext(sessionId);
1331
1717
  const attachmentRoot = this.admission.attachmentRoot();
1332
1718
  try {
1333
- return await previewConvertibleDocument({
1719
+ const value = await previewConvertibleDocument({
1334
1720
  filePath: path ?? "",
1335
1721
  cwd,
1336
1722
  sharedReadOnlyRoots: config.lockdown.sharedReadOnlyRoots,
@@ -1339,6 +1725,8 @@ let QaSurface = (() => {
1339
1725
  sessionId,
1340
1726
  maxBytes: config.sources.filePreview.maxBytes,
1341
1727
  });
1728
+ finish();
1729
+ return value;
1342
1730
  }
1343
1731
  catch (error) {
1344
1732
  throw this.browseRefusal("workspace.preview-refused", sessionId, error);