@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.
Files changed (161) hide show
  1. package/CHANGELOG.md +84 -1
  2. package/README.md +87 -12
  3. package/compatibility.json +11 -3
  4. package/docs/ARCHITECTURE.md +1 -1
  5. package/docs/COMPATIBILITY.md +1 -1
  6. package/docs/CONFIGURATION.md +88 -1
  7. package/docs/SOURCES-MIGRATION.md +28 -0
  8. package/docs/SOURCES-PROVENANCE-AUDIT.md +88 -0
  9. package/docs/SPEC-dsh-qa-surface-accounts.md +219 -0
  10. package/docs/SPEC-dsh-qa-surface-sources-provenance.md +1692 -0
  11. package/lib/accounts/index.js +2 -0
  12. package/lib/accounts/index.js.map +1 -0
  13. package/lib/accounts/store.js +478 -0
  14. package/lib/accounts/store.js.map +1 -0
  15. package/lib/attestation.js.map +1 -1
  16. package/lib/cli.js +143 -0
  17. package/lib/cli.js.map +1 -0
  18. package/lib/client/QaAccountsController.js +329 -0
  19. package/lib/client/QaAccountsController.js.map +1 -0
  20. package/lib/client/QaSessionController.js +203 -127
  21. package/lib/client/QaSessionController.js.map +1 -1
  22. package/lib/client/QaSurface.js +234 -72
  23. package/lib/client/QaSurface.js.map +1 -1
  24. package/lib/client/QaTranscriptAdapter.js +27 -241
  25. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  26. package/lib/client/attestation.js +6 -0
  27. package/lib/client/attestation.js.map +1 -1
  28. package/lib/client/components/Markdown.js +54 -13
  29. package/lib/client/components/Markdown.js.map +1 -1
  30. package/lib/client/components/QaAuthGate.js +40 -0
  31. package/lib/client/components/QaAuthGate.js.map +1 -0
  32. package/lib/client/components/QaChangelog.js +112 -0
  33. package/lib/client/components/QaChangelog.js.map +1 -0
  34. package/lib/client/components/QaMessage.js +47 -17
  35. package/lib/client/components/QaMessage.js.map +1 -1
  36. package/lib/client/components/QaSidebar.js +63 -20
  37. package/lib/client/components/QaSidebar.js.map +1 -1
  38. package/lib/client/components/QaSourcesDrawer.js +113 -32
  39. package/lib/client/components/QaSourcesDrawer.js.map +1 -1
  40. package/lib/client/components/QaTurnRail.js +281 -0
  41. package/lib/client/components/QaTurnRail.js.map +1 -0
  42. package/lib/client/components/QaWelcomeNotice.js +125 -0
  43. package/lib/client/components/QaWelcomeNotice.js.map +1 -0
  44. package/lib/client/components/QaWidthHandle.js +142 -0
  45. package/lib/client/components/QaWidthHandle.js.map +1 -0
  46. package/lib/client/components/source-refs.js +78 -0
  47. package/lib/client/components/source-refs.js.map +1 -0
  48. package/lib/client/create-session.js +51 -0
  49. package/lib/client/create-session.js.map +1 -0
  50. package/lib/client/index.js +100 -12
  51. package/lib/client/index.js.map +1 -1
  52. package/lib/client/project-session-state.js +78 -0
  53. package/lib/client/project-session-state.js.map +1 -0
  54. package/lib/client/session-admission.js +38 -0
  55. package/lib/client/session-admission.js.map +1 -0
  56. package/lib/client/session-assets.js +52 -0
  57. package/lib/client/session-assets.js.map +1 -0
  58. package/lib/client/session-sources.js +61 -0
  59. package/lib/client/session-sources.js.map +1 -0
  60. package/lib/client/settlement.js +24 -0
  61. package/lib/client/settlement.js.map +1 -0
  62. package/lib/client/styles.js +151 -9
  63. package/lib/client/styles.js.map +1 -1
  64. package/lib/client/tool-presentation.js +102 -0
  65. package/lib/client/tool-presentation.js.map +1 -0
  66. package/lib/client/turn-sources.js +98 -0
  67. package/lib/client/turn-sources.js.map +1 -0
  68. package/lib/client/types.js +2 -0
  69. package/lib/client/types.js.map +1 -1
  70. package/lib/client/use-session-ui-state.js +68 -0
  71. package/lib/client/use-session-ui-state.js.map +1 -0
  72. package/lib/client/use-transcript-view.js +44 -0
  73. package/lib/client/use-transcript-view.js.map +1 -0
  74. package/lib/client.js +4649 -861
  75. package/lib/client.js.map +1 -1
  76. package/lib/config.js +218 -102
  77. package/lib/config.js.map +1 -1
  78. package/lib/entry-redirect.js +44 -0
  79. package/lib/entry-redirect.js.map +1 -0
  80. package/lib/host-route.js +25 -1
  81. package/lib/host-route.js.map +1 -1
  82. package/lib/index.js +209 -23
  83. package/lib/index.js.map +1 -1
  84. package/lib/launch-token.js +42 -0
  85. package/lib/launch-token.js.map +1 -0
  86. package/lib/provenance/collector.js +40 -0
  87. package/lib/provenance/collector.js.map +1 -0
  88. package/lib/provenance/connectors.js +147 -0
  89. package/lib/provenance/connectors.js.map +1 -0
  90. package/lib/provenance/dedupe.js +89 -0
  91. package/lib/provenance/dedupe.js.map +1 -0
  92. package/lib/provenance/extractors.js +340 -0
  93. package/lib/provenance/extractors.js.map +1 -0
  94. package/lib/provenance/file-preview.js +39 -0
  95. package/lib/provenance/file-preview.js.map +1 -0
  96. package/lib/provenance/host-store.js +387 -0
  97. package/lib/provenance/host-store.js.map +1 -0
  98. package/lib/provenance/index.js +9 -0
  99. package/lib/provenance/index.js.map +1 -0
  100. package/lib/provenance/normalize.js +128 -0
  101. package/lib/provenance/normalize.js.map +1 -0
  102. package/lib/provenance/reported.js +53 -0
  103. package/lib/provenance/reported.js.map +1 -0
  104. package/lib/provenance/types.js +2 -0
  105. package/lib/provenance/types.js.map +1 -0
  106. package/lib/resolve-config.js +161 -0
  107. package/lib/resolve-config.js.map +1 -1
  108. package/lib/secure-session.js +50 -8
  109. package/lib/secure-session.js.map +1 -1
  110. package/lib/typert.host.js +599 -6
  111. package/lib/typert.remote-client.d.ts +19 -3
  112. package/lib/typert.remote-client.js +471 -3
  113. package/lib/types/accounts/index.d.ts +2 -0
  114. package/lib/types/accounts/store.d.ts +121 -0
  115. package/lib/types/attestation.d.ts +1 -1
  116. package/lib/types/cli.d.ts +9 -0
  117. package/lib/types/client/QaAccountsController.d.ts +95 -0
  118. package/lib/types/client/QaConfigController.d.ts +1 -1
  119. package/lib/types/client/QaSessionController.d.ts +46 -7
  120. package/lib/types/client/QaSurface.d.ts +8 -3
  121. package/lib/types/client/QaTranscriptAdapter.d.ts +5 -10
  122. package/lib/types/client/components/Markdown.d.ts +11 -1
  123. package/lib/types/client/components/QaAgentsDrawer.d.ts +1 -1
  124. package/lib/types/client/components/QaAuthGate.d.ts +15 -0
  125. package/lib/types/client/components/QaChangelog.d.ts +21 -0
  126. package/lib/types/client/components/QaMessage.d.ts +10 -3
  127. package/lib/types/client/components/QaSidebar.d.ts +30 -2
  128. package/lib/types/client/components/QaSourcesDrawer.d.ts +15 -3
  129. package/lib/types/client/components/QaTurnRail.d.ts +59 -0
  130. package/lib/types/client/components/QaWelcomeNotice.d.ts +27 -0
  131. package/lib/types/client/components/QaWidthHandle.d.ts +36 -0
  132. package/lib/types/client/components/source-refs.d.ts +16 -0
  133. package/lib/types/client/create-session.d.ts +16 -0
  134. package/lib/types/client/index.d.ts +1 -0
  135. package/lib/types/client/project-session-state.d.ts +30 -0
  136. package/lib/types/client/session-admission.d.ts +23 -0
  137. package/lib/types/client/session-assets.d.ts +20 -0
  138. package/lib/types/client/session-sources.d.ts +28 -0
  139. package/lib/types/client/settlement.d.ts +6 -0
  140. package/lib/types/client/tool-presentation.d.ts +6 -0
  141. package/lib/types/client/turn-sources.d.ts +14 -0
  142. package/lib/types/client/types.d.ts +73 -9
  143. package/lib/types/client/use-session-ui-state.d.ts +35 -0
  144. package/lib/types/client/use-transcript-view.d.ts +20 -0
  145. package/lib/types/entry-redirect.d.ts +20 -0
  146. package/lib/types/host-route.d.ts +14 -1
  147. package/lib/types/index.d.ts +47 -3
  148. package/lib/types/launch-token.d.ts +21 -0
  149. package/lib/types/provenance/collector.d.ts +26 -0
  150. package/lib/types/provenance/connectors.d.ts +11 -0
  151. package/lib/types/provenance/dedupe.d.ts +6 -0
  152. package/lib/types/provenance/extractors.d.ts +14 -0
  153. package/lib/types/provenance/file-preview.d.ts +10 -0
  154. package/lib/types/provenance/host-store.d.ts +54 -0
  155. package/lib/types/provenance/index.d.ts +10 -0
  156. package/lib/types/provenance/normalize.d.ts +13 -0
  157. package/lib/types/provenance/reported.d.ts +5 -0
  158. package/lib/types/provenance/types.d.ts +78 -0
  159. package/lib/types/secure-session.d.ts +11 -2
  160. package/lib/types/types.d.ts +167 -11
  161. package/package.json +58 -41
