@yadsh/dsh-qa-surface 0.8.0 → 0.10.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 (242) hide show
  1. package/README.md +142 -4
  2. package/compatibility.json +5 -0
  3. package/lib/access/capability-catalog.js +32 -3
  4. package/lib/access/capability-catalog.js.map +1 -1
  5. package/lib/access/service.js +45 -17
  6. package/lib/access/service.js.map +1 -1
  7. package/lib/accounts/errors.js.map +1 -1
  8. package/lib/accounts/store.js +14 -0
  9. package/lib/accounts/store.js.map +1 -1
  10. package/lib/admin/permissions.js +4 -0
  11. package/lib/admin/permissions.js.map +1 -1
  12. package/lib/admin/quality-store.js +71 -0
  13. package/lib/admin/quality-store.js.map +1 -1
  14. package/lib/admin/service.js +113 -8
  15. package/lib/admin/service.js.map +1 -1
  16. package/lib/admin/session-log.js +66 -5
  17. package/lib/admin/session-log.js.map +1 -1
  18. package/lib/client/QaSessionController.js +371 -37
  19. package/lib/client/QaSessionController.js.map +1 -1
  20. package/lib/client/QaSurface.js +48 -8
  21. package/lib/client/QaSurface.js.map +1 -1
  22. package/lib/client/QaSurfaceGuard.js +12 -5
  23. package/lib/client/QaSurfaceGuard.js.map +1 -1
  24. package/lib/client/QaTranscriptAdapter.js +36 -0
  25. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  26. package/lib/client/admin/QaAdmin.js +14 -2
  27. package/lib/client/admin/QaAdmin.js.map +1 -1
  28. package/lib/client/admin/pages/Conversations.js +33 -7
  29. package/lib/client/admin/pages/Conversations.js.map +1 -1
  30. package/lib/client/admin/pages/Users.js +9 -2
  31. package/lib/client/admin/pages/Users.js.map +1 -1
  32. package/lib/client/admin/shared.js +14 -1
  33. package/lib/client/admin/shared.js.map +1 -1
  34. package/lib/client/admin/styles.js +2 -0
  35. package/lib/client/admin/styles.js.map +1 -1
  36. package/lib/client/audit/QaAuditDialog.js +74 -0
  37. package/lib/client/audit/QaAuditDialog.js.map +1 -0
  38. package/lib/client/audit/QaAuditRowBadge.js +17 -0
  39. package/lib/client/audit/QaAuditRowBadge.js.map +1 -0
  40. package/lib/client/audit/controller.js +39 -0
  41. package/lib/client/audit/controller.js.map +1 -0
  42. package/lib/client/audit/types.js +36 -0
  43. package/lib/client/audit/types.js.map +1 -0
  44. package/lib/client/audit/use-chat-audits.js +139 -0
  45. package/lib/client/audit/use-chat-audits.js.map +1 -0
  46. package/lib/client/base64.js +22 -1
  47. package/lib/client/base64.js.map +1 -1
  48. package/lib/client/components/QaAgentsDrawer.js +9 -6
  49. package/lib/client/components/QaAgentsDrawer.js.map +1 -1
  50. package/lib/client/components/QaApproval.js +1 -1
  51. package/lib/client/components/QaApproval.js.map +1 -1
  52. package/lib/client/components/QaChangelog.js +72 -0
  53. package/lib/client/components/QaChangelog.js.map +1 -1
  54. package/lib/client/components/QaComposer.js +63 -3
  55. package/lib/client/components/QaComposer.js.map +1 -1
  56. package/lib/client/components/QaFilesPanel.js +17 -11
  57. package/lib/client/components/QaFilesPanel.js.map +1 -1
  58. package/lib/client/components/QaHeader.js +3 -11
  59. package/lib/client/components/QaHeader.js.map +1 -1
  60. package/lib/client/components/QaMessage.js +16 -0
  61. package/lib/client/components/QaMessage.js.map +1 -1
  62. package/lib/client/components/QaModal.js.map +1 -1
  63. package/lib/client/components/QaQuestions.js +5 -5
  64. package/lib/client/components/QaQuestions.js.map +1 -1
  65. package/lib/client/components/QaSidebar.js +22 -3
  66. package/lib/client/components/QaSidebar.js.map +1 -1
  67. package/lib/client/components/QaWidthHandle.js +111 -5
  68. package/lib/client/components/QaWidthHandle.js.map +1 -1
  69. package/lib/client/components/QaWorkspaceBrowser.js +231 -0
  70. package/lib/client/components/QaWorkspaceBrowser.js.map +1 -0
  71. package/lib/client/index.js +127 -51
  72. package/lib/client/index.js.map +1 -1
  73. package/lib/client/kiosk.js +51 -0
  74. package/lib/client/kiosk.js.map +1 -0
  75. package/lib/client/markdown/blocks.js +122 -7
  76. package/lib/client/markdown/blocks.js.map +1 -1
  77. package/lib/client/markdown/inline.js +108 -12
  78. package/lib/client/markdown/inline.js.map +1 -1
  79. package/lib/client/markdown/katex-css.js +12 -0
  80. package/lib/client/markdown/katex-css.js.map +1 -0
  81. package/lib/client/markdown/math.js +84 -0
  82. package/lib/client/markdown/math.js.map +1 -0
  83. package/lib/client/markdown/render.js +74 -5
  84. package/lib/client/markdown/render.js.map +1 -1
  85. package/lib/client/project-session-state.js +15 -2
  86. package/lib/client/project-session-state.js.map +1 -1
  87. package/lib/client/prompt-content.js +26 -0
  88. package/lib/client/prompt-content.js.map +1 -1
  89. package/lib/client/settings/card.js +2 -2
  90. package/lib/client/settings/card.js.map +1 -1
  91. package/lib/client/settings/sections/lockdown.js +1 -6
  92. package/lib/client/settings/sections/lockdown.js.map +1 -1
  93. package/lib/client/settings/sections/notes.js +46 -0
  94. package/lib/client/settings/sections/notes.js.map +1 -0
  95. package/lib/client/settings/sections/slash.js +57 -0
  96. package/lib/client/settings/sections/slash.js.map +1 -0
  97. package/lib/client/settings/sections/sources.js +4 -1
  98. package/lib/client/settings/sections/sources.js.map +1 -1
  99. package/lib/client/settings/sections/status.js +9 -1
  100. package/lib/client/settings/sections/status.js.map +1 -1
  101. package/lib/client/settings/sections.js +2 -0
  102. package/lib/client/settings/sections.js.map +1 -1
  103. package/lib/client/settlement.js +1 -1
  104. package/lib/client/settlement.js.map +1 -1
  105. package/lib/client/slash/SlashPalette.js +48 -0
  106. package/lib/client/slash/SlashPalette.js.map +1 -0
  107. package/lib/client/slash/copy.js +54 -0
  108. package/lib/client/slash/copy.js.map +1 -0
  109. package/lib/client/slash/slash-router.js +49 -0
  110. package/lib/client/slash/slash-router.js.map +1 -0
  111. package/lib/client/slash/useSlashNavigation.js +95 -0
  112. package/lib/client/slash/useSlashNavigation.js.map +1 -0
  113. package/lib/client/source-preview.js +3 -0
  114. package/lib/client/source-preview.js.map +1 -1
  115. package/lib/client/styles.js +145 -16
  116. package/lib/client/styles.js.map +1 -1
  117. package/lib/client/types.js +11 -0
  118. package/lib/client/types.js.map +1 -1
  119. package/lib/client.js +33548 -1876
  120. package/lib/client.js.map +1 -1
  121. package/lib/config-resolvers/basics.js +11 -2
  122. package/lib/config-resolvers/basics.js.map +1 -1
  123. package/lib/config-resolvers/defaults.js +32 -0
  124. package/lib/config-resolvers/defaults.js.map +1 -1
  125. package/lib/config-resolvers/lockdown.js +8 -2
  126. package/lib/config-resolvers/lockdown.js.map +1 -1
  127. package/lib/config-resolvers/notes.js +24 -0
  128. package/lib/config-resolvers/notes.js.map +1 -0
  129. package/lib/config-resolvers/slash-commands.js +60 -0
  130. package/lib/config-resolvers/slash-commands.js.map +1 -0
  131. package/lib/config-resolvers/sources.js +4 -0
  132. package/lib/config-resolvers/sources.js.map +1 -1
  133. package/lib/config.js +96 -2
  134. package/lib/config.js.map +1 -1
  135. package/lib/index.js +309 -11
  136. package/lib/index.js.map +1 -1
  137. package/lib/personal-skills/service.js +16 -3
  138. package/lib/personal-skills/service.js.map +1 -1
  139. package/lib/prompt-notes.js +45 -6
  140. package/lib/prompt-notes.js.map +1 -1
  141. package/lib/provenance/document-preview.js +51 -0
  142. package/lib/provenance/document-preview.js.map +1 -0
  143. package/lib/provenance/file-preview.js +191 -19
  144. package/lib/provenance/file-preview.js.map +1 -1
  145. package/lib/provenance/host-store.js +18 -1
  146. package/lib/provenance/host-store.js.map +1 -1
  147. package/lib/qa-tools/catalog.js +7 -1
  148. package/lib/qa-tools/catalog.js.map +1 -1
  149. package/lib/qa-tools/file-delete-gate.js +60 -0
  150. package/lib/qa-tools/file-delete-gate.js.map +1 -0
  151. package/lib/qa-tools/file-delete.js +156 -0
  152. package/lib/qa-tools/file-delete.js.map +1 -0
  153. package/lib/questions.js +90 -43
  154. package/lib/questions.js.map +1 -1
  155. package/lib/resolve-config.js +7 -0
  156. package/lib/resolve-config.js.map +1 -1
  157. package/lib/secure-session.js +24 -0
  158. package/lib/secure-session.js.map +1 -1
  159. package/lib/shared/documents.js +22 -0
  160. package/lib/shared/documents.js.map +1 -0
  161. package/lib/slash/catalog.js +77 -0
  162. package/lib/slash/catalog.js.map +1 -0
  163. package/lib/slash/matcher.js +100 -0
  164. package/lib/slash/matcher.js.map +1 -0
  165. package/lib/slash/parser.js +79 -0
  166. package/lib/slash/parser.js.map +1 -0
  167. package/lib/slash/policy.js +72 -0
  168. package/lib/slash/policy.js.map +1 -0
  169. package/lib/slash/remotes.js +272 -0
  170. package/lib/slash/remotes.js.map +1 -0
  171. package/lib/typert.host.js +544 -56
  172. package/lib/typert.remote-client.d.ts +13 -1
  173. package/lib/typert.remote-client.js +435 -53
  174. package/lib/types/access/capability-catalog.d.ts +28 -1
  175. package/lib/types/access/service.d.ts +33 -4
  176. package/lib/types/accounts/errors.d.ts +7 -1
  177. package/lib/types/accounts/store.d.ts +12 -0
  178. package/lib/types/admin/quality-store.d.ts +18 -0
  179. package/lib/types/admin/service.d.ts +34 -2
  180. package/lib/types/admin/session-log.d.ts +65 -1
  181. package/lib/types/client/QaSessionController.d.ts +84 -2
  182. package/lib/types/client/QaSurface.d.ts +14 -1
  183. package/lib/types/client/admin/pages/Conversations.d.ts +4 -0
  184. package/lib/types/client/admin/shared.d.ts +2 -0
  185. package/lib/types/client/audit/QaAuditDialog.d.ts +21 -0
  186. package/lib/types/client/audit/QaAuditRowBadge.d.ts +18 -0
  187. package/lib/types/client/audit/controller.d.ts +27 -0
  188. package/lib/types/client/audit/types.d.ts +72 -0
  189. package/lib/types/client/audit/use-chat-audits.d.ts +20 -0
  190. package/lib/types/client/base64.d.ts +13 -1
  191. package/lib/types/client/components/QaAgentsDrawer.d.ts +2 -1
  192. package/lib/types/client/components/QaComposer.d.ts +12 -2
  193. package/lib/types/client/components/QaFilesPanel.d.ts +16 -4
  194. package/lib/types/client/components/QaHeader.d.ts +9 -3
  195. package/lib/types/client/components/QaModal.d.ts +4 -3
  196. package/lib/types/client/components/QaQuestions.d.ts +7 -0
  197. package/lib/types/client/components/QaSidebar.d.ts +8 -0
  198. package/lib/types/client/components/QaWidthHandle.d.ts +48 -2
  199. package/lib/types/client/components/QaWorkspaceBrowser.d.ts +15 -0
  200. package/lib/types/client/index.d.ts +1 -1
  201. package/lib/types/client/kiosk.d.ts +34 -0
  202. package/lib/types/client/markdown/blocks.d.ts +14 -1
  203. package/lib/types/client/markdown/inline.d.ts +23 -7
  204. package/lib/types/client/markdown/katex-css.d.ts +11 -0
  205. package/lib/types/client/markdown/math.d.ts +23 -0
  206. package/lib/types/client/markdown/render.d.ts +2 -1
  207. package/lib/types/client/project-session-state.d.ts +3 -1
  208. package/lib/types/client/prompt-content.d.ts +9 -1
  209. package/lib/types/client/settings/sections/notes.d.ts +10 -0
  210. package/lib/types/client/settings/sections/slash.d.ts +16 -0
  211. package/lib/types/client/settings/sections.d.ts +2 -0
  212. package/lib/types/client/settlement.d.ts +4 -1
  213. package/lib/types/client/slash/SlashPalette.d.ts +24 -0
  214. package/lib/types/client/slash/copy.d.ts +30 -0
  215. package/lib/types/client/slash/slash-router.d.ts +67 -0
  216. package/lib/types/client/slash/useSlashNavigation.d.ts +47 -0
  217. package/lib/types/client/styles.d.ts +22 -0
  218. package/lib/types/client/types.d.ts +65 -1
  219. package/lib/types/config-resolvers/notes.d.ts +10 -0
  220. package/lib/types/config-resolvers/slash-commands.d.ts +20 -0
  221. package/lib/types/index.d.ts +116 -1
  222. package/lib/types/personal-skills/service.d.ts +5 -0
  223. package/lib/types/prompt-notes.d.ts +9 -0
  224. package/lib/types/provenance/document-preview.d.ts +24 -0
  225. package/lib/types/provenance/file-preview.d.ts +69 -2
  226. package/lib/types/provenance/host-store.d.ts +13 -0
  227. package/lib/types/qa-tools/catalog.d.ts +1 -1
  228. package/lib/types/qa-tools/file-delete-gate.d.ts +42 -0
  229. package/lib/types/qa-tools/file-delete.d.ts +32 -0
  230. package/lib/types/questions.d.ts +8 -0
  231. package/lib/types/shared/documents.d.ts +20 -0
  232. package/lib/types/slash/catalog.d.ts +56 -0
  233. package/lib/types/slash/matcher.d.ts +51 -0
  234. package/lib/types/slash/parser.d.ts +46 -0
  235. package/lib/types/slash/policy.d.ts +40 -0
  236. package/lib/types/slash/remotes.d.ts +35 -0
  237. package/lib/types/types.d.ts +293 -6
  238. package/lib/types/ui-mode.d.ts +18 -0
  239. package/lib/ui-mode.js +22 -0
  240. package/lib/ui-mode.js.map +1 -0
  241. package/package.json +15 -9
  242. package/scripts/attach-workspace-sessions.mjs +472 -0
