@yadsh/dsh-qa-surface 0.6.0 → 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 (292) hide show
  1. package/README.md +148 -9
  2. package/capability-policy.json +1 -1
  3. package/cordis.patch.yml +2 -1
  4. package/lib/access/capability-catalog.js +144 -0
  5. package/lib/access/capability-catalog.js.map +1 -0
  6. package/lib/access/model.js +379 -0
  7. package/lib/access/model.js.map +1 -0
  8. package/lib/access/role-repository.js +195 -0
  9. package/lib/access/role-repository.js.map +1 -0
  10. package/lib/access/service.js +380 -0
  11. package/lib/access/service.js.map +1 -0
  12. package/lib/access/skill-metadata.js +234 -0
  13. package/lib/access/skill-metadata.js.map +1 -0
  14. package/lib/account-remotes.js +20 -10
  15. package/lib/account-remotes.js.map +1 -1
  16. package/lib/accounts/errors.js.map +1 -1
  17. package/lib/accounts/file.js.map +1 -1
  18. package/lib/accounts/store.js +202 -3
  19. package/lib/accounts/store.js.map +1 -1
  20. package/lib/admin/conversation-log.js +256 -0
  21. package/lib/admin/conversation-log.js.map +1 -0
  22. package/lib/admin/index.js +17 -0
  23. package/lib/admin/index.js.map +1 -0
  24. package/lib/admin/metrics.js +103 -0
  25. package/lib/admin/metrics.js.map +1 -0
  26. package/lib/admin/paging.js +23 -0
  27. package/lib/admin/paging.js.map +1 -0
  28. package/lib/admin/permissions.js +50 -0
  29. package/lib/admin/permissions.js.map +1 -0
  30. package/lib/admin/quality-store.js +485 -0
  31. package/lib/admin/quality-store.js.map +1 -0
  32. package/lib/admin/queue.js +107 -0
  33. package/lib/admin/queue.js.map +1 -0
  34. package/lib/admin/redaction.js +45 -0
  35. package/lib/admin/redaction.js.map +1 -0
  36. package/lib/admin/service.js +897 -0
  37. package/lib/admin/service.js.map +1 -0
  38. package/lib/admin/session-log.js +142 -0
  39. package/lib/admin/session-log.js.map +1 -0
  40. package/lib/attestation.js +6 -0
  41. package/lib/attestation.js.map +1 -1
  42. package/lib/cli.js +9 -6
  43. package/lib/cli.js.map +1 -1
  44. package/lib/client/QaSessionController.js +65 -15
  45. package/lib/client/QaSessionController.js.map +1 -1
  46. package/lib/client/QaSurface.js +144 -6
  47. package/lib/client/QaSurface.js.map +1 -1
  48. package/lib/client/QaTranscriptAdapter.js +1 -0
  49. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  50. package/lib/client/admin/QaAdmin.js +458 -0
  51. package/lib/client/admin/QaAdmin.js.map +1 -0
  52. package/lib/client/admin/format.js +177 -0
  53. package/lib/client/admin/format.js.map +1 -0
  54. package/lib/client/admin/pages/Conversations.js +114 -0
  55. package/lib/client/admin/pages/Conversations.js.map +1 -0
  56. package/lib/client/admin/pages/Overview.js +24 -0
  57. package/lib/client/admin/pages/Overview.js.map +1 -0
  58. package/lib/client/admin/pages/Quality.js +71 -0
  59. package/lib/client/admin/pages/Quality.js.map +1 -0
  60. package/lib/client/admin/pages/Review.js +93 -0
  61. package/lib/client/admin/pages/Review.js.map +1 -0
  62. package/lib/client/admin/pages/Users.js +95 -0
  63. package/lib/client/admin/pages/Users.js.map +1 -0
  64. package/lib/client/admin/routes.js +127 -0
  65. package/lib/client/admin/routes.js.map +1 -0
  66. package/lib/client/admin/shared.js +91 -0
  67. package/lib/client/admin/shared.js.map +1 -0
  68. package/lib/client/admin/styles.js +111 -0
  69. package/lib/client/admin/styles.js.map +1 -0
  70. package/lib/client/attestation.js +14 -2
  71. package/lib/client/attestation.js.map +1 -1
  72. package/lib/client/components/QaChangelog.js +48 -0
  73. package/lib/client/components/QaChangelog.js.map +1 -1
  74. package/lib/client/components/QaHeader.js +3 -3
  75. package/lib/client/components/QaHeader.js.map +1 -1
  76. package/lib/client/components/QaMessage.js +61 -2
  77. package/lib/client/components/QaMessage.js.map +1 -1
  78. package/lib/client/create-session.js +1 -1
  79. package/lib/client/create-session.js.map +1 -1
  80. package/lib/client/index.js +33 -1
  81. package/lib/client/index.js.map +1 -1
  82. package/lib/client/project-session-state.js +10 -5
  83. package/lib/client/project-session-state.js.map +1 -1
  84. package/lib/client/role/RoleSelector.js +31 -0
  85. package/lib/client/role/RoleSelector.js.map +1 -0
  86. package/lib/client/session-sources.js +37 -1
  87. package/lib/client/session-sources.js.map +1 -1
  88. package/lib/client/settings/card.js +2 -2
  89. package/lib/client/settings/card.js.map +1 -1
  90. package/lib/client/settings/sections.js +0 -1
  91. package/lib/client/settings/sections.js.map +1 -1
  92. package/lib/client/styles.js +32 -0
  93. package/lib/client/styles.js.map +1 -1
  94. package/lib/client/types.js +1 -0
  95. package/lib/client/types.js.map +1 -1
  96. package/lib/client.js +10786 -5684
  97. package/lib/client.js.map +1 -1
  98. package/lib/config-resolvers/defaults.js +0 -2
  99. package/lib/config-resolvers/defaults.js.map +1 -1
  100. package/lib/config.js +0 -249
  101. package/lib/config.js.map +1 -1
  102. package/lib/enforcement/skill-policy.js +172 -0
  103. package/lib/enforcement/skill-policy.js.map +1 -0
  104. package/lib/enforcement/tool-grants.js +151 -0
  105. package/lib/enforcement/tool-grants.js.map +1 -0
  106. package/lib/index.js +230 -44
  107. package/lib/index.js.map +1 -1
  108. package/lib/personal-skills/service.js +10 -3
  109. package/lib/personal-skills/service.js.map +1 -1
  110. package/lib/qa-tools/index.js +4 -0
  111. package/lib/qa-tools/index.js.map +1 -1
  112. package/lib/resolve-config.js +0 -2
  113. package/lib/resolve-config.js.map +1 -1
  114. package/lib/secure-session.js +111 -32
  115. package/lib/secure-session.js.map +1 -1
  116. package/lib/typert.host.js +2237 -202
  117. package/lib/typert.remote-client.d.ts +49 -3
  118. package/lib/typert.remote-client.js +1863 -183
  119. package/lib/types/access/capability-catalog.d.ts +37 -0
  120. package/lib/types/access/model.d.ts +60 -0
  121. package/lib/types/access/role-repository.d.ts +32 -0
  122. package/lib/types/access/service.d.ts +57 -0
  123. package/lib/types/access/skill-metadata.d.ts +53 -0
  124. package/lib/types/account-remotes.d.ts +6 -0
  125. package/lib/types/accounts/errors.d.ts +1 -1
  126. package/lib/types/accounts/file.d.ts +16 -5
  127. package/lib/types/accounts/store.d.ts +83 -3
  128. package/lib/types/admin/conversation-log.d.ts +39 -0
  129. package/lib/types/admin/index.d.ts +24 -0
  130. package/lib/types/admin/metrics.d.ts +29 -0
  131. package/lib/types/admin/paging.d.ts +33 -0
  132. package/lib/types/admin/permissions.d.ts +10 -0
  133. package/lib/types/admin/quality-store.d.ts +82 -0
  134. package/lib/types/admin/queue.d.ts +21 -0
  135. package/lib/types/admin/redaction.d.ts +29 -0
  136. package/lib/types/admin/service.d.ts +105 -0
  137. package/lib/types/admin/session-log.d.ts +53 -0
  138. package/lib/types/attestation.d.ts +2 -0
  139. package/lib/types/client/QaSessionController.d.ts +14 -1
  140. package/lib/types/client/QaSurface.d.ts +7 -1
  141. package/lib/types/client/admin/QaAdmin.d.ts +17 -0
  142. package/lib/types/client/admin/format.d.ts +43 -0
  143. package/lib/types/client/admin/pages/Conversations.d.ts +21 -0
  144. package/lib/types/client/admin/pages/Overview.d.ts +13 -0
  145. package/lib/types/client/admin/pages/Quality.d.ts +18 -0
  146. package/lib/types/client/admin/pages/Review.d.ts +15 -0
  147. package/lib/types/client/admin/pages/Users.d.ts +22 -0
  148. package/lib/types/client/admin/routes.d.ts +50 -0
  149. package/lib/types/client/admin/shared.d.ts +53 -0
  150. package/lib/types/client/admin/styles.d.ts +11 -0
  151. package/lib/types/client/attestation.d.ts +8 -1
  152. package/lib/types/client/components/QaHeader.d.ts +5 -1
  153. package/lib/types/client/components/QaMessage.d.ts +14 -1
  154. package/lib/types/client/create-session.d.ts +2 -0
  155. package/lib/types/client/project-session-state.d.ts +2 -0
  156. package/lib/types/client/role/RoleSelector.d.ts +14 -0
  157. package/lib/types/client/session-sources.d.ts +9 -0
  158. package/lib/types/client/settings/sections.d.ts +0 -1
  159. package/lib/types/client/types.d.ts +39 -2
  160. package/lib/types/enforcement/skill-policy.d.ts +29 -0
  161. package/lib/types/enforcement/tool-grants.d.ts +84 -0
  162. package/lib/types/index.d.ts +62 -14
  163. package/lib/types/qa-tools/index.d.ts +2 -0
  164. package/lib/types/secure-session.d.ts +19 -1
  165. package/lib/types/types.d.ts +574 -5
  166. package/package.json +3 -3
  167. package/lib/client/settings/sections/documents.js +0 -88
  168. package/lib/client/settings/sections/documents.js.map +0 -1
  169. package/lib/documents/artifacts/ids.js +0 -43
  170. package/lib/documents/artifacts/ids.js.map +0 -1
  171. package/lib/documents/artifacts/manifest.js +0 -66
  172. package/lib/documents/artifacts/manifest.js.map +0 -1
  173. package/lib/documents/artifacts/store.js +0 -169
  174. package/lib/documents/artifacts/store.js.map +0 -1
  175. package/lib/documents/capabilities.js +0 -93
  176. package/lib/documents/capabilities.js.map +0 -1
  177. package/lib/documents/config.js +0 -302
  178. package/lib/documents/config.js.map +0 -1
  179. package/lib/documents/defaults.js +0 -78
  180. package/lib/documents/defaults.js.map +0 -1
  181. package/lib/documents/errors.js +0 -101
  182. package/lib/documents/errors.js.map +0 -1
  183. package/lib/documents/index.js +0 -80
  184. package/lib/documents/index.js.map +0 -1
  185. package/lib/documents/inspect/facts.js +0 -161
  186. package/lib/documents/inspect/facts.js.map +0 -1
  187. package/lib/documents/inspect/zip.js +0 -108
  188. package/lib/documents/inspect/zip.js.map +0 -1
  189. package/lib/documents/markdown/directives.js +0 -135
  190. package/lib/documents/markdown/directives.js.map +0 -1
  191. package/lib/documents/markdown/frontmatter.js +0 -35
  192. package/lib/documents/markdown/frontmatter.js.map +0 -1
  193. package/lib/documents/markdown/normalize.js +0 -113
  194. package/lib/documents/markdown/normalize.js.map +0 -1
  195. package/lib/documents/orchestrator/assets.js +0 -243
  196. package/lib/documents/orchestrator/assets.js.map +0 -1
  197. package/lib/documents/orchestrator/convert-document.js +0 -186
  198. package/lib/documents/orchestrator/convert-document.js.map +0 -1
  199. package/lib/documents/orchestrator/create-document.js +0 -292
  200. package/lib/documents/orchestrator/create-document.js.map +0 -1
  201. package/lib/documents/orchestrator/extract-document.js +0 -162
  202. package/lib/documents/orchestrator/extract-document.js.map +0 -1
  203. package/lib/documents/orchestrator/inspect-document.js +0 -89
  204. package/lib/documents/orchestrator/inspect-document.js.map +0 -1
  205. package/lib/documents/orchestrator/runtime-deps.js +0 -59
  206. package/lib/documents/orchestrator/runtime-deps.js.map +0 -1
  207. package/lib/documents/orchestrator/scope.js +0 -132
  208. package/lib/documents/orchestrator/scope.js.map +0 -1
  209. package/lib/documents/providers/docling.js +0 -247
  210. package/lib/documents/providers/docling.js.map +0 -1
  211. package/lib/documents/providers/libreoffice.js +0 -130
  212. package/lib/documents/providers/libreoffice.js.map +0 -1
  213. package/lib/documents/providers/markitdown.js +0 -89
  214. package/lib/documents/providers/markitdown.js.map +0 -1
  215. package/lib/documents/providers/pandoc.js +0 -161
  216. package/lib/documents/providers/pandoc.js.map +0 -1
  217. package/lib/documents/providers/process.js +0 -164
  218. package/lib/documents/providers/process.js.map +0 -1
  219. package/lib/documents/providers/registry.js +0 -152
  220. package/lib/documents/providers/registry.js.map +0 -1
  221. package/lib/documents/providers/shared.js +0 -75
  222. package/lib/documents/providers/shared.js.map +0 -1
  223. package/lib/documents/runtime.js +0 -114
  224. package/lib/documents/runtime.js.map +0 -1
  225. package/lib/documents/security/file-types.js +0 -188
  226. package/lib/documents/security/file-types.js.map +0 -1
  227. package/lib/documents/security/limits.js +0 -78
  228. package/lib/documents/security/limits.js.map +0 -1
  229. package/lib/documents/security/mime.js +0 -43
  230. package/lib/documents/security/mime.js.map +0 -1
  231. package/lib/documents/security/paths.js +0 -133
  232. package/lib/documents/security/paths.js.map +0 -1
  233. package/lib/documents/templates/registry.js +0 -147
  234. package/lib/documents/templates/registry.js.map +0 -1
  235. package/lib/documents/templates/resolver.js +0 -59
  236. package/lib/documents/templates/resolver.js.map +0 -1
  237. package/lib/documents/tools/convert.js +0 -125
  238. package/lib/documents/tools/convert.js.map +0 -1
  239. package/lib/documents/tools/create.js +0 -187
  240. package/lib/documents/tools/create.js.map +0 -1
  241. package/lib/documents/tools/index.js +0 -41
  242. package/lib/documents/tools/index.js.map +0 -1
  243. package/lib/documents/tools/inspect.js +0 -135
  244. package/lib/documents/tools/inspect.js.map +0 -1
  245. package/lib/documents/tools/shared.js +0 -88
  246. package/lib/documents/tools/shared.js.map +0 -1
  247. package/lib/documents/tools/to-markdown.js +0 -125
  248. package/lib/documents/tools/to-markdown.js.map +0 -1
  249. package/lib/documents/types.js +0 -12
  250. package/lib/documents/types.js.map +0 -1
  251. package/lib/types/client/settings/sections/documents.d.ts +0 -13
  252. package/lib/types/documents/artifacts/ids.d.ts +0 -14
  253. package/lib/types/documents/artifacts/manifest.d.ts +0 -32
  254. package/lib/types/documents/artifacts/store.d.ts +0 -67
  255. package/lib/types/documents/capabilities.d.ts +0 -32
  256. package/lib/types/documents/config.d.ts +0 -27
  257. package/lib/types/documents/defaults.d.ts +0 -161
  258. package/lib/types/documents/errors.d.ts +0 -42
  259. package/lib/types/documents/index.d.ts +0 -63
  260. package/lib/types/documents/inspect/facts.d.ts +0 -43
  261. package/lib/types/documents/inspect/zip.d.ts +0 -28
  262. package/lib/types/documents/markdown/directives.d.ts +0 -39
  263. package/lib/types/documents/markdown/frontmatter.d.ts +0 -15
  264. package/lib/types/documents/markdown/normalize.d.ts +0 -30
  265. package/lib/types/documents/orchestrator/assets.d.ts +0 -55
  266. package/lib/types/documents/orchestrator/convert-document.d.ts +0 -25
  267. package/lib/types/documents/orchestrator/create-document.d.ts +0 -18
  268. package/lib/types/documents/orchestrator/extract-document.d.ts +0 -24
  269. package/lib/types/documents/orchestrator/inspect-document.d.ts +0 -12
  270. package/lib/types/documents/orchestrator/runtime-deps.d.ts +0 -43
  271. package/lib/types/documents/orchestrator/scope.d.ts +0 -52
  272. package/lib/types/documents/providers/docling.d.ts +0 -54
  273. package/lib/types/documents/providers/libreoffice.d.ts +0 -40
  274. package/lib/types/documents/providers/markitdown.d.ts +0 -28
  275. package/lib/types/documents/providers/pandoc.d.ts +0 -42
  276. package/lib/types/documents/providers/process.d.ts +0 -54
  277. package/lib/types/documents/providers/registry.d.ts +0 -68
  278. package/lib/types/documents/providers/shared.d.ts +0 -27
  279. package/lib/types/documents/runtime.d.ts +0 -59
  280. package/lib/types/documents/security/file-types.d.ts +0 -39
  281. package/lib/types/documents/security/limits.d.ts +0 -24
  282. package/lib/types/documents/security/mime.d.ts +0 -13
  283. package/lib/types/documents/security/paths.d.ts +0 -38
  284. package/lib/types/documents/templates/registry.d.ts +0 -50
  285. package/lib/types/documents/templates/resolver.d.ts +0 -30
  286. package/lib/types/documents/tools/convert.d.ts +0 -9
  287. package/lib/types/documents/tools/create.d.ts +0 -14
  288. package/lib/types/documents/tools/index.d.ts +0 -33
  289. package/lib/types/documents/tools/inspect.d.ts +0 -9
  290. package/lib/types/documents/tools/shared.d.ts +0 -77
  291. package/lib/types/documents/tools/to-markdown.d.ts +0 -12
  292. 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
