@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.
- package/README.md +29 -1
- package/lib/admin/service.js +7 -7
- package/lib/admin/service.js.map +1 -1
- package/lib/client/QaSessionController.js +12 -0
- package/lib/client/QaSessionController.js.map +1 -1
- package/lib/client/QaSurface.js +23 -5
- package/lib/client/QaSurface.js.map +1 -1
- package/lib/client/QaSurfaceGuard.js +12 -5
- package/lib/client/QaSurfaceGuard.js.map +1 -1
- package/lib/client/admin/QaAdmin.js +5 -1
- package/lib/client/admin/QaAdmin.js.map +1 -1
- package/lib/client/admin/pages/Users.js +9 -2
- package/lib/client/admin/pages/Users.js.map +1 -1
- package/lib/client/admin/shared.js +5 -1
- package/lib/client/admin/shared.js.map +1 -1
- package/lib/client/base64.js +22 -1
- package/lib/client/base64.js.map +1 -1
- package/lib/client/components/QaAgentsDrawer.js +9 -6
- package/lib/client/components/QaAgentsDrawer.js.map +1 -1
- package/lib/client/components/QaApproval.js +1 -1
- package/lib/client/components/QaApproval.js.map +1 -1
- package/lib/client/components/QaChangelog.js +29 -0
- package/lib/client/components/QaChangelog.js.map +1 -1
- package/lib/client/components/QaFilesPanel.js +17 -11
- package/lib/client/components/QaFilesPanel.js.map +1 -1
- package/lib/client/components/QaHeader.js +3 -11
- package/lib/client/components/QaHeader.js.map +1 -1
- package/lib/client/components/QaModal.js.map +1 -1
- package/lib/client/components/QaQuestions.js +4 -4
- package/lib/client/components/QaQuestions.js.map +1 -1
- package/lib/client/components/QaSidebar.js +10 -2
- package/lib/client/components/QaSidebar.js.map +1 -1
- package/lib/client/components/QaWidthHandle.js +111 -5
- package/lib/client/components/QaWidthHandle.js.map +1 -1
- package/lib/client/components/QaWorkspaceBrowser.js +231 -0
- package/lib/client/components/QaWorkspaceBrowser.js.map +1 -0
- package/lib/client/index.js +109 -53
- package/lib/client/index.js.map +1 -1
- package/lib/client/kiosk.js +51 -0
- package/lib/client/kiosk.js.map +1 -0
- package/lib/client/markdown/blocks.js +122 -7
- package/lib/client/markdown/blocks.js.map +1 -1
- package/lib/client/markdown/inline.js +108 -12
- package/lib/client/markdown/inline.js.map +1 -1
- package/lib/client/markdown/katex-css.js +12 -0
- package/lib/client/markdown/katex-css.js.map +1 -0
- package/lib/client/markdown/math.js +84 -0
- package/lib/client/markdown/math.js.map +1 -0
- package/lib/client/markdown/render.js +74 -5
- package/lib/client/markdown/render.js.map +1 -1
- package/lib/client/settings/card.js +2 -2
- package/lib/client/settings/card.js.map +1 -1
- package/lib/client/settings/sections/notes.js +46 -0
- package/lib/client/settings/sections/notes.js.map +1 -0
- package/lib/client/settings/sections/sources.js +4 -1
- package/lib/client/settings/sections/sources.js.map +1 -1
- package/lib/client/settings/sections.js +1 -0
- package/lib/client/settings/sections.js.map +1 -1
- package/lib/client/settlement.js +1 -1
- package/lib/client/settlement.js.map +1 -1
- package/lib/client/source-preview.js +3 -0
- package/lib/client/source-preview.js.map +1 -1
- package/lib/client/styles.js +97 -18
- package/lib/client/styles.js.map +1 -1
- package/lib/client/types.js.map +1 -1
- package/lib/client.js +28587 -595
- package/lib/client.js.map +1 -1
- package/lib/config-resolvers/defaults.js +10 -0
- package/lib/config-resolvers/defaults.js.map +1 -1
- package/lib/config-resolvers/notes.js +24 -0
- package/lib/config-resolvers/notes.js.map +1 -0
- package/lib/config-resolvers/sources.js +4 -0
- package/lib/config-resolvers/sources.js.map +1 -1
- package/lib/config.js +35 -0
- package/lib/config.js.map +1 -1
- package/lib/index.js +151 -10
- package/lib/index.js.map +1 -1
- package/lib/prompt-notes.js +45 -6
- package/lib/prompt-notes.js.map +1 -1
- package/lib/provenance/document-preview.js +51 -0
- package/lib/provenance/document-preview.js.map +1 -0
- package/lib/provenance/file-preview.js +191 -19
- package/lib/provenance/file-preview.js.map +1 -1
- package/lib/qa-tools/catalog.js +7 -1
- package/lib/qa-tools/catalog.js.map +1 -1
- package/lib/qa-tools/file-delete-gate.js +60 -0
- package/lib/qa-tools/file-delete-gate.js.map +1 -0
- package/lib/qa-tools/file-delete.js +156 -0
- package/lib/qa-tools/file-delete.js.map +1 -0
- package/lib/resolve-config.js +2 -0
- package/lib/resolve-config.js.map +1 -1
- package/lib/shared/documents.js +22 -0
- package/lib/shared/documents.js.map +1 -0
- package/lib/typert.host.js +278 -55
- package/lib/typert.remote-client.d.ts +7 -1
- package/lib/typert.remote-client.js +239 -53
- package/lib/types/client/admin/shared.d.ts +2 -0
- package/lib/types/client/base64.d.ts +13 -1
- package/lib/types/client/components/QaAgentsDrawer.d.ts +2 -1
- package/lib/types/client/components/QaFilesPanel.d.ts +16 -4
- package/lib/types/client/components/QaHeader.d.ts +9 -3
- package/lib/types/client/components/QaModal.d.ts +4 -3
- package/lib/types/client/components/QaWidthHandle.d.ts +48 -2
- package/lib/types/client/components/QaWorkspaceBrowser.d.ts +15 -0
- package/lib/types/client/index.d.ts +1 -1
- package/lib/types/client/kiosk.d.ts +34 -0
- package/lib/types/client/markdown/blocks.d.ts +14 -1
- package/lib/types/client/markdown/inline.d.ts +23 -7
- package/lib/types/client/markdown/katex-css.d.ts +11 -0
- package/lib/types/client/markdown/math.d.ts +23 -0
- package/lib/types/client/markdown/render.d.ts +2 -1
- package/lib/types/client/settings/sections/notes.d.ts +10 -0
- package/lib/types/client/settings/sections.d.ts +1 -0
- package/lib/types/client/settlement.d.ts +4 -1
- package/lib/types/client/styles.d.ts +15 -2
- package/lib/types/client/types.d.ts +50 -1
- package/lib/types/config-resolvers/notes.d.ts +10 -0
- package/lib/types/index.d.ts +39 -1
- package/lib/types/prompt-notes.d.ts +9 -0
- package/lib/types/provenance/document-preview.d.ts +24 -0
- package/lib/types/provenance/file-preview.d.ts +69 -2
- package/lib/types/qa-tools/catalog.d.ts +1 -1
- package/lib/types/qa-tools/file-delete-gate.d.ts +42 -0
- package/lib/types/qa-tools/file-delete.d.ts +32 -0
- package/lib/types/shared/documents.d.ts +20 -0
- package/lib/types/types.d.ts +93 -1
- package/lib/types/ui-mode.d.ts +18 -0
- package/lib/ui-mode.js +22 -0
- package/lib/ui-mode.js.map +1 -0
- package/package.json +10 -8
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { DocumentsFace } from "@yadsh/dsh-documents";
|
|
2
|
+
import type { QaDocumentPreview } from "../types.js";
|
|
3
|
+
import { type QaAllowedFileRequest } from "./file-preview.js";
|
|
4
|
+
/** Look up the document subsystem a sibling Host plugin published. */
|
|
5
|
+
export type DocumentsLookup = () => DocumentsFace | undefined;
|
|
6
|
+
export interface QaDocumentPreviewRequest extends QaAllowedFileRequest {
|
|
7
|
+
/** The document pipeline, resolved per call so a late provider still counts. */
|
|
8
|
+
readonly documents: DocumentsLookup;
|
|
9
|
+
readonly sessionId: string;
|
|
10
|
+
/** Bytes of the rendered PDF the panel accepts before it gives up. */
|
|
11
|
+
readonly maxBytes: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Render one Word document as a PDF for the files panel.
|
|
15
|
+
*
|
|
16
|
+
* The conversion is the document pipeline's own — the same runtime, providers
|
|
17
|
+
* and limits the `document_*` tools use — reached through the face that plugin
|
|
18
|
+
* publishes for its Host siblings; a deployment without the pipeline installed
|
|
19
|
+
* refuses with `unsupported` rather than growing a second converter here. The
|
|
20
|
+
* input path passes the same containment check the panel's other reads use, so
|
|
21
|
+
* a preview cannot read what a listing could not reach.
|
|
22
|
+
*/
|
|
23
|
+
export declare function previewConvertibleDocument({ documents, sessionId, maxBytes, ...file }: QaDocumentPreviewRequest): Promise<QaDocumentPreview>;
|
|
24
|
+
//# sourceMappingURL=document-preview.d.ts.map
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import type { QaSourceFilePreview } from "../types.js";
|
|
1
|
+
import type { QaSourceFilePreview, QaWorkspaceFile, QaWorkspaceListing } from "../types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Coarse, wire-safe preview refusal codes. They ride the shared
|
|
4
4
|
* `(reason: <code>)` marker, so the panel can tell "this file is not in a
|
|
5
5
|
* directory the QA read policy opens" from "this file is gone" instead of
|
|
6
6
|
* telling every audience that a present file moved away.
|
|
7
7
|
*/
|
|
8
|
-
export type QaSourcePreviewReason = "outside-roots" | "not-evidence" | "unavailable"
|
|
8
|
+
export type QaSourcePreviewReason = "outside-roots" | "not-evidence" | "unavailable"
|
|
9
|
+
/** The panel has no way to render this format at all. */
|
|
10
|
+
| "unsupported";
|
|
9
11
|
/** Host refusal whose wire message carries the coarse reason marker. */
|
|
10
12
|
export declare class QaSourcePreviewError extends Error {
|
|
11
13
|
readonly reason: QaSourcePreviewReason;
|
|
@@ -39,6 +41,32 @@ export interface QaSourceFilePreviewRequest {
|
|
|
39
41
|
readonly maxBytes: number;
|
|
40
42
|
readonly maxMarkdownRenderBytes: number;
|
|
41
43
|
}
|
|
44
|
+
/** A file request the panel may make: the chat's own tree or a shared root. */
|
|
45
|
+
export interface QaAllowedFileRequest {
|
|
46
|
+
readonly filePath: string;
|
|
47
|
+
/** The attested chat's cwd: the anchor a relative request resolves against. */
|
|
48
|
+
readonly cwd: string;
|
|
49
|
+
readonly sharedReadOnlyRoots?: readonly string[];
|
|
50
|
+
readonly attachmentRoot?: string;
|
|
51
|
+
}
|
|
52
|
+
/** One resolved file that passed the read policy. */
|
|
53
|
+
interface QaAllowedFile {
|
|
54
|
+
/** The path as the caller spelled it, canonicalized against the chat cwd. */
|
|
55
|
+
readonly canonicalPath: string;
|
|
56
|
+
/** Its real filesystem path, once symlinks are followed. */
|
|
57
|
+
readonly canonical: string;
|
|
58
|
+
readonly size: number;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Resolve one requested file and check it against the readable roots.
|
|
62
|
+
*
|
|
63
|
+
* The roots mirror the per-user execution guard — the chat's own cwd plus the
|
|
64
|
+
* deployment's shared read-only directories and the attachment store — so a
|
|
65
|
+
* file the model was explicitly allowed to read stays readable in the panel,
|
|
66
|
+
* while anything else is refused with the coarse `outside-roots` reason
|
|
67
|
+
* instead of leaking whether it exists.
|
|
68
|
+
*/
|
|
69
|
+
export declare function resolveAllowedFile({ filePath, cwd, sharedReadOnlyRoots, attachmentRoot, }: QaAllowedFileRequest): Promise<QaAllowedFile>;
|
|
42
70
|
/**
|
|
43
71
|
* Read one evidence file from the roots the QA read policy opens.
|
|
44
72
|
*
|
|
@@ -50,4 +78,43 @@ export interface QaSourceFilePreviewRequest {
|
|
|
50
78
|
* refused as foreign evidence.
|
|
51
79
|
*/
|
|
52
80
|
export declare function readSourceFilePreview({ sourcePath, cwd, isEvidence, sharedReadOnlyRoots, attachmentRoot, maxBytes, maxMarkdownRenderBytes, }: QaSourceFilePreviewRequest): Promise<QaSourceFilePreview>;
|
|
81
|
+
/** One directory request from the files panel. */
|
|
82
|
+
export interface QaWorkspaceListRequest {
|
|
83
|
+
/** The directory to list, absolute or relative to the chat cwd. Empty = root. */
|
|
84
|
+
readonly dirPath: string;
|
|
85
|
+
readonly cwd: string;
|
|
86
|
+
/** Children one listing carries; the rest is reported as truncated. */
|
|
87
|
+
readonly maxEntries: number;
|
|
88
|
+
}
|
|
89
|
+
/** The advertised type of one file: by extension, else opaque bytes. */
|
|
90
|
+
export declare function mediaTypeOf(path: string): string;
|
|
91
|
+
/**
|
|
92
|
+
* List one directory of the chat's own workspace.
|
|
93
|
+
*
|
|
94
|
+
* Browsing is deliberately narrower than previewing: the panel walks the tree
|
|
95
|
+
* the chat works in, never the deployment's shared read-only roots, so the
|
|
96
|
+
* visitor cannot enumerate the deployment from the rail. The request is
|
|
97
|
+
* confined with the same realpath-then-contain check the preview uses, which
|
|
98
|
+
* is what makes `..` and symlinked directories harmless.
|
|
99
|
+
* Symlinked children are omitted rather than followed: a link inside the
|
|
100
|
+
* workspace may point anywhere, and a tree that silently leaves the chat's
|
|
101
|
+
* directory is worse than one that hides a link.
|
|
102
|
+
*/
|
|
103
|
+
export declare function listWorkspaceDirectory({ dirPath, cwd, maxEntries, }: QaWorkspaceListRequest): Promise<QaWorkspaceListing>;
|
|
104
|
+
/** One file request from the files panel. */
|
|
105
|
+
export interface QaWorkspaceFileRequest extends QaAllowedFileRequest {
|
|
106
|
+
readonly maxBytes: number;
|
|
107
|
+
readonly maxMarkdownRenderBytes: number;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Read one file of the chat's workspace for the panel: text when it decodes as
|
|
111
|
+
* UTF-8, base64 bytes when it does not, so a document the agent produced can be
|
|
112
|
+
* offered for download while a note previews inline.
|
|
113
|
+
*
|
|
114
|
+
* Unlike the source preview this is not bound to recorded evidence — the panel
|
|
115
|
+
* browses what the chat's workspace holds — but it is bound to the same roots
|
|
116
|
+
* the model itself may read.
|
|
117
|
+
*/
|
|
118
|
+
export declare function readWorkspaceFile({ filePath, cwd, sharedReadOnlyRoots, attachmentRoot, maxBytes, maxMarkdownRenderBytes, }: QaWorkspaceFileRequest): Promise<QaWorkspaceFile>;
|
|
119
|
+
export {};
|
|
53
120
|
//# sourceMappingURL=file-preview.d.ts.map
|
|
@@ -8,7 +8,7 @@ import type { QaToolDescriptor } from "./types.js";
|
|
|
8
8
|
*
|
|
9
9
|
* Bump it whenever the catalog's tool set or their schemas change.
|
|
10
10
|
*/
|
|
11
|
-
export declare const QA_TOOL_CATALOG_VERSION = "
|
|
11
|
+
export declare const QA_TOOL_CATALOG_VERSION = "2";
|
|
12
12
|
/** One QA tool reports the activation state of whichever agent calls it. */
|
|
13
13
|
export interface QaToolsSelfcheckDeps {
|
|
14
14
|
readonly catalogVersion: string;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
2
|
+
import type { QaSessionOwnership } from "../session-ownership.js";
|
|
3
|
+
/** The one QA tool whose every call is parked for the operator. */
|
|
4
|
+
export declare const QA_FILE_DELETE_TOOL = "file_delete";
|
|
5
|
+
/** Why the gate answers `ask` before the chain can decide alone. */
|
|
6
|
+
export declare const QA_FILE_DELETE_ASK_REASON = "deleting a workspace file requires operator confirmation";
|
|
7
|
+
/**
|
|
8
|
+
* The inner half of `file_delete`'s safety: the decision that composes the
|
|
9
|
+
* approval flow around one destructive tool.
|
|
10
|
+
*
|
|
11
|
+
* Installed WITHOUT `prepend`, deliberately. The approval gate sits outside
|
|
12
|
+
* every other `tools/pre-execute` listener and resolves the decision the rest
|
|
13
|
+
* of the chain produced — an `ask` from an inner gate is what it parks for
|
|
14
|
+
* the operator. This listener is that inner gate: for a `file_delete` call
|
|
15
|
+
* from an attested QA session it answers `ask` on its own, without asking
|
|
16
|
+
* the chain, so the interactive approval card appears for every deletion,
|
|
17
|
+
* whatever the deployment's other policies would have said. The operator's
|
|
18
|
+
* answer becomes the decision, and on a deployment with
|
|
19
|
+
* `interaction.approvals: blocked` the approval gate keeps its fail-closed
|
|
20
|
+
* behavior and refuses the call — nothing is ever deleted without a person.
|
|
21
|
+
*
|
|
22
|
+
* Any other tool, and any caller this deployment did not attest, is handed
|
|
23
|
+
* back to the chain untouched.
|
|
24
|
+
*/
|
|
25
|
+
export declare class QaFileDeleteGate {
|
|
26
|
+
private readonly ctx;
|
|
27
|
+
private readonly ownership;
|
|
28
|
+
private readonly disposers;
|
|
29
|
+
constructor(ctx: Context, ownership: QaSessionOwnership);
|
|
30
|
+
/** Sit inside the approval gate; registration order is the composition. */
|
|
31
|
+
install(): void;
|
|
32
|
+
/** Detach the listener. Wired as an effect, like every other gate. */
|
|
33
|
+
dispose(): void;
|
|
34
|
+
private handle;
|
|
35
|
+
/**
|
|
36
|
+
* Whether this deployment attested the chat the call belongs to, delegated
|
|
37
|
+
* children included. The same ownership service the approval gate reads,
|
|
38
|
+
* so one chat is parked under exactly one surface.
|
|
39
|
+
*/
|
|
40
|
+
private attested;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=file-delete-gate.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ToolDefinition } from "@deepseek-ai/dsh-tools";
|
|
2
|
+
/**
|
|
3
|
+
* `file_delete` — the QA catalog's one destructive capability.
|
|
4
|
+
*
|
|
5
|
+
* The QA surface serves untrusted-audience chats pinned to a read-only or
|
|
6
|
+
* workspace-write sandbox, and until now no chat could remove a file it had
|
|
7
|
+
* created. This tool deletes exactly one regular file strictly inside the
|
|
8
|
+
* calling agent's workspace root (the session cwd) and refuses everything
|
|
9
|
+
* else with a reason the model can act on: directories, missing paths, paths
|
|
10
|
+
* spelled outside the root, and paths that leave it through a symbolic link.
|
|
11
|
+
* Every call is additionally answered `ask` by the always-ask gate, so the
|
|
12
|
+
* interactive approval card parks it for the operator before this body ever
|
|
13
|
+
* runs — the fence here is the second of two boundaries, not the only one.
|
|
14
|
+
*
|
|
15
|
+
* The workspace root is read from `exec.agent` at call time, so building the
|
|
16
|
+
* tool (and the catalog that carries it) stays side-effect free.
|
|
17
|
+
*/
|
|
18
|
+
/** Why `file_delete` refused a call. */
|
|
19
|
+
export type QaFileDeleteRefusal = "workspace-unavailable" | "outside-workspace" | "symlink-escape" | "not-found" | "not-a-file";
|
|
20
|
+
/**
|
|
21
|
+
* A typed refusal of one `file_delete` call.
|
|
22
|
+
*
|
|
23
|
+
* The message is what the model reads; it names the reason in words and
|
|
24
|
+
* deliberately never echoes the requested absolute host path, so a refusal
|
|
25
|
+
* cannot leak the deployment's layout into the conversation.
|
|
26
|
+
*/
|
|
27
|
+
export declare class QaFileDeleteError extends Error {
|
|
28
|
+
readonly code: QaFileDeleteRefusal;
|
|
29
|
+
constructor(code: QaFileDeleteRefusal, message: string, options?: ErrorOptions);
|
|
30
|
+
}
|
|
31
|
+
export declare function createFileDeleteTool(): ToolDefinition;
|
|
32
|
+
//# sourceMappingURL=file-delete.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats the files panel previews by conversion instead of by bytes.
|
|
3
|
+
*
|
|
4
|
+
* Shared by the Host half (which owns the conversion) and the browser card
|
|
5
|
+
* (which decides whether opening a file should ask for one), so the two cannot
|
|
6
|
+
* drift on what "we can render this" means. Dependency-free on purpose: the
|
|
7
|
+
* card bundle inlines it.
|
|
8
|
+
*/
|
|
9
|
+
/** OOXML word-processing documents, as the deployment detects them. */
|
|
10
|
+
export declare const QA_WORD_MEDIA_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
11
|
+
/** The media type of the PDF a converted document arrives as. */
|
|
12
|
+
export declare const QA_PDF_MEDIA_TYPE = "application/pdf";
|
|
13
|
+
/**
|
|
14
|
+
* Whether the panel asks the Host for a converted PDF rather than rendering the
|
|
15
|
+
* bytes it already holds. Word documents are the whole set: the document
|
|
16
|
+
* pipeline reads them and renders PDF, while its other inputs are already
|
|
17
|
+
* previewable (Markdown as text, PDF through the browser's own viewer).
|
|
18
|
+
*/
|
|
19
|
+
export declare function isConvertibleDocument(mediaType: string): boolean;
|
|
20
|
+
//# sourceMappingURL=documents.d.ts.map
|
package/lib/types/types.d.ts
CHANGED
|
@@ -489,6 +489,7 @@ export interface QaSourcesConfig {
|
|
|
489
489
|
readonly allowRawToggle?: boolean;
|
|
490
490
|
readonly maxBytes?: number;
|
|
491
491
|
readonly maxMarkdownRenderBytes?: number;
|
|
492
|
+
readonly maxListingEntries?: number;
|
|
492
493
|
};
|
|
493
494
|
readonly subagents?: {
|
|
494
495
|
readonly inheritSources?: boolean;
|
|
@@ -504,6 +505,30 @@ export interface QaSourcesConfig {
|
|
|
504
505
|
readonly parseAssistantSourcesBlock?: boolean;
|
|
505
506
|
};
|
|
506
507
|
}
|
|
508
|
+
/**
|
|
509
|
+
* The ambient notes the injector writes into a QA chat as plugin-sourced user
|
|
510
|
+
* messages (`prompt-notes.ts`). Each note can be switched off and reworded;
|
|
511
|
+
* an empty template keeps the built-in wording.
|
|
512
|
+
*/
|
|
513
|
+
export interface QaNotesConfig {
|
|
514
|
+
/** Who the assistant is talking to; `{identity}` + `{instructions}`. */
|
|
515
|
+
readonly identity?: {
|
|
516
|
+
readonly enabled?: boolean;
|
|
517
|
+
readonly template?: string;
|
|
518
|
+
};
|
|
519
|
+
/** Source-provenance rules; `{reportTool}` names the subagent report tool. */
|
|
520
|
+
readonly sources?: {
|
|
521
|
+
readonly enabled?: boolean;
|
|
522
|
+
readonly template?: string;
|
|
523
|
+
/** The sentence appended when the report-tool fallback is on. */
|
|
524
|
+
readonly fallbackTemplate?: string;
|
|
525
|
+
};
|
|
526
|
+
/** How to label background delegations; no placeholders. */
|
|
527
|
+
readonly delegation?: {
|
|
528
|
+
readonly enabled?: boolean;
|
|
529
|
+
readonly template?: string;
|
|
530
|
+
};
|
|
531
|
+
}
|
|
507
532
|
export interface QaSurfaceConfig {
|
|
508
533
|
readonly enabled?: boolean;
|
|
509
534
|
readonly route?: {
|
|
@@ -684,6 +709,7 @@ export interface QaSurfaceConfig {
|
|
|
684
709
|
};
|
|
685
710
|
readonly sources?: QaSourcesConfig;
|
|
686
711
|
readonly attachments?: QaAttachmentsConfig;
|
|
712
|
+
readonly notes?: QaNotesConfig;
|
|
687
713
|
}
|
|
688
714
|
/** What a QA visitor may attach to one message. */
|
|
689
715
|
export interface QaAttachmentsConfig {
|
|
@@ -854,6 +880,7 @@ export interface ResolvedQaSurfaceConfig {
|
|
|
854
880
|
readonly allowRawToggle: boolean;
|
|
855
881
|
readonly maxBytes: number;
|
|
856
882
|
readonly maxMarkdownRenderBytes: number;
|
|
883
|
+
readonly maxListingEntries: number;
|
|
857
884
|
};
|
|
858
885
|
readonly subagents: {
|
|
859
886
|
readonly inheritSources: boolean;
|
|
@@ -872,6 +899,21 @@ export interface ResolvedQaSurfaceConfig {
|
|
|
872
899
|
readonly maxPending: number;
|
|
873
900
|
readonly extensions: readonly string[];
|
|
874
901
|
};
|
|
902
|
+
readonly notes: {
|
|
903
|
+
readonly identity: {
|
|
904
|
+
readonly enabled: boolean;
|
|
905
|
+
readonly template: string;
|
|
906
|
+
};
|
|
907
|
+
readonly sources: {
|
|
908
|
+
readonly enabled: boolean;
|
|
909
|
+
readonly template: string;
|
|
910
|
+
readonly fallbackTemplate: string;
|
|
911
|
+
};
|
|
912
|
+
readonly delegation: {
|
|
913
|
+
readonly enabled: boolean;
|
|
914
|
+
readonly template: string;
|
|
915
|
+
};
|
|
916
|
+
};
|
|
875
917
|
}
|
|
876
918
|
/** Which native registry one unified entry came from. */
|
|
877
919
|
export type QaSlashEntryKind = "skill" | "command";
|
|
@@ -1038,6 +1080,51 @@ export interface QaSourceFilePreview {
|
|
|
1038
1080
|
readonly markdown: boolean;
|
|
1039
1081
|
readonly renderableMarkdown: boolean;
|
|
1040
1082
|
}
|
|
1083
|
+
/**
|
|
1084
|
+
* A file the panel renders by conversion rather than by bytes: the document
|
|
1085
|
+
* pipeline turned a Word file into PDF, and the browser shows that PDF.
|
|
1086
|
+
*/
|
|
1087
|
+
export interface QaDocumentPreview {
|
|
1088
|
+
readonly kind: "pdf";
|
|
1089
|
+
readonly base64: string;
|
|
1090
|
+
readonly mime: "application/pdf";
|
|
1091
|
+
readonly name: string;
|
|
1092
|
+
readonly bytes: number;
|
|
1093
|
+
}
|
|
1094
|
+
/** One directory entry of a chat's own workspace, as the files panel browses it. */
|
|
1095
|
+
export interface QaWorkspaceEntry {
|
|
1096
|
+
readonly name: string;
|
|
1097
|
+
readonly type: "file" | "directory";
|
|
1098
|
+
readonly size: number | null;
|
|
1099
|
+
}
|
|
1100
|
+
/**
|
|
1101
|
+
* One directory of the chat's workspace. `path` is the canonical form of the
|
|
1102
|
+
* directory as requested — the chat root itself is the empty string — so the
|
|
1103
|
+
* panel can build a breadcrumb without another round trip.
|
|
1104
|
+
*/
|
|
1105
|
+
export interface QaWorkspaceListing {
|
|
1106
|
+
readonly path: string;
|
|
1107
|
+
readonly entries: readonly QaWorkspaceEntry[];
|
|
1108
|
+
/** More children existed than one listing carries. */
|
|
1109
|
+
readonly truncated: boolean;
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* One file of the chat's workspace: decoded text when it reads as UTF-8, base64
|
|
1113
|
+
* bytes when it does not. The panel needs both — documents the agent produced
|
|
1114
|
+
* are binary, while notes and transcripts preview as text.
|
|
1115
|
+
*/
|
|
1116
|
+
export interface QaWorkspaceFile {
|
|
1117
|
+
readonly path: string;
|
|
1118
|
+
readonly size: number;
|
|
1119
|
+
readonly truncated: boolean;
|
|
1120
|
+
readonly markdown: boolean;
|
|
1121
|
+
readonly renderableMarkdown: boolean;
|
|
1122
|
+
readonly mime: string;
|
|
1123
|
+
/** Present when the file decoded as text; absent for binary content. */
|
|
1124
|
+
readonly text?: string;
|
|
1125
|
+
/** Present when the file is not text; base64 of at most the byte cap. */
|
|
1126
|
+
readonly base64?: string;
|
|
1127
|
+
}
|
|
1041
1128
|
/** Host-attested facts required before the QA composer may become writable. */
|
|
1042
1129
|
export interface QaLockdownProof {
|
|
1043
1130
|
readonly sessionId: string;
|
|
@@ -1614,7 +1701,12 @@ export interface QaAdminUserDetail {
|
|
|
1614
1701
|
}[];
|
|
1615
1702
|
readonly activity: {
|
|
1616
1703
|
readonly conversations: number;
|
|
1617
|
-
|
|
1704
|
+
/**
|
|
1705
|
+
* Unknown until the conversations page is opened: the count needs every
|
|
1706
|
+
* conversation's log read, so the detail card reports null instead of
|
|
1707
|
+
* blocking its payload on the scan.
|
|
1708
|
+
*/
|
|
1709
|
+
readonly messages: number | null;
|
|
1618
1710
|
readonly positiveRatings: number;
|
|
1619
1711
|
readonly negativeRatings: number;
|
|
1620
1712
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The deployment UI mode, as the host half of the plugin sees it.
|
|
3
|
+
*
|
|
4
|
+
* `DSH_UI_MODE=qa` (the kiosk) moves the frontend URL-space ownership from
|
|
5
|
+
* this plugin to the harness: the harness route policy serves `/qa` directly,
|
|
6
|
+
* redirects `/` into it, and answers every other frontend path with 404. The
|
|
7
|
+
* plugin's own navigation redirect route must then stay unregistered — it
|
|
8
|
+
* exists for the overlay composition, where the index is served at `/` and a
|
|
9
|
+
* browser navigation to `/qa` has to bounce through the marker hand-off —
|
|
10
|
+
* because a registered route shadows the harness fallback seat and would
|
|
11
|
+
* loop every `/qa` navigation back onto itself.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Whether this harness process runs the QA kiosk UI mode.
|
|
15
|
+
* @param env - the process environment; overridable for tests.
|
|
16
|
+
*/
|
|
17
|
+
export declare function qaKioskDeployment(env?: Readonly<Record<string, string | undefined>>): boolean;
|
|
18
|
+
//# sourceMappingURL=ui-mode.d.ts.map
|
package/lib/ui-mode.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The deployment UI mode, as the host half of the plugin sees it.
|
|
3
|
+
*
|
|
4
|
+
* `DSH_UI_MODE=qa` (the kiosk) moves the frontend URL-space ownership from
|
|
5
|
+
* this plugin to the harness: the harness route policy serves `/qa` directly,
|
|
6
|
+
* redirects `/` into it, and answers every other frontend path with 404. The
|
|
7
|
+
* plugin's own navigation redirect route must then stay unregistered — it
|
|
8
|
+
* exists for the overlay composition, where the index is served at `/` and a
|
|
9
|
+
* browser navigation to `/qa` has to bounce through the marker hand-off —
|
|
10
|
+
* because a registered route shadows the harness fallback seat and would
|
|
11
|
+
* loop every `/qa` navigation back onto itself.
|
|
12
|
+
*/
|
|
13
|
+
/** Environment variable selecting the deployment UI mode (`qa` = kiosk). */
|
|
14
|
+
const UI_MODE_ENV = "DSH_UI_MODE";
|
|
15
|
+
/**
|
|
16
|
+
* Whether this harness process runs the QA kiosk UI mode.
|
|
17
|
+
* @param env - the process environment; overridable for tests.
|
|
18
|
+
*/
|
|
19
|
+
export function qaKioskDeployment(env = process.env) {
|
|
20
|
+
return (env[UI_MODE_ENV] ?? "").trim() === "qa";
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=ui-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-mode.js","sourceRoot":"","sources":["../src/ui-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,4EAA4E;AAC5E,MAAM,WAAW,GAAG,aAAa,CAAC;AAElC;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,GAAG,GAAiD,OAAO,CAAC,GAAG;IAE/D,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC;AAClD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yadsh/dsh-qa-surface",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "A focused end-user QA surface backed by native DeepSeek Harness sessions",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -102,15 +102,14 @@
|
|
|
102
102
|
},
|
|
103
103
|
"peerDependencies": {
|
|
104
104
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
105
|
-
"@deepseek-ai/schemastery": "^3.18.2",
|
|
106
|
-
"@deepseek-ai/dsh-api-gateway": ">=0.1.5-rc.2 <0.2.0",
|
|
107
105
|
"@deepseek-ai/dsh-agent": ">=0.1.5-rc.2 <0.2.0",
|
|
108
106
|
"@deepseek-ai/dsh-agent-presets": ">=0.1.5-rc.2 <0.2.0",
|
|
107
|
+
"@deepseek-ai/dsh-api-gateway": ">=0.1.5-rc.2 <0.2.0",
|
|
109
108
|
"@deepseek-ai/dsh-api-session-controller": ">=0.1.5-rc.2 <0.2.0",
|
|
110
109
|
"@deepseek-ai/dsh-api-workspace-controller": ">=0.1.5-rc.2 <0.2.0",
|
|
111
110
|
"@deepseek-ai/dsh-client-connection": ">=0.1.5-rc.2 <0.2.0",
|
|
112
|
-
"@deepseek-ai/dsh-client-ui-conversation": ">=0.1.5-rc.2 <0.2.0",
|
|
113
111
|
"@deepseek-ai/dsh-client-ui-chat": ">=0.1.5-rc.2 <0.2.0",
|
|
112
|
+
"@deepseek-ai/dsh-client-ui-conversation": ">=0.1.5-rc.2 <0.2.0",
|
|
114
113
|
"@deepseek-ai/dsh-client-ui-layout": ">=0.1.5-rc.2 <0.2.0",
|
|
115
114
|
"@deepseek-ai/dsh-client-ui-renderer": ">=0.1.5-rc.2 <0.2.0",
|
|
116
115
|
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.5-rc.2 <0.2.0",
|
|
@@ -127,28 +126,29 @@
|
|
|
127
126
|
"@deepseek-ai/dsh-tools": ">=0.1.5-rc.2 <0.2.0",
|
|
128
127
|
"@deepseek-ai/dsh-typert-protocol": ">=0.1.5-rc.2 <0.2.0",
|
|
129
128
|
"@deepseek-ai/dsh-workspace": ">=0.1.5-rc.2 <0.2.0",
|
|
129
|
+
"@deepseek-ai/schemastery": "^3.18.2",
|
|
130
130
|
"react": "^18.2.0",
|
|
131
131
|
"react-dom": "^18.2.0"
|
|
132
132
|
},
|
|
133
133
|
"dependencies": {
|
|
134
134
|
"yaml": "^2.9.0",
|
|
135
135
|
"zod": "^4.4.3",
|
|
136
|
-
"@yadsh/dsh-audit-ui": "^0.1.0",
|
|
137
136
|
"@yadsh/dsh-audit-core": "^0.1.0",
|
|
137
|
+
"@yadsh/dsh-audit-ui": "^0.1.0",
|
|
138
|
+
"@yadsh/dsh-documents": "^0.4.0",
|
|
138
139
|
"@yadsh/dsh-plugin-kit": "^0.3.0",
|
|
139
140
|
"@yadsh/dsh-plugin-log": "^0.4.0"
|
|
140
141
|
},
|
|
141
142
|
"devDependencies": {
|
|
142
143
|
"@deepseek-ai/cordis": "4.0.2",
|
|
143
|
-
"@deepseek-ai/schemastery": "3.18.2",
|
|
144
|
-
"@deepseek-ai/dsh-api-gateway": "0.1.5-rc.2",
|
|
145
144
|
"@deepseek-ai/dsh-agent": "0.1.5-rc.2",
|
|
146
145
|
"@deepseek-ai/dsh-agent-presets": "0.1.5-rc.2",
|
|
146
|
+
"@deepseek-ai/dsh-api-gateway": "0.1.5-rc.2",
|
|
147
147
|
"@deepseek-ai/dsh-api-session-controller": "0.1.5-rc.2",
|
|
148
148
|
"@deepseek-ai/dsh-api-workspace-controller": "0.1.5-rc.2",
|
|
149
149
|
"@deepseek-ai/dsh-client-connection": "0.1.5-rc.2",
|
|
150
|
-
"@deepseek-ai/dsh-client-ui-conversation": "0.1.5-rc.2",
|
|
151
150
|
"@deepseek-ai/dsh-client-ui-chat": "0.1.5-rc.2",
|
|
151
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.1.5-rc.2",
|
|
152
152
|
"@deepseek-ai/dsh-client-ui-layout": "0.1.5-rc.2",
|
|
153
153
|
"@deepseek-ai/dsh-client-ui-renderer": "0.1.5-rc.2",
|
|
154
154
|
"@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.2",
|
|
@@ -167,12 +167,14 @@
|
|
|
167
167
|
"@deepseek-ai/dsh-typert-generator": "0.1.5-rc.2",
|
|
168
168
|
"@deepseek-ai/dsh-typert-protocol": "0.1.5-rc.2",
|
|
169
169
|
"@deepseek-ai/dsh-workspace": "0.1.5-rc.2",
|
|
170
|
+
"@deepseek-ai/schemastery": "3.18.2",
|
|
170
171
|
"@testing-library/react": "^16.3.0",
|
|
171
172
|
"@types/node": "^26.4.0",
|
|
172
173
|
"@types/react": "18.3.28",
|
|
173
174
|
"@types/react-dom": "18.3.7",
|
|
174
175
|
"eslint": "10.9.1",
|
|
175
176
|
"jsdom": "^26.1.0",
|
|
177
|
+
"katex": "^0.16.47",
|
|
176
178
|
"playwright": "1.62.1",
|
|
177
179
|
"react": "18.3.1",
|
|
178
180
|
"react-dom": "18.3.1",
|