@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
@@ -0,0 +1,67 @@
1
+ import type { QaSlashCatalogEntry } from "../../types.js";
2
+ /**
3
+ * Where one composer draft should go.
4
+ *
5
+ * The composer used to have a single path — `sendPrompt` — with a guard that
6
+ * turned every `/`-leading line away. That guard is now the `disabled` case
7
+ * below, and everything else is decided here, in one place, from the draft and
8
+ * the catalog alone. Keeping it pure is what makes the ambiguous, unknown and
9
+ * withheld cases testable without a browser or a Host.
10
+ */
11
+ export type QaSlashRoute =
12
+ /**
13
+ * Ordinary text: the model gets it, exactly as before this feature. It may
14
+ * still name a skill this deployment withholds — the turn runs, and the
15
+ * surface says so rather than letting the user believe it took effect.
16
+ */
17
+ {
18
+ readonly kind: "prompt";
19
+ readonly withheld?: readonly string[];
20
+ }
21
+ /** A user-invocable skill: the native prompt path carries the gesture. */
22
+ | {
23
+ readonly kind: "skill";
24
+ readonly entry: QaSlashCatalogEntry;
25
+ }
26
+ /** A human command: the Host's command runtime answers it, the model never sees it. */
27
+ | {
28
+ readonly kind: "command";
29
+ readonly entry: QaSlashCatalogEntry;
30
+ }
31
+ /** Nothing by that name is offered here. */
32
+ | {
33
+ readonly kind: "unknown";
34
+ readonly name: string;
35
+ }
36
+ /** A skill and a command share the name; only the user may choose. */
37
+ | {
38
+ readonly kind: "ambiguous";
39
+ readonly name: string;
40
+ readonly entries: readonly QaSlashCatalogEntry[];
41
+ }
42
+ /** The catalog could not be read, so no `/name` can be classified. */
43
+ | {
44
+ readonly kind: "unavailable";
45
+ readonly name: string;
46
+ }
47
+ /** The deployment runs with the slash interface off. */
48
+ | {
49
+ readonly kind: "disabled";
50
+ };
51
+ export interface ResolveSlashRouteInput {
52
+ readonly text: string;
53
+ readonly enabled: boolean;
54
+ readonly catalogReady: boolean;
55
+ readonly entries: readonly QaSlashCatalogEntry[];
56
+ /** User-invocable skills this deployment withholds from this chat. */
57
+ readonly deniedSkills: readonly string[];
58
+ /**
59
+ * The entry the user picked in the palette, while the draft still reads as
60
+ * its invocation. A picked identity outranks name resolution: when a skill
61
+ * and a command share a name, the user already answered the only question
62
+ * the router would otherwise have to guess at.
63
+ */
64
+ readonly picked?: string | null;
65
+ }
66
+ export declare function resolveSlashRoute(input: ResolveSlashRouteInput): QaSlashRoute;
67
+ //# sourceMappingURL=slash-router.d.ts.map
@@ -0,0 +1,47 @@
1
+ import type { QaSlashCatalogEntry, QaSlashView } from "../../types.js";
2
+ export interface QaSlashNavigation {
3
+ /** True while the palette is on screen. */
4
+ readonly open: boolean;
5
+ readonly query: string;
6
+ /** The rows the palette renders, best match first. */
7
+ readonly rows: readonly QaSlashCatalogEntry[];
8
+ /** Index into `rows`; -1 when there is nothing to select. */
9
+ readonly active: number;
10
+ readonly activeId: string | null;
11
+ /** Move the selection by one row, wrapping at both ends. */
12
+ readonly move: (delta: number) => void;
13
+ /** Point the selection at one row, as a tap does. */
14
+ readonly hover: (index: number) => void;
15
+ /** Insert the active row's invocation into the draft. */
16
+ readonly pickActive: () => void;
17
+ /** Insert one row, as a click or a tap does. */
18
+ readonly pick: (entry: QaSlashCatalogEntry) => void;
19
+ /** Dismiss the palette for this draft. */
20
+ readonly dismiss: () => void;
21
+ /** The identity the user picked, while the draft still reads as its call. */
22
+ readonly picked: QaSlashCatalogEntry | undefined;
23
+ }
24
+ export interface UseSlashNavigationOptions {
25
+ readonly draft: string;
26
+ readonly slash: QaSlashView;
27
+ readonly maxVisible: number;
28
+ readonly fuzzySearch: boolean;
29
+ /** Set the draft to `text` and put the caret at its end. */
30
+ readonly setDraft: (text: string) => void;
31
+ /** Monotonic token; a change re-opens a palette the user had dismissed. */
32
+ readonly reopen: number;
33
+ }
34
+ /**
35
+ * Palette state for one composer draft.
36
+ *
37
+ * The palette is a pure function of the draft: it is open while the draft is
38
+ * `/` plus a name still being typed, and closes the moment the user types a
39
+ * space and starts writing arguments. Nothing has to be kept in sync — which
40
+ * is also why switching chats (the composer is keyed by chat and remounts)
41
+ * cannot leave a palette behind.
42
+ *
43
+ * Selection is one index over the filtered rows; the arrow keys, the mouse and
44
+ * the touch screen all move the same number.
45
+ */
46
+ export declare function useSlashNavigation(options: UseSlashNavigationOptions): QaSlashNavigation;
47
+ //# sourceMappingURL=useSlashNavigation.d.ts.map
@@ -1,4 +1,26 @@
1
1
  /** Every `--dsh-qa-*` custom property the root rule declares. */
