@yadsh/dsh-qa-surface 0.6.1 → 0.7.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 (281) hide show
  1. package/README.md +136 -7
  2. package/capability-policy.json +1 -1
  3. package/lib/access/capability-catalog.js +144 -0
  4. package/lib/access/capability-catalog.js.map +1 -0
  5. package/lib/access/model.js +379 -0
  6. package/lib/access/model.js.map +1 -0
  7. package/lib/access/role-repository.js +195 -0
  8. package/lib/access/role-repository.js.map +1 -0
  9. package/lib/access/service.js +380 -0
  10. package/lib/access/service.js.map +1 -0
  11. package/lib/access/skill-metadata.js +234 -0
  12. package/lib/access/skill-metadata.js.map +1 -0
  13. package/lib/account-remotes.js +20 -10
  14. package/lib/account-remotes.js.map +1 -1
  15. package/lib/accounts/errors.js.map +1 -1
  16. package/lib/accounts/file.js.map +1 -1
  17. package/lib/accounts/store.js +202 -3
  18. package/lib/accounts/store.js.map +1 -1
  19. package/lib/admin/conversation-log.js +256 -0
  20. package/lib/admin/conversation-log.js.map +1 -0
  21. package/lib/admin/index.js +17 -0
  22. package/lib/admin/index.js.map +1 -0
  23. package/lib/admin/metrics.js +103 -0
  24. package/lib/admin/metrics.js.map +1 -0
  25. package/lib/admin/paging.js +23 -0
  26. package/lib/admin/paging.js.map +1 -0
  27. package/lib/admin/permissions.js +50 -0
  28. package/lib/admin/permissions.js.map +1 -0
  29. package/lib/admin/quality-store.js +485 -0
  30. package/lib/admin/quality-store.js.map +1 -0
  31. package/lib/admin/queue.js +107 -0
  32. package/lib/admin/queue.js.map +1 -0
  33. package/lib/admin/redaction.js +45 -0
  34. package/lib/admin/redaction.js.map +1 -0
  35. package/lib/admin/service.js +897 -0
  36. package/lib/admin/service.js.map +1 -0
  37. package/lib/admin/session-log.js +142 -0
  38. package/lib/admin/session-log.js.map +1 -0
  39. package/lib/cli.js +9 -6
  40. package/lib/cli.js.map +1 -1
  41. package/lib/client/QaSessionController.js +28 -2
  42. package/lib/client/QaSessionController.js.map +1 -1
  43. package/lib/client/QaSurface.js +143 -5
  44. package/lib/client/QaSurface.js.map +1 -1
  45. package/lib/client/QaTranscriptAdapter.js +1 -0
  46. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  47. package/lib/client/admin/QaAdmin.js +458 -0
  48. package/lib/client/admin/QaAdmin.js.map +1 -0
  49. package/lib/client/admin/format.js +177 -0
  50. package/lib/client/admin/format.js.map +1 -0
  51. package/lib/client/admin/pages/Conversations.js +114 -0
  52. package/lib/client/admin/pages/Conversations.js.map +1 -0
  53. package/lib/client/admin/pages/Overview.js +24 -0
  54. package/lib/client/admin/pages/Overview.js.map +1 -0
  55. package/lib/client/admin/pages/Quality.js +71 -0
  56. package/lib/client/admin/pages/Quality.js.map +1 -0
  57. package/lib/client/admin/pages/Review.js +93 -0
  58. package/lib/client/admin/pages/Review.js.map +1 -0
  59. package/lib/client/admin/pages/Users.js +95 -0
  60. package/lib/client/admin/pages/Users.js.map +1 -0
  61. package/lib/client/admin/routes.js +127 -0
  62. package/lib/client/admin/routes.js.map +1 -0
  63. package/lib/client/admin/shared.js +91 -0
  64. package/lib/client/admin/shared.js.map +1 -0
  65. package/lib/client/admin/styles.js +111 -0
  66. package/lib/client/admin/styles.js.map +1 -0
  67. package/lib/client/components/QaChangelog.js +35 -0
  68. package/lib/client/components/QaChangelog.js.map +1 -1
  69. package/lib/client/components/QaHeader.js +3 -3
  70. package/lib/client/components/QaHeader.js.map +1 -1
  71. package/lib/client/components/QaMessage.js +61 -2
  72. package/lib/client/components/QaMessage.js.map +1 -1
  73. package/lib/client/create-session.js +1 -1
  74. package/lib/client/create-session.js.map +1 -1
  75. package/lib/client/index.js +33 -1
  76. package/lib/client/index.js.map +1 -1
  77. package/lib/client/role/RoleSelector.js +31 -0
  78. package/lib/client/role/RoleSelector.js.map +1 -0
  79. package/lib/client/session-sources.js +37 -1
  80. package/lib/client/session-sources.js.map +1 -1
  81. package/lib/client/settings/card.js +2 -2
  82. package/lib/client/settings/card.js.map +1 -1
  83. package/lib/client/settings/sections.js +0 -1
  84. package/lib/client/settings/sections.js.map +1 -1
  85. package/lib/client/styles.js +31 -0
  86. package/lib/client/styles.js.map +1 -1
  87. package/lib/client/types.js.map +1 -1
  88. package/lib/client.js +9908 -4857
  89. package/lib/client.js.map +1 -1
  90. package/lib/config-resolvers/defaults.js +0 -2
  91. package/lib/config-resolvers/defaults.js.map +1 -1
  92. package/lib/config.js +0 -249
  93. package/lib/config.js.map +1 -1
  94. package/lib/enforcement/skill-policy.js +172 -0
  95. package/lib/enforcement/skill-policy.js.map +1 -0
  96. package/lib/enforcement/tool-grants.js +151 -0
  97. package/lib/enforcement/tool-grants.js.map +1 -0
  98. package/lib/index.js +224 -42
  99. package/lib/index.js.map +1 -1
  100. package/lib/personal-skills/service.js +10 -3
  101. package/lib/personal-skills/service.js.map +1 -1
  102. package/lib/qa-tools/index.js +4 -0
  103. package/lib/qa-tools/index.js.map +1 -1
  104. package/lib/resolve-config.js +0 -2
  105. package/lib/resolve-config.js.map +1 -1
  106. package/lib/secure-session.js +71 -17
  107. package/lib/secure-session.js.map +1 -1
  108. package/lib/typert.host.js +2237 -202
  109. package/lib/typert.remote-client.d.ts +49 -3
  110. package/lib/typert.remote-client.js +1863 -183
  111. package/lib/types/access/capability-catalog.d.ts +37 -0
  112. package/lib/types/access/model.d.ts +60 -0
  113. package/lib/types/access/role-repository.d.ts +32 -0
  114. package/lib/types/access/service.d.ts +57 -0
  115. package/lib/types/access/skill-metadata.d.ts +53 -0
  116. package/lib/types/account-remotes.d.ts +6 -0
  117. package/lib/types/accounts/errors.d.ts +1 -1
  118. package/lib/types/accounts/file.d.ts +16 -5
  119. package/lib/types/accounts/store.d.ts +83 -3
  120. package/lib/types/admin/conversation-log.d.ts +39 -0
  121. package/lib/types/admin/index.d.ts +24 -0
  122. package/lib/types/admin/metrics.d.ts +29 -0
  123. package/lib/types/admin/paging.d.ts +33 -0
  124. package/lib/types/admin/permissions.d.ts +10 -0
  125. package/lib/types/admin/quality-store.d.ts +82 -0
  126. package/lib/types/admin/queue.d.ts +21 -0
  127. package/lib/types/admin/redaction.d.ts +29 -0
  128. package/lib/types/admin/service.d.ts +105 -0
  129. package/lib/types/admin/session-log.d.ts +53 -0
  130. package/lib/types/client/QaSessionController.d.ts +12 -1
  131. package/lib/types/client/QaSurface.d.ts +7 -1
  132. package/lib/types/client/admin/QaAdmin.d.ts +17 -0
  133. package/lib/types/client/admin/format.d.ts +43 -0
  134. package/lib/types/client/admin/pages/Conversations.d.ts +21 -0
  135. package/lib/types/client/admin/pages/Overview.d.ts +13 -0
  136. package/lib/types/client/admin/pages/Quality.d.ts +18 -0
  137. package/lib/types/client/admin/pages/Review.d.ts +15 -0
  138. package/lib/types/client/admin/pages/Users.d.ts +22 -0
  139. package/lib/types/client/admin/routes.d.ts +50 -0
  140. package/lib/types/client/admin/shared.d.ts +53 -0
  141. package/lib/types/client/admin/styles.d.ts +11 -0
  142. package/lib/types/client/components/QaHeader.d.ts +5 -1
  143. package/lib/types/client/components/QaMessage.d.ts +14 -1
  144. package/lib/types/client/create-session.d.ts +2 -0
  145. package/lib/types/client/role/RoleSelector.d.ts +14 -0
  146. package/lib/types/client/session-sources.d.ts +9 -0
  147. package/lib/types/client/settings/sections.d.ts +0 -1
  148. package/lib/types/client/types.d.ts +39 -2
  149. package/lib/types/enforcement/skill-policy.d.ts +29 -0
  150. package/lib/types/enforcement/tool-grants.d.ts +84 -0
  151. package/lib/types/index.d.ts +62 -14
  152. package/lib/types/qa-tools/index.d.ts +2 -0
  153. package/lib/types/secure-session.d.ts +10 -1
  154. package/lib/types/types.d.ts +568 -5
  155. package/package.json +1 -1
  156. package/lib/client/settings/sections/documents.js +0 -88
  157. package/lib/client/settings/sections/documents.js.map +0 -1
  158. package/lib/documents/artifacts/ids.js +0 -43
  159. package/lib/documents/artifacts/ids.js.map +0 -1
  160. package/lib/documents/artifacts/manifest.js +0 -66
  161. package/lib/documents/artifacts/manifest.js.map +0 -1
  162. package/lib/documents/artifacts/store.js +0 -169
  163. package/lib/documents/artifacts/store.js.map +0 -1
  164. package/lib/documents/capabilities.js +0 -93
  165. package/lib/documents/capabilities.js.map +0 -1
  166. package/lib/documents/config.js +0 -302
  167. package/lib/documents/config.js.map +0 -1
  168. package/lib/documents/defaults.js +0 -78
  169. package/lib/documents/defaults.js.map +0 -1
  170. package/lib/documents/errors.js +0 -101
  171. package/lib/documents/errors.js.map +0 -1
  172. package/lib/documents/index.js +0 -80
  173. package/lib/documents/index.js.map +0 -1
  174. package/lib/documents/inspect/facts.js +0 -161
  175. package/lib/documents/inspect/facts.js.map +0 -1
  176. package/lib/documents/inspect/zip.js +0 -108
  177. package/lib/documents/inspect/zip.js.map +0 -1
  178. package/lib/documents/markdown/directives.js +0 -135
  179. package/lib/documents/markdown/directives.js.map +0 -1
  180. package/lib/documents/markdown/frontmatter.js +0 -35
  181. package/lib/documents/markdown/frontmatter.js.map +0 -1
  182. package/lib/documents/markdown/normalize.js +0 -113
  183. package/lib/documents/markdown/normalize.js.map +0 -1
  184. package/lib/documents/orchestrator/assets.js +0 -243
  185. package/lib/documents/orchestrator/assets.js.map +0 -1
  186. package/lib/documents/orchestrator/convert-document.js +0 -186
  187. package/lib/documents/orchestrator/convert-document.js.map +0 -1
  188. package/lib/documents/orchestrator/create-document.js +0 -292
  189. package/lib/documents/orchestrator/create-document.js.map +0 -1
  190. package/lib/documents/orchestrator/extract-document.js +0 -162
  191. package/lib/documents/orchestrator/extract-document.js.map +0 -1
  192. package/lib/documents/orchestrator/inspect-document.js +0 -89
  193. package/lib/documents/orchestrator/inspect-document.js.map +0 -1
  194. package/lib/documents/orchestrator/runtime-deps.js +0 -59
  195. package/lib/documents/orchestrator/runtime-deps.js.map +0 -1
  196. package/lib/documents/orchestrator/scope.js +0 -132
  197. package/lib/documents/orchestrator/scope.js.map +0 -1
  198. package/lib/documents/providers/docling.js +0 -247
  199. package/lib/documents/providers/docling.js.map +0 -1
  200. package/lib/documents/providers/libreoffice.js +0 -130
  201. package/lib/documents/providers/libreoffice.js.map +0 -1
  202. package/lib/documents/providers/markitdown.js +0 -89
  203. package/lib/documents/providers/markitdown.js.map +0 -1
  204. package/lib/documents/providers/pandoc.js +0 -161
  205. package/lib/documents/providers/pandoc.js.map +0 -1
  206. package/lib/documents/providers/process.js +0 -164
  207. package/lib/documents/providers/process.js.map +0 -1
  208. package/lib/documents/providers/registry.js +0 -152
  209. package/lib/documents/providers/registry.js.map +0 -1
  210. package/lib/documents/providers/shared.js +0 -75
  211. package/lib/documents/providers/shared.js.map +0 -1
  212. package/lib/documents/runtime.js +0 -114
  213. package/lib/documents/runtime.js.map +0 -1
  214. package/lib/documents/security/file-types.js +0 -188
  215. package/lib/documents/security/file-types.js.map +0 -1
  216. package/lib/documents/security/limits.js +0 -78
  217. package/lib/documents/security/limits.js.map +0 -1
  218. package/lib/documents/security/mime.js +0 -43
  219. package/lib/documents/security/mime.js.map +0 -1
  220. package/lib/documents/security/paths.js +0 -133
  221. package/lib/documents/security/paths.js.map +0 -1
  222. package/lib/documents/templates/registry.js +0 -147
  223. package/lib/documents/templates/registry.js.map +0 -1
  224. package/lib/documents/templates/resolver.js +0 -59
  225. package/lib/documents/templates/resolver.js.map +0 -1
  226. package/lib/documents/tools/convert.js +0 -125
  227. package/lib/documents/tools/convert.js.map +0 -1
  228. package/lib/documents/tools/create.js +0 -187
  229. package/lib/documents/tools/create.js.map +0 -1
  230. package/lib/documents/tools/index.js +0 -41
  231. package/lib/documents/tools/index.js.map +0 -1
  232. package/lib/documents/tools/inspect.js +0 -135
  233. package/lib/documents/tools/inspect.js.map +0 -1
  234. package/lib/documents/tools/shared.js +0 -88
  235. package/lib/documents/tools/shared.js.map +0 -1
  236. package/lib/documents/tools/to-markdown.js +0 -125
  237. package/lib/documents/tools/to-markdown.js.map +0 -1
  238. package/lib/documents/types.js +0 -12
  239. package/lib/documents/types.js.map +0 -1
  240. package/lib/types/client/settings/sections/documents.d.ts +0 -13
  241. package/lib/types/documents/artifacts/ids.d.ts +0 -14
  242. package/lib/types/documents/artifacts/manifest.d.ts +0 -32
  243. package/lib/types/documents/artifacts/store.d.ts +0 -67
  244. package/lib/types/documents/capabilities.d.ts +0 -32
  245. package/lib/types/documents/config.d.ts +0 -27
  246. package/lib/types/documents/defaults.d.ts +0 -161
  247. package/lib/types/documents/errors.d.ts +0 -42
  248. package/lib/types/documents/index.d.ts +0 -63
  249. package/lib/types/documents/inspect/facts.d.ts +0 -43
  250. package/lib/types/documents/inspect/zip.d.ts +0 -28
  251. package/lib/types/documents/markdown/directives.d.ts +0 -39
  252. package/lib/types/documents/markdown/frontmatter.d.ts +0 -15
  253. package/lib/types/documents/markdown/normalize.d.ts +0 -30
  254. package/lib/types/documents/orchestrator/assets.d.ts +0 -55
  255. package/lib/types/documents/orchestrator/convert-document.d.ts +0 -25
  256. package/lib/types/documents/orchestrator/create-document.d.ts +0 -18
  257. package/lib/types/documents/orchestrator/extract-document.d.ts +0 -24
  258. package/lib/types/documents/orchestrator/inspect-document.d.ts +0 -12
  259. package/lib/types/documents/orchestrator/runtime-deps.d.ts +0 -43
  260. package/lib/types/documents/orchestrator/scope.d.ts +0 -52
  261. package/lib/types/documents/providers/docling.d.ts +0 -54
  262. package/lib/types/documents/providers/libreoffice.d.ts +0 -40
  263. package/lib/types/documents/providers/markitdown.d.ts +0 -28
  264. package/lib/types/documents/providers/pandoc.d.ts +0 -42
  265. package/lib/types/documents/providers/process.d.ts +0 -54
  266. package/lib/types/documents/providers/registry.d.ts +0 -68
  267. package/lib/types/documents/providers/shared.d.ts +0 -27
  268. package/lib/types/documents/runtime.d.ts +0 -59
  269. package/lib/types/documents/security/file-types.d.ts +0 -39
  270. package/lib/types/documents/security/limits.d.ts +0 -24
  271. package/lib/types/documents/security/mime.d.ts +0 -13
  272. package/lib/types/documents/security/paths.d.ts +0 -38
  273. package/lib/types/documents/templates/registry.d.ts +0 -50
  274. package/lib/types/documents/templates/resolver.d.ts +0 -30
  275. package/lib/types/documents/tools/convert.d.ts +0 -9
  276. package/lib/types/documents/tools/create.d.ts +0 -14
  277. package/lib/types/documents/tools/index.d.ts +0 -33
  278. package/lib/types/documents/tools/inspect.d.ts +0 -9
  279. package/lib/types/documents/tools/shared.d.ts +0 -77
  280. package/lib/types/documents/tools/to-markdown.d.ts +0 -12
  281. package/lib/types/documents/types.d.ts +0 -294
