@yadsh/dsh-qa-surface 0.2.0 → 0.3.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.
- package/CHANGELOG.md +84 -1
- package/README.md +87 -12
- package/compatibility.json +11 -3
- package/docs/ARCHITECTURE.md +1 -1
- package/docs/COMPATIBILITY.md +1 -1
- package/docs/CONFIGURATION.md +88 -1
- package/docs/SOURCES-MIGRATION.md +28 -0
- package/docs/SOURCES-PROVENANCE-AUDIT.md +88 -0
- package/docs/SPEC-dsh-qa-surface-accounts.md +219 -0
- package/docs/SPEC-dsh-qa-surface-sources-provenance.md +1692 -0
- package/lib/accounts/index.js +2 -0
- package/lib/accounts/index.js.map +1 -0
- package/lib/accounts/store.js +478 -0
- package/lib/accounts/store.js.map +1 -0
- package/lib/attestation.js.map +1 -1
- package/lib/cli.js +143 -0
- package/lib/cli.js.map +1 -0
- package/lib/client/QaAccountsController.js +329 -0
- package/lib/client/QaAccountsController.js.map +1 -0
- package/lib/client/QaSessionController.js +203 -127
- package/lib/client/QaSessionController.js.map +1 -1
- package/lib/client/QaSurface.js +234 -72
- package/lib/client/QaSurface.js.map +1 -1
- package/lib/client/QaTranscriptAdapter.js +27 -241
- package/lib/client/QaTranscriptAdapter.js.map +1 -1
- package/lib/client/attestation.js +6 -0
- package/lib/client/attestation.js.map +1 -1
- package/lib/client/components/Markdown.js +54 -13
- package/lib/client/components/Markdown.js.map +1 -1
- package/lib/client/components/QaAuthGate.js +40 -0
- package/lib/client/components/QaAuthGate.js.map +1 -0
- package/lib/client/components/QaChangelog.js +112 -0
- package/lib/client/components/QaChangelog.js.map +1 -0
- package/lib/client/components/QaMessage.js +47 -17
- package/lib/client/components/QaMessage.js.map +1 -1
- package/lib/client/components/QaSidebar.js +63 -20
- package/lib/client/components/QaSidebar.js.map +1 -1
- package/lib/client/components/QaSourcesDrawer.js +113 -32
- package/lib/client/components/QaSourcesDrawer.js.map +1 -1
- package/lib/client/components/QaTurnRail.js +281 -0
- package/lib/client/components/QaTurnRail.js.map +1 -0
- package/lib/client/components/QaWelcomeNotice.js +125 -0
- package/lib/client/components/QaWelcomeNotice.js.map +1 -0
- package/lib/client/components/QaWidthHandle.js +142 -0
- package/lib/client/components/QaWidthHandle.js.map +1 -0
- package/lib/client/components/source-refs.js +78 -0
- package/lib/client/components/source-refs.js.map +1 -0
- package/lib/client/create-session.js +51 -0
- package/lib/client/create-session.js.map +1 -0
- package/lib/client/index.js +100 -12
- package/lib/client/index.js.map +1 -1
- package/lib/client/project-session-state.js +78 -0
- package/lib/client/project-session-state.js.map +1 -0
- package/lib/client/session-admission.js +38 -0
- package/lib/client/session-admission.js.map +1 -0
- package/lib/client/session-assets.js +52 -0
- package/lib/client/session-assets.js.map +1 -0
- package/lib/client/session-sources.js +61 -0
- package/lib/client/session-sources.js.map +1 -0
- package/lib/client/settlement.js +24 -0
- package/lib/client/settlement.js.map +1 -0
- package/lib/client/styles.js +151 -9
- package/lib/client/styles.js.map +1 -1
- package/lib/client/tool-presentation.js +102 -0
- package/lib/client/tool-presentation.js.map +1 -0
- package/lib/client/turn-sources.js +98 -0
- package/lib/client/turn-sources.js.map +1 -0
- package/lib/client/types.js +2 -0
- package/lib/client/types.js.map +1 -1
- package/lib/client/use-session-ui-state.js +68 -0
- package/lib/client/use-session-ui-state.js.map +1 -0
- package/lib/client/use-transcript-view.js +44 -0
- package/lib/client/use-transcript-view.js.map +1 -0
- package/lib/client.js +4649 -861
- package/lib/client.js.map +1 -1
- package/lib/config.js +218 -102
- package/lib/config.js.map +1 -1
- package/lib/entry-redirect.js +44 -0
- package/lib/entry-redirect.js.map +1 -0
- package/lib/host-route.js +25 -1
- package/lib/host-route.js.map +1 -1
- package/lib/index.js +209 -23
- package/lib/index.js.map +1 -1
- package/lib/launch-token.js +42 -0
- package/lib/launch-token.js.map +1 -0
- package/lib/provenance/collector.js +40 -0
- package/lib/provenance/collector.js.map +1 -0
- package/lib/provenance/connectors.js +147 -0
- package/lib/provenance/connectors.js.map +1 -0
- package/lib/provenance/dedupe.js +89 -0
- package/lib/provenance/dedupe.js.map +1 -0
- package/lib/provenance/extractors.js +340 -0
- package/lib/provenance/extractors.js.map +1 -0
- package/lib/provenance/file-preview.js +39 -0
- package/lib/provenance/file-preview.js.map +1 -0
- package/lib/provenance/host-store.js +387 -0
- package/lib/provenance/host-store.js.map +1 -0
- package/lib/provenance/index.js +9 -0
- package/lib/provenance/index.js.map +1 -0
- package/lib/provenance/normalize.js +128 -0
- package/lib/provenance/normalize.js.map +1 -0
- package/lib/provenance/reported.js +53 -0
- package/lib/provenance/reported.js.map +1 -0
- package/lib/provenance/types.js +2 -0
- package/lib/provenance/types.js.map +1 -0
- package/lib/resolve-config.js +161 -0
- package/lib/resolve-config.js.map +1 -1
- package/lib/secure-session.js +50 -8
- package/lib/secure-session.js.map +1 -1
- package/lib/typert.host.js +599 -6
- package/lib/typert.remote-client.d.ts +19 -3
- package/lib/typert.remote-client.js +471 -3
- package/lib/types/accounts/index.d.ts +2 -0
- package/lib/types/accounts/store.d.ts +121 -0
- package/lib/types/attestation.d.ts +1 -1
- package/lib/types/cli.d.ts +9 -0
- package/lib/types/client/QaAccountsController.d.ts +95 -0
- package/lib/types/client/QaConfigController.d.ts +1 -1
- package/lib/types/client/QaSessionController.d.ts +46 -7
- package/lib/types/client/QaSurface.d.ts +8 -3
- package/lib/types/client/QaTranscriptAdapter.d.ts +5 -10
- package/lib/types/client/components/Markdown.d.ts +11 -1
- package/lib/types/client/components/QaAgentsDrawer.d.ts +1 -1
- package/lib/types/client/components/QaAuthGate.d.ts +15 -0
- package/lib/types/client/components/QaChangelog.d.ts +21 -0
- package/lib/types/client/components/QaMessage.d.ts +10 -3
- package/lib/types/client/components/QaSidebar.d.ts +30 -2
- package/lib/types/client/components/QaSourcesDrawer.d.ts +15 -3
- package/lib/types/client/components/QaTurnRail.d.ts +59 -0
- package/lib/types/client/components/QaWelcomeNotice.d.ts +27 -0
- package/lib/types/client/components/QaWidthHandle.d.ts +36 -0
- package/lib/types/client/components/source-refs.d.ts +16 -0
- package/lib/types/client/create-session.d.ts +16 -0
- package/lib/types/client/index.d.ts +1 -0
- package/lib/types/client/project-session-state.d.ts +30 -0
- package/lib/types/client/session-admission.d.ts +23 -0
- package/lib/types/client/session-assets.d.ts +20 -0
- package/lib/types/client/session-sources.d.ts +28 -0
- package/lib/types/client/settlement.d.ts +6 -0
- package/lib/types/client/tool-presentation.d.ts +6 -0
- package/lib/types/client/turn-sources.d.ts +14 -0
- package/lib/types/client/types.d.ts +73 -9
- package/lib/types/client/use-session-ui-state.d.ts +35 -0
- package/lib/types/client/use-transcript-view.d.ts +20 -0
- package/lib/types/entry-redirect.d.ts +20 -0
- package/lib/types/host-route.d.ts +14 -1
- package/lib/types/index.d.ts +47 -3
- package/lib/types/launch-token.d.ts +21 -0
- package/lib/types/provenance/collector.d.ts +26 -0
- package/lib/types/provenance/connectors.d.ts +11 -0
- package/lib/types/provenance/dedupe.d.ts +6 -0
- package/lib/types/provenance/extractors.d.ts +14 -0
- package/lib/types/provenance/file-preview.d.ts +10 -0
- package/lib/types/provenance/host-store.d.ts +54 -0
- package/lib/types/provenance/index.d.ts +10 -0
- package/lib/types/provenance/normalize.d.ts +13 -0
- package/lib/types/provenance/reported.d.ts +5 -0
- package/lib/types/provenance/types.d.ts +78 -0
- package/lib/types/secure-session.d.ts +11 -2
- package/lib/types/types.d.ts +167 -11
- package/package.json +58 -41
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,89 @@
|
|
|
1
|
+
## 0.3.0 (2026-09-12)
|
|
2
|
+
|
|
3
|
+
### 🚀 Features
|
|
4
|
+
|
|
5
|
+
- Optional QA accounts and entry routing. `accounts.enabled` mounts a ([dc2f582](https://github.com/xarleyn/dsh-plugins/commit/dc2f582))
|
|
6
|
+
full-frame login/registration gate (email + password, coarse audience-safe
|
|
7
|
+
refusals, per-store rate limiting, self-registration toggle) backed by
|
|
8
|
+
`$DSH_HOME/qa-accounts.json`: scrypt password hashes, a persisted HMAC secret
|
|
9
|
+
for stateful-expiry account tokens, and a session ownership map. Ownership is
|
|
10
|
+
first come, first served - attesting or bulk-claiming an unowned session binds
|
|
11
|
+
it to the caller (the migration path for existing per-browser chats on first
|
|
12
|
+
login); sessions owned by another user refuse attestation with
|
|
13
|
+
`session-owned-elsewhere` and stay hidden from the sidebar, admins are not
|
|
14
|
+
refused. The identity rides as an explicit token argument into the gated
|
|
15
|
+
`qaSurface` remotes (the typert carrier never exposes HTTP requests), the
|
|
16
|
+
policy admission checks it before any session fact is revealed
|
|
17
|
+
(`auth-required` reopens the gate on expiry), and the account chip with
|
|
18
|
+
logout lives in the sidebar footer. `entry.redirectNonLoopback` injects a
|
|
19
|
+
guarded head script through the `webserver/index-inject` event that continues
|
|
20
|
+
non-loopback hostnames into the QA route - the navigation-marker hand-off is
|
|
21
|
+
never redirected (no loops), `/?ui=admin` persists an operator bypass and
|
|
22
|
+
`/?ui=qa` clears it. Accounts are an identity layer for the QA surface, not a
|
|
23
|
+
harness boundary: QA users still hold the shared host launch-token cookie.
|
|
24
|
+
|
|
25
|
+
Follow-ups adopted from a review of the independent dsh-auth-gate plugin: a
|
|
26
|
+
proxy-side deny list for the privileged config-plane RPC methods behind the
|
|
27
|
+
deploy proxy's Host/Origin rewrite, a plugin-side launch-token bridge
|
|
28
|
+
(`entry.cookieBootstrap`) that performs the one-time host-cookie exchange on
|
|
29
|
+
the `/qa` route itself, a `qa-accounts` bin CLI (list/add/set-role/disable/
|
|
30
|
+
enable/revoke) so account administration never requires hand-editing the
|
|
31
|
+
JSON file, and per-account state — a `disabled` flag refusing logins with
|
|
32
|
+
`account-disabled` plus a `tokenVersion` burned into tokens that
|
|
33
|
+
`disable`/`revoke` bump, making logout and lockout server-side facts.
|
|
34
|
+
|
|
35
|
+
Admins get cross-user views over the same ownership map:
|
|
36
|
+
`qaSurface/accountsListOwnership` (admin-only, `admin-required` refusal
|
|
37
|
+
otherwise) returns every chat with its owner's resolved display name, the
|
|
38
|
+
admin sidebar switches to per-owner sections ordered by their freshest chat
|
|
39
|
+
(unclaimed chats trail under "Без владельца"), and user messages in foreign
|
|
40
|
+
chats carry an `author` byline naming the chat owner. Ordinary accounts and
|
|
41
|
+
deployments with accounts disabled keep the flat sidebar and unlabeled
|
|
42
|
+
messages.
|
|
43
|
+
|
|
44
|
+
- The chat-history sidebar gained a footer version button that opens an ([d9d5868](https://github.com/xarleyn/dsh-plugins/commit/d9d5868))
|
|
45
|
+
end-user changelog dialog: a curated per-version summary (new features and
|
|
46
|
+
fixes in Russian) rendered in a themed modal with Escape/backdrop close.
|
|
47
|
+
The bundled version and entries are pinned to package.json and the release
|
|
48
|
+
CHANGELOG by a unit test, so a release cannot ship a stale dialog.
|
|
49
|
+
|
|
50
|
+
- Rebuild the client on the 0.1.5 surfaces: the transcript projects from the ([458b9c2](https://github.com/xarleyn/dsh-plugins/commit/458b9c2))
|
|
51
|
+
ui-chat conversation view's legacy slice, chat/model pinning moves to the
|
|
52
|
+
wire remotes (`agentPresets.select` on the still-blank session, then
|
|
53
|
+
`session.selectModel`) with the attestation ordering preserved, and
|
|
54
|
+
history reads go through the session-v3 surface. The supported host range
|
|
55
|
+
moves to `>=0.1.5-rc.2 <0.2.0`, dropping 0.1.1-rc.2.
|
|
56
|
+
|
|
57
|
+
- Harden the gated QA experience and make cross-user history explicitly ([2ed2024](https://github.com/xarleyn/dsh-plugins/commit/2ed2024))
|
|
58
|
+
opt-in. A new `accounts.showOtherUsersChats` setting defaults to `false`, so
|
|
59
|
+
administrators only see their own chats unless the deployment enables the
|
|
60
|
+
shared ownership view. Account storage now follows external CLI updates and
|
|
61
|
+
uses process-scoped temporary writes, while session admission and client state
|
|
62
|
+
handling avoid stale async results and reset session-bound assets reliably.
|
|
63
|
+
|
|
64
|
+
The QA client now presents a dedicated test-interface disclosure, improves
|
|
65
|
+
chat search and owner matching, keeps row actions from disturbing result
|
|
66
|
+
layout, distinguishes administrator roles, and removes decorative middle-dot
|
|
67
|
+
separators from the sidebar, messages, and source details. Its curated 0.3.0
|
|
68
|
+
history entry is prepared in advance, while the current-version marker is
|
|
69
|
+
injected from package.json at build time so the release bump promotes it
|
|
70
|
+
without another source edit.
|
|
71
|
+
|
|
72
|
+
### ❤️ Thank You
|
|
73
|
+
|
|
74
|
+
- xarleyn @xarleyn
|
|
75
|
+
|
|
1
76
|
## 0.2.0 (2026-09-10)
|
|
2
77
|
|
|
78
|
+
- Added DSH-style symmetric transcript/composer width handles with adaptive
|
|
79
|
+
defaults, viewport clamping, and per-route browser persistence.
|
|
80
|
+
- Added Host-owned structured source provenance for parent and delegated turns,
|
|
81
|
+
replayable `qa/sources` snapshots, dedupe/ranking, opaque-provider reporting,
|
|
82
|
+
grouped source UI, and safe rendered/raw file previews.
|
|
83
|
+
- Updated packed Host/browser smoke coverage for browser authentication,
|
|
84
|
+
revisioned client batches, scoped Remote injection, and current Typert RPC
|
|
85
|
+
envelopes.
|
|
86
|
+
|
|
3
87
|
### 🚀 Features
|
|
4
88
|
|
|
5
89
|
- Make the QA surface a complete end-user assistant shell: image attachments ([b9af082](https://github.com/xarleyn/dsh-plugins/commit/b9af082))
|
|
@@ -19,7 +103,6 @@
|
|
|
19
103
|
interaction palette as `--dsh-qa-*` tokens, and a split of the surface into
|
|
20
104
|
focused drawer, switcher, and formatting modules.
|
|
21
105
|
|
|
22
|
-
|
|
23
106
|
### 🩹 Fixes
|
|
24
107
|
|
|
25
108
|
- Pack the generated Typert host and remote-client entrypoints: the `files` ([0059cb4](https://github.com/xarleyn/dsh-plugins/commit/0059cb4))
|
package/README.md
CHANGED
|
@@ -18,6 +18,14 @@ Session and Agent Loop.
|
|
|
18
18
|
- blocks unsupported approvals/questions instead of auto-approving them;
|
|
19
19
|
- pins locked sessions to `read-only` + `approval=never` before Send is enabled;
|
|
20
20
|
- applies a Host-side tool allow-list plus a monotonic execution guard;
|
|
21
|
+
- optionally gates the surface behind email + password accounts
|
|
22
|
+
(`accounts.enabled`) with server-side session ownership, a first-login
|
|
23
|
+
migration of the browser's existing chats, a `qa-accounts` management CLI
|
|
24
|
+
(list/add/set-role/disable/revoke), and a coarse honest boundary:
|
|
25
|
+
accounts identify QA users, they do not fence the harness root;
|
|
26
|
+
- optionally redirects non-loopback hostnames from the harness root into the
|
|
27
|
+
QA route (`entry.redirectNonLoopback`), keeping the operator's localhost
|
|
28
|
+
harness UI untouched;
|
|
21
29
|
- uses the existing same-origin DSH connection and trust boundary.
|
|
22
30
|
|
|
23
31
|
It does not add another HTTP server, provider proxy, permissive CORS rule, or
|
|
@@ -43,8 +51,8 @@ Some DSH patch operations replace a row's complete `config` instead of deeply
|
|
|
43
51
|
merging it. When editing an existing row, provide every value that deployment
|
|
44
52
|
needs.
|
|
45
53
|
|
|
46
|
-
DSH
|
|
47
|
-
to `index.html`. The Host half therefore claims only the configured QA
|
|
54
|
+
Tested DSH releases serve unknown frontend paths as 404 rather than falling
|
|
55
|
+
back to `index.html`. The Host half therefore claims only the configured QA
|
|
48
56
|
navigation path and redirects it through the canonical `/` document with a
|
|
49
57
|
short-lived query marker. The browser restores the requested `/qa` URL with
|
|
50
58
|
`history.replaceState` before mounting the overlay. No second server, duplicate
|
|
@@ -90,6 +98,11 @@ config:
|
|
|
90
98
|
renderMarkdown: true
|
|
91
99
|
maxContentWidth: 900
|
|
92
100
|
showSessionList: false
|
|
101
|
+
accounts:
|
|
102
|
+
enabled: false
|
|
103
|
+
allowRegistration: true
|
|
104
|
+
sessionTtlDays: 30
|
|
105
|
+
showOtherUsersChats: false
|
|
93
106
|
suggestedQuestions:
|
|
94
107
|
- Как запросить доступ?
|
|
95
108
|
- Где лежит инструкция?
|
|
@@ -114,6 +127,38 @@ config:
|
|
|
114
127
|
toolPolicy:
|
|
115
128
|
mode: allow-list
|
|
116
129
|
allow: []
|
|
130
|
+
sources:
|
|
131
|
+
enabled: true
|
|
132
|
+
collect:
|
|
133
|
+
parentAgent: true
|
|
134
|
+
subagents: true
|
|
135
|
+
persistTurnEvent: true
|
|
136
|
+
display:
|
|
137
|
+
sidebar: true
|
|
138
|
+
footer: true
|
|
139
|
+
groupByKind: true
|
|
140
|
+
showDiscovered: false
|
|
141
|
+
showOriginBadges: false
|
|
142
|
+
maxInitiallyVisiblePerGroup: 8
|
|
143
|
+
webSearch:
|
|
144
|
+
promoteSearchResultsWithoutFetch: true
|
|
145
|
+
maxPromotedPerSearch: 5
|
|
146
|
+
dedupe:
|
|
147
|
+
normalizeUrls: true
|
|
148
|
+
stripTrackingParams: true
|
|
149
|
+
mergeFileRanges: true
|
|
150
|
+
filePreview:
|
|
151
|
+
enabled: true
|
|
152
|
+
markdownRenderedByDefault: true
|
|
153
|
+
allowRawToggle: true
|
|
154
|
+
maxBytes: 2000000
|
|
155
|
+
maxMarkdownRenderBytes: 1000000
|
|
156
|
+
subagents:
|
|
157
|
+
inheritSources: true
|
|
158
|
+
enableReportToolFallback: true
|
|
159
|
+
markIncompleteOpaqueRuns: true
|
|
160
|
+
legacy:
|
|
161
|
+
parseAssistantSourcesBlock: false
|
|
117
162
|
```
|
|
118
163
|
|
|
119
164
|
`workspaceId` is recommended for a deterministic assistant. Without it, DSH
|
|
@@ -151,12 +196,25 @@ prompt and the answer arrives as a follow-up turn; the projection hides that
|
|
|
151
196
|
instruction and the consecutive turns read as variants of one question,
|
|
152
197
|
navigable with a `< 2/2 >` switcher (newest shown by default).
|
|
153
198
|
|
|
154
|
-
Sources
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
199
|
+
Sources are structured Host-owned provenance, independent of
|
|
200
|
+
`ui.showToolActivity`. Successful reads/fetches, bounded web-search evidence,
|
|
201
|
+
Jira/Confluence/knowledge results, and inherited subagent sources are
|
|
202
|
+
normalized and deduplicated into one turn bundle. That exact bundle feeds the
|
|
203
|
+
answer footer and grouped drawer and is persisted as `qa/sources`, so reload
|
|
204
|
+
does not rerun tools. Search-only discovery stays hidden by default.
|
|
205
|
+
|
|
206
|
+
Local file cards open a source-scoped, read-only preview after Host-side real
|
|
207
|
+
path validation against the attested session root. Markdown opens rendered by
|
|
208
|
+
default with an HTML-free renderer and offers `Rendered / Raw`; raw mode jumps
|
|
209
|
+
to recorded line ranges. The endpoint cannot browse or write files and refuses
|
|
210
|
+
paths that are not evidence in the canonical bundle.
|
|
211
|
+
|
|
212
|
+
Observable local subagents are inherited recursively. The internal
|
|
213
|
+
`qa_report_sources` tool covers opaque delegated providers and is admitted as
|
|
214
|
+
a provenance-only capability even when it is not listed among ordinary QA
|
|
215
|
+
tools. A provider that neither exposes events nor reports sources marks the
|
|
216
|
+
turn provenance incomplete. The QA prompt tells models not to append a manual
|
|
217
|
+
`Sources`/`Источники` bibliography.
|
|
160
218
|
|
|
161
219
|
Images: the composer accepts PNG/JPEG/WebP/GIF via drag & drop onto the
|
|
162
220
|
composer, paste, and the picker button, several at once (soft client caps:
|
|
@@ -175,17 +233,32 @@ live transcript (composer disabled, one click back to the chat) - viewing
|
|
|
175
233
|
never attests or writes.
|
|
176
234
|
|
|
177
235
|
`ui.showSessionList: true` renders a minimal chat-history sidebar beside the
|
|
178
|
-
conversation.
|
|
236
|
+
conversation. By default it lists only the current user's chats: the
|
|
179
237
|
client keeps a per-browser id index under
|
|
180
238
|
`<storageKey>:v1:<route>:chats` in localStorage (capped at 50, most recently
|
|
181
239
|
used first) and intersects it with the Host session list, so users sharing the
|
|
182
|
-
deployment never see each other's chats.
|
|
240
|
+
deployment never see each other's chats. An admin can explicitly enable
|
|
241
|
+
`accounts.showOtherUsersChats: true` to add chats owned by other QA accounts,
|
|
242
|
+
grouped by owner. Switching re-runs the full policy
|
|
183
243
|
attestation; a chat the Host no longer lists is pruned from the index. Each
|
|
184
244
|
row carries a two-click delete control that removes the chat from this
|
|
185
245
|
browser's index; deleting the chat that is currently open continues in a
|
|
186
246
|
fresh attested session. Host-side sessions are not deleted — DSH 0.1.x
|
|
187
247
|
exposes no session-deletion seam. The sidebar hides below 600px viewports.
|
|
188
248
|
|
|
249
|
+
The sidebar footer shows the deployed plugin version. Clicking it opens a
|
|
250
|
+
changelog dialog with a curated per-version summary (features and fixes);
|
|
251
|
+
Escape or a backdrop click closes it.
|
|
252
|
+
|
|
253
|
+
On `/qa`, the plugin shadows DSH's stock `welcome-notice` onboarding entry and
|
|
254
|
+
renders a route-owned Russian testing disclosure. Keeping the visible dialog
|
|
255
|
+
in the QA overlay prevents DSH's blank-session onboarding lifecycle from
|
|
256
|
+
dismissing it when a question is submitted. It explains the DeepSeek Harness
|
|
257
|
+
preview foundation, QA review of questions and answers, the work-related
|
|
258
|
+
scope, and local in-contour model processing. Explicit acknowledgement is
|
|
259
|
+
stored as a versioned browser-local flag; changing the disclosure version
|
|
260
|
+
shows it again. Other DSH routes retain the stock onboarding entry.
|
|
261
|
+
|
|
189
262
|
Locked mode requires a deployment permission preset named `qa-read-only`.
|
|
190
263
|
Extend the existing `@deepseek-ai/dsh-permission-presets` row without changing
|
|
191
264
|
its process-wide default:
|
|
@@ -264,8 +337,10 @@ What a LAN deployment does not change:
|
|
|
264
337
|
`/qa`. Scope the port's reachability (subnet-limited firewall rule, VPN or
|
|
265
338
|
tailnet, authenticating reverse proxy) and use a dedicated process identity.
|
|
266
339
|
- Loopback-only settings, directory picking and credential RPCs stay refused
|
|
267
|
-
for LAN clients
|
|
268
|
-
|
|
340
|
+
for LAN clients. On `/qa`, the plugin replaces DSH's non-persistent welcome
|
|
341
|
+
step with a QA-specific testing disclosure and remembers its exact copy
|
|
342
|
+
version in that browser's local storage. The stock DSH notice remains
|
|
343
|
+
unchanged on operator routes.
|
|
269
344
|
|
|
270
345
|
See [Configuration](docs/CONFIGURATION.md) for the config-channel details.
|
|
271
346
|
|
package/compatibility.json
CHANGED
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"deepseekHarness": {
|
|
3
3
|
"channel": "next",
|
|
4
|
-
"range": ">=0.1.
|
|
5
|
-
"testedReleases": ["0.1.
|
|
4
|
+
"range": ">=0.1.5-rc.2 <0.2.0",
|
|
5
|
+
"testedReleases": ["0.1.5-rc.2"],
|
|
6
6
|
"requiredClientFeatures": [
|
|
7
7
|
"shell.overlay",
|
|
8
|
-
"
|
|
8
|
+
"remote.session.selectModel",
|
|
9
|
+
"remote.agentPresets.select",
|
|
10
|
+
"uiConversation.binding",
|
|
9
11
|
"sessions.binding",
|
|
10
12
|
"settingsScope",
|
|
13
|
+
"settings.onboarding list-slot shadowing",
|
|
11
14
|
"webServer.register",
|
|
12
15
|
"typert.remote",
|
|
13
16
|
"agentPresets.composedPreset",
|
|
14
17
|
"permissionPresets.set",
|
|
15
18
|
"tools.restrict",
|
|
16
19
|
"tools.guard",
|
|
20
|
+
"tools.register",
|
|
21
|
+
"session.event-extension",
|
|
22
|
+
"agent.turn-stopping",
|
|
23
|
+
"agent.currentInitiator",
|
|
24
|
+
"systemPrompt.section",
|
|
17
25
|
"workspaceRegistry.get"
|
|
18
26
|
]
|
|
19
27
|
},
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The Host half validates the Loader configuration, registers the `qa-surface`
|
|
4
4
|
settings namespace and owns one narrow GET/HEAD route for the configured QA
|
|
5
|
-
path. Published DSH
|
|
5
|
+
path. Published DSH releases return 404 for unknown frontend paths, so the
|
|
6
6
|
route redirects navigation through the canonical `/` index with an encoded
|
|
7
7
|
same-origin path marker. It also exposes one typed
|
|
8
8
|
`secureSession(sessionId)` operation whose policy is read only from Host
|
package/docs/COMPATIBILITY.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
| Plugin version | Tested DSH release | Required public contracts |
|
|
4
4
|
| -------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
5
|
-
| 0.1.x | 0.1.
|
|
5
|
+
| 0.1.x | 0.1.5-rc.2 | `shell.overlay`, Typert remote, `agentPresets.composedPreset`, `permissionPresets`, agent-scoped `tools.restrict/guard`, `workspaceRegistry`, session/model APIs, `webServer.register` |
|
|
6
6
|
|
|
7
7
|
DSH is developer-preview software. Compatibility-sensitive calls are isolated
|
|
8
8
|
in `QaSessionController`, `QaTranscriptAdapter`, `QaConfigController` and
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -7,12 +7,17 @@ rules are:
|
|
|
7
7
|
`/`, `/api` or `/plugins`;
|
|
8
8
|
- `fixed` requires `fixedSessionId`;
|
|
9
9
|
- `provider` and `model` are either both absent or both present;
|
|
10
|
-
- `maxContentWidth` is an integer from 480 through 1600
|
|
10
|
+
- `maxContentWidth` is an integer from 480 through 1600 and caps the
|
|
11
|
+
user-resizable transcript/composer width; each QA route persists its chosen
|
|
12
|
+
width in browser storage;
|
|
11
13
|
- duplicate/blank suggested questions are removed;
|
|
12
14
|
- approval and question policies are fixed to safe blocking behavior;
|
|
13
15
|
- reasoning and tool details are opt-in through `ui.showReasoning` and
|
|
14
16
|
`ui.showToolActivity`; enable them only where those contents are appropriate
|
|
15
17
|
for the QA audience;
|
|
18
|
+
- accounts default to disabled; when enabled, `sessionTtlDays` is an integer
|
|
19
|
+
from 1 through 365, and other users' chats stay hidden unless an admin view
|
|
20
|
+
explicitly enables `accounts.showOtherUsersChats`;
|
|
16
21
|
- lockdown defaults to enabled and requires a non-empty permission preset;
|
|
17
22
|
- the preset must resolve on the Host to exactly `read-only` + `never`;
|
|
18
23
|
- permission, slash-command, settings, rename, delete and arbitrary-open
|
|
@@ -77,6 +82,88 @@ part of the same change. The package's
|
|
|
77
82
|
[default inventory](../capability-policy.json) is intentionally empty, matching
|
|
78
83
|
the default `toolPolicy.allow`.
|
|
79
84
|
|
|
85
|
+
## Structured sources
|
|
86
|
+
|
|
87
|
+
The `sources` block controls provenance independently from Activity rendering.
|
|
88
|
+
The defaults collect parent and subagent results, persist a `qa/sources` event,
|
|
89
|
+
hide discovery-only candidates, group visible evidence by kind, and promote at
|
|
90
|
+
most five substantive `web_search` results when no fetch occurs. URL tracking
|
|
91
|
+
parameters and overlapping file ranges are normalized during deduplication.
|
|
92
|
+
|
|
93
|
+
`sources.filePreview` is a narrow read capability, not a filesystem browser.
|
|
94
|
+
The Host serves only a path already present in the attested session's canonical
|
|
95
|
+
evidence bundle, resolves symlinks with `realpath`, rejects root escape, and
|
|
96
|
+
applies `maxBytes` plus `maxMarkdownRenderBytes`. Markdown uses the client's
|
|
97
|
+
HTML-free renderer; relative links and executable raw HTML are not activated.
|
|
98
|
+
|
|
99
|
+
Set `sources.display.showOriginBadges: true` while auditing inheritance. Local
|
|
100
|
+
subagent sources carry run/session origins automatically. An opaque provider
|
|
101
|
+
can call the internal `qa_report_sources` tool; if it does not, and
|
|
102
|
+
`markIncompleteOpaqueRuns` remains enabled, the bundle is explicitly marked
|
|
103
|
+
incomplete.
|
|
104
|
+
|
|
105
|
+
See [Structured sources migration](SOURCES-MIGRATION.md) before removing an
|
|
106
|
+
older prompt-authored bibliography convention.
|
|
107
|
+
|
|
108
|
+
## Accounts and the QA gate
|
|
109
|
+
|
|
110
|
+
`accounts.enabled: true` mounts the login/registration gate in front of the
|
|
111
|
+
QA surface and turns on server-side session ownership:
|
|
112
|
+
|
|
113
|
+
- The store lives at `$DSH_HOME/qa-accounts.json` (created on first use). It
|
|
114
|
+
holds scrypt password hashes, a persisted HMAC secret for the account
|
|
115
|
+
tokens, and the session ownership map. The path is not configurable and no
|
|
116
|
+
secret ever reaches `describe()`.
|
|
117
|
+
- `accounts.allowRegistration` (default true) controls self-service signup
|
|
118
|
+
in the gate; the first account ever registered becomes `admin`.
|
|
119
|
+
- `accounts.sessionTtlDays` (default 30) is the account token lifetime. The
|
|
120
|
+
token is an HMAC-signed value the browser keeps in `localStorage`; logout
|
|
121
|
+
or expiry returns the browser to the gate, and the Host re-derives the
|
|
122
|
+
identity on every attestation.
|
|
123
|
+
- `accounts.showOtherUsersChats` (default false) lets admins load and display
|
|
124
|
+
chats owned by other QA accounts. It has no effect for ordinary users.
|
|
125
|
+
- Session ownership is first come, first served: attesting or bulk-claiming
|
|
126
|
+
an unowned session binds it to the caller's account (this is how existing
|
|
127
|
+
per-browser chats migrate on the first login). Sessions owned by another
|
|
128
|
+
user are refused with the coarse `session-owned-elsewhere` reason and
|
|
129
|
+
hidden from the sidebar; admins are not refused.
|
|
130
|
+
- Manage accounts with the bundled CLI (no hand-editing of the JSON):
|
|
131
|
+
|
|
132
|
+
```sh
|
|
133
|
+
qa-accounts list
|
|
134
|
+
qa-accounts add user@example.com --password-stdin --role user
|
|
135
|
+
qa-accounts set-role user@example.com admin
|
|
136
|
+
qa-accounts disable user@example.com # blocks logins, revokes live tokens
|
|
137
|
+
qa-accounts revoke user@example.com # invalidates every issued token
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`disable` bumps the account's token version, so all outstanding tokens die
|
|
141
|
+
server-side; `enable` requires a fresh sign-in. After a secret rotation
|
|
142
|
+
suspicion, `revoke` is the single-step response.
|
|
143
|
+
|
|
144
|
+
- Honest boundary: accounts identify QA users and gate the QA surface and
|
|
145
|
+
its remotes. They do not fence the harness: every QA user also holds the
|
|
146
|
+
host launch-token cookie, with which the full root UI stays technically
|
|
147
|
+
reachable. Keep the network scoping advice from the deployment kit.
|
|
148
|
+
|
|
149
|
+
## Entry redirect
|
|
150
|
+
|
|
151
|
+
`entry.redirectNonLoopback: true` (default) injects one script into the
|
|
152
|
+
served root `index.html`: browsers whose URL host is not loopback
|
|
153
|
+
(`localhost`, `127.0.0.1`, `::1`, `*.localhost`) continue into the QA route,
|
|
154
|
+
so LAN visitors never see the full harness root. The check is client-side on
|
|
155
|
+
`location.hostname` on purpose - behind a local reverse proxy every request
|
|
156
|
+
looks loopback to the server. The navigation hand-off `/?__dsh_qa_route=…`
|
|
157
|
+
is never redirected (that would loop), `/?ui=admin` bypasses the redirect
|
|
158
|
+
and is remembered for the browser, and `/?ui=qa` clears the bypass.
|
|
159
|
+
|
|
160
|
+
`entry.cookieBootstrap: true` (default) additionally lets the `/qa` route
|
|
161
|
+
itself bootstrap the host cookie: a browser without any `dsh-auth-` cookie is
|
|
162
|
+
sent to the one-time `/?token=…` exchange (relative redirect, token resolved
|
|
163
|
+
from the host connection service) before the marker hand-off. This makes the
|
|
164
|
+
transparent entry work without the deploy proxy; with the proxy in front,
|
|
165
|
+
either side may perform the exchange and the other becomes a no-op.
|
|
166
|
+
|
|
80
167
|
## Configuration channel over the LAN
|
|
81
168
|
|
|
82
169
|
The browser normally reads the effective configuration from the Host-owned
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Structured sources migration
|
|
2
|
+
|
|
3
|
+
`dsh-qa-surface` now treats `QaTurnSources` as the only canonical provenance
|
|
4
|
+
model. Assistant prose is never parsed for a `Sources` or `Источники` section,
|
|
5
|
+
and the default `sources.legacy.parseAssistantSourcesBlock` remains `false`.
|
|
6
|
+
|
|
7
|
+
## Deployment steps
|
|
8
|
+
|
|
9
|
+
1. Keep the QA agent's existing read-only retrieval tools in
|
|
10
|
+
`lockdown.toolPolicy.allow`.
|
|
11
|
+
2. Leave `sources.collect.persistTurnEvent: true` so completed turns append a
|
|
12
|
+
replayable `qa/sources` snapshot.
|
|
13
|
+
3. Remove prompt instructions that ask the assistant to manually write a
|
|
14
|
+
bibliography. The plugin contributes its own scoped guidance after QA
|
|
15
|
+
attestation.
|
|
16
|
+
4. For an opaque subagent provider, expose the inherited
|
|
17
|
+
`qa_report_sources` tool and ask the provider to call it before completion.
|
|
18
|
+
Local DSH subagents require no reporting prompt.
|
|
19
|
+
5. Start with `sources.display.showDiscovered: false`; enable it only for
|
|
20
|
+
provenance debugging.
|
|
21
|
+
|
|
22
|
+
Historical sessions without `qa/sources` remain readable: the Host reconstructs
|
|
23
|
+
bundles from durable structured tool metadata when available. Historical
|
|
24
|
+
assistant-authored source prose remains ordinary answer text and is not trusted
|
|
25
|
+
as provenance.
|
|
26
|
+
|
|
27
|
+
The `qa/sources` event is a required plugin-owned session event. Keep
|
|
28
|
+
`dsh-qa-surface` loaded in any Host that restores sessions containing it.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Sources / provenance implementation audit
|
|
2
|
+
|
|
3
|
+
Date: 2026-09-11
|
|
4
|
+
Pinned DSH development API: `0.1.5-rc.2`
|
|
5
|
+
|
|
6
|
+
This note records the Phase 0 findings for
|
|
7
|
+
`SPEC-dsh-qa-surface-sources-provenance.md`. It is intentionally tied to the
|
|
8
|
+
versions in this repository rather than to DSH `master`.
|
|
9
|
+
|
|
10
|
+
## Existing QA data path
|
|
11
|
+
|
|
12
|
+
- `QaSessionController` binds the client `UiConversation` snapshot.
|
|
13
|
+
- `QaTranscriptAdapter` reads the `chat.legacy` projection.
|
|
14
|
+
- The former Sources drawer inferred one row from selected tool names and raw
|
|
15
|
+
arguments. It counted a search query as a source and did not retain turn,
|
|
16
|
+
line-range, evidence, or origin data.
|
|
17
|
+
- `ToolResultNode.meta` is available in the client projection. DSH documents it
|
|
18
|
+
as the tool-private, JSON-safe result presentation payload persisted on the
|
|
19
|
+
corresponding `tool/result` event.
|
|
20
|
+
|
|
21
|
+
## Structured metadata available in the pinned version
|
|
22
|
+
|
|
23
|
+
`@deepseek-ai/dsh-tools` exports the provider-neutral result shapes needed by
|
|
24
|
+
the first implementation slice:
|
|
25
|
+
|
|
26
|
+
- `ReadResultView`: `path`, numbered `lines`, `offset`, `totalLines`, `lang`;
|
|
27
|
+
- `SearchResultView`: grouped grep matches or path discovery;
|
|
28
|
+
- `WebSearchResultView`: structured `sources[]` and truncation state;
|
|
29
|
+
- `WebFetchResultView`: final redirect URL, status, and truncation state;
|
|
30
|
+
- generic call `FileLocation` values.
|
|
31
|
+
|
|
32
|
+
The QA extractor layer therefore consumes `ToolResultNode.meta` first and uses
|
|
33
|
+
tool arguments only as a compatibility fallback for direct read/fetch calls.
|
|
34
|
+
It does not parse assistant prose.
|
|
35
|
+
|
|
36
|
+
## Replay and persistence
|
|
37
|
+
|
|
38
|
+
The completed implementation rebuilds collectors from persisted
|
|
39
|
+
`tool/call`/`tool/result.meta` events and writes one materialized `qa/sources`
|
|
40
|
+
snapshot at `agent/turn-stopping`. The type is declaration-merged into
|
|
41
|
+
`SessionEventMap`.
|
|
42
|
+
|
|
43
|
+
The pinned DSH exports its live `KNOWN_SESSION_EVENT_TYPES` set. As already
|
|
44
|
+
demonstrated by the repository's `dsh-session-scope` plugin, registering the
|
|
45
|
+
plugin event there is the supported compatibility mechanism when
|
|
46
|
+
`Session.append` cannot mark an extension event ignorable. Registration is
|
|
47
|
+
effect-scoped and removed on plugin disposal. A Host that owns sessions with
|
|
48
|
+
these events must load `dsh-qa-surface`, just as it must load any plugin that
|
|
49
|
+
owns a required durable event vocabulary.
|
|
50
|
+
|
|
51
|
+
## Subagent lifecycle
|
|
52
|
+
|
|
53
|
+
The pinned `@deepseek-ai/dsh-subagent` does expose process-local
|
|
54
|
+
`subagent/start` and `subagent/end` events. Both carry `runId`, `provider`, child
|
|
55
|
+
session `id`, and `local`; the terminal payload additionally carries
|
|
56
|
+
`stopReason` and optional `lastAssistantMessage`. Scoped dispatch is keyed by
|
|
57
|
+
the delegating parent.
|
|
58
|
+
|
|
59
|
+
The Host now maintains that lineage registry, uses the child header or causal
|
|
60
|
+
`AgentRegistry.currentInitiator()` attribution, bubbles nested local-child
|
|
61
|
+
sources to the original root turn, and retains run/session origin fields.
|
|
62
|
+
Opaque providers can call `qa_report_sources`; an unreported opaque run sets
|
|
63
|
+
`complete=false` with an `incompleteOrigins` entry.
|
|
64
|
+
|
|
65
|
+
## File preview reuse
|
|
66
|
+
|
|
67
|
+
The new `readSourceFile` Remote is limited to evidence paths in canonical
|
|
68
|
+
bundles, re-attests the session, resolves both root and target with `realpath`,
|
|
69
|
+
rejects traversal/symlink escape, caps bytes, and exposes no write/list API.
|
|
70
|
+
|
|
71
|
+
## Implemented scope
|
|
72
|
+
|
|
73
|
+
- canonical source and turn-bundle types;
|
|
74
|
+
- URL/path/range normalization;
|
|
75
|
+
- extractor registry with read, grep discovery, web search, and web fetch;
|
|
76
|
+
- evidence promotion, deduplication, ranking, and a default display threshold;
|
|
77
|
+
- bounded structured web-search promotion (five results by default);
|
|
78
|
+
- Host per-turn collectors and materialized/replayable `qa/sources` events;
|
|
79
|
+
- local and nested subagent inheritance plus opaque-provider reporting;
|
|
80
|
+
- structured Jira, Confluence, knowledge and reported-source adapters;
|
|
81
|
+
- one canonical snapshot used by grouped drawer and answer footer;
|
|
82
|
+
- source details, origin/partial badges and completeness state;
|
|
83
|
+
- safe local-file preview, rendered/raw Markdown, range chips and exact raw
|
|
84
|
+
line highlighting;
|
|
85
|
+
- configuration and tests for the feature surface.
|
|
86
|
+
|
|
87
|
+
Optional inline citation rendering (SPEC Phase 5) remains intentionally out of
|
|
88
|
+
the MVP, as specified.
|