2
2
  export declare const QA_BRAND_TOKEN_NAMES: readonly string[];
3
3
  export declare const QA_SURFACE_STYLES: string;
4
+ /**
5
+ * Everything the QA surface paints, as one sheet for one `<style>` tag — the
6
+ * kiosk form, with no host-hiding rules: in the kiosk composition the native
7
+ * shell never mounts, so the sheet carries nothing aimed at it.
8
+ *
9
+ * The shared audit components keep their own stylesheet in
10
+ * `@yadsh/dsh-audit-ui`; it is folded in here so the surface is self-contained
11
+ * — the audit dialog must look right whether or not the audit plugin's own
12
+ * client bundle happens to have injected the same rules into the document.
13
+ *
14
+ * The math styles and their fonts come from the bundled KaTeX copy the same
15
+ * way: the data-URI fonts resolve whatever the Host page loads, and identical
16
+ * rules from its own KaTeX stylesheet are harmless.
17
+ */
18
+ export declare const QA_ROOT_STYLES: string;
19
+ /**
20
+ * The overlay-composition sheet: the same rules as {@link QA_ROOT_STYLES}
21
+ * plus the host-column mask. Deployed into hosts without the kiosk patches,
22
+ * where the surface still covers a mounted native shell and the mask is what
23
+ * a deleted overlay element uncovers — a blank page instead of the shell.
24
+ */
25
+ export declare const QA_OVERLAY_STYLES: string;
4
26
  //# sourceMappingURL=styles.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import type { ClientRemote } from "@deepseek-ai/dsh-api-gateway/client";
2
2
  import type { ISessions, SessionFace } from "@deepseek-ai/dsh-api-session-controller/client";
3
3
  import type { UiConversation } from "@deepseek-ai/dsh-client-ui-conversation/client";
4
- import type { QaAccountProfileInput, QaAccountSession, QaAccountStartersInput, QaAccountStarter, QaAccountUserPublic, QaAccessAdminSnapshot, QaApprovalDecision, QaClaimResult, QaLockdownProof, QaOwnershipEntry, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaSessionState, QaSkillDocument, QaSkillDraftInput, QaSkillRemoval, QaSkillSummary, QaSkillToolDescriptor, QaSkillValidation, QaSourceFilePreview, QaTurnSources, QaWhoamiResult, QaCapabilitySelection, QaCurrentAccess, QaSessionAccess, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, QaAdminAuditEvent, QaAdminOverview, QaAdminPage, QaAdminUserDetail, QaAdminUserRow, QaAdminUserUpdate, QaAuditQuery, QaConversationDetail, QaConversationQuery, QaConversationReview, QaConversationReviewInput, QaConversationSummary, QaFeedbackQuery, QaFeedbackRow, QaMessageFeedback, QaMessageFeedbackInput, QaQualityMetrics, QaReviewQueueItem, QaReviewQueueRow, QaUserQuery } from "../types.js";
4
+ import type { QaAccountProfileInput, QaAccountSession, QaAccountStartersInput, QaAccountStarter, QaAccountUserPublic, QaAccessAdminSnapshot, QaApprovalDecision, QaClaimResult, QaLockdownProof, QaOwnershipEntry, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaSessionState, QaSkillDocument, QaSkillDraftInput, QaSkillRemoval, QaSkillSummary, QaSkillToolDescriptor, QaSkillValidation, QaSourceFilePreview, QaTurnSources, QaWhoamiResult, QaDocumentPreview, QaWorkspaceFile, QaWorkspaceListing, QaCapabilitySelection, QaCurrentAccess, QaSessionAccess, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, QaAdminAuditEvent, QaAdminOverview, QaAdminPage, QaAdminUserDetail, QaAdminUserRow, QaAdminUserUpdate, QaAuditQuery, QaConversationDetail, QaConversationDeletion, QaConversationQuery, QaConversationReview, QaConversationReviewInput, QaConversationSummary, QaFeedbackQuery, QaFeedbackRow, QaMessageFeedback, QaMessageFeedbackInput, QaQualityMetrics, QaReviewQueueItem, QaReviewQueueRow, QaSlashCatalog, QaSlashExecution, QaSlashSubmitAttachment, QaUserQuery } from "../types.js";
5
5
  /** Wire content one prompt carries: text plus base64 image uploads. */
6
6
  export type QaPromptContent = Parameters<SessionFace["prompt"]>[0];
