@yadsh/dsh-qa-surface 0.9.0 → 0.10.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 (130) hide show
  1. package/README.md +29 -1
  2. package/lib/admin/service.js +7 -7
  3. package/lib/admin/service.js.map +1 -1
  4. package/lib/client/QaSessionController.js +12 -0
  5. package/lib/client/QaSessionController.js.map +1 -1
  6. package/lib/client/QaSurface.js +23 -5
  7. package/lib/client/QaSurface.js.map +1 -1
  8. package/lib/client/QaSurfaceGuard.js +12 -5
  9. package/lib/client/QaSurfaceGuard.js.map +1 -1
  10. package/lib/client/admin/QaAdmin.js +5 -1
  11. package/lib/client/admin/QaAdmin.js.map +1 -1
  12. package/lib/client/admin/pages/Users.js +9 -2
  13. package/lib/client/admin/pages/Users.js.map +1 -1
  14. package/lib/client/admin/shared.js +5 -1
  15. package/lib/client/admin/shared.js.map +1 -1
  16. package/lib/client/base64.js +22 -1
  17. package/lib/client/base64.js.map +1 -1
  18. package/lib/client/components/QaAgentsDrawer.js +9 -6
  19. package/lib/client/components/QaAgentsDrawer.js.map +1 -1
  20. package/lib/client/components/QaApproval.js +1 -1
  21. package/lib/client/components/QaApproval.js.map +1 -1
  22. package/lib/client/components/QaChangelog.js +29 -0
  23. package/lib/client/components/QaChangelog.js.map +1 -1
  24. package/lib/client/components/QaFilesPanel.js +17 -11
  25. package/lib/client/components/QaFilesPanel.js.map +1 -1
  26. package/lib/client/components/QaHeader.js +3 -11
  27. package/lib/client/components/QaHeader.js.map +1 -1
  28. package/lib/client/components/QaModal.js.map +1 -1
  29. package/lib/client/components/QaQuestions.js +4 -4
  30. package/lib/client/components/QaQuestions.js.map +1 -1
  31. package/lib/client/components/QaSidebar.js +10 -2
  32. package/lib/client/components/QaSidebar.js.map +1 -1
  33. package/lib/client/components/QaWidthHandle.js +111 -5
  34. package/lib/client/components/QaWidthHandle.js.map +1 -1
  35. package/lib/client/components/QaWorkspaceBrowser.js +231 -0
  36. package/lib/client/components/QaWorkspaceBrowser.js.map +1 -0
  37. package/lib/client/index.js +109 -53
  38. package/lib/client/index.js.map +1 -1
  39. package/lib/client/kiosk.js +51 -0
  40. package/lib/client/kiosk.js.map +1 -0
  41. package/lib/client/markdown/blocks.js +122 -7
  42. package/lib/client/markdown/blocks.js.map +1 -1
  43. package/lib/client/markdown/inline.js +108 -12
  44. package/lib/client/markdown/inline.js.map +1 -1
  45. package/lib/client/markdown/katex-css.js +12 -0
  46. package/lib/client/markdown/katex-css.js.map +1 -0
  47. package/lib/client/markdown/math.js +84 -0
  48. package/lib/client/markdown/math.js.map +1 -0
  49. package/lib/client/markdown/render.js +74 -5
  50. package/lib/client/markdown/render.js.map +1 -1
  51. package/lib/client/settings/card.js +2 -2
  52. package/lib/client/settings/card.js.map +1 -1
  53. package/lib/client/settings/sections/notes.js +46 -0
  54. package/lib/client/settings/sections/notes.js.map +1 -0
  55. package/lib/client/settings/sections/sources.js +4 -1
  56. package/lib/client/settings/sections/sources.js.map +1 -1
  57. package/lib/client/settings/sections.js +1 -0
  58. package/lib/client/settings/sections.js.map +1 -1
  59. package/lib/client/settlement.js +1 -1
  60. package/lib/client/settlement.js.map +1 -1
  61. package/lib/client/source-preview.js +3 -0
  62. package/lib/client/source-preview.js.map +1 -1
  63. package/lib/client/styles.js +97 -18
  64. package/lib/client/styles.js.map +1 -1
  65. package/lib/client/types.js.map +1 -1
  66. package/lib/client.js +28587 -595
  67. package/lib/client.js.map +1 -1
  68. package/lib/config-resolvers/defaults.js +10 -0
  69. package/lib/config-resolvers/defaults.js.map +1 -1
  70. package/lib/config-resolvers/notes.js +24 -0
  71. package/lib/config-resolvers/notes.js.map +1 -0
  72. package/lib/config-resolvers/sources.js +4 -0
  73. package/lib/config-resolvers/sources.js.map +1 -1
  74. package/lib/config.js +35 -0
  75. package/lib/config.js.map +1 -1
  76. package/lib/index.js +151 -10
  77. package/lib/index.js.map +1 -1
  78. package/lib/prompt-notes.js +45 -6
  79. package/lib/prompt-notes.js.map +1 -1
  80. package/lib/provenance/document-preview.js +51 -0
  81. package/lib/provenance/document-preview.js.map +1 -0
  82. package/lib/provenance/file-preview.js +191 -19
  83. package/lib/provenance/file-preview.js.map +1 -1
  84. package/lib/qa-tools/catalog.js +7 -1
  85. package/lib/qa-tools/catalog.js.map +1 -1
  86. package/lib/qa-tools/file-delete-gate.js +60 -0
  87. package/lib/qa-tools/file-delete-gate.js.map +1 -0
  88. package/lib/qa-tools/file-delete.js +156 -0
  89. package/lib/qa-tools/file-delete.js.map +1 -0
  90. package/lib/resolve-config.js +2 -0
  91. package/lib/resolve-config.js.map +1 -1
  92. package/lib/shared/documents.js +22 -0
  93. package/lib/shared/documents.js.map +1 -0
  94. package/lib/typert.host.js +278 -55
  95. package/lib/typert.remote-client.d.ts +7 -1
  96. package/lib/typert.remote-client.js +239 -53
  97. package/lib/types/client/admin/shared.d.ts +2 -0
  98. package/lib/types/client/base64.d.ts +13 -1
  99. package/lib/types/client/components/QaAgentsDrawer.d.ts +2 -1
  100. package/lib/types/client/components/QaFilesPanel.d.ts +16 -4
  101. package/lib/types/client/components/QaHeader.d.ts +9 -3
  102. package/lib/types/client/components/QaModal.d.ts +4 -3
  103. package/lib/types/client/components/QaWidthHandle.d.ts +48 -2
  104. package/lib/types/client/components/QaWorkspaceBrowser.d.ts +15 -0
  105. package/lib/types/client/index.d.ts +1 -1
  106. package/lib/types/client/kiosk.d.ts +34 -0
  107. package/lib/types/client/markdown/blocks.d.ts +14 -1
  108. package/lib/types/client/markdown/inline.d.ts +23 -7
  109. package/lib/types/client/markdown/katex-css.d.ts +11 -0
  110. package/lib/types/client/markdown/math.d.ts +23 -0
  111. package/lib/types/client/markdown/render.d.ts +2 -1
  112. package/lib/types/client/settings/sections/notes.d.ts +10 -0
  113. package/lib/types/client/settings/sections.d.ts +1 -0
  114. package/lib/types/client/settlement.d.ts +4 -1
  115. package/lib/types/client/styles.d.ts +15 -2
  116. package/lib/types/client/types.d.ts +50 -1
  117. package/lib/types/config-resolvers/notes.d.ts +10 -0
  118. package/lib/types/index.d.ts +39 -1
  119. package/lib/types/prompt-notes.d.ts +9 -0
  120. package/lib/types/provenance/document-preview.d.ts +24 -0
  121. package/lib/types/provenance/file-preview.d.ts +69 -2
  122. package/lib/types/qa-tools/catalog.d.ts +1 -1
  123. package/lib/types/qa-tools/file-delete-gate.d.ts +42 -0
  124. package/lib/types/qa-tools/file-delete.d.ts +32 -0
  125. package/lib/types/shared/documents.d.ts +20 -0
  126. package/lib/types/types.d.ts +93 -1
  127. package/lib/types/ui-mode.d.ts +18 -0
  128. package/lib/ui-mode.js +22 -0
  129. package/lib/ui-mode.js.map +1 -0
  130. package/package.json +10 -8
