@yadsh/dsh-qa-surface 0.15.1 → 0.15.3
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/lib/access/model.js +15 -0
- package/lib/access/model.js.map +1 -1
- package/lib/access/service.js +56 -16
- package/lib/access/service.js.map +1 -1
- package/lib/attestation.js.map +1 -1
- package/lib/client/QaAccountsController.js +3 -1
- package/lib/client/QaAccountsController.js.map +1 -1
- package/lib/client/QaSessionController.js +66 -18
- package/lib/client/QaSessionController.js.map +1 -1
- package/lib/client/QaSurface.js +64 -2
- package/lib/client/QaSurface.js.map +1 -1
- package/lib/client/QaTranscriptAdapter.js +46 -8
- package/lib/client/QaTranscriptAdapter.js.map +1 -1
- package/lib/client/admin/pages/Users.js +2 -2
- package/lib/client/admin/pages/Users.js.map +1 -1
- package/lib/client/attestation.js +13 -5
- package/lib/client/attestation.js.map +1 -1
- package/lib/client/chat-artifacts.js +94 -0
- package/lib/client/chat-artifacts.js.map +1 -0
- package/lib/client/chat-files.js +24 -14
- package/lib/client/chat-files.js.map +1 -1
- package/lib/client/clipboard.js +86 -0
- package/lib/client/clipboard.js.map +1 -0
- package/lib/client/components/QaAuthGate.js +41 -5
- package/lib/client/components/QaAuthGate.js.map +1 -1
- package/lib/client/components/QaChangelog.js +46 -0
- package/lib/client/components/QaChangelog.js.map +1 -1
- package/lib/client/components/QaFileAttachment.js +7 -5
- package/lib/client/components/QaFileAttachment.js.map +1 -1
- package/lib/client/components/QaFilesPanel.js +7 -3
- package/lib/client/components/QaFilesPanel.js.map +1 -1
- package/lib/client/components/QaMessage.js +27 -24
- package/lib/client/components/QaMessage.js.map +1 -1
- package/lib/client/components/QaWorkspaceBrowser.js +18 -25
- package/lib/client/components/QaWorkspaceBrowser.js.map +1 -1
- package/lib/client/components/copy-hint.js +10 -0
- package/lib/client/components/copy-hint.js.map +1 -0
- package/lib/client/markdown/CodeBlock.js +6 -13
- package/lib/client/markdown/CodeBlock.js.map +1 -1
- package/lib/client/project-session-state.js +1 -0
- package/lib/client/project-session-state.js.map +1 -1
- package/lib/client/settings/styles.js +1 -1
- package/lib/client/styles.js +11 -4
- package/lib/client/styles.js.map +1 -1
- package/lib/client/user-settings/IntegrationTokensPage.js +4 -12
- package/lib/client/user-settings/IntegrationTokensPage.js.map +1 -1
- package/lib/client/user-settings/PasswordSettingsPage.js +6 -1
- package/lib/client/user-settings/PasswordSettingsPage.js.map +1 -1
- package/lib/client/workspace-download.js +32 -0
- package/lib/client/workspace-download.js.map +1 -0
- package/lib/client/workspace-paths.js +55 -0
- package/lib/client/workspace-paths.js.map +1 -0
- package/lib/client.js +727 -253
- package/lib/client.js.map +1 -1
- package/lib/enforcement/skill-policy.js +2 -1
- package/lib/enforcement/skill-policy.js.map +1 -1
- package/lib/index.js +26 -10
- package/lib/index.js.map +1 -1
- package/lib/secure-session.js +36 -11
- package/lib/secure-session.js.map +1 -1
- package/lib/slash/catalog.js.map +1 -1
- package/lib/typert.host.js +75 -75
- package/lib/typert.remote-client.js +75 -75
- package/lib/types/access/model.d.ts +13 -0
- package/lib/types/access/service.d.ts +26 -0
- package/lib/types/attestation.d.ts +1 -1
- package/lib/types/client/QaAccountsController.d.ts +2 -0
- package/lib/types/client/QaSessionController.d.ts +13 -0
- package/lib/types/client/QaTranscriptAdapter.d.ts +6 -0
- package/lib/types/client/attestation.d.ts +7 -3
- package/lib/types/client/chat-artifacts.d.ts +10 -0
- package/lib/types/client/chat-files.d.ts +13 -8
- package/lib/types/client/clipboard.d.ts +37 -0
- package/lib/types/client/components/QaAuthGate.d.ts +4 -2
- package/lib/types/client/components/QaFileAttachment.d.ts +13 -4
- package/lib/types/client/components/QaFilesPanel.d.ts +15 -2
- package/lib/types/client/components/QaMessage.d.ts +10 -2
- package/lib/types/client/components/QaWorkspaceBrowser.d.ts +7 -1
- package/lib/types/client/components/copy-hint.d.ts +8 -0
- package/lib/types/client/project-session-state.d.ts +5 -0
- package/lib/types/client/workspace-download.d.ts +16 -0
- package/lib/types/client/workspace-paths.d.ts +25 -0
- package/lib/types/index.d.ts +6 -4
- package/lib/types/secure-session.d.ts +4 -0
- package/lib/types/slash/catalog.d.ts +5 -0
- package/lib/types/types.d.ts +26 -0
- package/locale/en.json +6 -0
- package/package.json +5 -3
|
@@ -64,6 +64,19 @@ export declare function withdrawnSkillNames(config: QaCapabilityConfig): Readonl
|
|
|
64
64
|
*/
|
|
65
65
|
export declare function personalUserSkillNames(config: QaCapabilityConfig, ownSkills: ReadonlySet<string> | undefined): readonly string[];
|
|
66
66
|
export declare function resolveCapabilityPolicy({ config, subroleId, systemTools, systemSkills, available: installed, skillMetadata, revision, }: ResolveCapabilityPolicyInput): QaEffectiveCapabilityPolicy;
|
|
67
|
+
/**
|
|
68
|
+
* The skills a person may invoke under one policy — the whole of the
|
|
69
|
+
* user-facing allow-list, and the one place it is read.
|
|
70
|
+
*
|
|
71
|
+
* An empty `userSkills` means the role keeps no separate user list, not that it
|
|
72
|
+
* grants nothing, so the model-facing set stands in for it. A typed gesture is
|
|
73
|
+
* admitted or refused by this list and the palette is narrowed by it, so both
|
|
74
|
+
* have to derive it here: a name the palette offers but the line refuses, or
|
|
75
|
+
* one the palette hides while the line would accept, is one rule read two ways.
|
|
76
|
+
*
|
|
77
|
+
* @param policy - the effective capability policy of one session.
|
|
78
|
+
*/
|
|
79
|
+
export declare function userInvocableSkillNames(policy: QaEffectiveCapabilityPolicy): readonly string[];
|
|
67
80
|
export interface ResolveSkillAccessInput {
|
|
68
81
|
readonly config: QaCapabilityConfig;
|
|
69
82
|
/** Every discovered skill with its normalized metadata. */
|
|
@@ -158,6 +158,32 @@ export declare class QaAccessService {
|
|
|
158
158
|
policyForSessionOwner(owner: {
|
|
159
159
|
readonly id: string;
|
|
160
160
|
} | undefined, sessionId: string, agent: Agent): Promise<QaResolvedSessionPolicy | undefined>;
|
|
161
|
+
/**
|
|
162
|
+
* The policy one session record answers with: the snapshot it froze, or the
|
|
163
|
+
* role as it is configured now when the chat has never frozen one.
|
|
164
|
+
*
|
|
165
|
+
* Every read of a session's capabilities goes through here, so a chat that is
|
|
166
|
+
* running and a chat nobody has woken cannot disagree about what its role
|
|
167
|
+
* grants.
|
|
168
|
+
*/
|
|
169
|
+
private policyForRecord;
|
|
170
|
+
/**
|
|
171
|
+
* The policy of a chat this process holds no live agent for.
|
|
172
|
+
*
|
|
173
|
+
* A cold chat has an owner and a role, and the reads that name its
|
|
174
|
+
* capabilities must narrow it by the rule above — the same one a live chat is
|
|
175
|
+
* narrowed by — rather than answer "no role opinion" because the agent that
|
|
176
|
+
* carries the capability snapshot happens to be asleep. What a cold chat has
|
|
177
|
+
* no answer for is that snapshot: the catalog the deployment mounts for every
|
|
178
|
+
* chat stands in for the agent's own, which is why the project layer of this
|
|
179
|
+
* chat's workspace is missing from it, and why nothing is frozen onto the
|
|
180
|
+
* session record here — a palette read must not decide what a later turn may
|
|
181
|
+
* do.
|
|
182
|
+
*
|
|
183
|
+
* @returns the resolved policy; the ownership check is the refusal, so a
|
|
184
|
+
* foreign browser never reaches it.
|
|
185
|
+
*/
|
|
186
|
+
policyForColdSession(token: string, sessionId: string): Promise<QaEffectiveCapabilityPolicy>;
|
|
161
187
|
/** The browser's entry point: the token resolves the owning account. */
|
|
162
188
|
policyForSession(token: string, sessionId: string, agent: Agent): Promise<QaResolvedSessionPolicy | undefined>;
|
|
163
189
|
/** Activation history of one session, for review and quality analysis. */
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* audience, precise enough for an operator reading the browser console to
|
|
9
9
|
* know which class of mismatch to look for in the Host logs.
|
|
10
10
|
*/
|
|
11
|
-
export type QaAttestationReason = "agent-unavailable" | "workspace-unavailable" | "composition-mismatch" | "permission-preset" | "adoption-refused" | "unknown-tools" | "auth-required" | "session-owned-elsewhere" | "attestation-failed";
|
|
11
|
+
export type QaAttestationReason = "agent-unavailable" | "workspace-unavailable" | "composition-mismatch" | "permission-preset" | "adoption-refused" | "subagent-session" | "unknown-tools" | "auth-required" | "session-owned-elsewhere" | "attestation-failed";
|
|
12
12
|
/** Host rejection whose wire message carries the coarse reason marker. */
|
|
13
13
|
export declare class QaAttestationError extends Error {
|
|
14
14
|
readonly reason: QaAttestationReason;
|
|
@@ -38,6 +38,8 @@ export type QaAccountsSnapshot = {
|
|
|
38
38
|
/** Bumped whenever ownedIds, ownIds or ownership changes; re-projects lists. */
|
|
39
39
|
readonly ownedRevision: number;
|
|
40
40
|
};
|
|
41
|
+
/** The Host's password floor, mirrored so a refusal and its copy name the same number. */
|
|
42
|
+
export declare const QA_MIN_PASSWORD_LENGTH = 8;
|
|
41
43
|
/**
|
|
42
44
|
* Audience-safe copy for the coarse account refusal codes; anything unknown
|
|
43
45
|
* falls back to the generic line.
|
|
@@ -307,6 +307,19 @@ export declare class QaSessionController {
|
|
|
307
307
|
* so this call gives up rather than taking the chat back from under them.
|
|
308
308
|
*/
|
|
309
309
|
startDraft(policyChange?: boolean): Promise<void>;
|
|
310
|
+
/**
|
|
311
|
+
* Put a draft on the screen: no session, so no row in the chat history and no
|
|
312
|
+
* record on the Host until the first prompt is sent into it
|
|
313
|
+
* ({@link materializeDraft}). Taking the screen moves the generation the way
|
|
314
|
+
* every other path that retires a binding does, so an adoption still looking
|
|
315
|
+
* for its session measures itself against the new one rather than taking the
|
|
316
|
+
* draft back.
|
|
317
|
+
*
|
|
318
|
+
* A draft that is already on screen — including one whose first send fell
|
|
319
|
+
* short of a claimed session — keeps its chat identity: a new one rebuilds the
|
|
320
|
+
* composer over the question the visitor is still looking at.
|
|
321
|
+
*/
|
|
322
|
+
private enterDraft;
|
|
310
323
|
/**
|
|
311
324
|
* Turn the current draft into a real attested session. Runs inside the
|
|
312
325
|
* send flow; concurrent sends share one materialization. A refusal here is
|
|
@@ -20,5 +20,11 @@ export declare function projectTranscript(snapshot: ConversationSnapshot | undef
|
|
|
20
20
|
readonly subagentNames?: Readonly<Record<string, string>>;
|
|
21
21
|
/** Sign settlement titles with deterministic codenames. */
|
|
22
22
|
readonly subagentCodenames?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* The chat's own workspace directory. An answer that quotes a file inside it
|
|
25
|
+
* is made to name the file instead of locating it, because the directory is
|
|
26
|
+
* the account's own and the transcript is not where that layout belongs.
|
|
27
|
+
*/
|
|
28
|
+
readonly workspaceRoot?: string;
|
|
23
29
|
}): readonly QaMessage[];
|
|
24
30
|
//# sourceMappingURL=QaTranscriptAdapter.d.ts.map
|
|
@@ -10,9 +10,13 @@ export declare class QaPolicyAttestationError extends Error {
|
|
|
10
10
|
constructor(reason?: string | null);
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* Refusals that classify
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* Refusals that classify what the browser has on screen rather than faulting
|
|
14
|
+
* the deployment: an existing chat of an older composition, one adopted from
|
|
15
|
+
* outside the QA policy, or an identity that is another conversation's
|
|
16
|
+
* delegated child.
|
|
17
|
+
*
|
|
18
|
+
* Keeping only its transcript is safe: policyReady stays false, so no prompt,
|
|
19
|
+
* cancel, approval or question reaches the Host.
|
|
16
20
|
*/
|
|
17
21
|
export declare function canOpenAsCompatibilityReadOnly(reason: string | null): boolean;
|
|
18
22
|
/**
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { QaArtifactView } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The files one tool result reports, in the order it reported them.
|
|
4
|
+
*
|
|
5
|
+
* `output` is the rendered text of the result, the same string the work group
|
|
6
|
+
* shows. A tool that produced nothing — a read, an inspection, a refusal — is
|
|
7
|
+
* not in the table and contributes no artifact.
|
|
8
|
+
*/
|
|
9
|
+
export declare function artifactsOfToolResult(toolName: string, output: string | null): readonly QaArtifactView[];
|
|
10
|
+
//# sourceMappingURL=chat-artifacts.d.ts.map
|
|
@@ -2,27 +2,32 @@
|
|
|
2
2
|
* Attachment roster of one chat, projected for the rail's files tab: a pure
|
|
3
3
|
* scan of the durable transcript, newest message first. The browser never
|
|
4
4
|
* re-reads file bytes (the attachment route serves images), so a row keeps
|
|
5
|
-
* the same handle the transcript shows.
|
|
5
|
+
* the same handle the transcript shows. A document the agent produced is on
|
|
6
|
+
* the same roster: it is an attachment of the conversation, sent by the answer
|
|
7
|
+
* rather than by the question.
|
|
6
8
|
*/
|
|
7
|
-
import type { QaImageView, QaMessage, QaFileView } from "../types.js";
|
|
8
|
-
/** Everything one
|
|
9
|
+
import type { QaArtifactView, QaImageView, QaMessage, QaFileView } from "../types.js";
|
|
10
|
+
/** Everything one message carried, in prompt order. */
|
|
9
11
|
export interface QaChatFileGroup {
|
|
10
|
-
/** The
|
|
12
|
+
/** The message id; doubles as the transcript turn anchor. */
|
|
11
13
|
readonly messageId: string;
|
|
12
14
|
/** Wall-clock send time, when the transcript recorded one. */
|
|
13
15
|
readonly timestamp?: number;
|
|
14
16
|
readonly files: readonly QaFileView[];
|
|
15
17
|
readonly images: readonly QaImageView[];
|
|
18
|
+
/** Files this message's turn produced; empty on a message that made none. */
|
|
19
|
+
readonly artifacts?: readonly QaArtifactView[];
|
|
16
20
|
}
|
|
17
21
|
/** Whether the group carries at least one attachment of either kind. */
|
|
18
22
|
export declare function groupHasAttachments(group: QaChatFileGroup): boolean;
|
|
19
23
|
/** Total attachment count across groups; the header badge's value. */
|
|
20
24
|
export declare function countChatAttachments(groups: readonly QaChatFileGroup[]): number;
|
|
21
25
|
/**
|
|
22
|
-
* Group the attachments of a chat by their
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
+
* Group the attachments of a chat by their message. A user message carries what
|
|
27
|
+
* was sent; an assistant message carries what its turn produced, so a document
|
|
28
|
+
* the stand made is listed beside the answer that made it instead of only on
|
|
29
|
+
* disk. Messages with neither are dropped. The groups come out newest first,
|
|
30
|
+
* matching a roster that grows at the bottom of the transcript.
|
|
26
31
|
* @param messages - the chat's projected transcript.
|
|
27
32
|
* @returns attachment groups, newest message first.
|
|
28
33
|
*/
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sentence a copy affordance falls back to. Three surfaces show it, so it
|
|
3
|
+
* is written once.
|
|
4
|
+
*/
|
|
5
|
+
export declare const COPY_MANUAL_HINT = "\u0421\u043A\u043E\u043F\u0438\u0440\u0443\u0439\u0442\u0435 \u0432\u0440\u0443\u0447\u043D\u0443\u044E";
|
|
6
|
+
/** The reason behind that sentence, for the tooltip that carries it. */
|
|
7
|
+
export declare const COPY_MANUAL_REASON = "\u0411\u0440\u0430\u0443\u0437\u0435\u0440 \u043D\u0435 \u043E\u0442\u0434\u0430\u0451\u0442 \u0431\u0443\u0444\u0435\u0440 \u043E\u0431\u043C\u0435\u043D\u0430 \u2014 \u0432\u044B\u0434\u0435\u043B\u0438\u0442\u0435 \u0442\u0435\u043A\u0441\u0442 \u0438 \u0441\u043A\u043E\u043F\u0438\u0440\u0443\u0439\u0442\u0435 \u0435\u0433\u043E \u0441\u0430\u043C\u0438";
|
|
8
|
+
/**
|
|
9
|
+
* Whether this browser can be asked to move text at all.
|
|
10
|
+
*
|
|
11
|
+
* The stand is served over plain HTTP on a LAN address, and there
|
|
12
|
+
* `window.isSecureContext` is false, so the browser never exposes
|
|
13
|
+
* `navigator.clipboard`. The older copy command still works in an insecure
|
|
14
|
+
* context, which is why the absence of the API alone does not mean copying is
|
|
15
|
+
* impossible — and why asking for it anyway only ends in silence.
|
|
16
|
+
*/
|
|
17
|
+
export declare function canCopyToClipboard(): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Write `text` to the clipboard, resolving false when nothing took it — the
|
|
20
|
+
* caller then says so instead of leaving the click unanswered.
|
|
21
|
+
*/
|
|
22
|
+
export declare function copyTextToClipboard(text: string): Promise<boolean>;
|
|
23
|
+
export interface CopyAction {
|
|
24
|
+
/** The flash that says the text left. */
|
|
25
|
+
readonly copied: boolean;
|
|
26
|
+
/** Nothing can copy here: the affordance is a hint, not a button. */
|
|
27
|
+
readonly impossible: boolean;
|
|
28
|
+
/** A copy was attempted and refused: the hint joins a still-live button. */
|
|
29
|
+
readonly refused: boolean;
|
|
30
|
+
readonly copy: () => void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The copy state one affordance needs: the confirmation window, the refusal
|
|
34
|
+
* that replaces it with the manual hint, and whether either was ever possible.
|
|
35
|
+
*/
|
|
36
|
+
export declare function useCopyAction(text: string): CopyAction;
|
|
37
|
+
//# sourceMappingURL=clipboard.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type QaAccountsController, type QaAccountsSnapshot } from "../QaAccountsController.js";
|
|
2
2
|
export interface QaAuthGateProps {
|
|
3
3
|
readonly accounts: QaAccountsController;
|
|
4
4
|
readonly snapshot: QaAccountsSnapshot;
|
|
@@ -9,7 +9,9 @@ export interface QaAuthGateProps {
|
|
|
9
9
|
/**
|
|
10
10
|
* The full-frame login/registration card shown instead of the chat while the
|
|
11
11
|
* deployment has accounts enabled and the browser holds no valid identity.
|
|
12
|
-
*
|
|
12
|
+
* Both halves of the error line are the surface's own copy: the card refuses
|
|
13
|
+
* mistyped input itself, and renders the Host's coarse codes in audience-safe
|
|
14
|
+
* words.
|
|
13
15
|
*/
|
|
14
16
|
export declare function QaAuthGate(props: QaAuthGateProps): import("react/jsx-runtime").JSX.Element;
|
|
15
17
|
//# sourceMappingURL=QaAuthGate.d.ts.map
|
|
@@ -4,11 +4,20 @@ export interface QaFileAttachmentProps {
|
|
|
4
4
|
/** Pending draft vs already-sent attachment: pending offers removal. */
|
|
5
5
|
readonly tone: "draft" | "sent";
|
|
6
6
|
readonly onRemove?: () => void;
|
|
7
|
+
/**
|
|
8
|
+
* Open the file: shown as a control on a card the reader can act on, and left
|
|
9
|
+
* out of a chip that only records what was sent. A produced document is
|
|
10
|
+
* worthless as a name in a paragraph — this is what makes it reachable.
|
|
11
|
+
*/
|
|
12
|
+
readonly onOpen?: () => void;
|
|
13
|
+
/** Save the file. Omitted where the surface cannot read its bytes. */
|
|
14
|
+
readonly onDownload?: () => void;
|
|
7
15
|
}
|
|
8
16
|
/**
|
|
9
|
-
* One attached file: the extension badge, the name and the size.
|
|
10
|
-
*
|
|
11
|
-
*
|
|
17
|
+
* One attached file: the extension badge, the name and the size. A sent
|
|
18
|
+
* attachment shows the handle the model resolved and the browser never
|
|
19
|
+
* re-reads its bytes; a file the turn produced is the same chip with the two
|
|
20
|
+
* controls that make it usable — open it, or take it away.
|
|
12
21
|
*/
|
|
13
|
-
export declare function QaFileAttachment({ name, bytes, tone, onRemove, }: QaFileAttachmentProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export declare function QaFileAttachment({ name, bytes, tone, onRemove, onOpen, onDownload, }: QaFileAttachmentProps): import("react/jsx-runtime").JSX.Element;
|
|
14
23
|
//# sourceMappingURL=QaFileAttachment.d.ts.map
|
|
@@ -1,11 +1,24 @@
|
|
|
1
|
+
import type { QaArtifactView } from "../../types.js";
|
|
1
2
|
import type { QaChatFileGroup } from "../chat-files.js";
|
|
2
3
|
import type { QaBoundSourceApi } from "../types.js";
|
|
3
4
|
export interface QaFilesPanelProps {
|
|
4
5
|
readonly groups: readonly QaChatFileGroup[];
|
|
5
6
|
/** Resolve an image attachment to an object URL; images render inert without it. */
|
|
6
7
|
readonly resolveImage?: (attachmentId: string) => Promise<string>;
|
|
7
|
-
/** Scroll the transcript to the group's
|
|
8
|
+
/** Scroll the transcript to the group's message. */
|
|
8
9
|
readonly onJumpToMessage: (messageId: string) => void;
|
|
10
|
+
/** Open a produced file in the workspace viewer below. */
|
|
11
|
+
readonly onArtifactOpen?: (artifact: QaArtifactView) => void;
|
|
12
|
+
/** Save a produced file. */
|
|
13
|
+
readonly onArtifactDownload?: (artifact: QaArtifactView) => void;
|
|
14
|
+
/**
|
|
15
|
+
* A file to open on arrival, with the request's stamp. The stamp is what makes
|
|
16
|
+
* a second click on the same card a fresh arrival rather than a no-op.
|
|
17
|
+
*/
|
|
18
|
+
readonly openArtifact?: {
|
|
19
|
+
readonly path: string;
|
|
20
|
+
readonly stamp: number;
|
|
21
|
+
};
|
|
9
22
|
/**
|
|
10
23
|
* The chat whose workspace the panel browses. Both this and `api` are absent
|
|
11
24
|
* in hosts that only render the attachment roster, where the workspace
|
|
@@ -23,5 +36,5 @@ export interface QaFilesPanelProps {
|
|
|
23
36
|
* back, and the images are the same object URLs the message showed — while the
|
|
24
37
|
* workspace section reads through the Host's fenced listing and file reads.
|
|
25
38
|
*/
|
|
26
|
-
export declare function QaFilesPanel({ groups, resolveImage, onJumpToMessage, sessionId, api, }: QaFilesPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
39
|
+
export declare function QaFilesPanel({ groups, resolveImage, onJumpToMessage, onArtifactOpen, onArtifactDownload, openArtifact, sessionId, api, }: QaFilesPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
27
40
|
//# sourceMappingURL=QaFilesPanel.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { QaMessage as QaMessageModel, QaSource, QaTurnSources } from "../../types.js";
|
|
1
|
+
import type { QaArtifactView, QaMessage as QaMessageModel, QaSource, QaTurnSources } from "../../types.js";
|
|
2
2
|
import type { QaFeedbackReason } from "../../types.js";
|
|
3
3
|
export interface QaMessageProps {
|
|
4
4
|
readonly message: QaMessageModel;
|
|
@@ -17,6 +17,14 @@ export interface QaMessageProps {
|
|
|
17
17
|
readonly onOpenSources?: (sources: readonly QaSource[], complete: boolean, incompleteOrigins: QaTurnSources["incompleteOrigins"]) => void;
|
|
18
18
|
/** Open one path-backed source's detail (an inline footnote click). */
|
|
19
19
|
readonly onSourceDetail?: (source: QaSource) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Open a file this answer's turn produced, in the surface's own file viewer.
|
|
22
|
+
* Omitted where the surface has no workspace reads: the card then names the
|
|
23
|
+
* file without promising an action it cannot perform.
|
|
24
|
+
*/
|
|
25
|
+
readonly onArtifactOpen?: (artifact: QaArtifactView) => void;
|
|
26
|
+
/** Save a produced file. Omitted on the same terms as {@link onArtifactOpen}. */
|
|
27
|
+
readonly onArtifactDownload?: (artifact: QaArtifactView) => void;
|
|
20
28
|
/** Operator-configured running phrases; omitted reads the built-in list. */
|
|
21
29
|
readonly thinkingPhrases?: readonly string[];
|
|
22
30
|
/**
|
|
@@ -39,5 +47,5 @@ export interface QaMessageProps {
|
|
|
39
47
|
* comparison is by value, which keeps fresh copies cheap to recognize.
|
|
40
48
|
*/
|
|
41
49
|
export declare function sameMessage(a: QaMessageModel, b: QaMessageModel): boolean;
|
|
42
|
-
export declare const QaMessage: import("react").MemoExoticComponent<({ message, renderMarkdown, showTimestamp, stateKey, onRegenerate, resolveImage, onOpenSources, onSourceDetail, thinkingPhrases, onRateFeedback, }: QaMessageProps) => import("react/jsx-runtime").JSX.Element>;
|
|
50
|
+
export declare const QaMessage: import("react").MemoExoticComponent<({ message, renderMarkdown, showTimestamp, stateKey, onRegenerate, resolveImage, onOpenSources, onSourceDetail, onArtifactOpen, onArtifactDownload, thinkingPhrases, onRateFeedback, }: QaMessageProps) => import("react/jsx-runtime").JSX.Element>;
|
|
43
51
|
//# sourceMappingURL=QaMessage.d.ts.map
|
|
@@ -2,6 +2,12 @@ import type { QaBoundSourceApi } from "../types.js";
|
|
|
2
2
|
export interface QaWorkspaceBrowserProps {
|
|
3
3
|
readonly sessionId: string;
|
|
4
4
|
readonly api: QaBoundSourceApi;
|
|
5
|
+
/**
|
|
6
|
+
* A file to open on arrival, named inside this workspace. The card under an
|
|
7
|
+
* answer points here rather than carrying its own viewer, so a document the
|
|
8
|
+
* turn produced previews through the same fenced read a browsed file uses.
|
|
9
|
+
*/
|
|
10
|
+
readonly initialFile?: string;
|
|
5
11
|
}
|
|
6
12
|
/**
|
|
7
13
|
* The chat's own workspace, browsable from the files rail.
|
|
@@ -11,5 +17,5 @@ export interface QaWorkspaceBrowserProps {
|
|
|
11
17
|
* the visitor out of the chat's tree. Opening a file reads exactly that file —
|
|
12
18
|
* text inline, anything else as a downloadable handle.
|
|
13
19
|
*/
|
|
14
|
-
export declare function QaWorkspaceBrowser({ sessionId, api, }: QaWorkspaceBrowserProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export declare function QaWorkspaceBrowser({ sessionId, api, initialFile, }: QaWorkspaceBrowserProps): import("react/jsx-runtime").JSX.Element;
|
|
15
21
|
//# sourceMappingURL=QaWorkspaceBrowser.d.ts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a copy affordance shows where copying cannot happen: a sentence naming
|
|
3
|
+
* the dead end, in place of a button that would only look like it worked.
|
|
4
|
+
*/
|
|
5
|
+
export declare function CopyHint({ testId }: {
|
|
6
|
+
readonly testId: string;
|
|
7
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=copy-hint.d.ts.map
|
|
@@ -25,6 +25,11 @@ export interface QaBoundProjectionInput {
|
|
|
25
25
|
readonly conversationSnapshot: ConversationSnapshot | undefined;
|
|
26
26
|
/** Turn bundles with the Host provenance already merged in (Host wins). */
|
|
27
27
|
readonly sourceBundles: readonly QaTurnSources[];
|
|
28
|
+
/**
|
|
29
|
+
* The chat's own workspace directory, as the Host records it for this session.
|
|
30
|
+
* The transcript masks it out of an answer that quotes a file it made.
|
|
31
|
+
*/
|
|
32
|
+
readonly workspaceRoot?: string;
|
|
28
33
|
/**
|
|
29
34
|
* Tool calls and questions the Host parked for the operator. They are
|
|
30
35
|
* host-side state, not part of the session snapshot, so the controller polls
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { QaWorkspaceFile } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Handing one file of the chat's workspace to the person the turn produced it
|
|
4
|
+
* for.
|
|
5
|
+
*
|
|
6
|
+
* A produced document has no attachment-store handle, so the download is the
|
|
7
|
+
* same read the files panel does: the Host returns the bytes under the chat's
|
|
8
|
+
* own fence and the browser's download machinery takes it from there. Shared by
|
|
9
|
+
* the panel's own viewer and the card under an answer, so the two can never
|
|
10
|
+
* disagree on what "download this file" means.
|
|
11
|
+
*/
|
|
12
|
+
/** Last segment of a workspace path, spelled with either separator. */
|
|
13
|
+
export declare function fileNameOf(path: string): string;
|
|
14
|
+
/** Save one workspace file under its own name. */
|
|
15
|
+
export declare function downloadWorkspaceFile(file: QaWorkspaceFile): void;
|
|
16
|
+
//# sourceMappingURL=workspace-download.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The answer a person reads names a file; it does not say where the deployment
|
|
3
|
+
* keeps the account that owns it.
|
|
4
|
+
*
|
|
5
|
+
* A model quoting a path it was handed prints it verbatim, and a QA deployment
|
|
6
|
+
* gives every account its own directory under one parent, so a path printed
|
|
7
|
+
* with an account identifier is a sentence about the server's layout — and
|
|
8
|
+
* stand dialogs below the signature line can be read by other accounts of the
|
|
9
|
+
* same server. The document tools report workspace-relative names, which is
|
|
10
|
+
* the fix at the source; this is the repair for what still arrives, because a
|
|
11
|
+
* model can rebuild a path from the working directory it is told, and because
|
|
12
|
+
* an answer written before this change is durable history that replays.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Rewrite an answer so a file is named, not located.
|
|
16
|
+
*
|
|
17
|
+
* The chat's own workspace directory is removed, leaving the spelling the
|
|
18
|
+
* producing tool reports and the workspace reads take. The per-account
|
|
19
|
+
* partition is removed the same way even when the root is unknown or the answer
|
|
20
|
+
* quotes a different chat's file, because the identifier inside it is the part
|
|
21
|
+
* that must not be printed. A path that is neither of those is left alone: a
|
|
22
|
+
* reader told about `/etc/hosts` is not being shown this deployment's layout.
|
|
23
|
+
*/
|
|
24
|
+
export declare function toWorkspaceRelativeText(text: string, workspaceRoot: string | undefined): string;
|
|
25
|
+
//# sourceMappingURL=workspace-paths.d.ts.map
|
package/lib/types/index.d.ts
CHANGED
|
@@ -107,10 +107,12 @@ export declare class QaSurface extends TypertRemoteService {
|
|
|
107
107
|
* check and the deployment's lockdown is the boundary, exactly as it is for
|
|
108
108
|
* every other remote.
|
|
109
109
|
*
|
|
110
|
-
* The grant
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
110
|
+
* The grant is {@link userInvocableSkillNames} — the one list the typed
|
|
111
|
+
* gesture is admitted or refused by — for every chat that has a role, woken
|
|
112
|
+
* or not: the palette a visitor sees before the chat runs is narrowed by that
|
|
113
|
+
* same rule, so it can neither offer a name the line would refuse nor hide
|
|
114
|
+
* one it would accept. `undefined` is answered only where the deployment has
|
|
115
|
+
* no roles to consult at all.
|
|
114
116
|
*/
|
|
115
117
|
private slashSessionGrant;
|
|
116
118
|
/**
|
|
@@ -137,6 +137,10 @@ export declare class QaPolicyAdmission {
|
|
|
137
137
|
* composition a stock prompt would produce — so a session composed outside
|
|
138
138
|
* the QA preset still lands on the mismatch refusals below ("composition
|
|
139
139
|
* mismatch"), and the adoption and permission checks stay the gate.
|
|
140
|
+
*
|
|
141
|
+
* Not every answer describes this deployment: the Host also names an identity
|
|
142
|
+
* subagent routing owns, which is a fact about another conversation's child
|
|
143
|
+
* rather than a failure of this chat. The two are refused apart below.
|
|
140
144
|
*/
|
|
141
145
|
private liveAgent;
|
|
142
146
|
/**
|
|
@@ -39,6 +39,11 @@ export interface BuildSlashCatalogOptions {
|
|
|
39
39
|
* The session role's own user-skill grant, when the access system is on.
|
|
40
40
|
* `undefined` means the role system has no opinion, which is its state on a
|
|
41
41
|
* deployment that never enabled roles — not "grant nothing".
|
|
42
|
+
*
|
|
43
|
+
* This is the only grant a read may answer with, whatever the chat looks
|
|
44
|
+
* like: a chat that is running and a chat nobody has woken are narrowed by
|
|
45
|
+
* the same allow-list and the same role, because the palette that names a
|
|
46
|
+
* skill this chat may not invoke teaches the visitor a gesture that fails.
|
|
42
47
|
*/
|
|
43
48
|
readonly grantedSkills?: readonly string[] | undefined;
|
|
44
49
|
readonly commandSurface: QaSlashCommandSurface;
|
package/lib/types/types.d.ts
CHANGED
|
@@ -1480,6 +1480,13 @@ export type QaMessage = QaUserMessage | {
|
|
|
1480
1480
|
readonly seq?: number;
|
|
1481
1481
|
/** Host turn this answer belongs to; groups regenerations into variants. */
|
|
1482
1482
|
readonly turn?: number;
|
|
1483
|
+
/**
|
|
1484
|
+
* Files this turn produced, in the order the tools reported them. The
|
|
1485
|
+
* answer is the place a produced document is handed over: without these
|
|
1486
|
+
* cards the file exists only as a path in a paragraph, and a reader who
|
|
1487
|
+
* does not know the files tab concludes nothing was made.
|
|
1488
|
+
*/
|
|
1489
|
+
readonly artifacts?: readonly QaArtifactView[];
|
|
1483
1490
|
/** Canonical evidence snapshot shared with this answer's source drawer. */
|
|
1484
1491
|
readonly sources?: readonly QaSource[];
|
|
1485
1492
|
readonly sourcesComplete?: boolean;
|
|
@@ -1589,6 +1596,25 @@ export interface QaFileView {
|
|
|
1589
1596
|
readonly name: string;
|
|
1590
1597
|
readonly bytes: number;
|
|
1591
1598
|
}
|
|
1599
|
+
/**
|
|
1600
|
+
* A file the agent produced during the turn an answer belongs to.
|
|
1601
|
+
*
|
|
1602
|
+
* An artifact has no attachment-store handle: it lives in the chat's own
|
|
1603
|
+
* workspace, so the card addresses it by the workspace-relative name the
|
|
1604
|
+
* producing tool reported — the spelling the Host's workspace reads take, and
|
|
1605
|
+
* the only spelling that cannot publish the directory the deployment keeps
|
|
1606
|
+
* this account's workspace in.
|
|
1607
|
+
*/
|
|
1608
|
+
export interface QaArtifactView {
|
|
1609
|
+
/** Workspace-relative path; the identifier every workspace read takes. */
|
|
1610
|
+
readonly path: string;
|
|
1611
|
+
/** Last path segment, which is what the card is signed with. */
|
|
1612
|
+
readonly name: string;
|
|
1613
|
+
/** Format the producing tool reported: `docx`, `pdf` or `md`. */
|
|
1614
|
+
readonly format: string;
|
|
1615
|
+
/** Bytes as the tool reported them; 0 when it reported no size. */
|
|
1616
|
+
readonly bytes: number;
|
|
1617
|
+
}
|
|
1592
1618
|
/** A subagent transcript opened read-only from the agents panel. */
|
|
1593
1619
|
export interface QaSubagentView {
|
|
1594
1620
|
readonly id: string;
|
package/locale/en.json
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yadsh/dsh-qa-surface",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.3",
|
|
4
4
|
"description": "A focused end-user QA surface backed by native DeepSeek Harness sessions",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"types": "./lib/types/types.d.ts",
|
|
49
49
|
"default": "./lib/types.js"
|
|
50
50
|
},
|
|
51
|
+
"./locale/en.json": "./locale/en.json",
|
|
51
52
|
"./package.json": "./package.json"
|
|
52
53
|
},
|
|
53
54
|
"dsh": {
|
|
@@ -78,6 +79,7 @@
|
|
|
78
79
|
"lib/**/*.d.ts",
|
|
79
80
|
"scripts/repair-session-events.mjs",
|
|
80
81
|
"scripts/attach-workspace-sessions.mjs",
|
|
82
|
+
"locale/*.json",
|
|
81
83
|
"cordis.patch.yml",
|
|
82
84
|
"compatibility.json",
|
|
83
85
|
"capability-policy.json",
|
|
@@ -133,10 +135,10 @@
|
|
|
133
135
|
"dependencies": {
|
|
134
136
|
"yaml": "^2.9.0",
|
|
135
137
|
"zod": "^4.4.3",
|
|
136
|
-
"@yadsh/dsh-audit-core": "^0.1.1",
|
|
137
138
|
"@yadsh/dsh-audit-ui": "^0.1.2",
|
|
138
|
-
"@yadsh/dsh-documents": "^0.6.
|
|
139
|
+
"@yadsh/dsh-documents": "^0.6.2",
|
|
139
140
|
"@yadsh/dsh-plugin-kit": "^0.5.0",
|
|
141
|
+
"@yadsh/dsh-audit-core": "^0.1.1",
|
|
140
142
|
"@yadsh/dsh-plugin-log": "^0.4.1"
|
|
141
143
|
},
|
|
142
144
|
"devDependencies": {
|