7
7
  /** DSH session runtime surface the QA controller is allowed to touch. */
@@ -58,6 +58,11 @@ export interface QaAdminApi {
58
58
  updateUser(token: string, userId: string, update: QaAdminUserUpdate): Promise<RemoteResult<QaAdminUserDetail>>;
59
59
  conversations(token: string, query: QaConversationQuery, cursor: string | null, limit: number | null): Promise<RemoteResult<QaAdminPage<QaConversationSummary>>>;
60
60
  conversation(token: string, conversationId: string): Promise<RemoteResult<QaConversationDetail>>;
61
+ /**
62
+ * Remove the conversation from the deployment, stored logs included. Only an
63
+ * administrator may call it; the sidebar's own delete is unrelated.
64
+ */
65
+ deleteConversation(token: string, conversationId: string): Promise<RemoteResult<QaConversationDeletion>>;
61
66
  feedback(token: string, query: QaFeedbackQuery, cursor: string | null, limit: number | null): Promise<RemoteResult<QaAdminPage<QaFeedbackRow>>>;
62
67
  /** The signed-in user's own verdict on one of their assistant messages. */
63
68
  rateMessage(token: string, conversationId: string, messageId: string, input: QaMessageFeedbackInput): Promise<RemoteResult<QaMessageFeedback>>;
@@ -106,6 +111,44 @@ export interface QaSourceApi {
106
111
  readonly ok: false;
107
112
  readonly error: unknown;
108
113
  }>;
114
+ /** One directory of the chat's own workspace, for the files panel. */
115
+ listWorkspaceFiles(token: string, sessionId: string, path: string): Promise<{
116
+ readonly ok: true;
117
+ readonly value: QaWorkspaceListing;
118
+ } | {
119
+ readonly ok: false;
120
+ readonly error: unknown;
121
+ }>;
122
+ /** One file of that workspace: decoded text, or bytes when it is binary. */
123
+ readWorkspaceFile(token: string, sessionId: string, path: string): Promise<{
124
+ readonly ok: true;
125
+ readonly value: QaWorkspaceFile;
126
+ } | {
127
+ readonly ok: false;
128
+ readonly error: unknown;
129
+ }>;
130
+ /**
131
+ * A Word document of that workspace rendered as PDF by the deployment's
132
+ * document pipeline; the panel shows the PDF the browser already knows how
133
+ * to draw instead of uploading the bytes anywhere.
134
+ */
135
+ previewWorkspaceDocument(token: string, sessionId: string, path: string): Promise<{
136
+ readonly ok: true;
137
+ readonly value: QaDocumentPreview;
138
+ } | {
139
+ readonly ok: false;
140
+ readonly error: unknown;
141
+ }>;
142
+ }
143
+ /**
144
+ * The slash half of the Host namespace. The catalog comes back already cut
145
+ * down by the deployment policy and the chat's role; `execute` takes the raw
146
+ * line, because admission re-derives the name from it rather than trusting
147
+ * anything the browser says about which entry it means.
148
+ */
149
+ export interface QaSlashApi {
150
+ catalog(token: string, sessionId: string): Promise<RemoteResult<QaSlashCatalog>>;
151
+ execute(token: string, sessionId: string, line: string, attachments: readonly QaSlashSubmitAttachment[]): Promise<RemoteResult<QaSlashExecution>>;
109
152
  }
110
153
  /** A source API with the account token already bound at the call site. */
111
154
  export type QaBoundSourceApi = {
@@ -123,6 +166,27 @@ export type QaBoundSourceApi = {
123
166
  readonly ok: false;
124
167
  readonly error: unknown;
125
168
  }>;
169
+ listWorkspaceFiles(sessionId: string, path: string): Promise<{
170
+ readonly ok: true;
171
+ readonly value: QaWorkspaceListing;
172
+ } | {
173
+ readonly ok: false;
174
+ readonly error: unknown;
175
+ }>;
176
+ readWorkspaceFile(sessionId: string, path: string): Promise<{
177
+ readonly ok: true;
178
+ readonly value: QaWorkspaceFile;
179
+ } | {
180
+ readonly ok: false;
181
+ readonly error: unknown;
182
+ }>;
183
+ previewWorkspaceDocument(sessionId: string, path: string): Promise<{
184
+ readonly ok: true;
185
+ readonly value: QaDocumentPreview;
186
+ } | {
187
+ readonly ok: false;
188
+ readonly error: unknown;
189
+ }>;
126
190
  };
