@yadsh/dsh-qa-surface 0.1.1 → 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 +151 -0
- package/README.md +239 -16
- package/SPEC-dsh-qa-surface.md +600 -96
- package/capability-policy.json +5 -0
- package/compatibility.json +18 -4
- package/cordis.patch.yml +11 -0
- package/docs/ARCHITECTURE.md +50 -8
- package/docs/COMPATIBILITY.md +5 -4
- package/docs/CONFIGURATION.md +184 -3
- 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 +10 -0
- package/lib/attestation.js.map +1 -0
- 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/QaConfigController.js +111 -4
- package/lib/client/QaConfigController.js.map +1 -1
- package/lib/client/QaSessionController.js +621 -163
- package/lib/client/QaSessionController.js.map +1 -1
- package/lib/client/QaSurface.js +303 -24
- package/lib/client/QaSurface.js.map +1 -1
- package/lib/client/QaTranscriptAdapter.js +324 -49
- package/lib/client/QaTranscriptAdapter.js.map +1 -1
- package/lib/client/attestation.js +66 -0
- package/lib/client/attestation.js.map +1 -0
- package/lib/client/chat-index.js +86 -0
- package/lib/client/chat-index.js.map +1 -0
- package/lib/client/components/Markdown.js +124 -13
- package/lib/client/components/Markdown.js.map +1 -1
- package/lib/client/components/QaAgentsDrawer.js +40 -0
- package/lib/client/components/QaAgentsDrawer.js.map +1 -0
- 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/QaComposer.js +132 -15
- package/lib/client/components/QaComposer.js.map +1 -1
- package/lib/client/components/QaMessage.js +214 -10
- package/lib/client/components/QaMessage.js.map +1 -1
- package/lib/client/components/QaSidebar.js +167 -0
- package/lib/client/components/QaSidebar.js.map +1 -0
- package/lib/client/components/QaSourcesDrawer.js +127 -0
- package/lib/client/components/QaSourcesDrawer.js.map +1 -0
- 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/QaWorkGroup.js +135 -0
- package/lib/client/components/QaWorkGroup.js.map +1 -0
- package/lib/client/components/VariantSwitcher.js +29 -0
- package/lib/client/components/VariantSwitcher.js.map +1 -0
- package/lib/client/components/format.js +48 -0
- package/lib/client/components/format.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 +166 -35
- 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 +450 -43
- 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 +15 -0
- package/lib/client/types.js.map +1 -0
- 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/wait-for.js +49 -0
- package/lib/client/wait-for.js.map +1 -0
- package/lib/client.js +12551 -918
- package/lib/client.js.map +1 -1
- package/lib/config.js +226 -58
- 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 +354 -72
- package/lib/index.js.map +1 -1
- package/lib/launch-token.js +42 -0
- package/lib/launch-token.js.map +1 -0
- package/lib/lockdown-policy.js +20 -0
- package/lib/lockdown-policy.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 +283 -10
- package/lib/resolve-config.js.map +1 -1
- package/lib/secure-session.js +212 -0
- package/lib/secure-session.js.map +1 -0
- package/lib/typert.host.d.ts +3 -0
- package/lib/typert.host.js +784 -0
- package/lib/typert.remote-client.d.ts +40 -0
- package/lib/typert.remote-client.js +597 -0
- package/lib/types/accounts/index.d.ts +2 -0
- package/lib/types/accounts/store.d.ts +121 -0
- package/lib/types/attestation.d.ts +17 -0
- package/lib/types/cli.d.ts +9 -0
- package/lib/types/client/QaAccountsController.d.ts +95 -0
- package/lib/types/client/QaConfigController.d.ts +35 -3
- package/lib/types/client/QaSessionController.d.ts +146 -20
- package/lib/types/client/QaSurface.d.ts +11 -5
- package/lib/types/client/QaTranscriptAdapter.d.ts +13 -3
- package/lib/types/client/attestation.d.ts +25 -0
- package/lib/types/client/chat-index.d.ts +28 -0
- package/lib/types/client/components/Markdown.d.ts +17 -3
- package/lib/types/client/components/QaAgentsDrawer.d.ts +25 -0
- 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/QaComposer.d.ts +12 -2
- package/lib/types/client/components/QaMessage.d.ts +22 -2
- package/lib/types/client/components/QaSidebar.d.ts +69 -0
- package/lib/types/client/components/QaSourcesDrawer.d.ts +20 -0
- 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/QaWorkGroup.d.ts +19 -0
- package/lib/types/client/components/VariantSwitcher.d.ts +19 -0
- package/lib/types/client/components/format.d.ts +9 -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 +2 -5
- 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 +93 -0
- 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/client/wait-for.d.ts +11 -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 +67 -7
- package/lib/types/launch-token.d.ts +21 -0
- package/lib/types/lockdown-policy.d.ts +18 -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 +31 -0
- package/lib/types/types.d.ts +304 -1
- package/package.json +70 -27
package/compatibility.json
CHANGED
|
@@ -1,14 +1,28 @@
|
|
|
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",
|
|
11
|
-
"
|
|
13
|
+
"settings.onboarding list-slot shadowing",
|
|
14
|
+
"webServer.register",
|
|
15
|
+
"typert.remote",
|
|
16
|
+
"agentPresets.composedPreset",
|
|
17
|
+
"permissionPresets.set",
|
|
18
|
+
"tools.restrict",
|
|
19
|
+
"tools.guard",
|
|
20
|
+
"tools.register",
|
|
21
|
+
"session.event-extension",
|
|
22
|
+
"agent.turn-stopping",
|
|
23
|
+
"agent.currentInitiator",
|
|
24
|
+
"systemPrompt.section",
|
|
25
|
+
"workspaceRegistry.get"
|
|
12
26
|
]
|
|
13
27
|
},
|
|
14
28
|
"node": "^22.19.0 || >=24.0.0"
|
package/cordis.patch.yml
CHANGED
|
@@ -7,3 +7,14 @@
|
|
|
7
7
|
route:
|
|
8
8
|
path: /qa
|
|
9
9
|
matchChildren: true
|
|
10
|
+
ui:
|
|
11
|
+
showReset: false
|
|
12
|
+
lockdown:
|
|
13
|
+
enabled: true
|
|
14
|
+
sandboxMode: read-only
|
|
15
|
+
approvalPolicy: never
|
|
16
|
+
permissionPreset: qa-read-only
|
|
17
|
+
allowSessionReset: false
|
|
18
|
+
toolPolicy:
|
|
19
|
+
mode: allow-list
|
|
20
|
+
allow: []
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -2,22 +2,64 @@
|
|
|
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
|
-
same-origin path marker. It
|
|
8
|
-
|
|
7
|
+
same-origin path marker. It also exposes one typed
|
|
8
|
+
`secureSession(sessionId)` operation whose policy is read only from Host
|
|
9
|
+
settings. The entry delegates that operation to `QaPolicyAdmission`
|
|
10
|
+
(`secure-session.ts`), the Host-side admission boundary. It does not serve
|
|
11
|
+
HTML, create another server, replace the frontend fallback, or touch
|
|
12
|
+
API/plugin routes. The browser removes the
|
|
9
13
|
marker and restores the requested path with `history.replaceState` before
|
|
10
|
-
route matching. The Host creates no sessions.
|
|
14
|
+
route matching. The Host creates no sessions itself.
|
|
11
15
|
|
|
12
16
|
The browser half registers `QaSurface` in the root-scoped `shell.overlay` list.
|
|
13
17
|
`QaRouteController` keeps that entry dormant outside the configured path and
|
|
14
18
|
reversibly observes `pushState`, `replaceState` and `popstate`.
|
|
15
19
|
|
|
16
|
-
`QaSessionController` is the only DSH session-coupled module. It uses
|
|
20
|
+
`QaSessionController` is the only browser-side DSH session-coupled module. It uses
|
|
17
21
|
`connection.api.sessions.create/selectModel` for creation policy and the public
|
|
18
|
-
`SessionFace` for prompt, cancel and snapshots
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
`SessionFace` for prompt, cancel and snapshots; the shared client contracts and
|
|
23
|
+
the idle state live in `client/types.ts`. Its supporting modules are pure
|
|
24
|
+
helpers: `client/wait-for.ts` waits on observable stores, `client/chat-index.ts`
|
|
25
|
+
(`QaChatIndex`) keeps the browser-local chat index and persisted active
|
|
26
|
+
session in storage, and `client/attestation.ts` parses Host reason markers and
|
|
27
|
+
validates proofs against the deployed lockdown config. `QaTranscriptAdapter`
|
|
28
|
+
projects session snapshots to plugin-local messages. "New chat" enters a
|
|
29
|
+
draft that materializes an attested session only when the first prompt is
|
|
30
|
+
sent, and the chat list orders by the host's `updatedAt`. The log is
|
|
31
|
+
append-only and there is no truncation seam, so regeneration prompts a
|
|
32
|
+
hidden instruction and projects the follow-up turns as variants of one
|
|
33
|
+
question; the same projection flattens tool activity into the sources
|
|
34
|
+
drawer (web targets, searches, files read). Subagent delegation, when the
|
|
35
|
+
deployment opts it in, renders launches and settlement notices inline, and
|
|
36
|
+
the agents drawer opens a child session as a read-only live transcript: the
|
|
37
|
+
binding skips attestation and every send path stays closed. By default it excludes
|
|
38
|
+
reasoning, tool arguments and tool results. When explicitly enabled, it
|
|
39
|
+
correlates assistant blocks, paired tool results, running calls and turn
|
|
40
|
+
timings into one plugin-local work group per turn; `QaWorkGroup` owns
|
|
41
|
+
disclosure state and collapses the group when the turn completes. System
|
|
42
|
+
context and raw failures remain excluded.
|
|
43
|
+
|
|
44
|
+
In locked mode the Host operation verifies immutable session composition,
|
|
45
|
+
refuses to adopt a non-QA session with user history, validates the named
|
|
46
|
+
permission preset, installs `ToolRestriction.allow`, installs an agent-scoped
|
|
47
|
+
monotonic execution guard, selects the permission preset, and returns only a
|
|
48
|
+
sanitized proof. The controller remains non-writable until every proof field
|
|
49
|
+
matches its Host-delivered config and repeats the check before prompt
|
|
50
|
+
admission. No private RPC handler, slash command, direct provider API, or DSH
|
|
51
|
+
core patch is used.
|
|
52
|
+
|
|
53
|
+
This narrows a QA agent's effective session/tool policy, but a route overlay on
|
|
54
|
+
a shared privileged Host is not an authorization boundary for other DSH
|
|
55
|
+
clients. Strong isolation requires a dedicated process/profile, restricted
|
|
56
|
+
identity and network boundary.
|
|
57
|
+
|
|
58
|
+
All interaction colors come from the company interaction palette
|
|
59
|
+
("Цвета взаимодействия"), defined once as the `QA_BRAND_PALETTE` object at the
|
|
60
|
+
top of `styles.ts` and emitted as `--dsh-qa-*` custom properties on the
|
|
61
|
+
overlay root; surfaces and typography keep using the themed `--dsw-alias-*`
|
|
62
|
+
tokens so light and dark hosts stay coherent.
|
|
21
63
|
|
|
22
64
|
The overlay locks document scrolling and contains keyboard focus while active.
|
|
23
65
|
It does not locate AppFrame through generated CSS classes and does not dispose
|
package/docs/COMPATIBILITY.md
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# Compatibility
|
|
2
2
|
|
|
3
|
-
| Plugin version | Tested DSH release | Required public contracts
|
|
4
|
-
| -------------- | ------------------ |
|
|
5
|
-
| 0.1.x | 0.1.
|
|
3
|
+
| Plugin version | Tested DSH release | Required public contracts |
|
|
4
|
+
| -------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
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
|
|
9
|
-
`QaRouteController
|
|
9
|
+
`QaRouteController`; Host lockdown coupling is isolated in
|
|
10
|
+
`QaSurface.secureSession`. The Host navigation adapter also works around this tested
|
|
10
11
|
release's exact-index static serving: `/qa` is redirected through `/`, then the
|
|
11
12
|
client restores the original pathname. Missing settings fall back to default
|
|
12
13
|
browser config; missing required client services prevent the browser plugin
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -7,12 +7,193 @@ 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
|
-
- reasoning
|
|
15
|
+
- reasoning and tool details are opt-in through `ui.showReasoning` and
|
|
16
|
+
`ui.showToolActivity`; enable them only where those contents are appropriate
|
|
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`;
|
|
21
|
+
- lockdown defaults to enabled and requires a non-empty permission preset;
|
|
22
|
+
- the preset must resolve on the Host to exactly `read-only` + `never`;
|
|
23
|
+
- permission, slash-command, settings, rename, delete and arbitrary-open
|
|
24
|
+
capability flags cannot be enabled;
|
|
25
|
+
- `showReset` requires the independent `allowSessionReset` opt-in;
|
|
26
|
+
- the tool policy is an allow-list; unknown configured tool names fail closed.
|
|
27
|
+
A name only resolves while its tool is actually mounted: MCP tools
|
|
28
|
+
(`mcp__<server>__*`) exist only while their server is reachable, so keep
|
|
29
|
+
them out of the allow list on hosts that cannot reach the server. Tools
|
|
30
|
+
mounted by an agent preset live in that preset's ancestor scope; the Host
|
|
31
|
+
validates and restricts the complete agent-scoped view, not just globals.
|
|
32
|
+
|
|
33
|
+
## Pinning chats to a directory
|
|
34
|
+
|
|
35
|
+
By default a QA chat is created against the Host working directory. Two
|
|
36
|
+
mutually exclusive pins anchor every new chat (and its subagents) to the
|
|
37
|
+
deployment's own directory:
|
|
38
|
+
|
|
39
|
+
- `session.cwd: "D:/qa-docs"` - an absolute directory used directly as the
|
|
40
|
+
session cwd; no registration needed. Attestation compares the session's
|
|
41
|
+
recorded cwd case- and separator-insensitively on Windows.
|
|
42
|
+
- `session.workspaceId: "<uuid>"` - a registered DSH workspace (created in
|
|
43
|
+
the web UI or via the workspace API; the id is a generated uuid, not the
|
|
44
|
+
path). Sessions attach to the workspace, so they group under it in the
|
|
45
|
+
host UI. When the id does not resolve, attestation refuses with
|
|
46
|
+
`reason: workspace-unavailable` instead of an opaque mismatch.
|
|
47
|
+
|
|
48
|
+
With `lockdown.enforceFixedWorkspace: true` (the default) a chat created
|
|
49
|
+
anywhere else refuses to attest, so the QA audience can never pull the
|
|
50
|
+
assistant out of the pinned directory.
|
|
14
51
|
|
|
15
52
|
Browser persistence stores only the DSH session id under
|
|
16
|
-
`<storageKey>:v1:<route>:session
|
|
53
|
+
`<storageKey>:v1:<route>:session`, plus — when `ui.showSessionList` is
|
|
54
|
+
enabled — a per-browser chat index under `<storageKey>:v1:<route>:chats`
|
|
55
|
+
(session ids only, capped at 50). Transcript content, credentials and tool
|
|
17
56
|
results remain in the Host-owned DSH Session and are never copied to browser
|
|
18
57
|
storage.
|
|
58
|
+
|
|
59
|
+
When either work-detail flag is enabled, the QA transcript groups reasoning,
|
|
60
|
+
intermediate assistant progress, and tool rows by DSH turn. Running work is
|
|
61
|
+
expanded. Completed work is collapsed behind a duration summary and can be
|
|
62
|
+
reopened; each tool row can separately reveal its formatted input and output.
|
|
63
|
+
These controls change presentation only and never widen the Host allow-list.
|
|
64
|
+
|
|
65
|
+
The browser cannot override lockdown settings. Before binding and immediately
|
|
66
|
+
before every prompt, it requests a Host attestation for the selected session.
|
|
67
|
+
Any unproved agent preset, workspace, model, permission bundle or tool policy
|
|
68
|
+
disables Send with the generic message `Настройки помощника недоступны.`
|
|
69
|
+
Detailed mismatch facts are written only to Host logs; the
|
|
70
|
+
browser console additionally prints one line with a stable coarse reason code
|
|
71
|
+
(`reason: unknown-tools`, `workspace-unavailable`, `composition-mismatch`, `permission-preset`,
|
|
72
|
+
`adoption-refused`, `proof-mismatch` or `attestation-failed`) plus an operator
|
|
73
|
+
hint, so a refused surface can be diagnosed without Host log access.
|
|
74
|
+
|
|
75
|
+
The built-in branding, controls, status messages and accessibility labels are
|
|
76
|
+
Russian. The default quick questions are rendered directly above the composer
|
|
77
|
+
only while the current chat is empty. Set `suggestedQuestions: []` to hide
|
|
78
|
+
them, or provide a deployment-specific list to replace them.
|
|
79
|
+
|
|
80
|
+
When adding tools, update the deployment's reviewed capability inventory as
|
|
81
|
+
part of the same change. The package's
|
|
82
|
+
[default inventory](../capability-policy.json) is intentionally empty, matching
|
|
83
|
+
the default `toolPolicy.allow`.
|
|
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
|
+
|
|
167
|
+
## Configuration channel over the LAN
|
|
168
|
+
|
|
169
|
+
The browser normally reads the effective configuration from the Host-owned
|
|
170
|
+
`qa-surface` settings namespace. DSH pins settings RPCs to loopback, so a
|
|
171
|
+
browser served over the LAN always sees that namespace as unavailable. In
|
|
172
|
+
that case the client calls the plugin's `qaSurface/describe` Host Remote and
|
|
173
|
+
uses the returned effective configuration; a rejected call falls back to the
|
|
174
|
+
client defaults with the same `unavailable` status as before. Only one
|
|
175
|
+
describe request runs per page load, and a settled answer survives scope
|
|
176
|
+
updates — the namespace (when readable) stays the authority and keeps
|
|
177
|
+
delivering live changes.
|
|
178
|
+
|
|
179
|
+
Host-side enforcement never depended on the browser's read path: `secureSession`
|
|
180
|
+
attestation re-derives everything from the Host-owned configuration on every
|
|
181
|
+
bind and every prompt.
|
|
182
|
+
|
|
183
|
+
## Skill catalog scope
|
|
184
|
+
|
|
185
|
+
The deployment's agent preset controls which skills the QA assistant sees.
|
|
186
|
+
The shipped `qa-research` preset mounts the skill filesystem with
|
|
187
|
+
`includeDefaultRoots: false`: project-root skills (for example the harness
|
|
188
|
+
checkout's own `.dsh/skills`) and user-home skills stay out of the catalog,
|
|
189
|
+
and skills enter only through plugin providers or an explicit
|
|
190
|
+
`customSkillDirs` list in the preset. Keep the QA catalog to exactly the
|
|
191
|
+
skills the audience is meant to use.
|
|
192
|
+
|
|
193
|
+
## Deleting chats
|
|
194
|
+
|
|
195
|
+
The sidebar delete control removes a chat from this browser's index only;
|
|
196
|
+
the Host session stays on disk. Deleting the chat that is currently open
|
|
197
|
+
continues in a fresh attested session when `lockdown.allowSessionReset` is
|
|
198
|
+
enabled. There is no Host session-deletion API in DSH 0.1.x for the plugin
|
|
199
|
+
to call.
|
|
@@ -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.
|