@@ -0,0 +1,54 @@
1
+ import type { Context } from "@deepseek-ai/cordis";
2
+ import type { QaTurnSources } from "./types.js";
3
+ import type { ResolvedQaSurfaceConfig } from "../types.js";
4
+ export declare const QA_REPORT_SOURCES_TOOL = "qa_report_sources";
5
+ declare module "@deepseek-ai/dsh-session" {
6
+ interface SessionEventMap {
7
+ "qa/sources": QaTurnSources;
8
+ }
9
+ }
10
+ interface SubagentInfo {
11
+ readonly runId: string;
12
+ readonly provider: string;
13
+ readonly id: string;
14
+ readonly local: boolean;
15
+ }
16
+ declare module "@deepseek-ai/cordis" {
17
+ interface Events {
18
+ "subagent/start"(info: SubagentInfo): void;
19
+ "subagent/end"(info: SubagentInfo): void;
20
+ }
21
+ }
22
+ /** Host authority for collection, replay, delegation inheritance and snapshots. */
23
+ export declare class QaProvenanceHost {
24
+ private readonly ctx;
25
+ private readonly config;
26
+ private readonly collectors;
27
+ private readonly snapshots;
28
+ private readonly calls;
29
+ private readonly lineage;
30
+ private readonly disposers;
31
+ constructor(ctx: Context, config: () => ResolvedQaSurfaceConfig);
32
+ dispose(): void;
33
+ /**
34
+ * Drop every per-session record of one chat. Long-lived servers outlive
35
+ * their sessions by weeks; without this the collector, snapshot, call and
36
+ * lineage maps grow with every chat and turn forever.
37
+ */
38
+ private forget;
39
+ private forgetAll;
40
+ bundles(sessionId: string): readonly QaTurnSources[];
41
+ sourceAllowed(sessionId: string, path: string): boolean;
42
+ private seed;
43
+ private observeEvent;
44
+ private shouldCollect;
45
+ private materialize;
46
+ private startSubagent;
47
+ private endSubagent;
48
+ private registerReportTool;
49
+ private collector;
50
+ private sessionCalls;
51
+ private sessionSnapshots;
52
+ }
53
+ export {};
54
+ //# sourceMappingURL=host-store.d.ts.map
@@ -0,0 +1,10 @@
1
+ export * from "./collector.js";
2
+ export * from "./connectors.js";
3
+ export * from "./dedupe.js";
4
+ export * from "./extractors.js";
5
+ export * from "./file-preview.js";
6
+ export * from "./host-store.js";
7
+ export * from "./normalize.js";
8
+ export * from "./reported.js";
9
+ export type * from "./types.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,13 @@
1
+ import type { QaSourceLocation } from "./types.js";
2
+ /** Strip model-added XML-like wrappers without interpreting arbitrary prose. */
3
+ export declare function unwrapSourceTarget(value: string): string;
4
+ /** Canonical HTTP(S) identity while retaining business-relevant parameters. */
5
+ export declare function canonicalizeUrl(value: string, options?: {
6
+ readonly normalize?: boolean;
7
+ readonly stripTrackingParams?: boolean;
8
+ }): string | null;
9
+ /** Normalize separators and, when possible, make a path workspace-relative. */
10
+ export declare function canonicalizeWorkspacePath(value: string, workspaceRoot?: string): string;
11
+ /** Union exact anchors and compact overlapping or adjacent ranges. */
12
+ export declare function compactLocations(locations: readonly QaSourceLocation[]): readonly QaSourceLocation[];
13
+ //# sourceMappingURL=normalize.d.ts.map
@@ -0,0 +1,5 @@
1
+ import { canonicalizeUrl } from "./normalize.js";
2
+ import type { QaReportedSource, QaSourceOrigin, QaSourceReference } from "./types.js";
3
+ /** Normalize a source explicitly reported by a delegated provider. */
4
+ export declare function normalizeReportedSource(source: QaReportedSource, origin: QaSourceOrigin, workspaceRoot?: string, urlOptions?: Parameters<typeof canonicalizeUrl>[1]): QaSourceReference | null;
5
+ //# sourceMappingURL=reported.d.ts.map
@@ -0,0 +1,78 @@
1
+ export type QaSourceKind = "file" | "code" | "web" | "jira" | "confluence" | "knowledge" | "other";
2
+ export type QaSourceEvidence = "read" | "fetched" | "queried" | "reported" | "inherited" | "discovered";
3
+ export type QaSourceMetadataValue = string | number | boolean | null | readonly QaSourceMetadataValue[] | {
4
+ readonly [key: string]: QaSourceMetadataValue;
5
+ };
6
+ export interface QaSourceMetadata {
7
+ readonly [key: string]: QaSourceMetadataValue;
8
+ }
9
+ export interface QaSourceLocation {
10
+ readonly path?: string;
11
+ readonly lineStart?: number;
12
+ readonly lineEnd?: number;
13
+ readonly anchor?: string;
14
+ readonly jiraKey?: string;
15
+ readonly confluencePageId?: string;
16
+ }
17
+ export interface QaSourceOrigin {
18
+ readonly sessionId: string;
19
+ readonly turn: number;
20
+ readonly step?: number;
21
+ readonly toolCallId?: string;
22
+ readonly toolName?: string;
23
+ readonly agentId?: string;
24
+ readonly role: "parent" | "subagent";
25
+ readonly subagentRunId?: string;
26
+ readonly subagentSessionId?: string;
27
+ }
28
+ export interface QaSourceReference {
29
+ /** Stable identity after path, URL or provider-specific normalization. */
30
+ readonly id: string;
31
+ readonly kind: QaSourceKind;
32
+ readonly title: string;
33
+ readonly uri?: string;
34
+ readonly path?: string;
35
+ readonly snippet?: string;
36
+ readonly locations: readonly QaSourceLocation[];
37
+ readonly evidence: QaSourceEvidence;
38
+ readonly origins: readonly QaSourceOrigin[];
39
+ readonly score: number;
40
+ readonly metadata?: QaSourceMetadata;
41
+ }
42
+ export interface QaTurnSources {
43
+ readonly version: 1;
44
+ readonly sessionId: string;
45
+ readonly turn: number;
46
+ readonly sources: readonly QaSourceReference[];
47
+ readonly discovered?: readonly QaSourceReference[];
48
+ readonly complete: boolean;
49
+ readonly incompleteOrigins?: readonly {
50
+ readonly subagentRunId?: string;
51
+ readonly provider?: string;
52
+ readonly reason: string;
53
+ }[];
54
+ }
55
+ export interface SourceExtractorContext {
56
+ readonly toolName: string;
57
+ readonly args: unknown;
58
+ readonly result: unknown;
59
+ readonly presentation?: unknown;
60
+ readonly origin: QaSourceOrigin;
61
+ /** Canonical session/workspace root used to make local paths portable. */
62
+ readonly workspaceRoot?: string;
63
+ }
64
+ export interface QaReportedSource {
65
+ readonly kind: QaSourceKind;
66
+ readonly title: string;
67
+ readonly uri?: string;
68
+ readonly path?: string;
69
+ readonly snippet?: string;
70
+ readonly locations?: readonly QaSourceLocation[];
71
+ readonly metadata?: QaSourceMetadata;
72
+ }
73
+ export interface SourceExtractor {
74
+ readonly id: string;
75
+ matches(context: SourceExtractorContext): boolean;
76
+ extract(context: SourceExtractorContext): readonly QaSourceReference[];
77
+ }
78
+ //# sourceMappingURL=types.d.ts.map
@@ -1,6 +1,14 @@
1
1
  import type { Context } from "@deepseek-ai/cordis";