127
191
  /**
128
192
  * Approval remotes of this plugin's namespace. Read-only listing plus the one
@@ -0,0 +1,10 @@
1
+ import type { QaNotesConfig, ResolvedQaSurfaceConfig } from "../types.js";
2
+ type ResolvedNotes = ResolvedQaSurfaceConfig["notes"];
3
+ /**
4
+ * The ambient model notes. Notes are advisory text, not capability: the
5
+ * default is the current behavior (every note on, built-in wording), and an
6
+ * empty template always resolves to the built-in text.
7
+ */
8
+ export declare function resolveNotes(input: QaNotesConfig | undefined): ResolvedNotes;
9
+ export {};
10
+ //# sourceMappingURL=notes.d.ts.map
@@ -0,0 +1,20 @@
1
+ import type { QaSurfaceConfig, ResolvedQaSlashCommands } from "../types.js";
2
+ /** Palette ceilings; a palette longer than the viewport is unusable on mobile. */
3
+ export declare const QA_SLASH_MAX_VISIBLE_MIN = 1;
4
+ export declare const QA_SLASH_MAX_VISIBLE_MAX = 100;
5
+ /**
6
+ * Resolve the slash interface policy.
7
+ *
8
+ * The master switch lives in lockdown, so it arrives as a neighbor rather than
9
+ * being re-read here — one owner per decision. Two consequences are deliberate:
10
+ *
11
+ * - An upgrade from a deployment that had already set
12
+ * `lockdown.allowSlashCommands: true` but knows nothing about this section
13
+ * keeps working: skills fall back to `all` (every user-invocable skill the
14
+ * session already exposed) and commands stay denied. The flag is reported as
15
+ * `legacyDefaults` so the Host can say so once, out loud.
16
+ * - A deployment that declares the section and leaves the switch off changes
17
+ * nothing at all: the resolved policy is inert until the switch is on.
18
+ */
19
+ export declare function resolveSlashCommands(input: QaSurfaceConfig, allowSlashCommands: boolean): ResolvedQaSlashCommands;
20
+ //# sourceMappingURL=slash-commands.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import { TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
2
2
  import type { Context } from "@deepseek-ai/cordis";
3
3
  import type { QaTurnSources } from "./provenance/types.js";
4
- import type { QaAccountProfileInput, QaAccountSession, QaAccountStartersInput, QaAccountUserPublic, QaApprovalDecision, QaClaimResult, QaLockdownProof, QaOwnershipEntry, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaSurfaceConfig, ResolvedQaSurfaceConfig, QaSkillDocument, QaSkillDraftInput, QaSkillRemoval, QaSkillSummary, QaSkillToolDescriptor, QaSkillValidation, QaSourceFilePreview, QaWhoamiResult, QaPrincipal, QaAccessAdminSnapshot, QaAdminAuditEvent, QaAdminOverview, QaAdminPage, QaAdminUserDetail, QaAdminUserRow, QaAdminUserUpdate, QaAuditQuery, QaCapabilitySelection, QaConversationDetail, QaConversationQuery, QaConversationReview, QaConversationReviewInput, QaConversationSummary, QaCurrentAccess, QaFeedbackQuery, QaFeedbackRow, QaMessageFeedback, QaMessageFeedbackInput, QaQualityMetrics, QaReviewQueueItem, QaReviewQueueRow, QaSessionAccess, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, QaUserQuery } from "./types.js";
4
+ import type { QaAccountProfileInput, QaAccountSession, QaAccountStartersInput, QaAccountUserPublic, QaApprovalDecision, QaClaimResult, QaDocumentPreview, QaLockdownProof, QaOwnershipEntry, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaSurfaceConfig, ResolvedQaSurfaceConfig, QaSkillDocument, QaSkillDraftInput, QaSkillRemoval, QaSkillSummary, QaSkillToolDescriptor, QaSkillValidation, QaSourceFilePreview, QaWhoamiResult, QaWorkspaceFile, QaWorkspaceListing, QaPrincipal, QaAccessAdminSnapshot, QaAdminAuditEvent, QaAdminOverview, QaAdminPage, QaAdminUserDetail, QaAdminUserRow, QaAdminUserUpdate, QaAuditQuery, QaCapabilitySelection, QaConversationDetail, QaConversationDeletion, QaConversationQuery, QaConversationReview, QaConversationReviewInput, QaConversationSummary, QaCurrentAccess, QaFeedbackQuery, QaFeedbackRow, QaMessageFeedback, QaMessageFeedbackInput, QaQualityMetrics, QaReviewQueueItem, QaReviewQueueRow, QaSessionAccess, QaSlashCatalog, QaSlashExecution, QaSlashSubmitAttachment, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, QaUserQuery } from "./types.js";
5
5
  export declare const name = "qa-surface";
6
6
  export declare const inject: string[];
7
7
  import { QA_SURFACE_SETTINGS_NAMESPACE } from "./shared/settings.js";