package/lib/index.js CHANGED
@@ -41,23 +41,27 @@ import { ConfigSchema, resolveConfig } from "./config.js";
41
41
  import { createQaAccountRemotes } from "./account-remotes.js";
42
42
  import { QaAdminService } from "./admin/service.js";
43
43
  import { QaQualityStore } from "./admin/quality-store.js";
44
- import { createSessionLogReader } from "./admin/session-log.js";
44
+ import { createSessionEraser, createSessionLogReader, } from "./admin/session-log.js";
45
45
  import { createQaPersonalSkillRemotes, QaPersonalSkillsHost, } from "./personal-skills/index.js";
46
46
  import { QaApprovalGate } from "./approvals.js";
47
47
  import { QaAttestationError, qaAttestationFailureMessage, } from "./attestation.js";
48
+ import { QaFileDeleteGate } from "./qa-tools/file-delete-gate.js";
48
49
  import { QaQuestionGate } from "./questions.js";
49
50
  import { QaSessionOwnership } from "./session-ownership.js";
50
51
  import { entryRedirectRow } from "./entry-redirect.js";
52
+ import { qaKioskDeployment } from "./ui-mode.js";
51
53
  import { registerQaNavigationRoute } from "./host-route.js";
52
54
  import { makeLaunchTokenSource } from "./launch-token.js";
