@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
@@ -20,6 +20,12 @@ export type QaApprovalInteraction = "blocked" | "interactive";
20
20
  * refuses the ask outright; `interactive` answers it from the QA view.
21
21
  */
22
22
  export type QaQuestionInteraction = "unsupported" | "interactive";
23
+ /**
24
+ * What a deployment may write for the question seam. `enabled` is accepted as
25
+ * the spelling of `interactive` a feature request asked for; the resolved
26
+ * config carries one name only.
27
+ */
28
+ export type QaQuestionInteractionInput = QaQuestionInteraction | "enabled";
23
29
  /** The operator's answer to one parked tool call. */
24
30
  export type QaApprovalDecision = "allowed-once" | "rejected";
25
31
  /** One answered question; `custom` is free text, and may accompany `selected`. */
@@ -36,7 +42,7 @@ export interface QaQuestionAnswerItem {
36
42
  */
37
43
  export type QaAccountRole = "user" | "reviewer" | "admin";
38
44
  /** Administrative permissions a role grants; see `admin/permissions.ts`. */
39
- export type QaPermission = "users.read" | "users.manage" | "roles.read" | "roles.manage" | "conversations.read.all" | "conversations.read.own" | "reviews.read" | "reviews.write" | "analytics.read" | "audit.read" | "settings.manage";
45
+ export type QaPermission = "users.read" | "users.manage" | "roles.read" | "roles.manage" | "conversations.read.all" | "conversations.read.own" | "conversations.delete" | "reviews.read" | "reviews.write" | "analytics.read" | "audit.read" | "settings.manage";
40
46
  /**
41
47
  * Tools split by how they become available. `always` is visible from the first
42
48
  * model step; `skillGrantable` is a ceiling — the tool only appears once an
@@ -483,6 +489,7 @@ export interface QaSourcesConfig {
483
489
  readonly allowRawToggle?: boolean;
484
490
  readonly maxBytes?: number;
485
491
  readonly maxMarkdownRenderBytes?: number;
492
+ readonly maxListingEntries?: number;
486
493
  };
487
494
  readonly subagents?: {
488
495
  readonly inheritSources?: boolean;
@@ -498,6 +505,30 @@ export interface QaSourcesConfig {
498
505
  readonly parseAssistantSourcesBlock?: boolean;
499
506
  };
500
507
  }
508
+ /**
509
+ * The ambient notes the injector writes into a QA chat as plugin-sourced user
510
+ * messages (`prompt-notes.ts`). Each note can be switched off and reworded;
511
+ * an empty template keeps the built-in wording.
512
+ */
513
+ export interface QaNotesConfig {
514
+ /** Who the assistant is talking to; `{identity}` + `{instructions}`. */
515
+ readonly identity?: {
516
+ readonly enabled?: boolean;
517
+ readonly template?: string;
518
+ };
519
+ /** Source-provenance rules; `{reportTool}` names the subagent report tool. */
520
+ readonly sources?: {
521
+ readonly enabled?: boolean;
522
+ readonly template?: string;
523
+ /** The sentence appended when the report-tool fallback is on. */
524
+ readonly fallbackTemplate?: string;
525
+ };
526
+ /** How to label background delegations; no placeholders. */
527
+ readonly delegation?: {
528
+ readonly enabled?: boolean;
529
+ readonly template?: string;
530
+ };
531
+ }
501
532
  export interface QaSurfaceConfig {
502
533
  readonly enabled?: boolean;
503
534
  readonly route?: {
@@ -550,7 +581,7 @@ export interface QaSurfaceConfig {
550
581
  readonly thinkingPhrases?: readonly string[];
551
582
  readonly interaction?: {
552
583
  readonly approvals?: QaApprovalInteraction;
553
- readonly questions?: QaQuestionInteraction;
584
+ readonly questions?: QaQuestionInteractionInput;
554
585
  };
555
586
  /**
556
587
  * QA tool delivery. Dynamic activation keeps the QA tool schemas out of the
@@ -582,7 +613,14 @@ export interface QaSurfaceConfig {
582
613
  readonly approvalPolicy?: QaApprovalPolicy;
583
614
  readonly permissionPreset?: string;
584
615
  readonly allowPermissionChanges?: false;
585
- readonly allowSlashCommands?: false;
616
+ /**
617
+ * Master switch for the slash interface, and the only capability flag the
618
+ * resolver lets a deployment turn on. It opens the palette, which then
619
+ * offers exactly what `slashCommands` admits — human commands stay denied
620
+ * until the deployment names them. Nothing here widens the tool allow-list,
621
+ * the sandbox or the approval policy.
622
+ */
623
+ readonly allowSlashCommands?: boolean;
586
624
  readonly allowSettingsMutation?: false;
587
625
  readonly allowSessionReset?: boolean;
588
626
  readonly allowSessionRename?: false;
@@ -595,6 +633,12 @@ export interface QaSurfaceConfig {
595
633
  /** Shared directories available to read-only filesystem tools. */
596
634
  readonly sharedReadOnlyRoots?: readonly string[];
597
635
  };
636
+ /**
637
+ * Slash interface policy. Admission only: the QA surface never implements a
638
+ * skill or command registry, it decides which native ones reach the palette.
639
+ * Inert while `lockdown.allowSlashCommands` is off.
640
+ */
641
+ readonly slashCommands?: QaSlashCommandsConfig;
598
642
  readonly embedding?: {
599
643
  readonly frameAncestors?: string | null;
600
644
  };
@@ -665,6 +709,7 @@ export interface QaSurfaceConfig {
665
709
  };
666
710
  readonly sources?: QaSourcesConfig;
667
711
  readonly attachments?: QaAttachmentsConfig;
712
+ readonly notes?: QaNotesConfig;
668
713
  }
669
714
  /** What a QA visitor may attach to one message. */
670
715
  export interface QaAttachmentsConfig {
@@ -737,7 +782,7 @@ export interface ResolvedQaSurfaceConfig {
737
782
  readonly approvalPolicy: QaApprovalPolicy;
738
783
  readonly permissionPreset: string;
739
784
  readonly allowPermissionChanges: false;
740
- readonly allowSlashCommands: false;
785
+ readonly allowSlashCommands: boolean;
741
786
  readonly allowSettingsMutation: false;
742
787
  readonly allowSessionReset: boolean;
743
788
  readonly allowSessionRename: false;
@@ -749,6 +794,7 @@ export interface ResolvedQaSurfaceConfig {
749
794
  };
750
795
  readonly sharedReadOnlyRoots: readonly string[];
751
796
  };
797
+ readonly slashCommands: ResolvedQaSlashCommands;
752
798
  readonly embedding: {
753
799
  readonly frameAncestors: string | null;
754
800
  };
@@ -834,6 +880,7 @@ export interface ResolvedQaSurfaceConfig {
834
880
  readonly allowRawToggle: boolean;
835
881
  readonly maxBytes: number;
836
882
  readonly maxMarkdownRenderBytes: number;
883
+ readonly maxListingEntries: number;
837
884
  };
838
885
  readonly subagents: {
839
886
  readonly inheritSources: boolean;
@@ -852,6 +899,178 @@ export interface ResolvedQaSurfaceConfig {
852
899
  readonly maxPending: number;
853
900
  readonly extensions: readonly string[];
854
901
  };
902
+ readonly notes: {
903
+ readonly identity: {
904
+ readonly enabled: boolean;
905
+ readonly template: string;
906
+ };
907
+ readonly sources: {
908
+ readonly enabled: boolean;
909
+ readonly template: string;
910
+ readonly fallbackTemplate: string;
911
+ };
912
+ readonly delegation: {
913
+ readonly enabled: boolean;
914
+ readonly template: string;
915
+ };
916
+ };
917
+ }
918
+ /** Which native registry one unified entry came from. */
919
+ export type QaSlashEntryKind = "skill" | "command";
920
+ /** How one half of the catalog admits native entries. */
921
+ export type QaSlashPolicyMode = "deny-all" | "allow-list" | "all";
922
+ export interface QaSlashPolicyConfig {
923
+ readonly mode?: QaSlashPolicyMode;
924
+ readonly allow?: readonly string[];
925
+ }
926
+ export interface QaSlashPaletteConfig {
927
+ readonly enabled?: boolean;
928
+ /** Run the two weakest matcher rungs (substring, subsequence). */
929
+ readonly fuzzySearch?: boolean;
930
+ readonly maxVisible?: number;
931
+ readonly showDescriptions?: boolean;
932
+ readonly showKindBadge?: boolean;
933
+ }
934
+ export interface QaSlashCommandsConfig {
935
+ readonly skills?: QaSlashPolicyConfig;
936
+ readonly commands?: QaSlashPolicyConfig;
937
+ readonly palette?: QaSlashPaletteConfig;
938
+ }
939
+ export interface ResolvedQaSlashCommands {
940
+ /** Mirror of `lockdown.allowSlashCommands`; the one master switch. */
941
+ readonly enabled: boolean;
942
+ readonly skills: {
943
+ readonly mode: QaSlashPolicyMode;
944
+ readonly allow: readonly string[];
945
+ };
946
+ readonly commands: {
947
+ readonly mode: QaSlashPolicyMode;
948
+ readonly allow: readonly string[];
949
+ };
950
+ readonly palette: {
951
+ readonly enabled: boolean;
952
+ readonly fuzzySearch: boolean;
953
+ readonly maxVisible: number;
954
+ readonly showDescriptions: boolean;
955
+ readonly showKindBadge: boolean;
956
+ };
957
+ /**
958
+ * True when the deployment turned the master switch on without declaring a
959
+ * `slashCommands` section: skills then admit every user-invocable skill the
960
+ * session already exposes, commands stay denied. The Host logs it once, so
961
+ * an upgrade cannot silently widen anything.
962
+ */
963
+ readonly legacyDefaults: boolean;
964
+ }
965
+ /**
966
+ * One palette row. `id` is the routing identity: skill and command may share a
967
+ * name, so identity is `skill:<name>` or `command:<name>` and never the bare
968
+ * name the two halves would collide on.
969
+ */
970
+ export interface QaSlashCatalogEntry {
971
+ readonly id: string;
972
+ readonly kind: QaSlashEntryKind;
973
+ readonly name: string;
974
+ readonly description: string;
975
+ /** Skill-only: the native `whenToUse`, rendered as secondary copy. */
976
+ readonly whenToUse?: string;
977
+ /** Skill-only: whether the model is also offered this skill. */
978
+ readonly modelInvocable?: boolean;
979
+ /** Command-only: the advertised argument shape. */
980
+ readonly inputHint?: string;
981
+ /** Command-only: whether the executor admits composer attachments. */
982
+ readonly acceptsAttachments?: boolean;
983
+ }
984
+ /**
985
+ * Whether the command half of the catalog could be read. `inactive` is the
986
+ * ordinary state of a cold chat: the native command registry resolves through
987
+ * a live Agent, and a chat with none answers with no commands rather than an
988
+ * error — the palette then offers skills alone.
989
+ */
990
+ export type QaSlashCommandSurface = "ready" | "unavailable" | "inactive";
991
+ export interface QaSlashCatalog {
992
+ /** False while `lockdown.allowSlashCommands` is off. */
993
+ readonly enabled: boolean;
994
+ readonly entries: readonly QaSlashCatalogEntry[];
995
+ readonly commandSurface: QaSlashCommandSurface;
996
+ /**
997
+ * User-invocable skills of this chat that the deployment or the chat's role
998
+ * withheld from the palette. Naming them is what lets the browser warn about
999
+ * a `/name` typed inside an ordinary prompt — the native gesture path never
1000
+ * consults this list, so it is a courtesy, not an authorization.
1001
+ */
1002
+ readonly deniedSkills: readonly string[];
1003
+ }
1004
+ /**
1005
+ * One composer attachment offered to a human command. The same two shapes the
1006
+ * prompt path uses — an image rides inline, a file rides its staged receipt —
1007
+ * because the native executor admits both through one attachment store.
1008
+ */
1009
+ export type QaSlashSubmitAttachment = {
1010
+ readonly type: "image";
1011
+ readonly mediaType: QaImageMediaType;
1012
+ readonly data: string;
1013
+ readonly name?: string;
1014
+ } | {
1015
+ readonly type: "file";
1016
+ readonly receiptId: string;
1017
+ };
1018
+ /** Why a command line was refused before, or instead of, running. */
1019
+ export type QaSlashRefusal = "slash-disabled" | "unknown-command" | "not-allowed" | "attachments-unsupported" | "inactive-session";
1020
+ export type QaSlashCommandOutcome = {
1021
+ readonly kind: "success";
1022
+ readonly text?: string;
1023
+ /** Earlier authoritative event this result is presented from. */
1024
+ readonly sourceEventSeq?: number;
1025
+ } | {
1026
+ readonly kind: "error";
1027
+ readonly text: string;
1028
+ };
1029
+ /**
1030
+ * The result of one admitted command. `refused` is an admission decision and
1031
+ * costs nothing; `executed` means the native runtime ran the handler and the
1032
+ * lifecycle is already in the session log, which is what the transcript row
1033
+ * projects.
1034
+ */
1035
+ export type QaSlashExecution = {
1036
+ readonly kind: "executed";
1037
+ readonly commandId: string;
1038
+ readonly outcome: QaSlashCommandOutcome;
1039
+ } | {
1040
+ readonly kind: "refused";
1041
+ readonly reason: QaSlashRefusal;
1042
+ /** Host-authored detail; the browser renders its own copy for `reason`. */
1043
+ readonly message: string;
1044
+ };
1045
+ /** One entry of the palette the browser is filtering. */
1046
+ export interface QaSlashView {
1047
+ readonly enabled: boolean;
1048
+ readonly state: "idle" | "loading" | "ready" | "error";
1049
+ readonly entries: readonly QaSlashCatalogEntry[];
1050
+ readonly commandSurface: QaSlashCommandSurface;
1051
+ readonly deniedSkills: readonly string[];
1052
+ /** Set when the catalog could not be read; ordinary prompts keep working. */
1053
+ readonly error: string | null;
1054
+ /**
1055
+ * Bumped when the surface must re-open a palette the user had dismissed —
1056
+ * an ambiguous `/name` is the case that needs it. The composer watches the
1057
+ * counter rather than the message, so a refusal can be re-stated.
1058
+ */
1059
+ readonly reopen: number;
1060
+ }
1061
+ /**
1062
+ * One human command line projected into the transcript. Commands never enter
1063
+ * the model conversation, so this row is their only visible trace; it is a
1064
+ * control row, not an assistant bubble.
1065
+ */
1066
+ export interface QaCommandActivity {
1067
+ readonly commandId: string;
1068
+ readonly name: string;
1069
+ /** Verbatim text after the name, with its separator whitespace removed. */
1070
+ readonly args?: string;
1071
+ readonly state: "running" | "success" | "error";
1072
+ readonly resultText?: string;
1073
+ readonly sourceEventSeq?: number;
855
1074
  }
856
1075
  export interface QaSourceFilePreview {
857
1076
  readonly path: string;
@@ -861,6 +1080,51 @@ export interface QaSourceFilePreview {
861
1080
  readonly markdown: boolean;
862
1081
  readonly renderableMarkdown: boolean;
863
1082
  }
1083
+ /**
1084
+ * A file the panel renders by conversion rather than by bytes: the document
1085
+ * pipeline turned a Word file into PDF, and the browser shows that PDF.
1086
+ */
1087
+ export interface QaDocumentPreview {
1088
+ readonly kind: "pdf";
1089
+ readonly base64: string;
1090
+ readonly mime: "application/pdf";
1091
+ readonly name: string;
1092
+ readonly bytes: number;
1093
+ }
1094
+ /** One directory entry of a chat's own workspace, as the files panel browses it. */
1095
+ export interface QaWorkspaceEntry {
1096
+ readonly name: string;
1097
+ readonly type: "file" | "directory";
1098
+ readonly size: number | null;
1099
+ }
1100
+ /**
1101
+ * One directory of the chat's workspace. `path` is the canonical form of the
1102
+ * directory as requested — the chat root itself is the empty string — so the
1103
+ * panel can build a breadcrumb without another round trip.
1104
+ */
1105
+ export interface QaWorkspaceListing {
1106
+ readonly path: string;
1107
+ readonly entries: readonly QaWorkspaceEntry[];
1108
+ /** More children existed than one listing carries. */
1109
+ readonly truncated: boolean;
1110
+ }
1111
+ /**
1112
+ * One file of the chat's workspace: decoded text when it reads as UTF-8, base64
1113
+ * bytes when it does not. The panel needs both — documents the agent produced
1114
+ * are binary, while notes and transcripts preview as text.
1115
+ */
1116
+ export interface QaWorkspaceFile {
1117
+ readonly path: string;
1118
+ readonly size: number;
1119
+ readonly truncated: boolean;
1120
+ readonly markdown: boolean;
1121
+ readonly renderableMarkdown: boolean;
1122
+ readonly mime: string;
1123
+ /** Present when the file decoded as text; absent for binary content. */
1124
+ readonly text?: string;
1125
+ /** Present when the file is not text; base64 of at most the byte cap. */
1126
+ readonly base64?: string;
1127
+ }
864
1128
  /** Host-attested facts required before the QA composer may become writable. */
865
1129
  export interface QaLockdownProof {
866
1130
  readonly sessionId: string;
@@ -927,6 +1191,11 @@ export type QaMessage = QaUserMessage | {
927
1191
  readonly text: string;
928
1192
  readonly status: "info" | "error";
929
1193
  readonly timestamp?: number;
1194
+ /**
1195
+ * Set on a human command row. Commands stay out of the model
1196
+ * conversation, so this projection is the only trace the user sees.
1197
+ */
1198
+ readonly command?: QaCommandActivity;
930
1199
  /** Collapsible settlement row (subagent finished/stopped/failed). */
931
1200
  readonly notice?: {
932
1201
  readonly title: string;
@@ -1088,6 +1357,8 @@ export interface QaSessionState {
1088
1357
  readonly approvals: readonly QaPendingApproval[];
1089
1358
  /** Question requests parked for the operator's answer, oldest first. */
1090
1359
  readonly questions: readonly QaPendingQuestion[];
1360
+ /** Slash palette state, keyed to the chat this snapshot describes. */
1361
+ readonly slash: QaSlashView;
1091
1362
  }
1092
1363
  /** Minimal server-trusted identity exposed to principal-scoped plugins. */
1093
1364
  export interface QaPrincipal {
@@ -1173,7 +1444,7 @@ export interface QaReviewQueueItem {
1173
1444
  readonly feedbackId?: string;
1174
1445
  }
1175
1446
  /** Administrative actions recorded in the audit trail. */
1176
- export type QaAdminAuditAction = "user.created" | "user.updated" | "user.enabled" | "user.disabled" | "authorization.changed" | "subrole.assignment.changed" | "subrole.created" | "subrole.updated" | "subrole.deleted" | "common_capabilities.updated" | "conversation.reviewed" | "review.updated" | "review.queued" | "admin.settings.updated";
1447
+ export type QaAdminAuditAction = "user.created" | "user.updated" | "user.enabled" | "user.disabled" | "authorization.changed" | "subrole.assignment.changed" | "subrole.created" | "subrole.updated" | "subrole.deleted" | "common_capabilities.updated" | "conversation.reviewed" | "conversation.deleted" | "review.updated" | "review.queued" | "admin.settings.updated";
1177
1448
  export interface QaAdminAuditEvent {
1178
1449
  readonly id: string;
1179
1450
  readonly timestamp: string;
@@ -1266,6 +1537,17 @@ export interface QaConversationDetail {
1266
1537
  readonly reviews: readonly QaConversationReview[];
1267
1538
  readonly queueItems: readonly QaReviewQueueItem[];
1268
1539
  }
1540
+ /** What one administrative deletion removed, for the console to report. */
1541
+ export interface QaConversationDeletion {
1542
+ readonly conversationId: string;
1543
+ /**
1544
+ * Every session whose stored log is gone, the chat first: a conversation's
1545
+ * subagent sessions are part of it and are removed with it.
1546
+ */
1547
+ readonly sessions: readonly string[];
1548
+ /** Quality rows dropped with the conversation. */
1549
+ readonly qualityRows: number;
1550
+ }
1269
1551
  /**
1270
1552
  * Server-side filter for the conversation list. Every field is optional and
1271
1553
  * accepts an explicit null: the wire carries whatever the browser has, and an
@@ -1419,7 +1701,12 @@ export interface QaAdminUserDetail {
1419
1701
  }[];
1420
1702
  readonly activity: {
1421
1703
  readonly conversations: number;
1422
- readonly messages: number;
1704
+ /**
1705
+ * Unknown until the conversations page is opened: the count needs every
1706
+ * conversation's log read, so the detail card reports null instead of
1707
+ * blocking its payload on the scan.
1708
+ */
1709
+ readonly messages: number | null;
1423
1710
  readonly positiveRatings: number;
1424
1711
  readonly negativeRatings: number;
1425
1712
  };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The deployment UI mode, as the host half of the plugin sees it.
3
+ *
4
+ * `DSH_UI_MODE=qa` (the kiosk) moves the frontend URL-space ownership from
5
+ * this plugin to the harness: the harness route policy serves `/qa` directly,
6
+ * redirects `/` into it, and answers every other frontend path with 404. The
7
+ * plugin's own navigation redirect route must then stay unregistered — it
8
+ * exists for the overlay composition, where the index is served at `/` and a
9
+ * browser navigation to `/qa` has to bounce through the marker hand-off —
10
+ * because a registered route shadows the harness fallback seat and would
11
+ * loop every `/qa` navigation back onto itself.
12
+ */
13
+ /**
14
+ * Whether this harness process runs the QA kiosk UI mode.
15
+ * @param env - the process environment; overridable for tests.
16
+ */
17
+ export declare function qaKioskDeployment(env?: Readonly<Record<string, string | undefined>>): boolean;
18
+ //# sourceMappingURL=ui-mode.d.ts.map
package/lib/ui-mode.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The deployment UI mode, as the host half of the plugin sees it.
3
+ *
4
+ * `DSH_UI_MODE=qa` (the kiosk) moves the frontend URL-space ownership from
5
+ * this plugin to the harness: the harness route policy serves `/qa` directly,
6
+ * redirects `/` into it, and answers every other frontend path with 404. The
7
+ * plugin's own navigation redirect route must then stay unregistered — it
8
+ * exists for the overlay composition, where the index is served at `/` and a
9
+ * browser navigation to `/qa` has to bounce through the marker hand-off —
10
+ * because a registered route shadows the harness fallback seat and would
11
+ * loop every `/qa` navigation back onto itself.
12
+ */
13
+ /** Environment variable selecting the deployment UI mode (`qa` = kiosk). */
14
+ const UI_MODE_ENV = "DSH_UI_MODE";
15
+ /**
16
+ * Whether this harness process runs the QA kiosk UI mode.
17
+ * @param env - the process environment; overridable for tests.
18
+ */
19
+ export function qaKioskDeployment(env = process.env) {
20
+ return (env[UI_MODE_ENV] ?? "").trim() === "qa";
21
+ }
22
+ //# sourceMappingURL=ui-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-mode.js","sourceRoot":"","sources":["../src/ui-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,4EAA4E;AAC5E,MAAM,WAAW,GAAG,aAAa,CAAC;AAElC;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,GAAG,GAAiD,OAAO,CAAC,GAAG;IAE/D,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC;AAClD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yadsh/dsh-qa-surface",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "A focused end-user QA surface backed by native DeepSeek Harness sessions",
5
5
  "repository": {
6
6
  "type": "git",
@@ -16,7 +16,8 @@
16
16
  "types": "./lib/types/index.d.ts",
17
17
  "bin": {
18
18
  "qa-accounts": "./lib/cli.js",
19
- "qa-repair-sessions": "./scripts/repair-session-events.mjs"
19
+ "qa-repair-sessions": "./scripts/repair-session-events.mjs",
20
+ "qa-attach-sessions": "./scripts/attach-workspace-sessions.mjs"
20
21
  },
21
22
  "exports": {
22
23
  ".": {
@@ -76,6 +77,7 @@
76
77
  "lib/**/*.js.map",
77
78
  "lib/**/*.d.ts",
78
79
  "scripts/repair-session-events.mjs",
80
+ "scripts/attach-workspace-sessions.mjs",
79
81
  "cordis.patch.yml",
80
82
  "compatibility.json",
81
83
  "capability-policy.json",
@@ -100,15 +102,14 @@
100
102
  },
101
103
  "peerDependencies": {
102
104
  "@deepseek-ai/cordis": "^4.0.2",
103
- "@deepseek-ai/schemastery": "^3.18.2",
104
- "@deepseek-ai/dsh-api-gateway": ">=0.1.5-rc.2 <0.2.0",
105
105
  "@deepseek-ai/dsh-agent": ">=0.1.5-rc.2 <0.2.0",
106
106
  "@deepseek-ai/dsh-agent-presets": ">=0.1.5-rc.2 <0.2.0",
107
+ "@deepseek-ai/dsh-api-gateway": ">=0.1.5-rc.2 <0.2.0",
107
108
  "@deepseek-ai/dsh-api-session-controller": ">=0.1.5-rc.2 <0.2.0",
108
109
  "@deepseek-ai/dsh-api-workspace-controller": ">=0.1.5-rc.2 <0.2.0",
109
110
  "@deepseek-ai/dsh-client-connection": ">=0.1.5-rc.2 <0.2.0",
110
- "@deepseek-ai/dsh-client-ui-conversation": ">=0.1.5-rc.2 <0.2.0",
111
111
  "@deepseek-ai/dsh-client-ui-chat": ">=0.1.5-rc.2 <0.2.0",
112
+ "@deepseek-ai/dsh-client-ui-conversation": ">=0.1.5-rc.2 <0.2.0",
112
113
  "@deepseek-ai/dsh-client-ui-layout": ">=0.1.5-rc.2 <0.2.0",
113
114
  "@deepseek-ai/dsh-client-ui-renderer": ">=0.1.5-rc.2 <0.2.0",
114
115
  "@deepseek-ai/dsh-client-ui-settings": ">=0.1.5-rc.2 <0.2.0",
@@ -125,26 +126,29 @@
125
126
  "@deepseek-ai/dsh-tools": ">=0.1.5-rc.2 <0.2.0",
126
127
  "@deepseek-ai/dsh-typert-protocol": ">=0.1.5-rc.2 <0.2.0",
127
128
  "@deepseek-ai/dsh-workspace": ">=0.1.5-rc.2 <0.2.0",
129
+ "@deepseek-ai/schemastery": "^3.18.2",
128
130
  "react": "^18.2.0",
129
131
  "react-dom": "^18.2.0"
130
132
  },
131
133
  "dependencies": {
132
134
  "yaml": "^2.9.0",
133
135
  "zod": "^4.4.3",
134
- "@yadsh/dsh-plugin-kit": "^0.2.0",
136
+ "@yadsh/dsh-audit-core": "^0.1.0",
137
+ "@yadsh/dsh-audit-ui": "^0.1.0",
138
+ "@yadsh/dsh-documents": "^0.4.0",
139
+ "@yadsh/dsh-plugin-kit": "^0.3.0",
135
140
  "@yadsh/dsh-plugin-log": "^0.4.0"
136
141
  },
137
142
  "devDependencies": {
138
143
  "@deepseek-ai/cordis": "4.0.2",
139
- "@deepseek-ai/schemastery": "3.18.2",
140
- "@deepseek-ai/dsh-api-gateway": "0.1.5-rc.2",
141
144
  "@deepseek-ai/dsh-agent": "0.1.5-rc.2",
142
145
  "@deepseek-ai/dsh-agent-presets": "0.1.5-rc.2",
146
+ "@deepseek-ai/dsh-api-gateway": "0.1.5-rc.2",
143
147
  "@deepseek-ai/dsh-api-session-controller": "0.1.5-rc.2",
144
148
  "@deepseek-ai/dsh-api-workspace-controller": "0.1.5-rc.2",
145
149
  "@deepseek-ai/dsh-client-connection": "0.1.5-rc.2",
146
- "@deepseek-ai/dsh-client-ui-conversation": "0.1.5-rc.2",
147
150
  "@deepseek-ai/dsh-client-ui-chat": "0.1.5-rc.2",
151
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.5-rc.2",
148
152
  "@deepseek-ai/dsh-client-ui-layout": "0.1.5-rc.2",
149
153
  "@deepseek-ai/dsh-client-ui-renderer": "0.1.5-rc.2",
150
154
  "@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.2",
@@ -163,12 +167,14 @@
163
167
  "@deepseek-ai/dsh-typert-generator": "0.1.5-rc.2",
164
168
  "@deepseek-ai/dsh-typert-protocol": "0.1.5-rc.2",
165
169
  "@deepseek-ai/dsh-workspace": "0.1.5-rc.2",
170
+ "@deepseek-ai/schemastery": "3.18.2",
166
171
  "@testing-library/react": "^16.3.0",
167
172
  "@types/node": "^26.4.0",
168
173
  "@types/react": "18.3.28",
169
174
  "@types/react-dom": "18.3.7",
170
175
  "eslint": "10.9.1",
171
176
  "jsdom": "^26.1.0",
177
+ "katex": "^0.16.47",
172
178
  "playwright": "1.62.1",
173
179
  "react": "18.3.1",
174
180
  "react-dom": "18.3.1",