@@ -20,6 +20,7 @@ export declare class QaSurface extends TypertRemoteService {
20
20
  private readonly logger;
21
21
  private readonly admission;
22
22
  private readonly approvals;
23
+ private readonly fileDeleteGate;
23
24
  private readonly userQuestions;
24
25
  private readonly provenance;
25
26
  private readonly notes;
@@ -38,6 +39,12 @@ export declare class QaSurface extends TypertRemoteService {
38
39
  private readonly personalSkills;
39
40
  /** Personal-skill remote bodies; the wire signatures stay on this class. */
40
41
  private readonly skillRemotes;
42
+ /**
43
+ * Slash-catalog and command-admission bodies. Admission, not execution:
44
+ * the native skill and command runtimes stay the only things that know what
45
+ * a `/name` means.
46
+ */
47
+ private readonly slashRemotes;
41
48
  private readonly launchToken;
42
49
  /** Root session principals attested for their owner, never for admin viewing. */
43
50
  private readonly integrationPrincipals;
@@ -52,6 +59,25 @@ export declare class QaSurface extends TypertRemoteService {
52
59
  constructor(ctx: Context, entry?: QaSurfaceConfig);
53
60
  /** The quality store, opening its file the first time anyone needs it. */
54
61
  private quality;
62
+ /**
63
+ * The standing scope of the preset QA chats run under, so an administrator's
64
+ * capability catalog is read the way a chat reads it. Everything a preset
65
+ * mounts — its skill catalog, its tool family — is registered in that scope,
66
+ * and a global-only read showed the operator an almost empty page. Resolving
67
+ * the preset composes it but starts no agent, no session and no turn;
68
+ * without a pinned preset there is nothing to borrow, and the read stays
69
+ * global.
70
+ */
71
+ private qaPresetScope;
72
+ /**
73
+ * Drop what the quality layer kept about chats that no longer exist in the
74
+ * Harness. The ownership sweep calls this with the ids it reclaimed: the
75
+ * record it removes is one thing the deployment held about a chat, and
76
+ * ratings, reviews and queue entries are the rest. Failure is logged and
77
+ * swallowed — housekeeping runs inside a review read, and a store that
78
+ * cannot be opened must not fail the page that triggered it.
79
+ */
80
+ private dropVanishedChats;
55
81
  /** Resolve browser authentication to the caller only; never accepts an id. */
56
82
  principalForToken(token: string): QaPrincipal | undefined;
57
83
  /** Resolve only a directly QA-owned root session; delegated children fail closed. */
@@ -59,6 +85,21 @@ export declare class QaSurface extends TypertRemoteService {
59
85
  /** Admit tools that independently enforce the same QA principal boundary. */
60
86
  registerPrincipalScopedTools(names: readonly string[]): () => void;
61
87
  getConfig(): ResolvedQaSurfaceConfig;
88
+ /**
89
+ * Ownership plus the role's user-skill grant for one slash read.
90
+ *
91
+ * Ownership comes first and for the same reason the rest of the plugin does
92
+ * it: a catalog names the skills a chat can reach, and a foreign browser has
93
+ * no business enumerating that. With accounts off there is no identity to
94
+ * check and the deployment's lockdown is the boundary, exactly as it is for
95
+ * every other remote.
96
+ *
97
+ * The grant mirrors `installQaSkillPolicy` to the letter — an empty
98
+ * `userSkills` list means the role keeps no separate user list, not that it
99
+ * grants nothing — so the palette can never offer a skill the typed gesture
100
+ * would refuse, nor hide one it would accept.
101
+ */
102
+ private slashSessionGrant;
62
103
  /**
63
104
  * Self-service signup; the first account ever created becomes admin. The
64
105
  * display name derives from the email: the generated client enforces exact
@@ -139,6 +180,12 @@ export declare class QaSurface extends TypertRemoteService {
139
180
  adminConversations(token: string, query: QaConversationQuery, cursor: string | null, limit: number | null): Promise<QaAdminPage<QaConversationSummary>>;
140
181
  /** One conversation with its messages, tool calls and review state. */
141
182
  adminConversation(token: string, conversationId: string): Promise<QaConversationDetail>;
183
+ /**
184
+ * Remove one conversation from the deployment. Admin-only, audited, and the
185
+ * only path that deletes what a person wrote — the sidebar's own delete
186
+ * stays what it always was, a per-browser row.
187
+ */
188
+ adminDeleteConversation(token: string, conversationId: string): Promise<QaConversationDeletion>;
142
189
  adminFeedback(token: string, query: QaFeedbackQuery, cursor: string | null, limit: number | null): Promise<QaAdminPage<QaFeedbackRow>>;
143
190
  /**
144
191
  * Rate one of the caller's own assistant messages. The token names the only
@@ -189,6 +236,43 @@ export declare class QaSurface extends TypertRemoteService {
189
236
  * the per-account scratch directory — could never be opened in the panel.
190
237
  */
191
238
  readSourceFile(token: string, sessionId: string, sourcePath: string): Promise<QaSourceFilePreview>;
239
+ /**
240
+ * List one directory of the chat's own workspace for the files panel.
241
+ *
242
+ * Browsing is deliberately narrower than the source preview: it stays inside
243
+ * the chat's own directory tree, so a visitor can look at what their
244
+ * conversation produced and at nothing else of the deployment.
245
+ * `readWorkspaceFile` opens one entry of such a listing.
246
+ */
247
+ listWorkspaceFiles(token: string, sessionId: string, path: string): Promise<QaWorkspaceListing>;
248
+ /**
249
+ * Read one file of the chat's workspace: text when it decodes as UTF-8, bytes
250
+ * when it does not, so a document the agent produced can be downloaded while
251
+ * a note previews inline. The readable roots are the ones the model itself
252
+ * may read; unlike the source preview this does not require the file to be
253
+ * recorded evidence, because the panel is browsing a tree rather than
254
+ * reopening a cited source.
255
+ */
256
+ readWorkspaceFile(token: string, sessionId: string, path: string): Promise<QaWorkspaceFile>;
257
+ /**
258
+ * Render one Word document of the chat's workspace as a PDF for the panel.
259
+ *
260
+ * The conversion is the document pipeline's own, reached through the service
261
+ * `@yadsh/dsh-documents` publishes for its Host siblings — the panel gets the
262
+ * same providers, limits and refusals the `document_*` tools see, and a
263
+ * deployment without that plugin refuses instead of showing a guess. The
264
+ * produced PDF is read back here and travels as base64, so the audience never
265
+ * reaches an unfenced byte route.
266
+ */
267
+ previewWorkspaceDocument(token: string, sessionId: string, path: string): Promise<QaDocumentPreview>;
268
+ /**
269
+ * Shared admission facts of both browse methods: the preview switch is what
270
+ * opens the panel's file reading at all, and the chat's cwd is the tree that
271
+ * browsing is confined to.
272
+ */
273
+ private browseContext;
274
+ /** One browse refusal, logged with its coarse reason and rethrown for the wire. */
275
+ private browseRefusal;
192
276
  /** Every personal skill of the token's account, sorted by name. */
193
277
  skillsList(token: string): {
194
278
  readonly skills: readonly QaSkillSummary[];
@@ -216,7 +300,38 @@ export declare class QaSurface extends TypertRemoteService {
216
300
  skillsTools(token: string): {
217
301
  readonly tools: readonly QaSkillToolDescriptor[];
218
302
  };
303
+ /**
304
+ * The slash entries this browser may offer for one chat: the session's
305
+ * user-invocable skills and its agent's effective commands, already cut down
306
+ * by the deployment policy and by the chat's role. The browser filters and
307
+ * ranks this list; it never widens it.
308
+ *
309
+ * Enabled is reported rather than assumed, so a page that loaded before the
310
+ * operator flipped the master switch learns the truth instead of showing an
311
+ * empty palette forever.
312
+ */
313
+ slashCatalog(token: string, sessionId: string): Promise<QaSlashCatalog>;
314
+ /**
315
+ * Run one human command line. The line is the whole request — the browser
316
+ * sends no name, no kind and no descriptor, so there is nothing for it to
317
+ * forge; admission re-derives the name and re-checks the policy against the
318
+ * deployment's own config.
319
+ *
320
+ * A command never becomes a model message: the native runtime answers it and
321
+ * writes `command/run`/`command/done` into the session log, which is where
322
+ * the transcript row is read from.
323
+ */
324
+ slashExecute(token: string, sessionId: string, line: string, attachments: readonly QaSlashSubmitAttachment[]): Promise<QaSlashExecution>;
219
325
  private refreshRoute;
326
+ /**
327
+ * A deployment that set `lockdown.allowSlashCommands: true` before this
328
+ * section existed keeps the behaviour it asked for — skills at `all`,
329
+ * commands denied — and is told so once per configuration change, because
330
+ * "skills appeared after the upgrade" is otherwise indistinguishable from a
331
+ * defect. Commands are never part of that fallback: an upgrade must not hand
332
+ * the user a control-plane command nobody named.
333
+ */
334
+ private warnLegacySlashDefaults;
220
335
  /**
221
336
  * The document pipeline moved out of this plugin into `@yadsh/dsh-documents`.
222
337
  * A deployment whose profile still carries the old `documents` section would
@@ -92,6 +92,11 @@ export declare class QaPersonalSkills {
92
92
  * The skills one session cwd exposes to DSH. A file the parser rejects, or
93
93
  * one whose name disagrees with its directory, is reported in the editor and
94
94
  * never handed to the model as a half-valid skill.
95
+ *
96
+ * This is the model-facing discovery path, so it degrades to empty instead
97
+ * of throwing: a provider that throws marks the whole catalog snapshot
98
+ * incomplete, and the harness then withholds the available-skills section
99
+ * from every session — not just this account's skills.
95
100
  */
96
101
  discover(cwd: string): readonly QaStoredSkill[];
97
102
  /** Re-read one skill of a session cwd, re-checking the same boundary. */
@@ -14,6 +14,15 @@ export declare const QA_IDENTITY_NOTE = "dsh-qa-surface:user-identity";
14
14
  export declare const QA_SOURCES_NOTE = "dsh-qa-surface:structured-sources";
15
15
  /** Note name asking the model to name its delegations. */
16
16
  export declare const QA_DELEGATION_NOTE = "dsh-qa-surface:delegation-naming";
17
+ /**
18
+ * Built-in note texts. Each is the fallback for its settings template
19
+ * (`notes.*.template`); the placeholders mark the parts the injector
20
+ * substitutes. Unknown or empty placeholders render as empty text.
21
+ */
22
+ export declare const QA_IDENTITY_NOTE_TEMPLATE = "{identity}\n\n{instructions}";
23
+ export declare const QA_SOURCES_NOTE_TEMPLATE = "Source provenance is collected automatically from your tool calls; the QA surface lists what it collected beside the answer. Do not append a manual Sources/\u0418\u0441\u0442\u043E\u0447\u043D\u0438\u043A\u0438 bibliography of your own.";
24
+ export declare const QA_SOURCES_FALLBACK_TEMPLATE = "A delegated run whose provider cannot expose tool events must call {reportTool} before finishing.";
25
+ export declare const QA_DELEGATION_NOTE_TEMPLATE = "When you start a background subagent, give the delegation a short vivid name in its description field: two or three words in the user's language that say what the run is for (\u00AB\u0421\u0432\u0435\u0440\u043A\u0430 \u043E\u0442\u0447\u0451\u0442\u043E\u0432\u00BB, \"Log triage\"). The QA surface shows that description as the subagent's display name in the operator's panel and completion notices.";
17
26
  export interface QaIdentityRenderInput {
18
27
  /** The owner's account address; the one fact accounts always provide. */
19
28
  readonly email: string;
@@ -0,0 +1,24 @@
1
+ import type { DocumentsFace } from "@yadsh/dsh-documents";
2
+ import type { QaDocumentPreview } from "../types.js";
3
+ import { type QaAllowedFileRequest } from "./file-preview.js";
4
+ /** Look up the document subsystem a sibling Host plugin published. */
5
+ export type DocumentsLookup = () => DocumentsFace | undefined;
6
+ export interface QaDocumentPreviewRequest extends QaAllowedFileRequest {
7
+ /** The document pipeline, resolved per call so a late provider still counts. */
8
+ readonly documents: DocumentsLookup;
9
+ readonly sessionId: string;
10
+ /** Bytes of the rendered PDF the panel accepts before it gives up. */
11
+ readonly maxBytes: number;
12
+ }
13
+ /**
14
+ * Render one Word document as a PDF for the files panel.
15
+ *
16
+ * The conversion is the document pipeline's own — the same runtime, providers
17
+ * and limits the `document_*` tools use — reached through the face that plugin
18
+ * publishes for its Host siblings; a deployment without the pipeline installed
19
+ * refuses with `unsupported` rather than growing a second converter here. The
20
+ * input path passes the same containment check the panel's other reads use, so
21
+ * a preview cannot read what a listing could not reach.
22
+ */
23
+ export declare function previewConvertibleDocument({ documents, sessionId, maxBytes, ...file }: QaDocumentPreviewRequest): Promise<QaDocumentPreview>;
24
+ //# sourceMappingURL=document-preview.d.ts.map
@@ -1,11 +1,13 @@
1
- import type { QaSourceFilePreview } from "../types.js";
1
+ import type { QaSourceFilePreview, QaWorkspaceFile, QaWorkspaceListing } from "../types.js";
2
2
  /**
3
3
  * Coarse, wire-safe preview refusal codes. They ride the shared
4
4
  * `(reason: <code>)` marker, so the panel can tell "this file is not in a
5
5
  * directory the QA read policy opens" from "this file is gone" instead of
6
6
  * telling every audience that a present file moved away.
7
7
  */
8
- export type QaSourcePreviewReason = "outside-roots" | "not-evidence" | "unavailable";
8
+ export type QaSourcePreviewReason = "outside-roots" | "not-evidence" | "unavailable"
9
+ /** The panel has no way to render this format at all. */
10
+ | "unsupported";
9
11
  /** Host refusal whose wire message carries the coarse reason marker. */
10
12
  export declare class QaSourcePreviewError extends Error {
11
13
  readonly reason: QaSourcePreviewReason;
@@ -39,6 +41,32 @@ export interface QaSourceFilePreviewRequest {
39
41
  readonly maxBytes: number;
40
42
  readonly maxMarkdownRenderBytes: number;
41
43
  }
44
+ /** A file request the panel may make: the chat's own tree or a shared root. */
45
+ export interface QaAllowedFileRequest {
46
+ readonly filePath: string;
47
+ /** The attested chat's cwd: the anchor a relative request resolves against. */
48
+ readonly cwd: string;
49
+ readonly sharedReadOnlyRoots?: readonly string[];
50
+ readonly attachmentRoot?: string;
51
+ }
52
+ /** One resolved file that passed the read policy. */
53
+ interface QaAllowedFile {
54
+ /** The path as the caller spelled it, canonicalized against the chat cwd. */
55
+ readonly canonicalPath: string;
56
+ /** Its real filesystem path, once symlinks are followed. */
57
+ readonly canonical: string;
58
+ readonly size: number;
59
+ }
60
+ /**
61
+ * Resolve one requested file and check it against the readable roots.
62
+ *
63
+ * The roots mirror the per-user execution guard — the chat's own cwd plus the
64
+ * deployment's shared read-only directories and the attachment store — so a
65
+ * file the model was explicitly allowed to read stays readable in the panel,
66
+ * while anything else is refused with the coarse `outside-roots` reason
67
+ * instead of leaking whether it exists.
68
+ */
69
+ export declare function resolveAllowedFile({ filePath, cwd, sharedReadOnlyRoots, attachmentRoot, }: QaAllowedFileRequest): Promise<QaAllowedFile>;
42
70
  /**
43
71
  * Read one evidence file from the roots the QA read policy opens.
44
72
  *
@@ -50,4 +78,43 @@ export interface QaSourceFilePreviewRequest {
50
78
  * refused as foreign evidence.
51
79
  */
52
80
  export declare function readSourceFilePreview({ sourcePath, cwd, isEvidence, sharedReadOnlyRoots, attachmentRoot, maxBytes, maxMarkdownRenderBytes, }: QaSourceFilePreviewRequest): Promise<QaSourceFilePreview>;
81
+ /** One directory request from the files panel. */
82
+ export interface QaWorkspaceListRequest {
83
+ /** The directory to list, absolute or relative to the chat cwd. Empty = root. */
84
+ readonly dirPath: string;
85
+ readonly cwd: string;
86
+ /** Children one listing carries; the rest is reported as truncated. */
87
+ readonly maxEntries: number;
88
+ }
89
+ /** The advertised type of one file: by extension, else opaque bytes. */
90
+ export declare function mediaTypeOf(path: string): string;
91
+ /**
92
+ * List one directory of the chat's own workspace.
93
+ *
94
+ * Browsing is deliberately narrower than previewing: the panel walks the tree
95
+ * the chat works in, never the deployment's shared read-only roots, so the
96
+ * visitor cannot enumerate the deployment from the rail. The request is
97
+ * confined with the same realpath-then-contain check the preview uses, which
98
+ * is what makes `..` and symlinked directories harmless.
99
+ * Symlinked children are omitted rather than followed: a link inside the
100
+ * workspace may point anywhere, and a tree that silently leaves the chat's
101
+ * directory is worse than one that hides a link.
102
+ */
103
+ export declare function listWorkspaceDirectory({ dirPath, cwd, maxEntries, }: QaWorkspaceListRequest): Promise<QaWorkspaceListing>;
104
+ /** One file request from the files panel. */
105
+ export interface QaWorkspaceFileRequest extends QaAllowedFileRequest {
106
+ readonly maxBytes: number;
107
+ readonly maxMarkdownRenderBytes: number;
108
+ }
109
+ /**
110
+ * Read one file of the chat's workspace for the panel: text when it decodes as
111
+ * UTF-8, base64 bytes when it does not, so a document the agent produced can be
112
+ * offered for download while a note previews inline.
113
+ *
114
+ * Unlike the source preview this is not bound to recorded evidence — the panel
115
+ * browses what the chat's workspace holds — but it is bound to the same roots
116
+ * the model itself may read.
117
+ */
118
+ export declare function readWorkspaceFile({ filePath, cwd, sharedReadOnlyRoots, attachmentRoot, maxBytes, maxMarkdownRenderBytes, }: QaWorkspaceFileRequest): Promise<QaWorkspaceFile>;
119
+ export {};
53
120
  //# sourceMappingURL=file-preview.d.ts.map
@@ -44,6 +44,19 @@ export declare class QaProvenanceHost {
44
44
  * restart. Growth of the file is bounded by the snapshot store's caps.
45
45
  */
46
46
  private forget;
47
+ private forgetById;
48
+ /**
49
+ * Drop everything kept about one chat, in memory and in storage alike.
50
+ *
51
+ * Unlike {@link forget}, which runs on every teardown of a chat that still
52
+ * exists and deliberately keeps its stored turns, this is for a chat that is
53
+ * gone: nothing will reopen it, so the durable shard goes with it. The
54
+ * administrative deletion calls this in the same act that removes the
55
+ * session's logs.
56
+ *
57
+ * @param sessionId - the chat whose collected sources are dropped.
58
+ */
59
+ dropSession(sessionId: string): void;
47
60
  private forgetAll;
48
61
  bundles(sessionId: string): readonly QaTurnSources[];
49
62
  sourceAllowed(sessionId: string, path: string): boolean;
@@ -8,7 +8,7 @@ import type { QaToolDescriptor } from "./types.js";
8
8
  *
9
9
  * Bump it whenever the catalog's tool set or their schemas change.
10
10
  */
11
- export declare const QA_TOOL_CATALOG_VERSION = "1";
11
+ export declare const QA_TOOL_CATALOG_VERSION = "2";
12
12
  /** One QA tool reports the activation state of whichever agent calls it. */
13
13
  export interface QaToolsSelfcheckDeps {
14
14
  readonly catalogVersion: string;