@@ -591,8 +597,13 @@ grouped by owner. Switching re-runs the full policy
591
597
  attestation, and that attestation materializes the chat's agent when the Host
592
598
  does not hold one: DSH builds an agent on demand, so a chat restored after a
593
599
  Host restart still opens (its composition is resumed from what the session
594
- recorded) instead of failing as unavailable. A chat the Host no longer lists is
595
- pruned from the index. Each
600
+ recorded) instead of failing as unavailable. If that recorded agent preset,
601
+ workspace or model belongs to an older deployment configuration, the history
602
+ still opens in an explicit compatibility read-only mode. Send, stop, approvals
603
+ and questions stay disabled so the historical session cannot bypass the
604
+ current workspace or permission boundary; use New chat to continue under the
605
+ current configuration. A chat the Host no longer lists is pruned from the
606
+ index. Each
596
607
  row carries a two-click delete control that removes the chat from this
597
608
  browser's index; deleting the chat that is currently open continues in a
598
609
  fresh attested session. Host-side sessions are not deleted — DSH 0.1.x
@@ -614,6 +625,11 @@ shows it again. Other DSH routes retain the stock onboarding entry.
614
625
  The default locked mode requires a deployment permission preset named
615
626
  `qa-read-only`. Per-user writable mode uses a separate preset such as