package/README.md CHANGED
@@ -22,6 +22,9 @@ Session and Agent Loop.
22
22
  - pins locked sessions to the configured `read-only` or isolated
23
23
  `workspace-write` policy plus `approval=never` before Send is enabled;
24
24
  - applies a Host-side tool allow-list plus a monotonic execution guard;
25
+ - separates account authorization (`admin`/`user`) from the QA agent's active
26
+ subrole, with server-owned Common, per-role Tools and Skills, immutable
27
+ session snapshots, and a dedicated administration page at `/qa/admin`;
25
28
  - attaches its own QA tool catalog per agent only after the activation skill
26
29
  loads (`tools.dynamicActivation`), keeping every QA schema out of the initial
27
30
  request and restoring the catalog on resume from the session's own journal;
@@ -44,14 +47,17 @@ Session and Agent Loop.
44
47
  - ships an operator settings card (Settings → Plugins → plugin configuration →
45
48
  «Помощник QA») that edits the `qa-surface` namespace in place — route,
46
49
  branding, session, interface, lockdown, accounts, sources, attachments,
47
- documents, embedding — and reports the configuration the running Host
50
+ embedding — and reports the configuration the running Host
48
51
  resolved;
49
- - registers four document tools (`document_create`, `document_to_markdown`,
50
- `document_convert`, `document_inspect`) behind `documents.enabled`: the agent
51
- writes Markdown and receives DOCX/PDF, or hands over a DOCX/PDF and receives
52
- Markdown, while the pipeline owns every backend command line, keeps source,
53
- assets, outputs and a manifest in one artifact bundle, and is visible to a QA
54
- chat only through the tool allow-list;
52
+ - no longer owns the document pipeline: `document_create`,
53
+ `document_to_markdown`, `document_from_url`, `document_convert` and
54
+ `document_inspect` come from [`@yadsh/dsh-documents`](https://github.com/xarleyn/dsh-plugins/tree/main/plugins/dsh-documents#readme),
55
+ which a QA chat reaches exactly as before — same tool names, same allow-list
56
+ entry, same artifact layout. What moved with it is the configuration: the
57
+ pipeline is configured in that plugin's own `documents` namespace and card
58
+ (`QA_DOCUMENTS_*` environment variables became `DSH_DOCUMENTS_*`), and a
59
+ leftover `documents:` section under `qa-surface` is ignored with a
60
+ `documents.moved` warning in the Host log;
55
61
  - uses the existing same-origin DSH connection and trust boundary.
56
62
 
57
63
  It does not add another HTTP server, provider proxy, permissive CORS rule, or
@@ -662,6 +668,129 @@ Host-installed integration plugins may add their own narrowly scoped tool names
662
668
  through the QA Surface service; those executors must independently resolve the
663
669
  owner-attested root principal and fail closed for unowned or child sessions.
664
670
 
671
+ ## Subroles and capability policies
672
+
673
+ With `accounts.enabled: true`, every QA session has exactly one active agent
674
+ subrole. The Host resolves its effective capabilities as the union of the
675
+ minimal system-required set, Common capabilities, and that one subrole; it
676
+ never unions all roles assigned to the user. The chosen role and effective
677
+ snapshot are stored with session ownership. Existing conversations never gain
678
+ new capabilities after an administrator edits a role, while a capability that
679
+ disappears from the running registry is revoked immediately.
680
+
681
+ Administrators manage subroles, Common Tools/Skills, user assignments and the
682
+ audit trail at `/qa/admin`. Capability choices come from the live tool and
683
+ skill registries; configured-but-missing entries remain visible and are not
684
+ deleted. Admin authorization affects only the management API and never grants
685
+ agent capabilities. `Preview as role` creates an ordinary session using the
686
+ selected role's real server-enforced policy and shows a persistent preview
687
+ banner.
688
+
689
+ The configuration lives in `$DSH_HOME/qa-capability-policies.json`; user
690
+ assignments and session snapshots stay with the existing account store. Tools
691
+ are filtered with an agent-scoped restriction and a pre-execution gate. Skills
692
+ use an agent-scoped `skill` consumer that publishes only the allow-listed
693
+ catalog and rejects direct out-of-policy loads with `SKILL_NOT_AVAILABLE`.
694
+ The browser selector is hidden for a single assigned role. Switching roles
695
+ after a meaningful turn requires confirmation and creates a new conversation.
696
+
697
+ ### Tools that arrive with a skill
698
+
699
+ A role's tools are split into two classes. `always` tools are visible from the
700
+ first model step. `skillGrantable` tools are a ceiling, not a grant: they stay
701
+ out of the model's tool list until an activated skill requires them, which
702
+ keeps a large catalog such as browser automation out of every step of every
703
+ conversation. An older flat `tools: []` list is read as `always`, so an
704
+ upgraded deployment never hands out more than it did before.
705
+
706
+ ### Skills declare their own audience
707
+
708
+ A skill describes itself inside the ordinary `metadata` block of its
709
+ `SKILL.md`, so the file stays a valid Agent Skill outside a QA deployment and
710
+ no upstream schema is forked:
711
+
712
+ ```yaml
713
+ ---
714
+ name: browser-research
715
+ description: Research websites through browser automation
716
+
717
+ metadata:
718
+ qa-surface:
719
+ version: 1
720
+ audience:
721
+ type: subroles # or: type: common
722
+ include: [analyst, presales]
723
+ tools:
724
+ requires: [browser_open, browser_click]
725
+ grant:
726
+ lifecycle: session # the only lifecycle in v1
727
+ requireAll: true
728
+ ---
729
+ ```
730
+
731
+ The audience decides visibility; the role ceiling decides what a skill may ever
732
+ receive. A load intersects the two, so a skill cannot widen its own access. A
733
+ skill that declares nothing stays `Unassigned` until an administrator assigns
734
+ it, which is safer than treating every new skill as Common.
735
+
736
+ Loading the instructions and widening the toolset is one operation. A strict
737
+ skill (`requireAll: true`) refuses to activate when one of its tools is
738
+ unavailable, and a best-effort skill activates with a visible warning that
739
+ names what it did not receive. The model's `skill` call and a typed
740
+ `/skill-name` activate the same grant; a `/name` naming a skill outside the
741
+ subrole is withdrawn before the step is assembled. Grants last for the current
742
+ agent, and several loaded skills union their tools — activating a second skill
743
+ never revokes what the first one still holds.
744
+
745
+ Administrators edit assignments as an overlay, never by rewriting `SKILL.md`: a
746
+ role can be added to or withdrawn from a declared audience, a skill can be
747
+ forced on for every role or disabled outright, and the Skills page shows the
748
+ declared audience next to the effective one with a
749
+ `Healthy`/`Degraded`/`Blocked` state. Every activation is recorded on the
750
+ session record with the requested, granted and denied tools, so a later review
751
+ can see what a conversation actually gained.
752
+ ## Administrative console
753
+
754
+ `/qa/admin` is the review and administration surface. It is part of the QA page
755
+ itself, not a separate application, and it is open to `admin` and `reviewer`
756
+ accounts. Reviewer sees conversations, the review queue, feedback and
757
+ analytics; only an administrator sees users, capability policies and audit.
758
+
759
+ The console covers the quality loop end to end:
760
+
761
+ - **Overview** — conversation, rating and review counters, the items that need
762
+ attention, and the newest signals.
763
+ - **Users** — authorization role, enabled/disabled status, assigned QA subroles
764
+ and the default one, plus per-account activity. Disabling an account is the
765
+ operation to reach for: historical conversations, feedback and reviews stay
766
+ attributed to their author, and the last enabled administrator cannot be
767
+ demoted, disabled or removed.
768
+ - **Conversations** — every conversation the deployment knows, filterable by
769
+ user, subrole, date range, rating and review state, with a viewer that reads
770
+ the stored transcript: messages in recorded order, tool calls with their
771
+ arguments, results and errors, per-message feedback, and the capability
772
+ snapshot frozen when the session started. A link can point at one message
773
+ (`/qa/admin/conversations/<id>/<seq>`).
774
+ - **Review queue** — what needs attention, derived from unanswered negative
775
+ feedback, explicitly queued conversations and failed tool calls. A reviewer
776
+ classifies issues across answer, context, tools, skills and access, sets a
777
+ severity, writes notes and names the remediation target.
778
+ - **Feedback** — every rating against the exact answer it judged, with the
779
+ optional reason and comment the user gave.
780
+ - **Analytics** — rating coverage, positive share overall and per subrole,
781
+ issue distribution and a daily trend. These are user-satisfaction signals;
782
+ the console never presents them as accuracy.
783
+ - **Audit** — one timeline of authorization changes, account status, subrole
784
+ assignments, policy edits and review verdicts, each with its before/after
785
+ image.
786
+
787
+ Authorization is a permission table, not an `isAdmin` flag, and every
788
+ administrative entry point names the permission it needs; the Host re-checks it
789
+ on the call it serves, so a hidden control is convenience rather than the
790
+ boundary. Review material is the most sensitive data the package handles, so
791
+ tool arguments and results are bounded previews with credential shapes masked,
792
+ behind a redactor a deployment can replace.
793
+
665
794
  ## Security and deployment
666
795
 
667
796
  `/qa` is a presentation boundary, not an authentication boundary. Protect it
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "version": 1,
3
- "description": "Reviewed capabilities in the shipped default QA tool allow-list.",
3
+ "description": "Minimal system-required tools inherited by every QA subrole. Common and role-specific grants are managed in /qa/admin.",
4
4
  "tools": []
5
5
  }