2
2
  import type { PluginLogger } from "@yadsh/dsh-plugin-log";
3
3
  import type { QaLockdownProof, ResolvedQaSurfaceConfig } from "./types.js";
4
+ /**
5
+ * The accounts half of admission, resolved per call by the entry (accounts
6
+ * may be toggled at runtime). A gate must either accept the token/session
7
+ * pair or throw the coarse `QaAttestationError`; see {@link QaAccounts}.
8
+ */
9
+ export interface QaAccountsGate {
10
+ enforceSessionAccess(token: string, sessionId: string): void;
11
+ }
4
12
  /**
5
13
  * Host-side QA policy admission boundary — the only browser-callable operation
6
14
  * that turns a session into a locked QA session. It verifies the immutable
@@ -13,9 +21,10 @@ export declare class QaPolicyAdmission {
13
21
  private readonly ctx;
14
22
  private readonly config;
15
23
  private readonly logger;
24
+ private readonly accounts?;
16
25
  private readonly appliedPolicies;
17
- constructor(ctx: Context, config: () => ResolvedQaSurfaceConfig, logger: PluginLogger);
18
- secureSession(sessionId: string): QaLockdownProof;
26
+ constructor(ctx: Context, config: () => ResolvedQaSurfaceConfig, logger: PluginLogger, accounts?: QaAccountsGate | undefined);
27
+ secureSession(token: string, sessionId: string): QaLockdownProof;
19
28
  /** Detach every pinned tool policy; wired as a disposal effect by the entry. */