616
627
  `qa-workspace-write`.
628
+ `interaction.approvals: interactive` does not change this requirement: it
629
+ parks an `ask` returned by a composed tool gate in the QA view, while the
630
+ permission preset must keep `approval: never` as the independent fail-closed
631
+ backstop. Setting the preset itself to `approval: ask` fails deployment
632
+ preflight with `(reason: permission-preset)` before a Host session is created.
617
633
  Extend the existing `@deepseek-ai/dsh-permission-presets` row without changing
618
634
  its process-wide default:
619
635
 
@@ -652,6 +668,129 @@ Host-installed integration plugins may add their own narrowly scoped tool names
652
668
  through the QA Surface service; those executors must independently resolve the
653
669
  owner-attested root principal and fail closed for unowned or child sessions.
654
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
+
655
794
  ## Security and deployment
656
795
 
657
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
  }
package/cordis.patch.yml CHANGED
@@ -11,7 +11,8 @@
11
11
  showReset: false
12
12
  # Fail closed: a composed tool gate's `ask` is refused, not answered.
13
13
  # A deployment that wants the operator to answer it opts in with
14
- # `interaction: { approvals: interactive }`.
14
+ # `interaction: { approvals: interactive }`; the permission preset
15
+ # itself must still resolve to `approval: never`.
15
16
  interaction:
16
17
  approvals: blocked
17
18
  # Ask_user_question is refused, not answered (the tool is mounted per
@@ -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":"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"}