@@ -0,0 +1,144 @@
1
+ import { parseQaSkillMetadata } from "./skill-metadata.js";
2
+ function toolSource(name) {
3
+ if (name.startsWith("mcp__")) {
4
+ const server = name.slice(5).split("__", 1)[0];
5
+ return { kind: "mcp", ...(server === "" ? {} : { name: server }) };
6
+ }
7
+ if (name.startsWith("qa_") || name.startsWith("document_")) {
8
+ return { kind: "plugin", name: "dsh-qa-surface" };
9
+ }
10
+ return { kind: "core" };
11
+ }
12
+ function skillSource(skill) {
13
+ const kind = skill.provider.includes("filesystem") || skill.source.includes("project")
14
+ ? "filesystem"
15
+ : skill.source === "runtime"
16
+ ? "runtime"
17
+ : "plugin";
18
+ return { kind, name: skill.provider || skill.source };
19
+ }
20
+ /** Read-only adapter over the current DSH registries. */
21
+ export class QaCapabilityCatalog {
22
+ ctx;
23
+ additionalToolNames;
24
+ knownSubroles;
25
+ constructor(ctx, additionalToolNames = () => [],
26
+ /** Role ids used to report unknown subrole ids in skill metadata. */
27
+ knownSubroles = () => []) {
28
+ this.ctx = ctx;
29
+ this.additionalToolNames = additionalToolNames;
30
+ this.knownSubroles = knownSubroles;
31
+ }
32
+ async snapshot(agent) {
33
+ const toolDescriptors = this.ctx.tools
34
+ .schemas(agent)
35
+ .map((schema) => ({
36
+ type: "tool",
37
+ id: schema.name,
38
+ title: schema.name,
39
+ ...(schema.description === undefined
40
+ ? {}
41
+ : { description: schema.description }),
42
+ source: toolSource(schema.name),
43
+ status: "available",
44
+ }));
45
+ const mountedToolIds = new Set(toolDescriptors.map(({ id }) => id));
46
+ for (const id of this.additionalToolNames()) {
47
+ if (mountedToolIds.has(id))
48
+ continue;
49
+ mountedToolIds.add(id);
50
+ toolDescriptors.push({
51
+ type: "tool",
52
+ id,
53
+ title: id,
54
+ source: toolSource(id),
55
+ status: "available",
56
+ });
57
+ }
58
+ const registry = this.ctx.get("skills");
59
+ const lookup = {
60
+ ...(agent === undefined ? {} : { scope: agent }),
61
+ ...(agent?.session.header.cwd === undefined
62
+ ? {}
63
+ : { cwd: agent.session.header.cwd }),
64
+ };
65
+ const skillList = registry === undefined ? [] : (await registry.snapshot(lookup)).skills;
66
+ const skills = new Map(skillList.map((skill) => [skill.name, skill]));
67
+ const skillDescriptors = skillList.map((skill) => ({
68
+ type: "skill",
69
+ id: skill.name,
70
+ title: skill.name,
71
+ description: skill.description,
72
+ source: skillSource(skill),
73
+ status: "available",
74
+ modelInvocable: skill.invocation.modelInvocable,
75
+ userInvocable: skill.invocation.userInvocable,
76
+ }));
77
+ const descriptors = [...toolDescriptors, ...skillDescriptors].sort((left, right) => left.type.localeCompare(right.type) || left.id.localeCompare(right.id));
78
+ return Object.freeze({
79
+ descriptors: Object.freeze(descriptors),
80
+ toolIds: new Set(toolDescriptors.map(({ id }) => id)),
81
+ skillIds: new Set(skillList
82
+ .filter(({ invocation }) => invocation.modelInvocable)
83
+ .map(({ name }) => name)),
84
+ userSkillIds: new Set(skillList
85
+ .filter(({ invocation }) => invocation.userInvocable)
86
+ .map(({ name }) => name)),
87
+ skills,
88
+ skillMetadata: registry === undefined
89
+ ? new Map()
90
+ : await this.readSkillMetadata(registry, skillList, lookup),
91
+ });
92
+ }
93
+ /**
94
+ * Read `metadata.qa-surface` of every discovered skill.
95
+ *
96
+ * The registry exposes metadata on loaded definitions only, so discovery has
97
+ * to fetch each body once. A provider that fails or a skill that disappears
98
+ * between the two reads degrades to the fail-closed descriptor instead of
99
+ * failing the whole catalog.
100
+ */
101
+ async readSkillMetadata(registry, skillList, lookup) {
102
+ const known = new Set(this.knownSubroles());
103
+ const metadata = new Map();
104
+ for (const skill of skillList) {
105
+ let definition;
106
+ try {
107
+ definition = await registry.get(skill.name, lookup);
108
+ }
109
+ catch {
110
+ definition = undefined;
111
+ }
112
+ metadata.set(skill.name, parseQaSkillMetadata(skill.name, definition?.metadata, known));
113
+ }
114
+ return metadata;
115
+ }
116
+ }
117
+ export function withMissingCapabilities(descriptors, configuredTools, configuredSkills) {
118
+ const keys = new Set(descriptors.map(({ type, id }) => `${type}:${id}`));
119
+ const missing = [];
120
+ for (const id of configuredTools) {
121
+ if (!keys.has(`tool:${id}`)) {
122
+ missing.push({
123
+ type: "tool",
124
+ id,
125
+ title: id,
126
+ source: { kind: "plugin" },
127
+ status: "missing",
128
+ });
129
+ }
130
+ }
131
+ for (const id of configuredSkills) {
132
+ if (!keys.has(`skill:${id}`)) {
133
+ missing.push({
134
+ type: "skill",
135
+ id,
136
+ title: id,
137
+ source: { kind: "plugin" },
138
+ status: "missing",
139
+ });
140
+ }
141
+ }
142
+ return Object.freeze([...descriptors, ...missing]);
143
+ }
144
+ //# sourceMappingURL=capability-catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-catalog.js","sourceRoot":"","sources":["../../src/access/capability-catalog.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAc3D,SAAS,UAAU,CAAC,IAAY;IAI9B,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/C,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IACrE,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC3D,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;IACpD,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1B,CAAC;AAED,SAAS,WAAW,CAAC,KAAmB;IACtC,MAAM,IAAI,GACR,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;QACvE,CAAC,CAAC,YAAY;QACd,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS;YAC1B,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,QAAQ,CAAC;IACjB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;AACxD,CAAC;AAED,yDAAyD;AACzD,MAAM,OAAO,mBAAmB;IAEX,GAAG;IACH,mBAAmB;IAEnB,aAAa;IAJhC,YACmB,GAAY,EACZ,mBAAmB,GAA4B,GAAG,EAAE,CAAC,EAAE;IACxE,qEAAqE;IACpD,aAAa,GAA4B,GAAG,EAAE,CAAC,EAAE;mBAHjD,GAAG;mCACH,mBAAmB;6BAEnB,aAAa;IAC7B,CAAC;IAEJ,KAAK,CAAC,QAAQ,CAAC,KAAa;QAC1B,MAAM,eAAe,GAA6B,IAAI,CAAC,GAAG,CAAC,KAAK;aAC7D,OAAO,CAAC,KAAK,CAAC;aACd,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAChB,IAAI,EAAE,MAAe;YACrB,EAAE,EAAE,MAAM,CAAC,IAAI;YACf,KAAK,EAAE,MAAM,CAAC,IAAI;YAClB,GAAG,CAAC,MAAM,CAAC,WAAW,KAAK,SAAS;gBAClC,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;YACxC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC;YAC/B,MAAM,EAAE,WAAoB;SAC7B,CAAC,CAAC,CAAC;QACN,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACpE,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,mBAAmB,EAAE,EAAE,CAAC;YAC5C,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,SAAS;YACrC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACvB,eAAe,CAAC,IAAI,CAAC;gBACnB,IAAI,EAAE,MAAM;gBACZ,EAAE;gBACF,KAAK,EAAE,EAAE;gBACT,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC;gBACtB,MAAM,EAAE,WAAW;aACpB,CAAC,CAAC;QACL,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAkC,CAAC;QACzE,MAAM,MAAM,GAAG;YACb,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;YAChD,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,KAAK,SAAS;gBACzC,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;SACvC,CAAC;QACF,MAAM,SAAS,GACb,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;QACzE,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QACtE,MAAM,gBAAgB,GAA6B,SAAS,CAAC,GAAG,CAC9D,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACV,IAAI,EAAE,OAAO;YACb,EAAE,EAAE,KAAK,CAAC,IAAI;YACd,KAAK,EAAE,KAAK,CAAC,IAAI;YACjB,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC;YAC1B,MAAM,EAAE,WAAW;YACnB,cAAc,EAAE,KAAK,CAAC,UAAU,CAAC,cAAc;YAC/C,aAAa,EAAE,KAAK,CAAC,UAAU,CAAC,aAAa;SAC9C,CAAC,CACH,CAAC;QACF,MAAM,WAAW,GAAG,CAAC,GAAG,eAAe,EAAE,GAAG,gBAAgB,CAAC,CAAC,IAAI,CAChE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CACd,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CACzE,CAAC;QACF,OAAO,MAAM,CAAC,MAAM,CAAC;YACnB,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC;YACvC,OAAO,EAAE,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;YACrD,QAAQ,EAAE,IAAI,GAAG,CACf,SAAS;iBACN,MAAM,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC;iBACrD,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAC3B;YACD,YAAY,EAAE,IAAI,GAAG,CACnB,SAAS;iBACN,MAAM,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC;iBACpD,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAC3B;YACD,MAAM;YACN,aAAa,EACX,QAAQ,KAAK,SAAS;gBACpB,CAAC,CAAC,IAAI,GAAG,EAA6B;gBACtC,CAAC,CAAC,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC;SAChE,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACK,KAAK,CAAC,iBAAiB,CAC7B,QAA2B,EAC3B,SAAkC,EAClC,MAAyD;QAEzD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA6B,CAAC;QACtD,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;YAC9B,IAAI,UAAyD,CAAC;YAC9D,IAAI,CAAC;gBACH,UAAU,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACtD,CAAC;YAAC,MAAM,CAAC;gBACP,UAAU,GAAG,SAAS,CAAC;YACzB,CAAC;YACD,QAAQ,CAAC,GAAG,CACV,KAAK,CAAC,IAAI,EACV,oBAAoB,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,CAC9D,CAAC;QACJ,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AAED,MAAM,UAAU,uBAAuB,CACrC,WAA8C,EAC9C,eAAkC,EAClC,gBAAmC;IAEnC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACzE,MAAM,OAAO,GAA6B,EAAE,CAAC;IAC7C,KAAK,MAAM,EAAE,IAAI,eAAe,EAAE,CAAC;QACjC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,MAAM;gBACZ,EAAE;gBACF,KAAK,EAAE,EAAE;gBACT,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC1B,MAAM,EAAE,SAAS;aAClB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,KAAK,MAAM,EAAE,IAAI,gBAAgB,EAAE,CAAC;QAClC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,OAAO;gBACb,EAAE;gBACF,KAAK,EAAE,EAAE;gBACT,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC1B,MAAM,EAAE,SAAS;aAClB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,WAAW,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC;AACrD,CAAC"}