53
55
  import { QaIntegrationPrincipalBindings } from "./integration-principals.js";
54
56
  import { QaPolicyAdmission } from "./secure-session.js";
55
57
  import { QaAccessService } from "./access/service.js";
58
+ import { createQaSlashRemotes } from "./slash/remotes.js";
56
59
  import { QaPromptNotes } from "./prompt-notes.js";
57
60
  import { QaTools } from "./qa-tools/index.js";
58
61
  import { QaProvenanceHost } from "./provenance/host-store.js";
59
62
  import { defaultLegacyProvenanceFilePath, defaultQaProvenanceDirectoryPath, FileQaProvenanceSnapshotStore, } from "./provenance/snapshot-store.js";
60
- import { readSourceFilePreview, QaSourcePreviewError, } from "./provenance/file-preview.js";
63
+ import { previewConvertibleDocument } from "./provenance/document-preview.js";
64
+ import { listWorkspaceDirectory, readSourceFilePreview, readWorkspaceFile, QaSourcePreviewError, } from "./provenance/file-preview.js";
61
65
  import { existingQaUserWorkspace, prepareQaUserWorkspace, } from "./user-workspace.js";
62
66
  export const name = "qa-surface";
63
67
  export const inject = [
@@ -113,6 +117,7 @@ let QaSurface = (() => {
113
117
  let _adminUpdateUser_decorators;
114
118
  let _adminConversations_decorators;
115
119
  let _adminConversation_decorators;
120
+ let _adminDeleteConversation_decorators;
116
121
  let _adminFeedback_decorators;
117
122
  let _adminRateMessage_decorators;
118
123
  let _adminReviewQueue_decorators;
@@ -128,6 +133,9 @@ let QaSurface = (() => {
128
133
  let _answerQuestion_decorators;
129
134
  let _cancelQuestion_decorators;
130
135
  let _readSourceFile_decorators;
136
+ let _listWorkspaceFiles_decorators;
137
+ let _readWorkspaceFile_decorators;
138
+ let _previewWorkspaceDocument_decorators;
131
139
  let _skillsList_decorators;
132
140
  let _skillsGet_decorators;
133
141
  let _skillsCreate_decorators;
@@ -135,6 +143,8 @@ let QaSurface = (() => {
135
143
  let _skillsRemove_decorators;
136
144
  let _skillsValidate_decorators;
137
145
  let _skillsTools_decorators;
146
+ let _slashCatalog_decorators;
147
+ let _slashExecute_decorators;
138
148
  return class QaSurface extends _classSuper {
139
149
  static {
140
150
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
@@ -164,6 +174,7 @@ let QaSurface = (() => {
164
174
  _adminUpdateUser_decorators = [Remote("adminUpdateUser")];
165
175
  _adminConversations_decorators = [Remote("adminConversations")];
166
176
  _adminConversation_decorators = [Remote("adminConversation")];
177
+ _adminDeleteConversation_decorators = [Remote("adminDeleteConversation")];
167
178
  _adminFeedback_decorators = [Remote("adminFeedback")];
168
179
  _adminRateMessage_decorators = [Remote("adminRateMessage")];
169
180
  _adminReviewQueue_decorators = [Remote("adminReviewQueue")];
@@ -179,6 +190,9 @@ let QaSurface = (() => {
179
190
  _answerQuestion_decorators = [Remote("answerQuestion")];
180
191
  _cancelQuestion_decorators = [Remote("cancelQuestion")];
181
192
  _readSourceFile_decorators = [Remote("readSourceFile")];
193
+ _listWorkspaceFiles_decorators = [Remote("listWorkspaceFiles")];
194
+ _readWorkspaceFile_decorators = [Remote("readWorkspaceFile")];
195
+ _previewWorkspaceDocument_decorators = [Remote("previewWorkspaceDocument")];
182
196
  _skillsList_decorators = [Remote("skillsList")];
183
197
  _skillsGet_decorators = [Remote("skillsGet")];
184
198
  _skillsCreate_decorators = [Remote("skillsCreate")];
@@ -186,6 +200,8 @@ let QaSurface = (() => {
186
200
  _skillsRemove_decorators = [Remote("skillsRemove")];
187
201
  _skillsValidate_decorators = [Remote("skillsValidate")];
188
202
  _skillsTools_decorators = [Remote("skillsTools")];
203
+ _slashCatalog_decorators = [Remote("slashCatalog")];
204
+ _slashExecute_decorators = [Remote("slashExecute")];
189
205
  __esDecorate(this, null, _accountsRegister_decorators, { kind: "method", name: "accountsRegister", static: false, private: false, access: { has: obj => "accountsRegister" in obj, get: obj => obj.accountsRegister }, metadata: _metadata }, null, _instanceExtraInitializers);
190
206
  __esDecorate(this, null, _accountsLogin_decorators, { kind: "method", name: "accountsLogin", static: false, private: false, access: { has: obj => "accountsLogin" in obj, get: obj => obj.accountsLogin }, metadata: _metadata }, null, _instanceExtraInitializers);
191
207
  __esDecorate(this, null, _accountsWhoami_decorators, { kind: "method", name: "accountsWhoami", static: false, private: false, access: { has: obj => "accountsWhoami" in obj, get: obj => obj.accountsWhoami }, metadata: _metadata }, null, _instanceExtraInitializers);
@@ -212,6 +228,7 @@ let QaSurface = (() => {
212
228
  __esDecorate(this, null, _adminUpdateUser_decorators, { kind: "method", name: "adminUpdateUser", static: false, private: false, access: { has: obj => "adminUpdateUser" in obj, get: obj => obj.adminUpdateUser }, metadata: _metadata }, null, _instanceExtraInitializers);
213
229
  __esDecorate(this, null, _adminConversations_decorators, { kind: "method", name: "adminConversations", static: false, private: false, access: { has: obj => "adminConversations" in obj, get: obj => obj.adminConversations }, metadata: _metadata }, null, _instanceExtraInitializers);
214
230
  __esDecorate(this, null, _adminConversation_decorators, { kind: "method", name: "adminConversation", static: false, private: false, access: { has: obj => "adminConversation" in obj, get: obj => obj.adminConversation }, metadata: _metadata }, null, _instanceExtraInitializers);
231
+ __esDecorate(this, null, _adminDeleteConversation_decorators, { kind: "method", name: "adminDeleteConversation", static: false, private: false, access: { has: obj => "adminDeleteConversation" in obj, get: obj => obj.adminDeleteConversation }, metadata: _metadata }, null, _instanceExtraInitializers);
215
232
  __esDecorate(this, null, _adminFeedback_decorators, { kind: "method", name: "adminFeedback", static: false, private: false, access: { has: obj => "adminFeedback" in obj, get: obj => obj.adminFeedback }, metadata: _metadata }, null, _instanceExtraInitializers);
216
233
  __esDecorate(this, null, _adminRateMessage_decorators, { kind: "method", name: "adminRateMessage", static: false, private: false, access: { has: obj => "adminRateMessage" in obj, get: obj => obj.adminRateMessage }, metadata: _metadata }, null, _instanceExtraInitializers);
217
234
  __esDecorate(this, null, _adminReviewQueue_decorators, { kind: "method", name: "adminReviewQueue", static: false, private: false, access: { has: obj => "adminReviewQueue" in obj, get: obj => obj.adminReviewQueue }, metadata: _metadata }, null, _instanceExtraInitializers);
@@ -227,6 +244,9 @@ let QaSurface = (() => {
227
244
  __esDecorate(this, null, _answerQuestion_decorators, { kind: "method", name: "answerQuestion", static: false, private: false, access: { has: obj => "answerQuestion" in obj, get: obj => obj.answerQuestion }, metadata: _metadata }, null, _instanceExtraInitializers);
228
245
  __esDecorate(this, null, _cancelQuestion_decorators, { kind: "method", name: "cancelQuestion", static: false, private: false, access: { has: obj => "cancelQuestion" in obj, get: obj => obj.cancelQuestion }, metadata: _metadata }, null, _instanceExtraInitializers);
229
246
  __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);
247
+ __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);
248
+ __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);
249
+ __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);
230
250
  __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);
231
251
  __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);
232
252
  __esDecorate(this, null, _skillsCreate_decorators, { kind: "method", name: "skillsCreate", static: false, private: false, access: { has: obj => "skillsCreate" in obj, get: obj => obj.skillsCreate }, metadata: _metadata }, null, _instanceExtraInitializers);
@@ -234,6 +254,8 @@ let QaSurface = (() => {
234
254
  __esDecorate(this, null, _skillsRemove_decorators, { kind: "method", name: "skillsRemove", static: false, private: false, access: { has: obj => "skillsRemove" in obj, get: obj => obj.skillsRemove }, metadata: _metadata }, null, _instanceExtraInitializers);
235
255
  __esDecorate(this, null, _skillsValidate_decorators, { kind: "method", name: "skillsValidate", static: false, private: false, access: { has: obj => "skillsValidate" in obj, get: obj => obj.skillsValidate }, metadata: _metadata }, null, _instanceExtraInitializers);
236
256
  __esDecorate(this, null, _skillsTools_decorators, { kind: "method", name: "skillsTools", static: false, private: false, access: { has: obj => "skillsTools" in obj, get: obj => obj.skillsTools }, metadata: _metadata }, null, _instanceExtraInitializers);
257
+ __esDecorate(this, null, _slashCatalog_decorators, { kind: "method", name: "slashCatalog", static: false, private: false, access: { has: obj => "slashCatalog" in obj, get: obj => obj.slashCatalog }, metadata: _metadata }, null, _instanceExtraInitializers);
258
+ __esDecorate(this, null, _slashExecute_decorators, { kind: "method", name: "slashExecute", static: false, private: false, access: { has: obj => "slashExecute" in obj, get: obj => obj.slashExecute }, metadata: _metadata }, null, _instanceExtraInitializers);
237
259
  if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
238
260
  }
239
261
  static inject = inject;
@@ -242,6 +264,7 @@ let QaSurface = (() => {
242
264
  logger;
243
265
  admission;
244
266
  approvals;
267
+ fileDeleteGate;
245
268
  userQuestions;
246
269
  provenance;
247
270
  notes;
@@ -260,6 +283,12 @@ let QaSurface = (() => {
260
283
  personalSkills;
261
284
  /** Personal-skill remote bodies; the wire signatures stay on this class. */
262
285
  skillRemotes;
286
+ /**
287
+ * Slash-catalog and command-admission bodies. Admission, not execution:
288
+ * the native skill and command runtimes stay the only things that know what
289
+ * a `/name` means.
290
+ */
291
+ slashRemotes;
263
292
  launchToken;
264
293
  /** Root session principals attested for their owner, never for admin viewing. */
265
294
  integrationPrincipals = new QaIntegrationPrincipalBindings();
@@ -292,7 +321,14 @@ let QaSurface = (() => {
292
321
  config: () => this.getConfig(),
293
322
  logger: this.logger,
294
323
  dynamicToolNames: () => this.tools?.catalogToolNames() ?? [],
324
+ presetScope: () => this.qaPresetScope(),
295
325
  sessionLog,
326
+ // The record the sweep reclaims is the authorization boundary, not the
327
+ // whole of what the deployment kept about a chat: the quality rows a
328
+ // conversation owns outlive it unless they are dropped here.
329
+ onVanishedSessions: (sessionIds) => {
330
+ this.dropVanishedChats(sessionIds);
331
+ },
296
332
  });
297
333
  this.personalSkills = new QaPersonalSkillsHost({
298
334
  ctx,
@@ -305,6 +341,10 @@ let QaSurface = (() => {
305
341
  roles: () => this.access.roles,
306
342
  access: () => this.access,
307
343
  sessionLog,
344
+ // Deletion is the console's alone: the sidebar's delete stays a
345
+ // per-browser row, and only an administrator removes the chat itself.
346
+ sessionFiles: createSessionEraser(),
347
+ dropSources: (sessionId) => this.provenance.dropSession(sessionId),
308
348
  logger: this.logger,
309
349
  });
310
350
  this.skillRemotes = createQaPersonalSkillRemotes({
@@ -313,6 +353,12 @@ let QaSurface = (() => {
313
353
  skills: this.personalSkills.service,
314
354
  accounts: this.accountRemotes,
315
355
  });
356
+ this.slashRemotes = createQaSlashRemotes({
357
+ ctx,
358
+ getConfig: () => this.getConfig(),
359
+ logger: this.logger,
360
+ sessionGrant: (token, sessionId, agent) => this.slashSessionGrant(token, sessionId, agent),
361
+ });
316
362
  this.admission = new QaPolicyAdmission(ctx, () => this.getConfig(), this.logger,
317
363
  // Identity half of admission; no-ops while accounts stay disabled.
318
364
  {
@@ -340,8 +386,15 @@ let QaSurface = (() => {
340
386
  const ownership = new QaSessionOwnership((sessionId) => this.admission.knowsSession(sessionId));
341
387
  this.approvals = new QaApprovalGate(ctx, () => this.getConfig().interaction.approvals === "interactive", ownership, this.logger);
342
388
  this.userQuestions = new QaQuestionGate(ctx, () => this.getConfig().interaction.questions === "interactive", ownership, this.logger);
389
+ // The destructive tool of the QA catalog composes the same approval flow
390
+ // around itself: registered without `prepend`, it sits inside the approval
391
+ // gate and answers `ask` for every file_delete call of an attested chat,
392
+ // so the interactive card parks it for the operator (or the blocked
393
+ // configuration refuses it — nothing is deleted without a person).
394
+ this.fileDeleteGate = new QaFileDeleteGate(ctx, ownership);
343
395
  this.approvals.install();
344
396
  this.userQuestions.install();
397
+ this.fileDeleteGate.install();
345
398
  // The identity note and the provenance rule ride the conversation as
346
399
  // durable context messages, delegated experts included: the QA preset's
347
400
  // complete persona closes the system prompt to plugins, the conversation
@@ -361,11 +414,13 @@ let QaSurface = (() => {
361
414
  ctx.effect(() => async () => this.logger.close(), "dsh-qa-surface.logger");
362
415
  ctx.effect(() => () => this.admission.dispose(), "dsh-qa-surface.lockdown-policies");
363
416
  ctx.effect(() => () => this.approvals.dispose(), "dsh-qa-surface.approvals");
417
+ ctx.effect(() => () => this.fileDeleteGate.dispose(), "dsh-qa-surface.file-delete-gate");
364
418
  ctx.effect(() => () => this.userQuestions.dispose(), "dsh-qa-surface.user-questions");
365
419
  ctx.effect(() => () => this.provenance.dispose(), "dsh-qa-surface.provenance");
366
420
  ctx.effect(() => () => this.notes.dispose(), "dsh-qa-surface.prompt-notes");
367
421
  ctx.effect(() => () => this.personalSkills.dispose(), "dsh-qa-surface.personal-skills");
368
422
  this.warnDocumentsMoved();
423
+ this.warnLegacySlashDefaults();
369
424
  // The QA tool catalog is attached per agent, never at boot: nothing here
370
425
  // reaches the model until a managed agent loads the activation skill.
371
426
  this.tools = new QaTools(ctx, {
@@ -377,12 +432,17 @@ let QaSurface = (() => {
377
432
  });
378
433
  ctx.effect(() => () => this.tools.dispose(), "dsh-qa-surface.qa-tools");
379
434
  // The root index gains one head script: non-loopback hostnames continue
380
- // into /qa, the loopback operator keeps the full harness UI.
381
- ctx.on("webserver/index-inject", (table) => {
382
- const row = entryRedirectRow(this.getConfig());
383
- if (row !== undefined)
384
- table.push(row);
385
- });
435
+ // into /qa, the loopback operator keeps the full harness UI. Not in the
436
+ // kiosk composition: there the index itself is served under /qa, so the
437
+ // script would meet its own target on every load and reload the page in
438
+ // a loop, and the server policy already routes the site root into /qa.
439
+ if (!qaKioskDeployment()) {
440
+ ctx.on("webserver/index-inject", (table) => {
441
+ const row = entryRedirectRow(this.getConfig());
442
+ if (row !== undefined)
443
+ table.push(row);
444
+ });
445
+ }
386
446
  ctx.inject(["settings"], (settingsCtx) => {
387
447
  settingsCtx.settings.installSection(ctx, QA_SURFACE_SETTINGS_NAMESPACE, ConfigSchema, entry, {
388
448
  setSource: (source) => {
@@ -392,6 +452,7 @@ let QaSurface = (() => {
392
452
  const config = this.getConfig();
393
453
  this.refreshRoute();
394
454
  this.warnDocumentsMoved();
455
+ this.warnLegacySlashDefaults();
395
456
  this.logger.info("config.updated", {
396
457
  enabled: config.enabled,
397
458
  route: config.route.path,
@@ -417,6 +478,11 @@ let QaSurface = (() => {
417
478
  enabled: resolvedEntry.enabled,
418
479
  route: resolvedEntry.route.path,
419
480
  sessionPolicy: resolvedEntry.session.policy,
481
+ // What the two parked-interaction seams resolve to on this deployment:
482
+ // the attestation path warns per session when the question seam and the
483
+ // tool policy disagree, and this is the config they are read against.
484
+ approvals: resolvedEntry.interaction.approvals,
485
+ questions: resolvedEntry.interaction.questions,
420
486
  });
421
487
  }
422
488
  /** The quality store, opening its file the first time anyone needs it. */
@@ -424,6 +490,44 @@ let QaSurface = (() => {
424
490
  this.qualityStore ??= new QaQualityStore();
425
491
  return this.qualityStore;
426
492
  }
493
+ /**
494
+ * The standing scope of the preset QA chats run under, so an administrator's
495
+ * capability catalog is read the way a chat reads it. Everything a preset
496
+ * mounts — its skill catalog, its tool family — is registered in that scope,
497
+ * and a global-only read showed the operator an almost empty page. Resolving
498
+ * the preset composes it but starts no agent, no session and no turn;
499
+ * without a pinned preset there is nothing to borrow, and the read stays
500
+ * global.
501
+ */
502
+ async qaPresetScope() {
503
+ const preset = this.getConfig().session.agentPreset;
504
+ if (preset === null || preset === undefined)
505
+ return undefined;
506
+ return await this.ctx.agentPresets.standingKeyFor(preset);
507
+ }
508
+ /**
509
+ * Drop what the quality layer kept about chats that no longer exist in the
510
+ * Harness. The ownership sweep calls this with the ids it reclaimed: the
511
+ * record it removes is one thing the deployment held about a chat, and
512
+ * ratings, reviews and queue entries are the rest. Failure is logged and
513
+ * swallowed — housekeeping runs inside a review read, and a store that
514
+ * cannot be opened must not fail the page that triggered it.
515
+ */
516
+ dropVanishedChats(sessionIds) {
517
+ try {
518
+ const rows = this.quality().dropConversations(sessionIds);
519
+ this.logger.info("quality.vanished-conversations-dropped", {
520
+ conversations: sessionIds.length,
521
+ rows,
522
+ sessionIds: sessionIds.slice(0, 20),
523
+ });
524
+ }
525
+ catch (error) {
526
+ this.logger.error("quality.vanished-conversations-drop-failed", {
527
+ message: error instanceof Error ? error.message : String(error),
528
+ });
529
+ }
530
+ }
427
531
  /** Resolve browser authentication to the caller only; never accepts an id. */
428
532
  principalForToken(token) {
429
533
  const accounts = this.accountRemotes.resolve(this.getConfig());
@@ -450,6 +554,36 @@ let QaSurface = (() => {
450
554
  getConfig() {
451
555
  return resolveConfig(this.source());
452
556
  }
557
+ /**
558
+ * Ownership plus the role's user-skill grant for one slash read.
559
+ *
560
+ * Ownership comes first and for the same reason the rest of the plugin does
561
+ * it: a catalog names the skills a chat can reach, and a foreign browser has
562
+ * no business enumerating that. With accounts off there is no identity to
563
+ * check and the deployment's lockdown is the boundary, exactly as it is for
564
+ * every other remote.
565
+ *
566
+ * The grant mirrors `installQaSkillPolicy` to the letter — an empty
567
+ * `userSkills` list means the role keeps no separate user list, not that it
568
+ * grants nothing — so the palette can never offer a skill the typed gesture
569
+ * would refuse, nor hide one it would accept.
570
+ */
571
+ async slashSessionGrant(token, sessionId, agent) {
572
+ const accounts = this.accountRemotes.resolve(this.getConfig());
573
+ if (accounts === undefined)
574
+ return undefined;
575
+ if (agent === undefined) {
576
+ // A cold chat has no capability snapshot to read, but it still has an
577
+ // owner, and that is what the catalog read must respect.
578
+ this.accountRemotes.run(() => this.access.session(token, sessionId));
579
+ return undefined;
580
+ }
581
+ const resolved = await this.access.policyForSession(token, sessionId, agent);
582
+ if (resolved === undefined)
583
+ return undefined;
584
+ const { policy } = resolved;
585
+ return policy.userSkills.length === 0 ? policy.skills : policy.userSkills;
586
+ }
453
587
  /**
454
588
  * Self-service signup; the first account ever created becomes admin. The
455
589
  * display name derives from the email: the generated client enforces exact
@@ -658,6 +792,14 @@ let QaSurface = (() => {
658
792
  adminConversation(token, conversationId) {
659
793
  return this.accountRemotes.runAsync(() => this.admin.conversation(token, conversationId));
660
794
  }
795
+ /**
796
+ * Remove one conversation from the deployment. Admin-only, audited, and the
797
+ * only path that deletes what a person wrote — the sidebar's own delete
798
+ * stays what it always was, a per-browser row.
799
+ */
800
+ adminDeleteConversation(token, conversationId) {
801
+ return this.accountRemotes.runAsync(() => this.admin.deleteConversation(token, conversationId));
802
+ }
661
803
  adminFeedback(token, query, cursor, limit) {
662
804
  return this.accountRemotes.runAsync(() => this.admin.feedback(token, query, cursor ?? undefined, limit ?? undefined));
663
805
  }
@@ -796,6 +938,105 @@ let QaSurface = (() => {
796
938
  throw sourcePreviewRefusal(error instanceof QaSourcePreviewError ? error.reason : "unavailable");
797
939
  }
798
940
  }
941
+ /**
942
+ * List one directory of the chat's own workspace for the files panel.
943
+ *
944
+ * Browsing is deliberately narrower than the source preview: it stays inside
945
+ * the chat's own directory tree, so a visitor can look at what their
946
+ * conversation produced and at nothing else of the deployment.
947
+ * `readWorkspaceFile` opens one entry of such a listing.
948
+ */
949
+ async listWorkspaceFiles(token, sessionId, path) {
950
+ await this.admission.secureSession(token, sessionId);
951
+ const { config, cwd } = await this.browseContext(sessionId);
952
+ try {
953
+ return await listWorkspaceDirectory({
954
+ dirPath: path ?? "",
955
+ cwd,
956
+ maxEntries: config.sources.filePreview.maxListingEntries,
957
+ });
958
+ }
959
+ catch (error) {
960
+ throw this.browseRefusal("workspace.list-refused", sessionId, error);
961
+ }
962
+ }
963
+ /**
964
+ * Read one file of the chat's workspace: text when it decodes as UTF-8, bytes
965
+ * when it does not, so a document the agent produced can be downloaded while
966
+ * a note previews inline. The readable roots are the ones the model itself
967
+ * may read; unlike the source preview this does not require the file to be
968
+ * recorded evidence, because the panel is browsing a tree rather than
969
+ * reopening a cited source.
970
+ */
971
+ async readWorkspaceFile(token, sessionId, path) {
972
+ await this.admission.secureSession(token, sessionId);
973
+ const { config, cwd } = await this.browseContext(sessionId);
974
+ const attachmentRoot = this.admission.attachmentRoot();
975
+ try {
976
+ return await readWorkspaceFile({
977
+ filePath: path ?? "",
978
+ cwd,
979
+ sharedReadOnlyRoots: config.lockdown.sharedReadOnlyRoots,
980
+ ...(attachmentRoot === undefined ? {} : { attachmentRoot }),
981
+ maxBytes: config.sources.filePreview.maxBytes,
982
+ maxMarkdownRenderBytes: config.sources.filePreview.maxMarkdownRenderBytes,
983
+ });
984
+ }
985
+ catch (error) {
986
+ throw this.browseRefusal("workspace.read-refused", sessionId, error);
987
+ }
988
+ }
989
+ /**
990
+ * Render one Word document of the chat's workspace as a PDF for the panel.
991
+ *
992
+ * The conversion is the document pipeline's own, reached through the service
993
+ * `@yadsh/dsh-documents` publishes for its Host siblings — the panel gets the
994
+ * same providers, limits and refusals the `document_*` tools see, and a
995
+ * deployment without that plugin refuses instead of showing a guess. The
996
+ * produced PDF is read back here and travels as base64, so the audience never
997
+ * reaches an unfenced byte route.
998
+ */
999
+ async previewWorkspaceDocument(token, sessionId, path) {
1000
+ await this.admission.secureSession(token, sessionId);
1001
+ const { config, cwd } = await this.browseContext(sessionId);
1002
+ const attachmentRoot = this.admission.attachmentRoot();
1003
+ try {
1004
+ return await previewConvertibleDocument({
1005
+ filePath: path ?? "",
1006
+ cwd,
1007
+ sharedReadOnlyRoots: config.lockdown.sharedReadOnlyRoots,
1008
+ ...(attachmentRoot === undefined ? {} : { attachmentRoot }),
1009
+ documents: () => this.ctx.get("documents"),
1010
+ sessionId,
1011
+ maxBytes: config.sources.filePreview.maxBytes,
1012
+ });
1013
+ }
1014
+ catch (error) {
1015
+ throw this.browseRefusal("workspace.preview-refused", sessionId, error);
1016
+ }
1017
+ }
1018
+ /**
1019
+ * Shared admission facts of both browse methods: the preview switch is what
1020
+ * opens the panel's file reading at all, and the chat's cwd is the tree that
1021
+ * browsing is confined to.
1022
+ */
1023
+ async browseContext(sessionId) {
1024
+ const config = this.getConfig();
1025
+ if (!config.sources.filePreview.enabled) {
1026
+ throw sourcePreviewRefusal("unavailable");
1027
+ }
1028
+ const agent = this.ctx.agents.get((await import("@deepseek-ai/dsh-session/types")).SessionId(sessionId));
1029
+ const cwd = agent?.session.header.cwd;
1030
+ if (cwd === undefined)
1031
+ throw sourcePreviewRefusal("unavailable");
1032
+ return { config, cwd };
1033
+ }
1034
+ /** One browse refusal, logged with its coarse reason and rethrown for the wire. */
1035
+ browseRefusal(event, sessionId, error) {
1036
+ const reason = error instanceof QaSourcePreviewError ? error.reason : "unavailable";
1037
+ this.logger.debug(event, { sessionId, reason });
1038
+ return sourcePreviewRefusal(reason);
1039
+ }
799
1040
  /** Every personal skill of the token's account, sorted by name. */
800
1041
  skillsList(token) {
801
1042
  return this.skillRemotes.list(token);
@@ -833,11 +1074,46 @@ let QaSurface = (() => {
833
1074
  skillsTools(token) {
834
1075
  return this.skillRemotes.tools(token);
835
1076
  }
1077
+ /**
1078
+ * The slash entries this browser may offer for one chat: the session's
1079
+ * user-invocable skills and its agent's effective commands, already cut down
1080
+ * by the deployment policy and by the chat's role. The browser filters and
1081
+ * ranks this list; it never widens it.
1082
+ *
1083
+ * Enabled is reported rather than assumed, so a page that loaded before the
1084
+ * operator flipped the master switch learns the truth instead of showing an
1085
+ * empty palette forever.
1086
+ */
1087
+ slashCatalog(token, sessionId) {
1088
+ return this.slashRemotes.catalog(token, sessionId);
1089
+ }
1090
+ /**
1091
+ * Run one human command line. The line is the whole request — the browser
1092
+ * sends no name, no kind and no descriptor, so there is nothing for it to
1093
+ * forge; admission re-derives the name and re-checks the policy against the
1094
+ * deployment's own config.
1095
+ *
1096
+ * A command never becomes a model message: the native runtime answers it and
1097
+ * writes `command/run`/`command/done` into the session log, which is where
1098
+ * the transcript row is read from.
1099
+ */
1100
+ slashExecute(token, sessionId, line, attachments) {
1101
+ return this.slashRemotes.execute(token, sessionId, line, attachments);
1102
+ }
836
1103
  refreshRoute() {
837
1104
  const config = this.getConfig();
838
- const key = config.enabled
839
- ? `${config.route.path}:${config.route.matchChildren}`
840
- : undefined;
1105
+ // Kiosk: the harness route policy owns the QA paths and serves the
1106
+ // application there directly. This plugin's navigation redirect route
1107
+ // must not register — a named route shadows the fallback seat, so it
1108
+ // would bounce every /qa navigation to /?marker while the policy bounces
1109
+ // / back to /qa: a redirect loop. The kiosk key keeps the transition
1110
+ // machinery honest (dispose on entering kiosk, no re-registration, one
1111
+ // log line per transition).
1112
+ const key = qaKioskDeployment()
1113
+ ? "kiosk"
1114
+ : config.enabled
1115
+ ? `${config.route.path}:${config.route.matchChildren}`
1116
+ : undefined;
841
1117
  if (key === this.routeKey)
842
1118
  return;
843
1119
  this.disposeRoute?.();
@@ -845,11 +1121,33 @@ let QaSurface = (() => {
845
1121
  this.routeKey = undefined;
846
1122
  if (key === undefined || this.webServer === undefined)
847
1123
  return;
1124
+ if (key === "kiosk") {
1125
+ this.logger.info("route.kiosk", {
1126
+ message: "DSH_UI_MODE=qa: the navigation redirect route is not registered; the harness route policy serves the QA surface directly",
1127
+ });
1128
+ this.routeKey = key;
1129
+ return;
1130
+ }
848
1131
  this.disposeRoute = registerQaNavigationRoute(this.webServer, config, {
849
1132
  launchToken: this.launchToken,
850
1133
  });
851
1134
  this.routeKey = key;
852
1135
  }
1136
+ /**
1137
+ * A deployment that set `lockdown.allowSlashCommands: true` before this
1138
+ * section existed keeps the behaviour it asked for — skills at `all`,
1139
+ * commands denied — and is told so once per configuration change, because
1140
+ * "skills appeared after the upgrade" is otherwise indistinguishable from a
1141
+ * defect. Commands are never part of that fallback: an upgrade must not hand
1142
+ * the user a control-plane command nobody named.
1143
+ */
1144
+ warnLegacySlashDefaults() {
1145
+ if (!this.getConfig().slashCommands.legacyDefaults)
1146
+ return;
1147
+ this.logger.warn("slash.legacy-defaults", {
1148
+ message: "lockdown.allowSlashCommands=true without a slashCommands section: every user-invocable skill is admitted and no human command is. Declare slashCommands.commands to enable commands explicitly.",
1149
+ });
1150
+ }
853
1151
  /**
854
1152
  * The document pipeline moved out of this plugin into `@yadsh/dsh-documents`.
855
1153
  * A deployment whose profile still carries the old `documents` section would