@@ -17,6 +17,8 @@ export declare function useAdminResource<T>(load: () => Promise<RemoteResult<T>>
17
17
  readonly error: string | undefined;
18
18
  readonly loading: boolean;
19
19
  reload: () => Promise<void>;
20
+ /** Adopt a value this page already holds, without re-asking the Host. */
21
+ apply: (value: T) => void;
20
22
  };
21
23
  /** A status chip; the modifier class carries the semantic colour. */
22
24
  export declare function Badge(props: {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Browser-side binary-to-base64. Chunked so `String.fromCharCode` never
2
+ * Browser-side base64. Encoding is chunked so `String.fromCharCode` never
3
3
  * crosses the engine's argument limit on large attachments.
4
4
  */
5
5
  /**
@@ -7,4 +7,16 @@
7
7
  * @returns the canonical base64 text (no `data:` prefix, no padding tricks).
8
8
  */
9
9
  export declare function bytesToBase64(bytes: Uint8Array): string;
10
+ /**
11
+ * Decode base64 the Host sent for a file the panel could not read as text.
12
+ *
13
+ * A malformed body is tolerated rather than thrown on: the caller is about to
14
+ * hand the bytes to a download or an image tag, and a partial file is a better
15
+ * outcome than losing the panel to an exception. `atob` still rejects input
16
+ * that is not base64 at all; the caller keeps that refusal.
17
+ *
18
+ * @param value - base64 text, with or without a data-URL prefix.
19
+ * @returns the decoded bytes.
20
+ */
21
+ export declare function base64ToBytes(value: string): Uint8Array;
10
22
  //# sourceMappingURL=base64.d.ts.map
@@ -5,7 +5,8 @@ export interface QaSubagentRow {
5
5
  readonly title: string;
6
6
  readonly running: boolean;
7
7
  readonly completed: boolean;
8
- readonly meta: string;
8
+ /** Muted facts rendered after the title, one span per part. */
9
+ readonly meta: readonly string[];
9
10
  }
10
11
  /**
11
12
  * Direct subagent children of the open chat, running first. Reads the host
@@ -1,15 +1,27 @@
1
1
  import type { QaChatFileGroup } from "../chat-files.js";
2
+ import type { QaBoundSourceApi } from "../types.js";
2
3
  export interface QaFilesPanelProps {
3
4
  readonly groups: readonly QaChatFileGroup[];
4
5
  /** Resolve an image attachment to an object URL; images render inert without it. */
5
6
  readonly resolveImage?: (attachmentId: string) => Promise<string>;
6
7
  /** Scroll the transcript to the group's user message. */
7
8
  readonly onJumpToMessage: (messageId: string) => void;
9
+ /**
10
+ * The chat whose workspace the panel browses. Both this and `api` are absent
11
+ * in hosts that only render the attachment roster, where the workspace
12
+ * section is left out rather than shown as a refusal.
13
+ */
14
+ readonly sessionId?: string;
15
+ readonly api?: QaBoundSourceApi;
8
16
  }
9
17
  /**
10
- * The chat's attachment roster: one section per sending message, newest
11
- * first. Rows mirror the transcript's handles — the browser never reads a
12
- * file back, and the images are the same object URLs the message showed.
18
+ * The chat's attachment roster plus, when the Host is reachable, the chat's
19
+ * own workspace: one section per sending message, newest first, and above it
20
+ * the file browser the conversation worked in.
21
+ *
22
+ * Rows mirror the transcript's handles — the browser never reads an attachment
23
+ * back, and the images are the same object URLs the message showed — while the
24
+ * workspace section reads through the Host's fenced listing and file reads.
13
25
  */
14
- export declare function QaFilesPanel({ groups, resolveImage, onJumpToMessage, }: QaFilesPanelProps): import("react/jsx-runtime").JSX.Element;
26
+ export declare function QaFilesPanel({ groups, resolveImage, onJumpToMessage, sessionId, api, }: QaFilesPanelProps): import("react/jsx-runtime").JSX.Element;
15
27
  //# sourceMappingURL=QaFilesPanel.d.ts.map
@@ -17,10 +17,9 @@ export interface QaHeaderProps {
17
17
  readonly logoUrl: string | null;
18
18
  /** The derived conversation title; null hides the heading. */
19
19
  readonly title: string | null;
20
- /** A subagent view replaces the mode caption with its return control. */
20
+ /** A subagent view shows its return control in the title row. */
21
21
  readonly viewingSubagent: boolean;
22
22
  readonly onCloseSubagent: () => void;
23
- readonly agentPreset: string | null;
24
23
  readonly roleSelector?: ReactNode;
25
24
  readonly administration?: {
26
25
  readonly onOpen: () => void;
@@ -36,6 +35,13 @@ export interface QaHeaderProps {
36
35
  readonly sourcesOpen: boolean;
37
36
  readonly onOpenSources: () => void;
38
37
  readonly fileCount: number;
38
+ /**
39
+ * Whether the files tab has anything to open: attachments, or the chat's own
40
+ * workspace when the deployment lets the panel read files. The count stays
41
+ * the attachment number, so an empty chat with a readable workspace shows no
42
+ * badge but still opens.
43
+ */
44
+ readonly filesEnabled: boolean;
39
45
  readonly filesOpen: boolean;
40
46
  readonly onOpenFiles: () => void;
41
47
  /**
@@ -53,5 +59,5 @@ export interface QaHeaderProps {
53
59
  readonly resetDisabled: boolean;
54
60
  readonly onReset: () => void;
55
61
  }
56
- export declare function QaHeader({ logoUrl, title, viewingSubagent, onCloseSubagent, agentPreset, roleSelector, administration, agentCount, agentsOpen, onToggleAgents, sourcesVisible, sourcesCount, sourcesComplete, sourcesOpen, onOpenSources, fileCount, filesOpen, onOpenFiles, settings, panelLauncher, showReset, resetDisabled, onReset, }: QaHeaderProps): import("react/jsx-runtime").JSX.Element;
62
+ export declare function QaHeader({ logoUrl, title, viewingSubagent, onCloseSubagent, roleSelector, administration, agentCount, agentsOpen, onToggleAgents, sourcesVisible, sourcesCount, sourcesComplete, sourcesOpen, onOpenSources, fileCount, filesEnabled, filesOpen, onOpenFiles, settings, panelLauncher, showReset, resetDisabled, onReset, }: QaHeaderProps): import("react/jsx-runtime").JSX.Element;
57
63
  //# sourceMappingURL=QaHeader.d.ts.map
@@ -11,11 +11,12 @@ export interface QaModalProps {
11
11
  readonly footer?: ReactNode;
12
12
  readonly wide?: boolean;
13
13
  /**
14
- * Panel size: `wide` fits prose that must not wrap mid-sentence, and
14
+ * Panel size: `wide` fits prose that must not wrap mid-sentence,
15
15
  * `settings` the sectioned user-settings dialog, which needs both a
16
- * comfortable height and a two-column body.
16
+ * comfortable height and a two-column body, and `document` a file
17
+ * preview the reader expanded out of the rail.
17
18
  */
18
- readonly size?: "default" | "wide" | "settings";
19
+ readonly size?: "default" | "wide" | "settings" | "document";
19
20
  }
20
21
  /**
21
22
  * The shared QA dialog shell: backdrop, panel, head with the close control,
@@ -19,8 +19,12 @@ export declare const QA_HANDLE_FREE_BAND = 40;
19
19
  * at every width; the stylesheet caps it once more by the live side gutter.
20
20
  */
21
21
  export declare const QA_BLEED_MAX_WIDTH: number;
22
- export declare function readQaContentWidth(storage: Pick<Storage, "getItem">, key: string): number | null;
23
- export declare function writeQaContentWidth(storage: Pick<Storage, "setItem">, key: string, width: number): void;
22
+ /**
23
+ * A stored positive width, or null when the browser has none (first visit,
24
+ * denied storage, corrupt value). Shared by every draggable width.
25
+ */
26
+ export declare function readQaStoredWidth(storage: Pick<Storage, "getItem">, key: string): number | null;
27
+ export declare function writeQaStoredWidth(storage: Pick<Storage, "setItem">, key: string, width: number): void;
24
28
  /**
25
29
  * Resolve the centered content width for the currently available column. The
26
30
  * operator sets only the floor; the column is the ceiling, so the content may
@@ -52,5 +56,47 @@ export declare function useQaContentWidth({ active, root, storage, storageKey, m
52
56
  readonly onEnd: () => void;
53
57
  };
54
58
  export type UseQaContentWidthResult = ReturnType<typeof useQaContentWidth>;
59
+ /** Drag clamp for the chat-list sidebar, borrowed from the DSH frame. */
60
+ export declare const QA_SIDEBAR_MIN_WIDTH = 264;
61
+ export declare const QA_SIDEBAR_MAX_WIDTH = 420;
62
+ /** The width the sidebar keeps until its first drag: today's fixed width. */
63
+ export declare const QA_SIDEBAR_DEFAULT_WIDTH = 264;
64
+ /** Integer pixels, no snapping and no step, like the DSH frame clamp. */
65
+ export declare function clampQaSidebarWidth(px: number): number;
66
+ /** Resolve the sidebar width for this browser: the stored drag or the default. */
67
+ export declare function resolveQaSidebarWidth(stored: number | null): number;
68
+ interface QaSidebarHandleProps {
69
+ readonly onStart: () => number;
70
+ readonly onDrag: (width: number) => void;
71
+ readonly onCommit: (width: number) => void;
72
+ readonly onEnd: () => void;
73
+ }
74
+ /**
75
+ * The invisible strip on the sidebar's border, like the DSH frame's handle: an
76
+ * 8px hit target straddling the edge, found by the cursor alone. One-sided —
77
+ * the pointer delta is the width delta — and pointer-captured, so the drag
78
+ * keeps tracking outside the strip and never selects text.
79
+ */
80
+ export declare function QaSidebarHandle(props: QaSidebarHandleProps): import("react/jsx-runtime").JSX.Element;
81
+ interface UseQaSidebarWidthOptions {
82
+ /** Whether the expanded sidebar is mounted (the collapsed rail has none). */
83
+ readonly active: boolean;
84
+ readonly root: RefObject<HTMLElement | null>;
85
+ readonly storage: Pick<Storage, "getItem" | "setItem">;
86
+ readonly storageKey: string;
87
+ }
88
+ /**
89
+ * Sidebar counterpart of `useQaContentWidth`: the width never enters React
90
+ * state — the drag writes the custom property straight onto the nav element,
91
+ * so the memoized sidebar does not re-render per frame — and only the
92
+ * committed value reaches storage, which the next mount restores.
93
+ */
94
+ export declare function useQaSidebarWidth({ active, root, storage, storageKey, }: UseQaSidebarWidthOptions): {
95
+ readonly onStart: () => number;
96
+ readonly onDrag: (width: number) => void;
97
+ readonly onCommit: (width: number) => void;
98
+ readonly onEnd: () => void;
99
+ };
100
+ export type UseQaSidebarWidthResult = ReturnType<typeof useQaSidebarWidth>;
55
101
  export {};
56
102
  //# sourceMappingURL=QaWidthHandle.d.ts.map
@@ -0,0 +1,15 @@
1
+ import type { QaBoundSourceApi } from "../types.js";
2
+ export interface QaWorkspaceBrowserProps {
3
+ readonly sessionId: string;
4
+ readonly api: QaBoundSourceApi;
5
+ }
6
+ /**
7
+ * The chat's own workspace, browsable from the files rail.
8
+ *
9
+ * One directory at a time: the Host lists a directory, the panel descends into
10
+ * its children and never travels by path, so a link in a listing cannot walk
11
+ * the visitor out of the chat's tree. Opening a file reads exactly that file —
12
+ * text inline, anything else as a downloadable handle.
13
+ */
14
+ export declare function QaWorkspaceBrowser({ sessionId, api, }: QaWorkspaceBrowserProps): import("react/jsx-runtime").JSX.Element;
15
+ //# sourceMappingURL=QaWorkspaceBrowser.d.ts.map
@@ -6,7 +6,7 @@ declare module "@deepseek-ai/cordis" {
6
6
  }
7
7
  }
8
8
  export declare const inject: string[];
9
- /** Register the route-aware, full-frame QA entry in the additive overlay slot. */
9
+ /** Register the route-aware, full-frame QA entry: root owner in the kiosk, additive overlay slot otherwise. */
10
10
  export declare function apply(ctx: Context): Promise<() => Promise<void>>;
11
11
  export { QaConfigController } from "./QaConfigController.js";
12
12
  export { QaAccountsController } from "./QaAccountsController.js";
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The QA kiosk presentation mode, as the client half of the plugin sees it.
3
+ *
4
+ * The harness publishes the deployment's UI mode into every served document
5
+ * ahead of the first application script (the index prelude injected for
6
+ * `DSH_UI_MODE=qa`): `window.DSH_UI_MODE` and, alongside it, the QA base path
7
+ * the server-side route policy serves the application under. The mode — not
8
+ * `location.pathname` — is what the client branches on: the route policy owns
9
+ * which paths carry a document at all, and a client that keyed off the
10
+ * pathname would re-introduce exactly the paths the policy closed.
11
+ *
12
+ * A document without the globals (a host without the kiosk patches, a plugin
13
+ * bundle served into an overlay deployment) reads as the overlay
14
+ * presentation: the `shell.overlay` registration this plugin has always
15
+ * used. That keeps one plugin build compatible with both compositions.
16
+ */
17
+ /**
18
+ * Whether one URL pathname lives on a surface: the surface path itself or any
19
+ * child of it. A plain prefix check would also match `/qadmin` or `/qa-test`.
20
+ */
21
+ export declare function matchesSurface(pathname: string, surface: string): boolean;
22
+ /**
23
+ * Whether this browser was served by a QA kiosk deployment.
24
+ * @param target - the global object; overridable for tests.
25
+ */
26
+ export declare function qaKioskMode(target?: Readonly<Record<string, unknown>>): boolean;
27
+ /**
28
+ * The QA surface's base path of a kiosk deployment, normalized: single
29
+ * leading slash, no trailing slash. A malformed value falls back to the
30
+ * default rather than disabling the mode.
31
+ * @param target - the global object; overridable for tests.
32
+ */
33
+ export declare function qaKioskBasePath(target?: Readonly<Record<string, unknown>>): string;
34
+ //# sourceMappingURL=kiosk.d.ts.map
@@ -9,6 +9,13 @@
9
9
  * blocks, setext inside lists, link reference definitions spanning lines) stay
10
10
  * out. Raw HTML never becomes a block: a tag line is a paragraph whose inline
11
11
  * pass leaves the tag as literal text.
12
+ *
13
+ * Math follows the Host transcript's settled grammar: display TeX is a
14
+ * `$$`-delimited block (a fence on its own lines or one line
15
+ * `$$…$$`) or a ```math fence, and nothing else — the `\(…\)` and `\[…\]`
16
+ * delimiters stay literal text, exactly as the Host renders them. Footnote
17
+ * definitions (`[^id]: …`) are collected the way GitHub's dialect does, with
18
+ * lazy and indented continuation lines.
12
19
  */
13
20
  /** `#`-through-`######` heading levels. */
14
21
  export type HeadingDepth = 1 | 2 | 3 | 4 | 5 | 6;
@@ -46,6 +53,9 @@ export type MarkdownBlock = {
46
53
  readonly align: readonly TableAlign[];
47
54
  readonly head: readonly string[];
48
55
  readonly rows: readonly (readonly string[])[];
56
+ } | {
57
+ readonly kind: "math";
58
+ readonly text: string;
49
59
  } | {
50
60
  readonly kind: "rule";
51
61
  };
@@ -54,6 +64,8 @@ export interface ParsedMarkdown {
54
64
  readonly blocks: readonly MarkdownBlock[];
55
65
  /** Link/image definitions by upper-cased identifier. */
56
66
  readonly definitions: ReadonlyMap<string, string>;
67
+ /** Footnote bodies by upper-cased identifier; first definition wins. */
68
+ readonly footnotes: ReadonlyMap<string, readonly MarkdownBlock[]>;
57
69
  }
58
70
  /** Split one table row into trimmed cells, honoring escaped pipes. */
59
71
  export declare function splitTableRow(line: string): string[];
@@ -67,8 +79,9 @@ export declare function parseMarkdown(text: string): ParsedMarkdown;
67
79
  * Parse the blocks of one container (document, quote, or list item).
68
80
  * @param lines - Container lines, already de-indented by the caller.
69
81
  * @param definitions - Document-wide definition accumulator.
82
+ * @param footnotes - Document-wide footnote accumulator.
70
83
  * @param depth - Container nesting depth.
71
84
  * @returns The container's blocks.
72
85
  */
73
- export declare function parseBlocks(lines: readonly string[], definitions: Map<string, string>, depth: number): MarkdownBlock[];
86
+ export declare function parseBlocks(lines: readonly string[], definitions: Map<string, string>, footnotes: Map<string, readonly MarkdownBlock[]>, depth: number): MarkdownBlock[];
74
87
  //# sourceMappingURL=blocks.d.ts.map
@@ -1,10 +1,13 @@
1
1
  /**
2
2
  * GFM inline grammar for the chat renderer: code spans, emphasis, links,
3
- * images, autolinks, and the two line-break flavors. Emphasis follows the
4
- * CommonMark intent (a closer must match its opener's delimiter run, `_` never
5
- * opens inside a word) rather than the full delimiter-stack algorithm — the
6
- * shapes this grammar cannot express are the pathological ones, and they
7
- * degrade to literal text instead of mangling the sentence.
3
+ * images, autolinks, TeX math, footnotes, and the two line-break flavors.
4
+ * Emphasis follows the CommonMark intent (a closer must match its opener's
5
+ * delimiter run, `_` never opens inside a word) rather than the full
6
+ * delimiter-stack algorithm — the shapes this grammar cannot express are the
7
+ * pathological ones, and they degrade to literal text instead of mangling the
8
+ * sentence. Math follows the Host transcript: `$…$` and `$$…$$` spans, with
9
+ * maximal-munch dollar runs and whitespace padding stripped only when both
10
+ * ends carry it.
8
11
  */
9
12
  /** One inline node; `children` nodes nest. */
10
13
  export type MarkdownInline = {
@@ -28,13 +31,26 @@ export type MarkdownInline = {
28
31
  readonly kind: "image";
29
32
  readonly src: string;
30
33
  readonly alt: string;
34
+ } | {
35
+ readonly kind: "inlineMath";
36
+ readonly value: string;
37
+ } | {
38
+ readonly kind: "footnoteRef";
39
+ readonly id: string;
31
40
  };
41
+ /** The reference targets one inline pass resolves against. */
42
+ export interface InlineTargets {
43
+ /** Link/image definitions by upper-cased identifier. */
44
+ readonly definitions: ReadonlyMap<string, string>;
45
+ /** Footnote identifiers that have a definition, by upper-cased label. */
46
+ readonly footnotes: ReadonlyMap<string, unknown>;
47
+ }
32
48
  /**
33
49
  * Parse the inline content of one leaf block.
34
50
  * @param text - Raw inline Markdown, newlines included.
35
- * @param definitions - Link/image definitions collected by the block pass.
51
+ * @param targets - The definitions and footnotes this pass resolves against.
36
52
  * @param depth - Inline nesting depth.
37
53
  * @returns The inline nodes in document order.
38
54
  */
39
- export declare function parseInline(text: string, definitions: ReadonlyMap<string, string>, depth?: number): MarkdownInline[];
55
+ export declare function parseInline(text: string, targets: ReadonlyMap<string, string> | InlineTargets, depth?: number): MarkdownInline[];
40
56
  //# sourceMappingURL=inline.d.ts.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * `katex/dist/katex.min.css` with every font inlined as a woff2 data URI.
3
+ * Generated by `scripts/generate-katex-css.mjs` from the pinned `katex`
4
+ * devDependency — do not edit by hand; regenerate after a `katex` upgrade.
5
+ *
6
+ * The QA overlay is a self-contained client bundle, so the math styles and
7
+ * their fonts travel inside it: nothing here may reference an external file,
8
+ * and a data URI cannot collide with the Host's own KaTeX font declarations.
9
+ */
10
+ export declare const KATEX_CSS: string;
11
+ //# sourceMappingURL=katex-css.d.ts.map
@@ -0,0 +1,23 @@
1
+ /**
2
+ * TeX-to-React via KaTeX, mirroring the Host transcript's math pipeline: the
3
+ * same two-arm error chain (strict render, `strict: 'ignore'` retry, error
4
+ * span) so a formula renders identically here and in DSH's own message. KaTeX
5
+ * emits an HTML string; the browser's HTML parser turns it into a tree this
6
+ * module maps onto React elements — the output is a static span/MathML/SVG
7
+ * vocabulary with no raw author HTML, the same trust the fenced-code
8
+ * highlighter's tree gets.
9
+ *
10
+ * React has no MathML support, so the `.katex-mathml` subtree's elements land
11
+ * in the HTML namespace; the visual arm is the `.katex-html` span tree and
12
+ * the MathML arm serves assistive technology, which reads it by tag name.
13
+ */
14
+ import type { ReactNode } from "react";
15
+ /**
16
+ * Render TeX source to React elements through KaTeX.
17
+ * @param value - The TeX source (a math node's raw content).
18
+ * @param displayMode - Display (block) versus inline rendering.
19
+ * @returns KaTeX's element tree, or the error span when the source does not
20
+ * parse even under `strict: 'ignore'`.
21
+ */
22
+ export declare function renderTexToReact(value: string, displayMode: boolean): ReactNode;
23
+ //# sourceMappingURL=math.d.ts.map
@@ -7,7 +7,8 @@ import { type MarkdownSourceContext } from "./source-chip.js";
7
7
  * instead of a plain link or code token.
8
8
  * @param text - Assistant-authored markdown.
9
9
  * @param context - Source resolution handed down by the owning message.
10
- * @returns The document's blocks.
10
+ * @returns The document's blocks, plus the footnote section when the document
11
+ * references a defined footnote.
11
12
  */
12
13
  export declare function renderMarkdown(text: string, context: MarkdownSourceContext): ReactNode[];
13
14
  //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Model notes: the ambient plugin messages the injector writes into a QA chat
3
+ * (who the user is, the source-provenance rules, delegation naming). Each note
4
+ * has a switch and an optional wording override; an empty template keeps the
5
+ * built-in text, so the fields double as a wording editor and a mute switch.
6
+ */
7
+ import { type ConfigProps } from "./common.js";
8
+ /** The ambient notes the Host writes into QA chats as hidden user messages. */
9
+ export declare function NotesSection(props: ConfigProps): import("react/jsx-runtime").JSX.Element;
10
+ //# sourceMappingURL=notes.d.ts.map
@@ -18,6 +18,7 @@ export { BrandingSection } from "./sections/branding.js";
18
18
  export { EmbeddingSection } from "./sections/embedding.js";
19
19
  export { InterfaceSection } from "./sections/interface.js";
20
20
  export { LockdownSection } from "./sections/lockdown.js";
21
+ export { NotesSection } from "./sections/notes.js";
21
22
  export { SessionSection } from "./sections/session.js";
22
23
  export { SlashSection } from "./sections/slash.js";
23
24
  export { SourcesSection } from "./sections/sources.js";
@@ -13,7 +13,10 @@ export declare function parseSettlement(text: string): SettledSubagent | undefin
13
13
  export interface SettlementView {
14
14
  readonly title: string;
15
15
  readonly body: string;
16
- /** Muted correlation line above the body; absent when the title says it all. */
16
+ /**
17
+ * Muted correlation lines above the body, one fact per line; absent when
18
+ * the title says it all.
19
+ */
17
20
  readonly meta?: string;
18
21
  }
19
22
  /**
@@ -2,12 +2,25 @@
2
2
  export declare const QA_BRAND_TOKEN_NAMES: readonly string[];
3
3
  export declare const QA_SURFACE_STYLES: string;
4
4
  /**
5
- * Everything the QA overlay paints, as one sheet for one `<style>` tag.
5
+ * Everything the QA surface paints, as one sheet for one `<style>` tag — the
6
+ * kiosk form, with no host-hiding rules: in the kiosk composition the native
7
+ * shell never mounts, so the sheet carries nothing aimed at it.
6
8
  *
7
9
  * The shared audit components keep their own stylesheet in
8
- * `@yadsh/dsh-audit-ui`; it is folded in here so the overlay is self-contained
10
+ * `@yadsh/dsh-audit-ui`; it is folded in here so the surface is self-contained
9
11
  * — the audit dialog must look right whether or not the audit plugin's own
10
12
  * client bundle happens to have injected the same rules into the document.
13
+ *
14
+ * The math styles and their fonts come from the bundled KaTeX copy the same
15
+ * way: the data-URI fonts resolve whatever the Host page loads, and identical
16
+ * rules from its own KaTeX stylesheet are harmless.
17
+ */
18
+ export declare const QA_ROOT_STYLES: string;
19
+ /**
20
+ * The overlay-composition sheet: the same rules as {@link QA_ROOT_STYLES}
21
+ * plus the host-column mask. Deployed into hosts without the kiosk patches,
22
+ * where the surface still covers a mounted native shell and the mask is what
23
+ * a deleted overlay element uncovers — a blank page instead of the shell.
11
24
  */
12
25
  export declare const QA_OVERLAY_STYLES: string;
13
26
  //# sourceMappingURL=styles.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import type { ClientRemote } from "@deepseek-ai/dsh-api-gateway/client";
2
2
  import type { ISessions, SessionFace } from "@deepseek-ai/dsh-api-session-controller/client";
3
3
  import type { UiConversation } from "@deepseek-ai/dsh-client-ui-conversation/client";
4
- import type { QaAccountProfileInput, QaAccountSession, QaAccountStartersInput, QaAccountStarter, QaAccountUserPublic, QaAccessAdminSnapshot, QaApprovalDecision, QaClaimResult, QaLockdownProof, QaOwnershipEntry, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaSessionState, QaSkillDocument, QaSkillDraftInput, QaSkillRemoval, QaSkillSummary, QaSkillToolDescriptor, QaSkillValidation, QaSourceFilePreview, QaTurnSources, QaWhoamiResult, QaCapabilitySelection, QaCurrentAccess, QaSessionAccess, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, QaAdminAuditEvent, QaAdminOverview, QaAdminPage, QaAdminUserDetail, QaAdminUserRow, QaAdminUserUpdate, QaAuditQuery, QaConversationDetail, QaConversationDeletion, QaConversationQuery, QaConversationReview, QaConversationReviewInput, QaConversationSummary, QaFeedbackQuery, QaFeedbackRow, QaMessageFeedback, QaMessageFeedbackInput, QaQualityMetrics, QaReviewQueueItem, QaReviewQueueRow, QaSlashCatalog, QaSlashExecution, QaSlashSubmitAttachment, QaUserQuery } from "../types.js";
4
+ import type { QaAccountProfileInput, QaAccountSession, QaAccountStartersInput, QaAccountStarter, QaAccountUserPublic, QaAccessAdminSnapshot, QaApprovalDecision, QaClaimResult, QaLockdownProof, QaOwnershipEntry, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaSessionState, QaSkillDocument, QaSkillDraftInput, QaSkillRemoval, QaSkillSummary, QaSkillToolDescriptor, QaSkillValidation, QaSourceFilePreview, QaTurnSources, QaWhoamiResult, QaDocumentPreview, QaWorkspaceFile, QaWorkspaceListing, QaCapabilitySelection, QaCurrentAccess, QaSessionAccess, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, QaAdminAuditEvent, QaAdminOverview, QaAdminPage, QaAdminUserDetail, QaAdminUserRow, QaAdminUserUpdate, QaAuditQuery, QaConversationDetail, QaConversationDeletion, QaConversationQuery, QaConversationReview, QaConversationReviewInput, QaConversationSummary, QaFeedbackQuery, QaFeedbackRow, QaMessageFeedback, QaMessageFeedbackInput, QaQualityMetrics, QaReviewQueueItem, QaReviewQueueRow, QaSlashCatalog, QaSlashExecution, QaSlashSubmitAttachment, QaUserQuery } from "../types.js";
5
5
  /** Wire content one prompt carries: text plus base64 image uploads. */
6
6
  export type QaPromptContent = Parameters<SessionFace["prompt"]>[0];
7
7
  /** DSH session runtime surface the QA controller is allowed to touch. */
@@ -111,6 +111,34 @@ export interface QaSourceApi {
111
111
  readonly ok: false;
112
112
  readonly error: unknown;
113
113
  }>;
114
+ /** One directory of the chat's own workspace, for the files panel. */
115
+ listWorkspaceFiles(token: string, sessionId: string, path: string): Promise<{
116
+ readonly ok: true;
117
+ readonly value: QaWorkspaceListing;
118
+ } | {
119
+ readonly ok: false;
120
+ readonly error: unknown;
121
+ }>;
122
+ /** One file of that workspace: decoded text, or bytes when it is binary. */
123
+ readWorkspaceFile(token: string, sessionId: string, path: string): Promise<{
124
+ readonly ok: true;
125
+ readonly value: QaWorkspaceFile;
126
+ } | {
127
+ readonly ok: false;
128
+ readonly error: unknown;
129
+ }>;
130
+ /**
131
+ * A Word document of that workspace rendered as PDF by the deployment's
132
+ * document pipeline; the panel shows the PDF the browser already knows how
133
+ * to draw instead of uploading the bytes anywhere.
134
+ */
135
+ previewWorkspaceDocument(token: string, sessionId: string, path: string): Promise<{
136
+ readonly ok: true;
137
+ readonly value: QaDocumentPreview;
138
+ } | {
139
+ readonly ok: false;
140
+ readonly error: unknown;
141
+ }>;
114
142
  }
115
143
  /**
116
144
  * The slash half of the Host namespace. The catalog comes back already cut
@@ -138,6 +166,27 @@ export type QaBoundSourceApi = {
138
166
  readonly ok: false;
139
167
  readonly error: unknown;
140
168
  }>;
169
+ listWorkspaceFiles(sessionId: string, path: string): Promise<{
170
+ readonly ok: true;
171
+ readonly value: QaWorkspaceListing;
172
+ } | {
173
+ readonly ok: false;
174
+ readonly error: unknown;
175
+ }>;
176
+ readWorkspaceFile(sessionId: string, path: string): Promise<{
177
+ readonly ok: true;
178
+ readonly value: QaWorkspaceFile;
179
+ } | {
180
+ readonly ok: false;
181
+ readonly error: unknown;
182
+ }>;
183
+ previewWorkspaceDocument(sessionId: string, path: string): Promise<{
184
+ readonly ok: true;
185
+ readonly value: QaDocumentPreview;
186
+ } | {
187
+ readonly ok: false;
188
+ readonly error: unknown;
189
+ }>;
141
190
  };
142
191
  /**
143
192
  * Approval remotes of this plugin's namespace. Read-only listing plus the one
@@ -0,0 +1,10 @@
1
+ import type { QaNotesConfig, ResolvedQaSurfaceConfig } from "../types.js";
2
+ type ResolvedNotes = ResolvedQaSurfaceConfig["notes"];
3
+ /**
4
+ * The ambient model notes. Notes are advisory text, not capability: the
5
+ * default is the current behavior (every note on, built-in wording), and an
6
+ * empty template always resolves to the built-in text.
7
+ */
8
+ export declare function resolveNotes(input: QaNotesConfig | undefined): ResolvedNotes;
9
+ export {};
10
+ //# sourceMappingURL=notes.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import { TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
2
2
  import type { Context } from "@deepseek-ai/cordis";
3
3
  import type { QaTurnSources } from "./provenance/types.js";
4
- import type { QaAccountProfileInput, QaAccountSession, QaAccountStartersInput, QaAccountUserPublic, QaApprovalDecision, QaClaimResult, QaLockdownProof, QaOwnershipEntry, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaSurfaceConfig, ResolvedQaSurfaceConfig, QaSkillDocument, QaSkillDraftInput, QaSkillRemoval, QaSkillSummary, QaSkillToolDescriptor, QaSkillValidation, QaSourceFilePreview, QaWhoamiResult, QaPrincipal, QaAccessAdminSnapshot, QaAdminAuditEvent, QaAdminOverview, QaAdminPage, QaAdminUserDetail, QaAdminUserRow, QaAdminUserUpdate, QaAuditQuery, QaCapabilitySelection, QaConversationDetail, QaConversationDeletion, QaConversationQuery, QaConversationReview, QaConversationReviewInput, QaConversationSummary, QaCurrentAccess, QaFeedbackQuery, QaFeedbackRow, QaMessageFeedback, QaMessageFeedbackInput, QaQualityMetrics, QaReviewQueueItem, QaReviewQueueRow, QaSessionAccess, QaSlashCatalog, QaSlashExecution, QaSlashSubmitAttachment, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, QaUserQuery } from "./types.js";
4
+ import type { QaAccountProfileInput, QaAccountSession, QaAccountStartersInput, QaAccountUserPublic, QaApprovalDecision, QaClaimResult, QaDocumentPreview, QaLockdownProof, QaOwnershipEntry, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaSurfaceConfig, ResolvedQaSurfaceConfig, QaSkillDocument, QaSkillDraftInput, QaSkillRemoval, QaSkillSummary, QaSkillToolDescriptor, QaSkillValidation, QaSourceFilePreview, QaWhoamiResult, QaWorkspaceFile, QaWorkspaceListing, QaPrincipal, QaAccessAdminSnapshot, QaAdminAuditEvent, QaAdminOverview, QaAdminPage, QaAdminUserDetail, QaAdminUserRow, QaAdminUserUpdate, QaAuditQuery, QaCapabilitySelection, QaConversationDetail, QaConversationDeletion, QaConversationQuery, QaConversationReview, QaConversationReviewInput, QaConversationSummary, QaCurrentAccess, QaFeedbackQuery, QaFeedbackRow, QaMessageFeedback, QaMessageFeedbackInput, QaQualityMetrics, QaReviewQueueItem, QaReviewQueueRow, QaSessionAccess, QaSlashCatalog, QaSlashExecution, QaSlashSubmitAttachment, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, QaUserQuery } from "./types.js";
5
5
  export declare const name = "qa-surface";
6
6
  export declare const inject: string[];
7
7
  import { QA_SURFACE_SETTINGS_NAMESPACE } from "./shared/settings.js";
@@ -20,6 +20,7 @@ export declare class QaSurface extends TypertRemoteService {
20
20
  private readonly logger;
21
21
  private readonly admission;
22
22
  private readonly approvals;
23
+ private readonly fileDeleteGate;
23
24
  private readonly userQuestions;
24
25
  private readonly provenance;
25
26
  private readonly notes;
@@ -235,6 +236,43 @@ export declare class QaSurface extends TypertRemoteService {
235
236
  * the per-account scratch directory — could never be opened in the panel.
236
237
  */
237
238
  readSourceFile(token: string, sessionId: string, sourcePath: string): Promise<QaSourceFilePreview>;
239
+ /**
240
+ * List one directory of the chat's own workspace for the files panel.
241
+ *
242
+ * Browsing is deliberately narrower than the source preview: it stays inside
243
+ * the chat's own directory tree, so a visitor can look at what their
244
+ * conversation produced and at nothing else of the deployment.
245
+ * `readWorkspaceFile` opens one entry of such a listing.
246
+ */
247
+ listWorkspaceFiles(token: string, sessionId: string, path: string): Promise<QaWorkspaceListing>;
248
+ /**
249
+ * Read one file of the chat's workspace: text when it decodes as UTF-8, bytes
250
+ * when it does not, so a document the agent produced can be downloaded while
251
+ * a note previews inline. The readable roots are the ones the model itself
252
+ * may read; unlike the source preview this does not require the file to be
253
+ * recorded evidence, because the panel is browsing a tree rather than
254
+ * reopening a cited source.
255
+ */
256
+ readWorkspaceFile(token: string, sessionId: string, path: string): Promise<QaWorkspaceFile>;
257
+ /**
258
+ * Render one Word document of the chat's workspace as a PDF for the panel.
259
+ *
260
+ * The conversion is the document pipeline's own, reached through the service
261
+ * `@yadsh/dsh-documents` publishes for its Host siblings — the panel gets the
262
+ * same providers, limits and refusals the `document_*` tools see, and a
263
+ * deployment without that plugin refuses instead of showing a guess. The
264
+ * produced PDF is read back here and travels as base64, so the audience never
265
+ * reaches an unfenced byte route.
266
+ */
267
+ previewWorkspaceDocument(token: string, sessionId: string, path: string): Promise<QaDocumentPreview>;
268
+ /**
269
+ * Shared admission facts of both browse methods: the preview switch is what
270
+ * opens the panel's file reading at all, and the chat's cwd is the tree that
271
+ * browsing is confined to.
272
+ */
273
+ private browseContext;
274
+ /** One browse refusal, logged with its coarse reason and rethrown for the wire. */
275
+ private browseRefusal;
238
276
  /** Every personal skill of the token's account, sorted by name. */
239
277
  skillsList(token: string): {
240
278
  readonly skills: readonly QaSkillSummary[];
@@ -14,6 +14,15 @@ export declare const QA_IDENTITY_NOTE = "dsh-qa-surface:user-identity";
14
14
  export declare const QA_SOURCES_NOTE = "dsh-qa-surface:structured-sources";
15
15
  /** Note name asking the model to name its delegations. */
16
16
  export declare const QA_DELEGATION_NOTE = "dsh-qa-surface:delegation-naming";
17
+ /**
18
+ * Built-in note texts. Each is the fallback for its settings template
19
+ * (`notes.*.template`); the placeholders mark the parts the injector
20
+ * substitutes. Unknown or empty placeholders render as empty text.
21
+ */
22
+ export declare const QA_IDENTITY_NOTE_TEMPLATE = "{identity}\n\n{instructions}";
23
+ export declare const QA_SOURCES_NOTE_TEMPLATE = "Source provenance is collected automatically from your tool calls; the QA surface lists what it collected beside the answer. Do not append a manual Sources/\u0418\u0441\u0442\u043E\u0447\u043D\u0438\u043A\u0438 bibliography of your own.";
24
+ export declare const QA_SOURCES_FALLBACK_TEMPLATE = "A delegated run whose provider cannot expose tool events must call {reportTool} before finishing.";
25
+ export declare const QA_DELEGATION_NOTE_TEMPLATE = "When you start a background subagent, give the delegation a short vivid name in its description field: two or three words in the user's language that say what the run is for (\u00AB\u0421\u0432\u0435\u0440\u043A\u0430 \u043E\u0442\u0447\u0451\u0442\u043E\u0432\u00BB, \"Log triage\"). The QA surface shows that description as the subagent's display name in the operator's panel and completion notices.";
17
26
  export interface QaIdentityRenderInput {
18
27
  /** The owner's account address; the one fact accounts always provide. */
19
28
  readonly email: string;