20
29
  dispose(): void;
21
30
  }
@@ -1,7 +1,87 @@
1
+ import type { QaTurnSources } from "./provenance/types.js";
1
2
  export type QaSessionPolicy = "browser-persistent" | "new-on-load" | "fixed";
2
3
  export type QaSandboxMode = "read-only";
3
4
  export type QaApprovalPolicy = "never";
4
5
  export type QaToolPolicyMode = "allow-list";
6
+ export type QaAccountRole = "user" | "admin";
7
+ /** The account fields projected to browsers; never includes credentials. */
8
+ export interface QaAccountUserPublic {
9
+ readonly id: string;
10
+ readonly email: string;
11
+ readonly displayName: string;
12
+ readonly role: QaAccountRole;
13
+ readonly createdAt: string;
14
+ readonly lastLoginAt: string | null;
15
+ readonly disabled: boolean;
16
+ }
17
+ /** One successful login/registration: the bearer token plus the user. */
18
+ export interface QaAccountSession {
19
+ readonly token: string;
20
+ readonly user: QaAccountUserPublic;
21
+ }
22
+ export type QaWhoamiResult = {
23
+ readonly authenticated: false;
24
+ } | {
25
+ readonly authenticated: true;
26
+ readonly user: QaAccountUserPublic;
27
+ };
28
+ /** Bulk ownership claim outcome for one browser's local chat index. */
29
+ export interface QaClaimResult {
30
+ readonly claimed: number;
31
+ /** Ids already owned by a different user; the browser drops them. */
32
+ readonly conflicts: readonly string[];
33
+ }
34
+ /**
35
+ * One chat-ownership entry as the admin views see it: the session, its owner
36
+ * and the owner's display name resolved at read time (a disabled account
37
+ * still names its chats).
38
+ */
39
+ export interface QaOwnershipEntry {
40
+ readonly sessionId: string;
41
+ readonly userId: string;
42
+ readonly displayName: string;
43
+ readonly claimedAt: string;
44
+ }
45
+ export interface QaSourcesConfig {
46
+ readonly enabled?: boolean;
47
+ readonly collect?: {
48
+ readonly parentAgent?: boolean;
49
+ readonly subagents?: boolean;
50
+ readonly persistTurnEvent?: boolean;
51
+ };
52
+ readonly display?: {
53
+ readonly sidebar?: boolean;
54
+ readonly footer?: boolean;
55
+ readonly groupByKind?: boolean;
56
+ readonly showDiscovered?: boolean;
57
+ readonly showOriginBadges?: boolean;
58
+ readonly maxInitiallyVisiblePerGroup?: number;
59
+ };
60
+ readonly webSearch?: {
61
+ readonly promoteSearchResultsWithoutFetch?: boolean;
62
+ readonly maxPromotedPerSearch?: number;
63
+ };
64
+ readonly dedupe?: {
65
+ readonly normalizeUrls?: boolean;
66
+ readonly stripTrackingParams?: boolean;
67
+ readonly mergeFileRanges?: boolean;
68
+ };
69
+ readonly filePreview?: {
70
+ readonly enabled?: boolean;
71
+ readonly markdownRenderedByDefault?: boolean;
72
+ readonly allowRawToggle?: boolean;
73
+ readonly maxBytes?: number;
74
+ readonly maxMarkdownRenderBytes?: number;
75
+ };
76
+ readonly subagents?: {
77
+ readonly inheritSources?: boolean;
78
+ readonly enableReportToolFallback?: boolean;
79
+ readonly markIncompleteOpaqueRuns?: boolean;
80
+ };
81
+ readonly legacy?: {
82
+ readonly parseAssistantSourcesBlock?: boolean;
83
+ };
84
+ }
5
85
  export interface QaSurfaceConfig {
6
86
  readonly enabled?: boolean;
7
87
  readonly route?: {
@@ -68,6 +148,21 @@ export interface QaSurfaceConfig {
68
148
  readonly embedding?: {
69
149
  readonly frameAncestors?: string | null;
70
150
  };
151
+ readonly accounts?: {
152
+ /** Opt-in; the QA gate stays off until the deployment turns this on. */
153
+ readonly enabled?: boolean;
154
+ readonly allowRegistration?: boolean;
155
+ readonly sessionTtlDays?: number;
156
+ /** Let admins see chats owned by other QA accounts. */
157
+ readonly showOtherUsersChats?: boolean;
158
+ };
159
+ readonly entry?: {
160
+ /** Inject the root → /qa redirect for non-loopback hostnames. */
161
+ readonly redirectNonLoopback?: boolean;
162
+ /** Cookie-less /qa navigations go through the one-time ?token= exchange. */
163
+ readonly cookieBootstrap?: boolean;
164
+ };
165
+ readonly sources?: QaSourcesConfig;
71
166
  }
72
167
  export interface ResolvedQaSurfaceConfig {
73
168
  readonly enabled: boolean;
@@ -133,6 +228,64 @@ export interface ResolvedQaSurfaceConfig {
133
228
  readonly embedding: {
134
229
  readonly frameAncestors: string | null;
135
230
  };
231
+ readonly accounts: {
232
+ readonly enabled: boolean;
233
+ readonly allowRegistration: boolean;
234
+ readonly sessionTtlDays: number;
235
+ readonly showOtherUsersChats: boolean;
236
+ };
237
+ readonly entry: {
238
+ readonly redirectNonLoopback: boolean;
239
+ readonly cookieBootstrap: boolean;
240
+ };
241
+ readonly sources: {
242
+ readonly enabled: boolean;
243
+ readonly collect: {
244
+ readonly parentAgent: boolean;
245
+ readonly subagents: boolean;
246
+ readonly persistTurnEvent: boolean;
247
+ };
248
+ readonly display: {
249
+ readonly sidebar: boolean;
250
+ readonly footer: boolean;
251
+ readonly groupByKind: boolean;
252
+ readonly showDiscovered: boolean;
253
+ readonly showOriginBadges: boolean;
254
+ readonly maxInitiallyVisiblePerGroup: number;
255
+ };
256
+ readonly webSearch: {
257
+ readonly promoteSearchResultsWithoutFetch: boolean;
258
+ readonly maxPromotedPerSearch: number;
259
+ };
260
+ readonly dedupe: {
261
+ readonly normalizeUrls: boolean;
262
+ readonly stripTrackingParams: boolean;
263
+ readonly mergeFileRanges: boolean;
264
+ };
265
+ readonly filePreview: {
266
+ readonly enabled: boolean;
267
+ readonly markdownRenderedByDefault: boolean;
268
+ readonly allowRawToggle: boolean;
269
+ readonly maxBytes: number;
270
+ readonly maxMarkdownRenderBytes: number;
271
+ };
272
+ readonly subagents: {
273
+ readonly inheritSources: boolean;
274
+ readonly enableReportToolFallback: boolean;
275
+ readonly markIncompleteOpaqueRuns: boolean;
276
+ };
277
+ readonly legacy: {
278
+ readonly parseAssistantSourcesBlock: boolean;
279
+ };
280
+ };
281
+ }
282
+ export interface QaSourceFilePreview {
283
+ readonly path: string;
284
+ readonly content: string;
285
+ readonly size: number;
286
+ readonly truncated: boolean;
287
+ readonly markdown: boolean;
288
+ readonly renderableMarkdown: boolean;
136
289
  }
137
290
  /** Host-attested facts required before the QA composer may become writable. */
138
291
  export interface QaLockdownProof {
@@ -154,6 +307,11 @@ export type QaMessage = {
154
307
  readonly status: "committed";
155
308
  readonly timestamp?: number;
156
309
  readonly images?: readonly QaImageView[];
310
+ /**
311
+ * Chat owner's display name, set only for an admin reading a foreign
312
+ * chat; the owner themself sees their messages unlabeled.
313
+ */
314
+ readonly author?: string;
157
315
  } | {
158
316
  readonly id: string;
159
317
  readonly role: "assistant";
@@ -162,6 +320,10 @@ export type QaMessage = {
162
320
  readonly timestamp?: number;
163
321
  /** Host turn this answer belongs to; groups regenerations into variants. */
164
322
  readonly turn?: number;
323
+ /** Canonical evidence snapshot shared with this answer's source drawer. */
324
+ readonly sources?: readonly QaSource[];
325
+ readonly sourcesComplete?: boolean;
326
+ readonly incompleteSourceOrigins?: QaTurnSources["incompleteOrigins"];
165
327
  /** Host-recorded response timing, present on finalized messages only. */
166
328
  readonly stats?: {
167
329
  /** step start → final message. */
@@ -211,17 +373,9 @@ export type QaWorkItem = {
211
373
  readonly endedAt?: number;
212
374
  };
213
375
  export type QaSessionPhase = "idle" | "creating" | "ready" | "running" | "reconnecting" | "blocked" | "error";
214
- /** One tool-derived source shown in the sources drawer. */
215
- export interface QaSource {
216
- readonly id: string;
217
- readonly kind: "web" | "search" | "file";
218
- /** URL, filesystem path or search query as the model supplied it. */
219
- readonly target: string;
220
- readonly title: string;
221
- readonly snippet: string;
222
- /** The tool's full text output, capped for the detail pane. */
223
- readonly output: string;
224
- }
376
+ export type { QaSourceEvidence, QaSourceKind, QaSourceLocation, QaSourceOrigin, QaSourceReference, QaTurnSources, } from "./provenance/types.js";
377
+ /** Transitional UI name; the drawer now consumes the canonical source object. */
378
+ export type QaSource = import("./provenance/types.js").QaSourceReference;
225
379
  /** Raster formats the attachment path accepts (mirrors the host contract). */
226
380
  export type QaImageMediaType = "image/png" | "image/jpeg" | "image/webp" | "image/gif";
227
381
  /** One image pending in the composer, browser-owned until the prompt lands. */
@@ -255,6 +409,8 @@ export interface QaSessionState {
255
409
  readonly chatsRevision: number;
256
410
  /** Tool-derived sources of the current chat (web targets and files read). */
257
411
  readonly sources: readonly QaSource[];
412
+ readonly sourcesComplete: boolean;
413
+ readonly incompleteSourceOrigins: QaTurnSources["incompleteOrigins"];
258
414
  /** Set while the bound session is a subagent watched from the panel. */
259
415
  readonly viewingSubagent: QaSubagentView | null;
260
416
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yadsh/dsh-qa-surface",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "A focused end-user QA surface backed by native DeepSeek Harness sessions",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,6 +14,9 @@
14
14
  "type": "module",
15
15
  "main": "./lib/index.js",
16
16
  "types": "./lib/types/index.d.ts",
17
+ "bin": {
18
+ "qa-accounts": "./lib/cli.js"
19
+ },
17
20
  "exports": {
18
21
  ".": {
19
22
  "types": "./lib/types/index.d.ts",
@@ -47,8 +50,9 @@
47
50
  ],
48
51
  "inject": [
49
52
  "@deepseek-ai/dsh-api-gateway",
53
+ "@deepseek-ai/dsh-api-session-controller",
54
+ "@deepseek-ai/dsh-agent-presets",
50
55
  "@deepseek-ai/dsh-client-connection",
51
- "@deepseek-ai/dsh-client-runtime",
52
56
  "@deepseek-ai/dsh-client-ui-layout",
53
57
  "@deepseek-ai/dsh-client-ui-settings",
54
58
  "@deepseek-ai/dsh-client-ui-theme"
@@ -83,58 +87,71 @@
83
87
  "node": "^22.19.0 || >=24.0.0"
84
88
  },
85
89
  "peerDependencies": {
86
- "@deepseek-ai/cordis": "^4.0.1",
87
- "@deepseek-ai/schemastery": "^3.18.1",
88
- "@deepseek-ai/dsh-api-gateway": ">=0.1.1-rc.2 <0.2.0",
89
- "@deepseek-ai/dsh-agent": ">=0.1.1-rc.2 <0.2.0",
90
- "@deepseek-ai/dsh-agent-presets": ">=0.1.1-rc.2 <0.2.0",
91
- "@deepseek-ai/dsh-client-connection": ">=0.1.1-rc.2 <0.2.0",
92
- "@deepseek-ai/dsh-client-runtime": ">=0.1.1-rc.2 <0.2.0",
93
- "@deepseek-ai/dsh-client-ui-layout": ">=0.1.1-rc.2 <0.2.0",
94
- "@deepseek-ai/dsh-client-ui-settings": ">=0.1.1-rc.2 <0.2.0",
95
- "@deepseek-ai/dsh-client-ui-slots": ">=0.1.1-rc.2 <0.2.0",
96
- "@deepseek-ai/dsh-client-ui-theme": ">=0.1.1-rc.2 <0.2.0",
97
- "@deepseek-ai/dsh-host-webserver": ">=0.1.1-rc.2 <0.2.0",
98
- "@deepseek-ai/dsh-permission-presets": ">=0.1.1-rc.2 <0.2.0",
99
- "@deepseek-ai/dsh-session": ">=0.1.1-rc.2 <0.2.0",
100
- "@deepseek-ai/dsh-settings": ">=0.1.1-rc.2 <0.2.0",
101
- "@deepseek-ai/dsh-tools": ">=0.1.1-rc.2 <0.2.0",
102
- "@deepseek-ai/dsh-typert-protocol": ">=0.1.1-rc.2 <0.2.0",
103
- "@deepseek-ai/dsh-workspace": ">=0.1.1-rc.2 <0.2.0",
104
- "react": "^18.2.0"
90
+ "@deepseek-ai/cordis": "^4.0.2",
91
+ "@deepseek-ai/schemastery": "^3.18.2",
92
+ "@deepseek-ai/dsh-api-gateway": ">=0.1.5-rc.2 <0.2.0",
93
+ "@deepseek-ai/dsh-agent": ">=0.1.5-rc.2 <0.2.0",
94
+ "@deepseek-ai/dsh-agent-presets": ">=0.1.5-rc.2 <0.2.0",
95
+ "@deepseek-ai/dsh-api-session-controller": ">=0.1.5-rc.2 <0.2.0",
96
+ "@deepseek-ai/dsh-api-workspace-controller": ">=0.1.5-rc.2 <0.2.0",
97
+ "@deepseek-ai/dsh-client-connection": ">=0.1.5-rc.2 <0.2.0",
98
+ "@deepseek-ai/dsh-client-ui-conversation": ">=0.1.5-rc.2 <0.2.0",
99
+ "@deepseek-ai/dsh-client-ui-chat": ">=0.1.5-rc.2 <0.2.0",
100
+ "@deepseek-ai/dsh-client-ui-layout": ">=0.1.5-rc.2 <0.2.0",
101
+ "@deepseek-ai/dsh-client-ui-renderer": ">=0.1.5-rc.2 <0.2.0",
102
+ "@deepseek-ai/dsh-client-ui-settings": ">=0.1.5-rc.2 <0.2.0",
103
+ "@deepseek-ai/dsh-client-ui-slots": ">=0.1.5-rc.2 <0.2.0",
104
+ "@deepseek-ai/dsh-client-ui-theme": ">=0.1.5-rc.2 <0.2.0",
105
+ "@deepseek-ai/dsh-host-webserver": ">=0.1.5-rc.2 <0.2.0",
106
+ "@deepseek-ai/dsh-permission-presets": ">=0.1.5-rc.2 <0.2.0",
107
+ "@deepseek-ai/dsh-session": ">=0.1.5-rc.2 <0.2.0",
108
+ "@deepseek-ai/dsh-settings": ">=0.1.5-rc.2 <0.2.0",
109
+ "@deepseek-ai/dsh-system-prompt": ">=0.1.5-rc.2 <0.2.0",
110
+ "@deepseek-ai/dsh-tools": ">=0.1.5-rc.2 <0.2.0",
111
+ "@deepseek-ai/dsh-typert-protocol": ">=0.1.5-rc.2 <0.2.0",
112
+ "@deepseek-ai/dsh-workspace": ">=0.1.5-rc.2 <0.2.0",
113
+ "react": "^18.2.0",
114
+ "react-dom": "^18.2.0"
105
115
  },
106
116
  "dependencies": {
107
117
  "zod": "^4.4.3",
108
118
  "@yadsh/dsh-plugin-log": "^0.2.1"
109
119
  },
110
120
  "devDependencies": {
111
- "@deepseek-ai/cordis": "4.0.1",
112
- "@deepseek-ai/schemastery": "3.18.1",
113
- "@deepseek-ai/dsh-api-gateway": "0.1.1-rc.2",
114
- "@deepseek-ai/dsh-agent": "0.1.1-rc.2",
115
- "@deepseek-ai/dsh-agent-presets": "0.1.1-rc.2",
116
- "@deepseek-ai/dsh-client-connection": "0.1.1-rc.2",
117
- "@deepseek-ai/dsh-client-runtime": "0.1.1-rc.2",
118
- "@deepseek-ai/dsh-client-ui-layout": "0.1.1-rc.2",
119
- "@deepseek-ai/dsh-client-ui-settings": "0.1.1-rc.2",
120
- "@deepseek-ai/dsh-client-ui-slots": "0.1.1-rc.2",
121
- "@deepseek-ai/dsh-client-ui-theme": "0.1.1-rc.2",
122
- "@deepseek-ai/dsh-host-webserver": "0.1.1-rc.2",
123
- "@deepseek-ai/dsh-permission-presets": "0.1.1-rc.2",
124
- "@deepseek-ai/dsh-session": "0.1.1-rc.2",
125
- "@deepseek-ai/dsh-settings": "0.1.1-rc.2",
126
- "@deepseek-ai/dsh-tools": "0.1.1-rc.2",
127
- "@deepseek-ai/dsh-typert-generator": "0.1.1-rc.2",
128
- "@deepseek-ai/dsh-typert-protocol": "0.1.1-rc.2",
129
- "@deepseek-ai/dsh-workspace": "0.1.1-rc.2",
121
+ "@deepseek-ai/cordis": "4.0.2",
122
+ "@deepseek-ai/schemastery": "3.18.2",
123
+ "@deepseek-ai/dsh-api-gateway": "0.1.5-rc.2",
124
+ "@deepseek-ai/dsh-agent": "0.1.5-rc.2",
125
+ "@deepseek-ai/dsh-agent-presets": "0.1.5-rc.2",
126
+ "@deepseek-ai/dsh-api-session-controller": "0.1.5-rc.2",
127
+ "@deepseek-ai/dsh-api-workspace-controller": "0.1.5-rc.2",
128
+ "@deepseek-ai/dsh-client-connection": "0.1.5-rc.2",
129
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.5-rc.2",
130
+ "@deepseek-ai/dsh-client-ui-chat": "0.1.5-rc.2",
131
+ "@deepseek-ai/dsh-client-ui-layout": "0.1.5-rc.2",
132
+ "@deepseek-ai/dsh-client-ui-renderer": "0.1.5-rc.2",
133
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.2",
134
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.5-rc.2",
135
+ "@deepseek-ai/dsh-client-ui-theme": "0.1.5-rc.2",
136
+ "@deepseek-ai/dsh-host-webserver": "0.1.5-rc.2",
137
+ "@deepseek-ai/dsh-permission-presets": "0.1.5-rc.2",
138
+ "@deepseek-ai/dsh-session": "0.1.5-rc.2",
139
+ "@deepseek-ai/dsh-settings": "0.1.5-rc.2",
140
+ "@deepseek-ai/dsh-system-prompt": "0.1.5-rc.2",
141
+ "@deepseek-ai/dsh-tools": "0.1.5-rc.2",
142
+ "@deepseek-ai/dsh-typert-generator": "0.1.5-rc.2",
143
+ "@deepseek-ai/dsh-typert-protocol": "0.1.5-rc.2",
144
+ "@deepseek-ai/dsh-workspace": "0.1.5-rc.2",
130
145
  "@testing-library/react": "^16.3.0",
131
146
  "@types/node": "^26.4.0",
132
147
  "@types/react": "18.3.28",
148
+ "@types/react-dom": "18.3.7",
133
149
  "eslint": "10.9.1",
134
150
  "jsdom": "^26.1.0",
135
151
  "playwright": "1.62.1",
136
152
  "prettier": "^3.6.2",
137
153
  "react": "18.3.1",
154
+ "react-dom": "18.3.1",
138
155
  "tsdown": "^0.22.14",
139
156
  "typescript": "^7.0.2",
140
157
  "vitest": "^4.1.11",
@@ -147,7 +164,7 @@
147
164
  },
148
165
  "scripts": {
149
166
  "clean": "node -e \"require('node:fs').rmSync('lib', { recursive: true, force: true })\"",
150
- "build": "pnpm run clean && node scripts/generate-typert.mjs && tsc -p tsconfig.build.json && tsdown",
167
+ "build": "pnpm run lint && pnpm run clean && node scripts/generate-typert.mjs && tsc -p tsconfig.build.json && tsdown",
151
168
  "lint": "eslint src tests scripts tsdown.config.ts",
152
169
  "format": "prettier --check . --end-of-line auto",
153
170
  "format:write": "prettier --write . --end-of-line auto",