@yadsh/dsh-qa-surface 0.6.1 → 0.7.1
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.
- package/README.md +163 -7
- package/capability-policy.json +1 -1
- package/lib/access/capability-catalog.js +144 -0
- package/lib/access/capability-catalog.js.map +1 -0
- package/lib/access/model.js +379 -0
- package/lib/access/model.js.map +1 -0
- package/lib/access/role-repository.js +195 -0
- package/lib/access/role-repository.js.map +1 -0
- package/lib/access/service.js +380 -0
- package/lib/access/service.js.map +1 -0
- package/lib/access/skill-metadata.js +234 -0
- package/lib/access/skill-metadata.js.map +1 -0
- package/lib/account-remotes.js +20 -10
- package/lib/account-remotes.js.map +1 -1
- package/lib/accounts/errors.js.map +1 -1
- package/lib/accounts/file.js.map +1 -1
- package/lib/accounts/store.js +202 -3
- package/lib/accounts/store.js.map +1 -1
- package/lib/admin/conversation-log.js +256 -0
- package/lib/admin/conversation-log.js.map +1 -0
- package/lib/admin/index.js +17 -0
- package/lib/admin/index.js.map +1 -0
- package/lib/admin/metrics.js +103 -0
- package/lib/admin/metrics.js.map +1 -0
- package/lib/admin/paging.js +23 -0
- package/lib/admin/paging.js.map +1 -0
- package/lib/admin/permissions.js +50 -0
- package/lib/admin/permissions.js.map +1 -0
- package/lib/admin/quality-store.js +485 -0
- package/lib/admin/quality-store.js.map +1 -0
- package/lib/admin/queue.js +107 -0
- package/lib/admin/queue.js.map +1 -0
- package/lib/admin/redaction.js +45 -0
- package/lib/admin/redaction.js.map +1 -0
- package/lib/admin/service.js +897 -0
- package/lib/admin/service.js.map +1 -0
- package/lib/admin/session-log.js +142 -0
- package/lib/admin/session-log.js.map +1 -0
- package/lib/cli.js +9 -6
- package/lib/cli.js.map +1 -1
- package/lib/client/QaSessionController.js +28 -2
- package/lib/client/QaSessionController.js.map +1 -1
- package/lib/client/QaSurface.js +143 -5
- package/lib/client/QaSurface.js.map +1 -1
- package/lib/client/QaTranscriptAdapter.js +1 -0
- package/lib/client/QaTranscriptAdapter.js.map +1 -1
- package/lib/client/admin/QaAdmin.js +458 -0
- package/lib/client/admin/QaAdmin.js.map +1 -0
- package/lib/client/admin/format.js +177 -0
- package/lib/client/admin/format.js.map +1 -0
- package/lib/client/admin/pages/Conversations.js +114 -0
- package/lib/client/admin/pages/Conversations.js.map +1 -0
- package/lib/client/admin/pages/Overview.js +24 -0
- package/lib/client/admin/pages/Overview.js.map +1 -0
- package/lib/client/admin/pages/Quality.js +71 -0
- package/lib/client/admin/pages/Quality.js.map +1 -0
- package/lib/client/admin/pages/Review.js +93 -0
- package/lib/client/admin/pages/Review.js.map +1 -0
- package/lib/client/admin/pages/Users.js +95 -0
- package/lib/client/admin/pages/Users.js.map +1 -0
- package/lib/client/admin/routes.js +143 -0
- package/lib/client/admin/routes.js.map +1 -0
- package/lib/client/admin/shared.js +91 -0
- package/lib/client/admin/shared.js.map +1 -0
- package/lib/client/admin/styles.js +111 -0
- package/lib/client/admin/styles.js.map +1 -0
- package/lib/client/components/QaChangelog.js +53 -0
- package/lib/client/components/QaChangelog.js.map +1 -1
- package/lib/client/components/QaHeader.js +3 -3
- package/lib/client/components/QaHeader.js.map +1 -1
- package/lib/client/components/QaMessage.js +61 -2
- package/lib/client/components/QaMessage.js.map +1 -1
- package/lib/client/create-session.js +1 -1
- package/lib/client/create-session.js.map +1 -1
- package/lib/client/index.js +48 -1
- package/lib/client/index.js.map +1 -1
- package/lib/client/role/RoleSelector.js +31 -0
- package/lib/client/role/RoleSelector.js.map +1 -0
- package/lib/client/session-sources.js +37 -1
- package/lib/client/session-sources.js.map +1 -1
- package/lib/client/settings/card.js +2 -2
- package/lib/client/settings/card.js.map +1 -1
- package/lib/client/settings/sections.js +0 -1
- package/lib/client/settings/sections.js.map +1 -1
- package/lib/client/settings-extensions/index.js +1 -0
- package/lib/client/settings-extensions/index.js.map +1 -1
- package/lib/client/settings-extensions/user-session.js +62 -0
- package/lib/client/settings-extensions/user-session.js.map +1 -0
- package/lib/client/styles.js +31 -0
- package/lib/client/styles.js.map +1 -1
- package/lib/client/types.js.map +1 -1
- package/lib/client.js +9993 -4848
- package/lib/client.js.map +1 -1
- package/lib/config-resolvers/defaults.js +0 -2
- package/lib/config-resolvers/defaults.js.map +1 -1
- package/lib/config.js +0 -249
- package/lib/config.js.map +1 -1
- package/lib/enforcement/skill-policy.js +172 -0
- package/lib/enforcement/skill-policy.js.map +1 -0
- package/lib/enforcement/tool-grants.js +151 -0
- package/lib/enforcement/tool-grants.js.map +1 -0
- package/lib/index.js +224 -42
- package/lib/index.js.map +1 -1
- package/lib/personal-skills/service.js +10 -3
- package/lib/personal-skills/service.js.map +1 -1
- package/lib/qa-tools/index.js +4 -0
- package/lib/qa-tools/index.js.map +1 -1
- package/lib/resolve-config.js +0 -2
- package/lib/resolve-config.js.map +1 -1
- package/lib/secure-session.js +71 -17
- package/lib/secure-session.js.map +1 -1
- package/lib/typert.host.js +2237 -202
- package/lib/typert.remote-client.d.ts +49 -3
- package/lib/typert.remote-client.js +1863 -183
- package/lib/types/access/capability-catalog.d.ts +37 -0
- package/lib/types/access/model.d.ts +60 -0
- package/lib/types/access/role-repository.d.ts +32 -0
- package/lib/types/access/service.d.ts +57 -0
- package/lib/types/access/skill-metadata.d.ts +53 -0
- package/lib/types/account-remotes.d.ts +6 -0
- package/lib/types/accounts/errors.d.ts +1 -1
- package/lib/types/accounts/file.d.ts +16 -5
- package/lib/types/accounts/store.d.ts +83 -3
- package/lib/types/admin/conversation-log.d.ts +39 -0
- package/lib/types/admin/index.d.ts +24 -0
- package/lib/types/admin/metrics.d.ts +29 -0
- package/lib/types/admin/paging.d.ts +33 -0
- package/lib/types/admin/permissions.d.ts +10 -0
- package/lib/types/admin/quality-store.d.ts +82 -0
- package/lib/types/admin/queue.d.ts +21 -0
- package/lib/types/admin/redaction.d.ts +29 -0
- package/lib/types/admin/service.d.ts +105 -0
- package/lib/types/admin/session-log.d.ts +53 -0
- package/lib/types/client/QaSessionController.d.ts +12 -1
- package/lib/types/client/QaSurface.d.ts +7 -1
- package/lib/types/client/admin/QaAdmin.d.ts +17 -0
- package/lib/types/client/admin/format.d.ts +43 -0
- package/lib/types/client/admin/pages/Conversations.d.ts +21 -0
- package/lib/types/client/admin/pages/Overview.d.ts +13 -0
- package/lib/types/client/admin/pages/Quality.d.ts +18 -0
- package/lib/types/client/admin/pages/Review.d.ts +15 -0
- package/lib/types/client/admin/pages/Users.d.ts +22 -0
- package/lib/types/client/admin/routes.d.ts +60 -0
- package/lib/types/client/admin/shared.d.ts +53 -0
- package/lib/types/client/admin/styles.d.ts +11 -0
- package/lib/types/client/components/QaHeader.d.ts +5 -1
- package/lib/types/client/components/QaMessage.d.ts +14 -1
- package/lib/types/client/create-session.d.ts +2 -0
- package/lib/types/client/role/RoleSelector.d.ts +14 -0
- package/lib/types/client/session-sources.d.ts +9 -0
- package/lib/types/client/settings/sections.d.ts +0 -1
- package/lib/types/client/settings-extensions/index.d.ts +2 -0
- package/lib/types/client/settings-extensions/user-session.d.ts +59 -0
- package/lib/types/client/types.d.ts +39 -2
- package/lib/types/enforcement/skill-policy.d.ts +29 -0
- package/lib/types/enforcement/tool-grants.d.ts +84 -0
- package/lib/types/index.d.ts +62 -14
- package/lib/types/qa-tools/index.d.ts +2 -0
- package/lib/types/secure-session.d.ts +10 -1
- package/lib/types/types.d.ts +568 -5
- package/package.json +2 -2
- package/lib/client/settings/sections/documents.js +0 -88
- package/lib/client/settings/sections/documents.js.map +0 -1
- package/lib/documents/artifacts/ids.js +0 -43
- package/lib/documents/artifacts/ids.js.map +0 -1
- package/lib/documents/artifacts/manifest.js +0 -66
- package/lib/documents/artifacts/manifest.js.map +0 -1
- package/lib/documents/artifacts/store.js +0 -169
- package/lib/documents/artifacts/store.js.map +0 -1
- package/lib/documents/capabilities.js +0 -93
- package/lib/documents/capabilities.js.map +0 -1
- package/lib/documents/config.js +0 -302
- package/lib/documents/config.js.map +0 -1
- package/lib/documents/defaults.js +0 -78
- package/lib/documents/defaults.js.map +0 -1
- package/lib/documents/errors.js +0 -101
- package/lib/documents/errors.js.map +0 -1
- package/lib/documents/index.js +0 -80
- package/lib/documents/index.js.map +0 -1
- package/lib/documents/inspect/facts.js +0 -161
- package/lib/documents/inspect/facts.js.map +0 -1
- package/lib/documents/inspect/zip.js +0 -108
- package/lib/documents/inspect/zip.js.map +0 -1
- package/lib/documents/markdown/directives.js +0 -135
- package/lib/documents/markdown/directives.js.map +0 -1
- package/lib/documents/markdown/frontmatter.js +0 -35
- package/lib/documents/markdown/frontmatter.js.map +0 -1
- package/lib/documents/markdown/normalize.js +0 -113
- package/lib/documents/markdown/normalize.js.map +0 -1
- package/lib/documents/orchestrator/assets.js +0 -243
- package/lib/documents/orchestrator/assets.js.map +0 -1
- package/lib/documents/orchestrator/convert-document.js +0 -186
- package/lib/documents/orchestrator/convert-document.js.map +0 -1
- package/lib/documents/orchestrator/create-document.js +0 -292
- package/lib/documents/orchestrator/create-document.js.map +0 -1
- package/lib/documents/orchestrator/extract-document.js +0 -162
- package/lib/documents/orchestrator/extract-document.js.map +0 -1
- package/lib/documents/orchestrator/inspect-document.js +0 -89
- package/lib/documents/orchestrator/inspect-document.js.map +0 -1
- package/lib/documents/orchestrator/runtime-deps.js +0 -59
- package/lib/documents/orchestrator/runtime-deps.js.map +0 -1
- package/lib/documents/orchestrator/scope.js +0 -132
- package/lib/documents/orchestrator/scope.js.map +0 -1
- package/lib/documents/providers/docling.js +0 -247
- package/lib/documents/providers/docling.js.map +0 -1
- package/lib/documents/providers/libreoffice.js +0 -130
- package/lib/documents/providers/libreoffice.js.map +0 -1
- package/lib/documents/providers/markitdown.js +0 -89
- package/lib/documents/providers/markitdown.js.map +0 -1
- package/lib/documents/providers/pandoc.js +0 -161
- package/lib/documents/providers/pandoc.js.map +0 -1
- package/lib/documents/providers/process.js +0 -164
- package/lib/documents/providers/process.js.map +0 -1
- package/lib/documents/providers/registry.js +0 -152
- package/lib/documents/providers/registry.js.map +0 -1
- package/lib/documents/providers/shared.js +0 -75
- package/lib/documents/providers/shared.js.map +0 -1
- package/lib/documents/runtime.js +0 -114
- package/lib/documents/runtime.js.map +0 -1
- package/lib/documents/security/file-types.js +0 -188
- package/lib/documents/security/file-types.js.map +0 -1
- package/lib/documents/security/limits.js +0 -78
- package/lib/documents/security/limits.js.map +0 -1
- package/lib/documents/security/mime.js +0 -43
- package/lib/documents/security/mime.js.map +0 -1
- package/lib/documents/security/paths.js +0 -133
- package/lib/documents/security/paths.js.map +0 -1
- package/lib/documents/templates/registry.js +0 -147
- package/lib/documents/templates/registry.js.map +0 -1
- package/lib/documents/templates/resolver.js +0 -59
- package/lib/documents/templates/resolver.js.map +0 -1
- package/lib/documents/tools/convert.js +0 -125
- package/lib/documents/tools/convert.js.map +0 -1
- package/lib/documents/tools/create.js +0 -187
- package/lib/documents/tools/create.js.map +0 -1
- package/lib/documents/tools/index.js +0 -41
- package/lib/documents/tools/index.js.map +0 -1
- package/lib/documents/tools/inspect.js +0 -135
- package/lib/documents/tools/inspect.js.map +0 -1
- package/lib/documents/tools/shared.js +0 -88
- package/lib/documents/tools/shared.js.map +0 -1
- package/lib/documents/tools/to-markdown.js +0 -125
- package/lib/documents/tools/to-markdown.js.map +0 -1
- package/lib/documents/types.js +0 -12
- package/lib/documents/types.js.map +0 -1
- package/lib/types/client/settings/sections/documents.d.ts +0 -13
- package/lib/types/documents/artifacts/ids.d.ts +0 -14
- package/lib/types/documents/artifacts/manifest.d.ts +0 -32
- package/lib/types/documents/artifacts/store.d.ts +0 -67
- package/lib/types/documents/capabilities.d.ts +0 -32
- package/lib/types/documents/config.d.ts +0 -27
- package/lib/types/documents/defaults.d.ts +0 -161
- package/lib/types/documents/errors.d.ts +0 -42
- package/lib/types/documents/index.d.ts +0 -63
- package/lib/types/documents/inspect/facts.d.ts +0 -43
- package/lib/types/documents/inspect/zip.d.ts +0 -28
- package/lib/types/documents/markdown/directives.d.ts +0 -39
- package/lib/types/documents/markdown/frontmatter.d.ts +0 -15
- package/lib/types/documents/markdown/normalize.d.ts +0 -30
- package/lib/types/documents/orchestrator/assets.d.ts +0 -55
- package/lib/types/documents/orchestrator/convert-document.d.ts +0 -25
- package/lib/types/documents/orchestrator/create-document.d.ts +0 -18
- package/lib/types/documents/orchestrator/extract-document.d.ts +0 -24
- package/lib/types/documents/orchestrator/inspect-document.d.ts +0 -12
- package/lib/types/documents/orchestrator/runtime-deps.d.ts +0 -43
- package/lib/types/documents/orchestrator/scope.d.ts +0 -52
- package/lib/types/documents/providers/docling.d.ts +0 -54
- package/lib/types/documents/providers/libreoffice.d.ts +0 -40
- package/lib/types/documents/providers/markitdown.d.ts +0 -28
- package/lib/types/documents/providers/pandoc.d.ts +0 -42
- package/lib/types/documents/providers/process.d.ts +0 -54
- package/lib/types/documents/providers/registry.d.ts +0 -68
- package/lib/types/documents/providers/shared.d.ts +0 -27
- package/lib/types/documents/runtime.d.ts +0 -59
- package/lib/types/documents/security/file-types.d.ts +0 -39
- package/lib/types/documents/security/limits.d.ts +0 -24
- package/lib/types/documents/security/mime.d.ts +0 -13
- package/lib/types/documents/security/paths.d.ts +0 -38
- package/lib/types/documents/templates/registry.d.ts +0 -50
- package/lib/types/documents/templates/resolver.d.ts +0 -30
- package/lib/types/documents/tools/convert.d.ts +0 -9
- package/lib/types/documents/tools/create.d.ts +0 -14
- package/lib/types/documents/tools/index.d.ts +0 -33
- package/lib/types/documents/tools/inspect.d.ts +0 -9
- package/lib/types/documents/tools/shared.d.ts +0 -77
- package/lib/types/documents/tools/to-markdown.d.ts +0 -12
- 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
|
-
|
|
50
|
+
embedding — and reports the configuration the running Host
|
|
48
51
|
resolved;
|
|
49
|
-
-
|
|
50
|
-
`
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
|
@@ -571,6 +577,33 @@ export function apply(ctx: Context) {
|
|
|
571
577
|
}
|
|
572
578
|
```
|
|
573
579
|
|
|
580
|
+
### The signed-in account outside the dialog
|
|
581
|
+
|
|
582
|
+
A card mounted in the host's own settings (`settings.plugin.item`) has no panel
|
|
583
|
+
props to read the account from, so the same contract also publishes the session
|
|
584
|
+
as the `qaUserSession` client service: `checking`, `anonymous` or `authed` with
|
|
585
|
+
the bearer credential the principal-scoped QA remotes authorize with. It follows
|
|
586
|
+
the same account controller the pages use, so a card and the dialog never
|
|
587
|
+
disagree. Subscribe to it with `useSyncExternalStore` and render account-bound
|
|
588
|
+
controls only for `authed` — without an account every call would be refused, and
|
|
589
|
+
the credential is transport authentication only: never persist it, log it, or
|
|
590
|
+
put it in a URL, a tool argument or any model-visible value.
|
|
591
|
+
|
|
592
|
+
```ts
|
|
593
|
+
import type { Context } from "@deepseek-ai/cordis"
|
|
594
|
+
|
|
595
|
+
export const inject = ["qaUserSession", "slots"]
|
|
596
|
+
|
|
597
|
+
export function apply(ctx: Context) {
|
|
598
|
+
ctx.effect(() =>
|
|
599
|
+
ctx.slots.inject("settings.plugin.item", () =>
|
|
600
|
+
ctx.slots.register(
|
|
601
|
+
{ name: "settings.plugin.item", key: "my-namespace" },
|
|
602
|
+
MyCard,
|
|
603
|
+
)))
|
|
604
|
+
}
|
|
605
|
+
```
|
|
606
|
+
|
|
574
607
|
Subagents: the deployment may opt the delegation family (`subagent`,
|
|
575
608
|
`subagent_fork`, `send_message`, `list_agents`, `interrupt_agent`) into the
|
|
576
609
|
lockdown allow-list; the preset must mount them. Launches then render as
|
|
@@ -662,6 +695,129 @@ Host-installed integration plugins may add their own narrowly scoped tool names
|
|
|
662
695
|
through the QA Surface service; those executors must independently resolve the
|
|
663
696
|
owner-attested root principal and fail closed for unowned or child sessions.
|
|
664
697
|
|
|
698
|
+
## Subroles and capability policies
|
|
699
|
+
|
|
700
|
+
With `accounts.enabled: true`, every QA session has exactly one active agent
|
|
701
|
+
subrole. The Host resolves its effective capabilities as the union of the
|
|
702
|
+
minimal system-required set, Common capabilities, and that one subrole; it
|
|
703
|
+
never unions all roles assigned to the user. The chosen role and effective
|
|
704
|
+
snapshot are stored with session ownership. Existing conversations never gain
|
|
705
|
+
new capabilities after an administrator edits a role, while a capability that
|
|
706
|
+
disappears from the running registry is revoked immediately.
|
|
707
|
+
|
|
708
|
+
Administrators manage subroles, Common Tools/Skills, user assignments and the
|
|
709
|
+
audit trail at `/qa/admin`. Capability choices come from the live tool and
|
|
710
|
+
skill registries; configured-but-missing entries remain visible and are not
|
|
711
|
+
deleted. Admin authorization affects only the management API and never grants
|
|
712
|
+
agent capabilities. `Preview as role` creates an ordinary session using the
|
|
713
|
+
selected role's real server-enforced policy and shows a persistent preview
|
|
714
|
+
banner.
|
|
715
|
+
|
|
716
|
+
The configuration lives in `$DSH_HOME/qa-capability-policies.json`; user
|
|
717
|
+
assignments and session snapshots stay with the existing account store. Tools
|
|
718
|
+
are filtered with an agent-scoped restriction and a pre-execution gate. Skills
|
|
719
|
+
use an agent-scoped `skill` consumer that publishes only the allow-listed
|
|
720
|
+
catalog and rejects direct out-of-policy loads with `SKILL_NOT_AVAILABLE`.
|
|
721
|
+
The browser selector is hidden for a single assigned role. Switching roles
|
|
722
|
+
after a meaningful turn requires confirmation and creates a new conversation.
|
|
723
|
+
|
|
724
|
+
### Tools that arrive with a skill
|
|
725
|
+
|
|
726
|
+
A role's tools are split into two classes. `always` tools are visible from the
|
|
727
|
+
first model step. `skillGrantable` tools are a ceiling, not a grant: they stay
|
|
728
|
+
out of the model's tool list until an activated skill requires them, which
|
|
729
|
+
keeps a large catalog such as browser automation out of every step of every
|
|
730
|
+
conversation. An older flat `tools: []` list is read as `always`, so an
|
|
731
|
+
upgraded deployment never hands out more than it did before.
|
|
732
|
+
|
|
733
|
+
### Skills declare their own audience
|
|
734
|
+
|
|
735
|
+
A skill describes itself inside the ordinary `metadata` block of its
|
|
736
|
+
`SKILL.md`, so the file stays a valid Agent Skill outside a QA deployment and
|
|
737
|
+
no upstream schema is forked:
|
|
738
|
+
|
|
739
|
+
```yaml
|
|
740
|
+
---
|
|
741
|
+
name: browser-research
|
|
742
|
+
description: Research websites through browser automation
|
|
743
|
+
|
|
744
|
+
metadata:
|
|
745
|
+
qa-surface:
|
|
746
|
+
version: 1
|
|
747
|
+
audience:
|
|
748
|
+
type: subroles # or: type: common
|
|
749
|
+
include: [analyst, presales]
|
|
750
|
+
tools:
|
|
751
|
+
requires: [browser_open, browser_click]
|
|
752
|
+
grant:
|
|
753
|
+
lifecycle: session # the only lifecycle in v1
|
|
754
|
+
requireAll: true
|
|
755
|
+
---
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
The audience decides visibility; the role ceiling decides what a skill may ever
|
|
759
|
+
receive. A load intersects the two, so a skill cannot widen its own access. A
|
|
760
|
+
skill that declares nothing stays `Unassigned` until an administrator assigns
|
|
761
|
+
it, which is safer than treating every new skill as Common.
|
|
762
|
+
|
|
763
|
+
Loading the instructions and widening the toolset is one operation. A strict
|
|
764
|
+
skill (`requireAll: true`) refuses to activate when one of its tools is
|
|
765
|
+
unavailable, and a best-effort skill activates with a visible warning that
|
|
766
|
+
names what it did not receive. The model's `skill` call and a typed
|
|
767
|
+
`/skill-name` activate the same grant; a `/name` naming a skill outside the
|
|
768
|
+
subrole is withdrawn before the step is assembled. Grants last for the current
|
|
769
|
+
agent, and several loaded skills union their tools — activating a second skill
|
|
770
|
+
never revokes what the first one still holds.
|
|
771
|
+
|
|
772
|
+
Administrators edit assignments as an overlay, never by rewriting `SKILL.md`: a
|
|
773
|
+
role can be added to or withdrawn from a declared audience, a skill can be
|
|
774
|
+
forced on for every role or disabled outright, and the Skills page shows the
|
|
775
|
+
declared audience next to the effective one with a
|
|
776
|
+
`Healthy`/`Degraded`/`Blocked` state. Every activation is recorded on the
|
|
777
|
+
session record with the requested, granted and denied tools, so a later review
|
|
778
|
+
can see what a conversation actually gained.
|
|
779
|
+
## Administrative console
|
|
780
|
+
|
|
781
|
+
`/qa/admin` is the review and administration surface. It is part of the QA page
|
|
782
|
+
itself, not a separate application, and it is open to `admin` and `reviewer`
|
|
783
|
+
accounts. Reviewer sees conversations, the review queue, feedback and
|
|
784
|
+
analytics; only an administrator sees users, capability policies and audit.
|
|
785
|
+
|
|
786
|
+
The console covers the quality loop end to end:
|
|
787
|
+
|
|
788
|
+
- **Overview** — conversation, rating and review counters, the items that need
|
|
789
|
+
attention, and the newest signals.
|
|
790
|
+
- **Users** — authorization role, enabled/disabled status, assigned QA subroles
|
|
791
|
+
and the default one, plus per-account activity. Disabling an account is the
|
|
792
|
+
operation to reach for: historical conversations, feedback and reviews stay
|
|
793
|
+
attributed to their author, and the last enabled administrator cannot be
|
|
794
|
+
demoted, disabled or removed.
|
|
795
|
+
- **Conversations** — every conversation the deployment knows, filterable by
|
|
796
|
+
user, subrole, date range, rating and review state, with a viewer that reads
|
|
797
|
+
the stored transcript: messages in recorded order, tool calls with their
|
|
798
|
+
arguments, results and errors, per-message feedback, and the capability
|
|
799
|
+
snapshot frozen when the session started. A link can point at one message
|
|
800
|
+
(`/qa/admin/conversations/<id>/<seq>`).
|
|
801
|
+
- **Review queue** — what needs attention, derived from unanswered negative
|
|
802
|
+
feedback, explicitly queued conversations and failed tool calls. A reviewer
|
|
803
|
+
classifies issues across answer, context, tools, skills and access, sets a
|
|
804
|
+
severity, writes notes and names the remediation target.
|
|
805
|
+
- **Feedback** — every rating against the exact answer it judged, with the
|
|
806
|
+
optional reason and comment the user gave.
|
|
807
|
+
- **Analytics** — rating coverage, positive share overall and per subrole,
|
|
808
|
+
issue distribution and a daily trend. These are user-satisfaction signals;
|
|
809
|
+
the console never presents them as accuracy.
|
|
810
|
+
- **Audit** — one timeline of authorization changes, account status, subrole
|
|
811
|
+
assignments, policy edits and review verdicts, each with its before/after
|
|
812
|
+
image.
|
|
813
|
+
|
|
814
|
+
Authorization is a permission table, not an `isAdmin` flag, and every
|
|
815
|
+
administrative entry point names the permission it needs; the Host re-checks it
|
|
816
|
+
on the call it serves, so a hidden control is convenience rather than the
|
|
817
|
+
boundary. Review material is the most sensitive data the package handles, so
|
|
818
|
+
tool arguments and results are bounded previews with credential shapes masked,
|
|
819
|
+
behind a redactor a deployment can replace.
|
|
820
|
+
|
|
665
821
|
## Security and deployment
|
|
666
822
|
|
|
667
823
|
`/qa` is a presentation boundary, not an authentication boundary. Protect it
|
package/capability-policy.json
CHANGED
|
@@ -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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"}
|