@yadsh/dsh-qa-surface 0.18.0 → 0.19.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 +20 -22
- package/lib/attachment-access.js +147 -0
- package/lib/attachment-access.js.map +1 -0
- package/lib/chat-sharing/search.js +89 -0
- package/lib/chat-sharing/search.js.map +1 -0
- package/lib/chat-sharing/transport.js +2 -7
- package/lib/chat-sharing/transport.js.map +1 -1
- package/lib/client/QaSessionController.js +51 -9
- package/lib/client/QaSessionController.js.map +1 -1
- package/lib/client/QaSurface.js +4 -3
- package/lib/client/QaSurface.js.map +1 -1
- package/lib/client/components/QaChangelog.js +27 -0
- package/lib/client/components/QaChangelog.js.map +1 -1
- package/lib/client/components/QaRequestWait.js +15 -0
- package/lib/client/components/QaRequestWait.js.map +1 -0
- package/lib/client/index.js +3 -1
- package/lib/client/index.js.map +1 -1
- package/lib/client/project-session-state.js.map +1 -1
- package/lib/client/request-wait-styles.js +7 -0
- package/lib/client/request-wait-styles.js.map +1 -0
- package/lib/client/styles.js +2 -0
- package/lib/client/styles.js.map +1 -1
- package/lib/client/types.js.map +1 -1
- package/lib/client.js +14 -8
- package/lib/client.js.map +1 -1
- package/lib/filesystem-intent.js +39 -0
- package/lib/filesystem-intent.js.map +1 -0
- package/lib/forms/attachments.js +18 -2
- package/lib/forms/attachments.js.map +1 -1
- package/lib/index.js +46 -80
- package/lib/index.js.map +1 -1
- package/lib/qa-tools/catalog.js.map +1 -1
- package/lib/qa-tools/index.js.map +1 -1
- package/lib/qa-tools/request-user-form.js +1 -1
- package/lib/qa-tools/request-user-form.js.map +1 -1
- package/lib/request-scheduler.js +235 -0
- package/lib/request-scheduler.js.map +1 -0
- package/lib/secure-session.js +46 -52
- package/lib/secure-session.js.map +1 -1
- package/lib/session-create.js +125 -0
- package/lib/session-create.js.map +1 -0
- package/lib/typert.host.js +163 -116
- package/lib/typert.remote-client.d.ts +3 -3
- package/lib/typert.remote-client.js +159 -112
- package/lib/types/attachment-access.d.ts +29 -0
- package/lib/types/chat-sharing/search.d.ts +5 -0
- package/lib/types/client/QaSessionController.d.ts +12 -9
- package/lib/types/client/components/QaRequestWait.d.ts +6 -0
- package/lib/types/client/project-session-state.d.ts +2 -4
- package/lib/types/client/request-wait-styles.d.ts +2 -0
- package/lib/types/client/types.d.ts +3 -3
- package/lib/types/filesystem-intent.d.ts +12 -0
- package/lib/types/forms/attachments.d.ts +5 -2
- package/lib/types/index.d.ts +6 -13
- package/lib/types/qa-tools/catalog.d.ts +1 -1
- package/lib/types/qa-tools/index.d.ts +1 -1
- package/lib/types/qa-tools/request-user-form.d.ts +1 -1
- package/lib/types/request-scheduler.d.ts +28 -0
- package/lib/types/secure-session.d.ts +12 -26
- package/lib/types/session-create.d.ts +29 -0
- package/lib/types/types/session.d.ts +8 -0
- package/lib/types/user-workspace.d.ts +4 -6
- package/lib/user-workspace.js +13 -67
- package/lib/user-workspace.js.map +1 -1
- package/package.json +11 -9
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
2
|
+
interface SessionSource {
|
|
3
|
+
readonly id: unknown;
|
|
4
|
+
snapshotEvents?(): readonly unknown[];
|
|
5
|
+
}
|
|
6
|
+
export interface QaAttachmentRecovery {
|
|
7
|
+
readonly readEvents?: (sessionId: string) => Promise<readonly unknown[]>;
|
|
8
|
+
readonly restoreFiles?: (sessionId: string) => Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
/** Exact attachment capabilities, owned by one admitted conversation. */
|
|
11
|
+
export declare class QaAttachmentAccess {
|
|
12
|
+
private readonly ctx;
|
|
13
|
+
private readonly recovery;
|
|
14
|
+
private readonly bindings;
|
|
15
|
+
constructor(ctx: Context, recovery?: QaAttachmentRecovery);
|
|
16
|
+
root(): string | undefined;
|
|
17
|
+
admit(session: SessionSource): Promise<void>;
|
|
18
|
+
inherit(session: SessionSource, parentId: string): void;
|
|
19
|
+
/** Only Host-admitted file blocks are authority; text and tool output are not. */
|
|
20
|
+
observe(sessionId: string, events: readonly unknown[]): void;
|
|
21
|
+
/** Called only after a durable form's bytes and session ownership are verified. */
|
|
22
|
+
grantFile(sessionId: string, file: string): void;
|
|
23
|
+
files(sessionId: string): readonly string[];
|
|
24
|
+
private publish;
|
|
25
|
+
revoke(sessionId: string): void;
|
|
26
|
+
dispose(): void;
|
|
27
|
+
}
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=attachment-access.d.ts.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
2
|
+
import type { SessionSearchValue } from "@deepseek-ai/dsh-api-session-controller/types";
|
|
3
|
+
/** Apply account scope before the provider's ranking/limit, then recheck each read. */
|
|
4
|
+
export declare function searchQaChats(ctx: Context, query: string, visible: () => Promise<ReadonlySet<string>>, signal: AbortSignal): Promise<SessionSearchValue>;
|
|
5
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -54,13 +54,13 @@ export interface QaSessionControllerOptions {
|
|
|
54
54
|
*/
|
|
55
55
|
readonly slashApi?: QaSlashApi;
|
|
56
56
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* arrangement between browsers about how much this stand can take, never a
|
|
61
|
-
* reason a question cannot be asked.
|
|
57
|
+
* Global admission snapshot. Managed queues accept sends even while full;
|
|
58
|
+
* legacy Hosts retain the courtesy refusal. A failed read still submits the
|
|
59
|
+
* prompt through the server's own admission boundary.
|
|
62
60
|
*/
|
|
63
61
|
readonly queueStatus?: QaQueueStatusRemote;
|
|
62
|
+
/** Authorized per-chat queue status, polled while the Host driver is live. */
|
|
63
|
+
readonly requestStatus?: QaQueueStatusRemote;
|
|
64
64
|
readonly storage?: StorageLike;
|
|
65
65
|
/**
|
|
66
66
|
* Browser file-upload service, resolved lazily: the page may not serve the
|
|
@@ -187,6 +187,10 @@ export declare class QaSessionController {
|
|
|
187
187
|
/** Host-side question requests of the bound chat waiting for the operator. */
|
|
188
188
|
private readonly hostQuestions;
|
|
189
189
|
private readonly queueRemote;
|
|
190
|
+
private readonly requestRemote;
|
|
191
|
+
private requestWaitStatus;
|
|
192
|
+
private requestReadRevision;
|
|
193
|
+
private requestReading;
|
|
190
194
|
/** Last send the stand had no room for; drives the request-ceiling dialog. */
|
|
191
195
|
private requestQueueNotice;
|
|
192
196
|
/** Set while a running turn is polled for parked requests. */
|
|
@@ -244,12 +248,11 @@ export declare class QaSessionController {
|
|
|
244
248
|
/**
|
|
245
249
|
* What the stand answers about its load, or null when it does not answer.
|
|
246
250
|
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
* unreadable count says nothing about the load, and refusing a visitor on
|
|
250
|
-
* that would be a worse answer than the one they would have got.
|
|
251
|
+
* A failed status read does not bypass the server queue. Submit normally;
|
|
252
|
+
* the Host owns admission even when the browser cannot read its load.
|
|
251
253
|
*/
|
|
252
254
|
private readQueueStatus;
|
|
255
|
+
private refreshRequestStatus;
|
|
253
256
|
/**
|
|
254
257
|
* Close the request-ceiling dialog. Nothing is retried and nothing is
|
|
255
258
|
* dropped: the held-back question is still the composer's own text, so asking
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { QaQueueStatus } from "../../types.js";
|
|
2
|
+
/** A queued turn belongs to the Host and starts without resending the question. */
|
|
3
|
+
export declare function QaRequestWait({ status, }: {
|
|
4
|
+
readonly status: QaQueueStatus | null;
|
|
5
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
6
|
+
//# sourceMappingURL=QaRequestWait.d.ts.map
|
|
@@ -40,10 +40,8 @@ export interface QaBoundProjectionInput {
|
|
|
40
40
|
readonly questions: readonly QaPendingQuestion[];
|
|
41
41
|
readonly operationError: string | null;
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* no row to carry the refusal on. Distinct from `queue`, the waiting rows of
|
|
46
|
-
* this chat.
|
|
43
|
+
* Server admission status for this waiting chat, or a legacy Host's
|
|
44
|
+
* pre-send refusal. Distinct from `queue`, the next messages of this chat.
|
|
47
45
|
*/
|
|
48
46
|
readonly requestQueue: QaQueueStatus | null;
|
|
49
47
|
readonly policyReady: boolean;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const requestWaitStyles = "\n.dsh-qa-request-wait{display:flex;align-items:center;gap:8px;align-self:flex-start;width:fit-content;max-width:100%;box-sizing:border-box;margin:0 0 10px;padding:6px 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.45;overflow-wrap:anywhere}\n.dsh-qa-request-wait__spinner{width:12px;height:12px;flex:none;border:1.5px solid var(--dsw-alias-border-l2);border-top-color:var(--dsw-alias-label-secondary);border-radius:50%;animation:dsh-qa-request-spin 1s linear infinite}\n@keyframes dsh-qa-request-spin{to{transform:rotate(360deg)}}\n@media(prefers-reduced-motion:reduce){.dsh-qa-request-wait__spinner{animation:none}}\n";
|
|
2
|
+
//# sourceMappingURL=request-wait-styles.d.ts.map
|
|
@@ -37,10 +37,10 @@ export type QaCreateSession = (token: string, subroleId: string | null, adminPre
|
|
|
37
37
|
export type QaForkSession = (token: string, sourceId: string, answerSeq: number) => Promise<RemoteResult<string>>;
|
|
38
38
|
/**
|
|
39
39
|
* The Host's live read of the request ceiling (`qaSurface/queueStatus`), asked
|
|
40
|
-
* per send
|
|
41
|
-
*
|
|
40
|
+
* per send and for the current waiting chat. Supplying a session id requires
|
|
41
|
+
* current account read access; global reads expose counts only.
|
|
42
42
|
*/
|
|
43
|
-
export type QaQueueStatusRemote = () => Promise<RemoteResult<QaQueueStatus>>;
|
|
43
|
+
export type QaQueueStatusRemote = (token?: string, sessionId?: string) => Promise<RemoteResult<QaQueueStatus>>;
|
|
44
44
|
/** Role selector plus administrator mutation channel. */
|
|
45
45
|
export interface QaAccessApi {
|
|
46
46
|
current(token: string): Promise<RemoteResult<QaCurrentAccess>>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** The Host tool contract, normalized once for path and storage policy. */
|
|
2
|
+
export type QaFilesystemIntent = {
|
|
3
|
+
readonly kind: "read";
|
|
4
|
+
readonly path: string;
|
|
5
|
+
readonly fileOnlyGrant: boolean;
|
|
6
|
+
} | {
|
|
7
|
+
readonly kind: "write";
|
|
8
|
+
readonly path: string;
|
|
9
|
+
readonly bytes: number;
|
|
10
|
+
};
|
|
11
|
+
export declare function qaFilesystemIntent(name: string, args: Record<string, unknown> | undefined): QaFilesystemIntent | undefined;
|
|
12
|
+
//# sourceMappingURL=filesystem-intent.d.ts.map
|
|
@@ -27,7 +27,8 @@ export declare function validateFormFile(name: string, data: Buffer): string;
|
|
|
27
27
|
export declare class QaFormAttachmentAdapter {
|
|
28
28
|
private readonly service;
|
|
29
29
|
private readonly host;
|
|
30
|
-
|
|
30
|
+
private readonly grantFile?;
|
|
31
|
+
constructor(service: () => QaFormService, host: () => QaFormHostAttachments | undefined, grantFile?: ((sessionId: string, file: string) => void) | undefined);
|
|
31
32
|
available(): boolean;
|
|
32
33
|
check(session: string, formId: string, uploadId: string): void;
|
|
33
34
|
claim(session: string, uploadId: string): {
|
|
@@ -37,12 +38,14 @@ export declare class QaFormAttachmentAdapter {
|
|
|
37
38
|
complete(session: string, formId: string, uploadId: string, raw: unknown, signal: AbortSignal, authorize: () => void): Promise<QaFormRecord>;
|
|
38
39
|
fail(session: string, formId: string, uploadId: string): void;
|
|
39
40
|
/** Exact saved bytes are re-projected through the Host on each successful resume. */
|
|
40
|
-
readable(submission: QaFormSubmission): Promise<QaFormSubmission & {
|
|
41
|
+
readable(submission: QaFormSubmission, sessionId?: string): Promise<QaFormSubmission & {
|
|
41
42
|
resources: {
|
|
42
43
|
resource_id: string;
|
|
43
44
|
read_path: string;
|
|
44
45
|
}[];
|
|
45
46
|
}>;
|
|
47
|
+
/** Rebuild exact grants from this chat's persisted, verified submissions. */
|
|
48
|
+
restore(sessionId: string): Promise<void>;
|
|
46
49
|
}
|
|
47
50
|
export {};
|
|
48
51
|
//# sourceMappingURL=attachments.d.ts.map
|
package/lib/types/index.d.ts
CHANGED
|
@@ -79,6 +79,7 @@ export declare class QaSurface extends TypertRemoteService {
|
|
|
79
79
|
private chatSharingStore;
|
|
80
80
|
private readonly chatTransport;
|
|
81
81
|
private readonly chatTurnGuard;
|
|
82
|
+
private readonly requestScheduler;
|
|
82
83
|
private sharing;
|
|
83
84
|
constructor(ctx: Context, entry?: Partial<QaSurfaceConfigRefs>);
|
|
84
85
|
/** The quality store, opening its file the first time anyone needs it. */
|
|
@@ -237,19 +238,11 @@ export declare class QaSurface extends TypertRemoteService {
|
|
|
237
238
|
*/
|
|
238
239
|
describe(): ResolvedQaSurfaceConfig;
|
|
239
240
|
/**
|
|
240
|
-
* Report
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
* account's chats, and the HTTP API's questions are invisible to every chat
|
|
246
|
-
* view. Read-only, and a ceiling rather than a lock — a prompt rides the
|
|
247
|
-
* native session RPC this plugin does not own, so the boundary is the
|
|
248
|
-
* browser's own courtesy, and two questions sent in the same instant can
|
|
249
|
-
* still overshoot by one. What the ceiling buys is that steady state, not a
|
|
250
|
-
* strict bound.
|
|
251
|
-
*/
|
|
252
|
-
queueStatus(): QaQueueStatus;
|
|
241
|
+
* Report server admission. Global reads expose counts only; a chat's FIFO
|
|
242
|
+
* position requires that account's current read access to the chat. The
|
|
243
|
+
* scheduler gates every root turn, including native and integration sends.
|
|
244
|
+
*/
|
|
245
|
+
queueStatus(token?: string, sessionId?: string): QaQueueStatus;
|
|
253
246
|
/**
|
|
254
247
|
* Create a QA session from Host-owned inputs. With account workspaces on,
|
|
255
248
|
* cwd is `<configured workspace>/.qa-users/<account UUID>` and the child is
|
|
@@ -13,7 +13,7 @@ export declare const QA_TOOL_CATALOG_VERSION = "4";
|
|
|
13
13
|
/** What the catalog's definitions read, beyond the execution record. */
|
|
14
14
|
export interface QaToolsSelfcheckDeps {
|
|
15
15
|
readonly forms?: QaFormGate;
|
|
16
|
-
readonly formProjection?: (submission: import("../forms/types.js").QaFormSubmission) => Promise<unknown>;
|
|
16
|
+
readonly formProjection?: (submission: import("../forms/types.js").QaFormSubmission, sessionId: string) => Promise<unknown>;
|
|
17
17
|
readonly catalogVersion: string;
|
|
18
18
|
readonly activationMode: string;
|
|
19
19
|
/** Names the catalog contributes, in catalog order. */
|
|
@@ -5,7 +5,7 @@ import type { QaToolActivation } from "./types.js";
|
|
|
5
5
|
export interface QaToolsOptions {
|
|
6
6
|
readonly forms?: import("../forms/gate.js").QaFormGate;
|
|
7
7
|
readonly formsEnabled?: () => boolean;
|
|
8
|
-
readonly formProjection?: (submission: import("../forms/types.js").QaFormSubmission) => Promise<unknown>;
|
|
8
|
+
readonly formProjection?: (submission: import("../forms/types.js").QaFormSubmission, sessionId: string) => Promise<unknown>;
|
|
9
9
|
readonly logger: PluginLogger;
|
|
10
10
|
readonly dynamicActivation: boolean;
|
|
11
11
|
readonly activationSkill: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ToolDefinition } from "@deepseek-ai/dsh-tools";
|
|
2
2
|
import type { QaFormGate } from "../forms/gate.js";
|
|
3
3
|
/** Build only; the QA activation manager owns registration and role admission. */
|
|
4
|
-
export declare function createRequestUserFormTool(gate: QaFormGate, project?: (submission: import("../forms/types.js").QaFormSubmission) => Promise<unknown>): ToolDefinition;
|
|
4
|
+
export declare function createRequestUserFormTool(gate: QaFormGate, project?: (submission: import("../forms/types.js").QaFormSubmission, sessionId: string) => Promise<unknown>): ToolDefinition;
|
|
5
5
|
//# sourceMappingURL=request-user-form.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
2
|
+
import type { Agent } from "@deepseek-ai/dsh-agent";
|
|
3
|
+
import type { QaQueueStatus } from "./types.js";
|
|
4
|
+
/** A FIFO admission lease covers a complete root turn, including its experts. */
|
|
5
|
+
export declare class QaRequestScheduler {
|
|
6
|
+
private readonly limit;
|
|
7
|
+
private readonly roots;
|
|
8
|
+
private readonly now;
|
|
9
|
+
private readonly familyBusy;
|
|
10
|
+
private readonly active;
|
|
11
|
+
private readonly waiting;
|
|
12
|
+
private readonly completed;
|
|
13
|
+
private readonly retiring;
|
|
14
|
+
private closed;
|
|
15
|
+
constructor(limit: () => number, roots: () => readonly Agent[], now?: () => number, familyBusy?: (agent: Agent) => boolean);
|
|
16
|
+
install(ctx: Context): () => void;
|
|
17
|
+
acquire(agent: Agent, signal: AbortSignal): Promise<void>;
|
|
18
|
+
release(agent: Agent, completed?: boolean): void;
|
|
19
|
+
private pump;
|
|
20
|
+
status(sessionId?: string): QaQueueStatus;
|
|
21
|
+
private estimate;
|
|
22
|
+
dispose(): void;
|
|
23
|
+
}
|
|
24
|
+
/** Include background descendants whose root has already ended its own turn. */
|
|
25
|
+
export declare function qaRequestFamilyBusy(ctx: Context, root: Agent): boolean;
|
|
26
|
+
/** Older optional compositions may lack the registry, but cannot enforce a cap. */
|
|
27
|
+
export declare function qaRequestRoots(ctx: Context, required: boolean): readonly Agent[];
|
|
28
|
+
//# sourceMappingURL=request-scheduler.d.ts.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Agent } from "@deepseek-ai/dsh-agent";
|
|
2
2
|
import type { Context } from "@deepseek-ai/cordis";
|
|
3
|
+
import { type QaAttachmentRecovery } from "./attachment-access.js";
|
|
3
4
|
import type { PluginLogger } from "@yadsh/dsh-plugin-log";
|
|
4
5
|
import { type QaSessionFacts } from "./accounts/store.js";
|
|
5
6
|
import type { QaIntegrationPrincipalBindings } from "./integration-principals.js";
|
|
@@ -71,13 +72,10 @@ export declare class QaPolicyAdmission {
|
|
|
71
72
|
* one set answers for the whole chat.
|
|
72
73
|
*/
|
|
73
74
|
private readonly attested;
|
|
75
|
+
private readonly rejected;
|
|
74
76
|
private readonly questionWarnings;
|
|
75
77
|
private readonly workspaceAccess;
|
|
76
|
-
|
|
77
|
-
* Removers of the document input roots granted per session, so a grant lives
|
|
78
|
-
* exactly as long as the workspace access that justified it.
|
|
79
|
-
*/
|
|
80
|
-
private readonly documentInputRoots;
|
|
78
|
+
private readonly attachmentAccess;
|
|
81
79
|
/**
|
|
82
80
|
* Every name reachable anywhere in one QA conversation, keyed by session id.
|
|
83
81
|
*
|
|
@@ -116,7 +114,7 @@ export declare class QaPolicyAdmission {
|
|
|
116
114
|
* deliberately not a delegation); {@link secureSessionForUser} has no token
|
|
117
115
|
* to compare, so it fills it here, against the ownership record it checked.
|
|
118
116
|
*/
|
|
119
|
-
principals?: QaIntegrationPrincipalBindings | undefined);
|
|
117
|
+
principals?: QaIntegrationPrincipalBindings | undefined, attachmentRecovery?: QaAttachmentRecovery);
|
|
120
118
|
/**
|
|
121
119
|
* Add tools whose own executor resolves the QA principal server-side.
|
|
122
120
|
* Enabling the contributing plugin is the operator decision; model arguments
|
|
@@ -130,29 +128,17 @@ export declare class QaPolicyAdmission {
|
|
|
130
128
|
* newly-created, permanently unusable chat behind.
|
|
131
129
|
*/
|
|
132
130
|
preflightDeployment(): void;
|
|
131
|
+
/** Keep a failed creation fenced even when its Host teardown cannot finish. */
|
|
132
|
+
rejectSession(sessionId: string): void;
|
|
133
|
+
/** Called only after failed creation confirms resource and ownership cleanup. */
|
|
134
|
+
forgetRejectedSession(sessionId: string): void;
|
|
133
135
|
/**
|
|
134
|
-
* The
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
* points it at. A backend without a resolvable root simply keeps the fence
|
|
138
|
-
* closed — attachments then only work where reads are not fenced per user.
|
|
139
|
-
* Source preview asks for the same root, so one upload is readable by both.
|
|
136
|
+
* The backend location used to validate exact file capabilities. The root
|
|
137
|
+
* itself grants no read access; only this conversation's Host-admitted
|
|
138
|
+
* user-message references and verified submitted form resources do.
|
|
140
139
|
*/
|
|
141
140
|
attachmentRoot(): string | undefined;
|
|
142
|
-
|
|
143
|
-
* Carry the fence's attachment exemption into the document pipeline.
|
|
144
|
-
*
|
|
145
|
-
* The guard above lets a single-file read reach the mounted store: an upload
|
|
146
|
-
* is content-addressed, immutable, outside every workspace, and the prompt
|
|
147
|
-
* hands the model exactly that path. The document pipeline keeps its own
|
|
148
|
-
* read scope and knew nothing about the store, so `document_*` refused the
|
|
149
|
-
* very file the model was allowed to read — the panel's own Word preview hit
|
|
150
|
-
* the same wall. The grant is the missing hand-over, made where the access it
|
|
151
|
-
* mirrors is made: per admitted session, and revoked with it.
|
|
152
|
-
*/
|
|
153
|
-
private grantDocumentInputRoots;
|
|
154
|
-
/** Drop one session's document grant, if the pipeline still holds it. */
|
|
155
|
-
private revokeDocumentInputRoots;
|
|
141
|
+
grantAttachmentFile(sessionId: string, file: string): void;
|
|
156
142
|
/**
|
|
157
143
|
* The live agent for one session, resuming a Session the Host has not
|
|
158
144
|
* materialized in this process.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
2
|
+
import type { PluginLogger } from "@yadsh/dsh-plugin-log";
|
|
3
|
+
import type { QaStoredSessionEraser } from "./admin/session-log.js";
|
|
4
|
+
import type { QaSessionModelPolicy } from "./access/model-policy.js";
|
|
5
|
+
import type { ResolvedQaSurfaceConfig } from "./types.js";
|
|
6
|
+
export interface QaSessionCreateOptions {
|
|
7
|
+
readonly ctx: Context;
|
|
8
|
+
readonly config: ResolvedQaSurfaceConfig;
|
|
9
|
+
readonly logger: PluginLogger;
|
|
10
|
+
readonly sessionFiles: QaStoredSessionEraser;
|
|
11
|
+
reserve(id: string): {
|
|
12
|
+
readonly id: string;
|
|
13
|
+
} | undefined;
|
|
14
|
+
release(owner: string, id: string): void;
|
|
15
|
+
modelPolicy(id: string): QaSessionModelPolicy;
|
|
16
|
+
preflight(): void;
|
|
17
|
+
admit(id: string): Promise<unknown>;
|
|
18
|
+
attest(id: string, owner: string | undefined): void;
|
|
19
|
+
reject(id: string): void;
|
|
20
|
+
/** Drop failure-only metadata after resource and ownership cleanup succeeds. */
|
|
21
|
+
forget(id: string): void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Admit inside the native factory's serial publication callback. A failure is
|
|
25
|
+
* rolled back by the Host's lifecycle owner before we erase this UUID's log;
|
|
26
|
+
* native preset composition and dynamic default-model hooks stay intact.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createQaSession(options: QaSessionCreateOptions): Promise<string>;
|
|
29
|
+
//# sourceMappingURL=session-create.d.ts.map
|
|
@@ -331,6 +331,14 @@ export interface QaQueueStatus {
|
|
|
331
331
|
readonly active: number;
|
|
332
332
|
/** Whether one more turn fits; false while no ceiling is set. */
|
|
333
333
|
readonly full: boolean;
|
|
334
|
+
/** The Host enforces admission and starts queued turns automatically. */
|
|
335
|
+
readonly managed?: boolean;
|
|
336
|
+
readonly queued?: number;
|
|
337
|
+
/** Present only for the authorized chat whose status was requested. */
|
|
338
|
+
readonly waiting?: boolean;
|
|
339
|
+
readonly position?: number | null;
|
|
340
|
+
/** Approximate delay derived from completed turns, or null without a sample. */
|
|
341
|
+
readonly estimatedWaitMs?: number | null;
|
|
334
342
|
}
|
|
335
343
|
export interface QaSessionState {
|
|
336
344
|
readonly chatAccess?: import("../chat-sharing/types.js").QaChatAccess;
|
|
@@ -10,6 +10,8 @@ export interface QaToolExecutionLike {
|
|
|
10
10
|
export interface QaUserWorkspaceReadPolicy {
|
|
11
11
|
/** Shared directories exposed only to read-only filesystem tools. */
|
|
12
12
|
readonly sharedReadOnlyRoots?: readonly string[];
|
|
13
|
+
/** Exact canonical files derived from this conversation's trusted references. */
|
|
14
|
+
readonly attachmentFiles?: readonly string[];
|
|
13
15
|
}
|
|
14
16
|
export declare function pathIsInside(target: string, root: string): boolean;
|
|
15
17
|
/**
|
|
@@ -31,12 +33,8 @@ export declare function existingQaUserWorkspace(workspaceRoot: string, userId: s
|
|
|
31
33
|
* fences model-controlled file paths for both reads and writes, rejects tools
|
|
32
34
|
* whose implementation can walk above cwd, and enforces bounded scratch use.
|
|
33
35
|
*
|
|
34
|
-
* `attachmentRoot`
|
|
35
|
-
*
|
|
36
|
-
* workspace, and the model reaches it exactly as the harness intends (the
|
|
37
|
-
* prompt carries the stored path). Reads of a single such file are allowed;
|
|
38
|
-
* directory-wide tools stay confined because the store is shared by every
|
|
39
|
-
* account, and writes are never exempted.
|
|
36
|
+
* `attachmentRoot` identifies the storage backend, never authority to read it.
|
|
37
|
+
* Only regular files in `attachmentFiles` may cross the workspace boundary.
|
|
40
38
|
*/
|
|
41
39
|
export declare function qaUserWorkspaceDenial(execution: QaToolExecutionLike, root: string, attachmentRoot?: string, readPolicy?: QaUserWorkspaceReadPolicy): string | undefined;
|
|
42
40
|
//# sourceMappingURL=user-workspace.d.ts.map
|
package/lib/user-workspace.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { chmodSync, lstatSync, mkdirSync, readdirSync, realpathSync, statSync, } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { qaFilesystemIntent } from "./filesystem-intent.js";
|
|
3
4
|
/** Stable, non-workspace child used to keep account directories out of sight. */
|
|
4
5
|
export const QA_USER_WORKSPACES_DIRECTORY = ".qa-users";
|
|
5
6
|
/** Conservative fixed budgets; there is deliberately no browser override. */
|
|
@@ -105,49 +106,6 @@ function record(value) {
|
|
|
105
106
|
? value
|
|
106
107
|
: undefined;
|
|
107
108
|
}
|
|
108
|
-
function requestedPaths(execution) {
|
|
109
|
-
const args = record(execution.arguments);
|
|
110
|
-
if (args === undefined)
|
|
111
|
-
return [];
|
|
112
|
-
switch (execution.name) {
|
|
113
|
-
case "read":
|
|
114
|
-
case "read_image":
|
|
115
|
-
case "write":
|
|
116
|
-
case "edit": {
|
|
117
|
-
return typeof args.file_path === "string" ? [args.file_path] : [];
|
|
118
|
-
}
|
|
119
|
-
case "glob":
|
|
120
|
-
case "grep": {
|
|
121
|
-
return [typeof args.path === "string" ? args.path : "."];
|
|
122
|
-
}
|
|
123
|
-
case "str_replace_editor": {
|
|
124
|
-
return typeof args.path === "string" ? [args.path] : [];
|
|
125
|
-
}
|
|
126
|
-
default:
|
|
127
|
-
return [];
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Whether the named path is only read. Directory-wide tools stay confined even
|
|
132
|
-
* for reads: the attachment store is shared by every account, and only the
|
|
133
|
-
* exact file an upload produced is meant to be reachable.
|
|
134
|
-
*/
|
|
135
|
-
function readsSharedRoot(execution) {
|
|
136
|
-
if (execution.name === "read" ||
|
|
137
|
-
execution.name === "read_image" ||
|
|
138
|
-
execution.name === "glob" ||
|
|
139
|
-
execution.name === "grep") {
|
|
140
|
-
return true;
|
|
141
|
-
}
|
|
142
|
-
return (execution.name === "str_replace_editor" &&
|
|
143
|
-
record(execution.arguments)?.command === "view");
|
|
144
|
-
}
|
|
145
|
-
function readsSingleFile(execution) {
|
|
146
|
-
if (execution.name === "read" || execution.name === "read_image")
|
|
147
|
-
return true;
|
|
148
|
-
return (execution.name === "str_replace_editor" &&
|
|
149
|
-
record(execution.arguments)?.command === "view");
|
|
150
|
-
}
|
|
151
109
|
function directoryBytes(root, stopAfter) {
|
|
152
110
|
let total = 0;
|
|
153
111
|
const pending = [root];
|
|
@@ -167,24 +125,13 @@ function directoryBytes(root, stopAfter) {
|
|
|
167
125
|
}
|
|
168
126
|
return total;
|
|
169
127
|
}
|
|
170
|
-
function requestedWriteBytes(execution) {
|
|
171
|
-
const args = record(execution.arguments);
|
|
172
|
-
if (args === undefined)
|
|
173
|
-
return 0;
|
|
174
|
-
const values = [args.content, args.new_string, args.new_str];
|
|
175
|
-
return values.reduce((total, value) => total + (typeof value === "string" ? Buffer.byteLength(value) : 0), 0);
|
|
176
|
-
}
|
|
177
128
|
/**
|
|
178
129
|
* Monotonic guard used in addition to DSH's workspace-write sandbox. It
|
|
179
130
|
* fences model-controlled file paths for both reads and writes, rejects tools
|
|
180
131
|
* whose implementation can walk above cwd, and enforces bounded scratch use.
|
|
181
132
|
*
|
|
182
|
-
* `attachmentRoot`
|
|
183
|
-
*
|
|
184
|
-
* workspace, and the model reaches it exactly as the harness intends (the
|
|
185
|
-
* prompt carries the stored path). Reads of a single such file are allowed;
|
|
186
|
-
* directory-wide tools stay confined because the store is shared by every
|
|
187
|
-
* account, and writes are never exempted.
|
|
133
|
+
* `attachmentRoot` identifies the storage backend, never authority to read it.
|
|
134
|
+
* Only regular files in `attachmentFiles` may cross the workspace boundary.
|
|
188
135
|
*/
|
|
189
136
|
export function qaUserWorkspaceDenial(execution, root, attachmentRoot, readPolicy = {}) {
|
|
190
137
|
const args = record(execution.arguments);
|
|
@@ -202,35 +149,34 @@ export function qaUserWorkspaceDenial(execution, root, attachmentRoot, readPolic
|
|
|
202
149
|
execution.name === "apply_patch") {
|
|
203
150
|
return PATH_DENIAL;
|
|
204
151
|
}
|
|
205
|
-
const
|
|
206
|
-
const readsOneFile = readsSingleFile(execution);
|
|
152
|
+
const intent = qaFilesystemIntent(execution.name, args);
|
|
207
153
|
try {
|
|
208
154
|
const sharedReadOnlyRoots = (readPolicy.sharedReadOnlyRoots ?? []).map(canonicalCandidate);
|
|
209
|
-
for (const requested of
|
|
155
|
+
for (const requested of intent === undefined ? [] : [intent.path]) {
|
|
210
156
|
const absolute = path.isAbsolute(requested)
|
|
211
157
|
? requested
|
|
212
158
|
: path.resolve(root, requested);
|
|
213
159
|
const canonical = canonicalCandidate(absolute);
|
|
214
160
|
if (pathIsInside(canonical, root))
|
|
215
161
|
continue;
|
|
216
|
-
if (
|
|
162
|
+
if (intent?.kind === "read" &&
|
|
217
163
|
sharedReadOnlyRoots.some((readRoot) => pathIsInside(canonical, readRoot))) {
|
|
218
164
|
continue;
|
|
219
165
|
}
|
|
220
166
|
// Resolved only for a path the fence would otherwise refuse, so the
|
|
221
167
|
// common case pays no extra filesystem walk.
|
|
222
|
-
if (
|
|
168
|
+
if (intent?.kind === "read" &&
|
|
169
|
+
intent.fileOnlyGrant &&
|
|
223
170
|
attachmentRoot !== undefined &&
|
|
224
|
-
pathIsInside(canonical, canonicalCandidate(attachmentRoot))
|
|
171
|
+
pathIsInside(canonical, canonicalCandidate(attachmentRoot)) &&
|
|
172
|
+
(readPolicy.attachmentFiles ?? []).some((file) => samePath(canonical, file)) &&
|
|
173
|
+
statSync(canonical).isFile()) {
|
|
225
174
|
continue;
|
|
226
175
|
}
|
|
227
176
|
return PATH_DENIAL;
|
|
228
177
|
}
|
|
229
|
-
if (
|
|
230
|
-
|
|
231
|
-
(execution.name === "str_replace_editor" &&
|
|
232
|
-
record(execution.arguments)?.command !== "view")) {
|
|
233
|
-
const requested = requestedWriteBytes(execution);
|
|
178
|
+
if (intent?.kind === "write") {
|
|
179
|
+
const requested = intent.bytes;
|
|
234
180
|
if (requested > QA_USER_WORKSPACE_MAX_WRITE_BYTES ||
|
|
235
181
|
directoryBytes(root, QA_USER_WORKSPACE_MAX_BYTES) + requested >
|
|
236
182
|
QA_USER_WORKSPACE_MAX_BYTES) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-workspace.js","sourceRoot":"","sources":["../src/user-workspace.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,SAAS,EACT,SAAS,EACT,WAAW,EACX,YAAY,EACZ,QAAQ,GACT,MAAM,SAAS,CAAC;AACjB,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"user-workspace.js","sourceRoot":"","sources":["../src/user-workspace.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yadsh/dsh-qa-surface",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "A focused end-user QA surface backed by native DeepSeek Harness sessions",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
"node": "^22.19.0 || >=24.0.0"
|
|
104
104
|
},
|
|
105
105
|
"peerDependencies": {
|
|
106
|
-
"@deepseek-ai/cordis": "
|
|
106
|
+
"@deepseek-ai/cordis": "~4.0.4",
|
|
107
107
|
"@deepseek-ai/dsh-agent": ">=0.1.7-rc.2 <0.3.0-0",
|
|
108
108
|
"@deepseek-ai/dsh-agent-preset-registry": ">=0.1.7-rc.2 <0.3.0-0",
|
|
109
109
|
"@deepseek-ai/dsh-api-gateway": ">=0.1.7-rc.2 <0.3.0-0",
|
|
@@ -137,15 +137,16 @@
|
|
|
137
137
|
"openid-client": "6.8.8",
|
|
138
138
|
"yaml": "^2.9.0",
|
|
139
139
|
"zod": "^4.4.3",
|
|
140
|
-
"@yadsh/dsh-audit-core": "^0.1.
|
|
141
|
-
"@yadsh/dsh-
|
|
142
|
-
"@yadsh/dsh-
|
|
143
|
-
"@yadsh/dsh-plugin-
|
|
144
|
-
"@yadsh/dsh-
|
|
140
|
+
"@yadsh/dsh-audit-core": "^0.1.3",
|
|
141
|
+
"@yadsh/dsh-plugin-kit": "^0.7.0",
|
|
142
|
+
"@yadsh/dsh-audit-ui": "^0.1.4",
|
|
143
|
+
"@yadsh/dsh-plugin-log": "^0.4.3",
|
|
144
|
+
"@yadsh/dsh-documents": "^0.8.2"
|
|
145
145
|
},
|
|
146
146
|
"devDependencies": {
|
|
147
147
|
"@deepseek-ai/cordis": "4.0.5",
|
|
148
148
|
"@deepseek-ai/dsh-agent": "0.2.1-rc.3",
|
|
149
|
+
"@deepseek-ai/dsh-agent-loop": "0.2.1-rc.3",
|
|
149
150
|
"@deepseek-ai/dsh-agent-preset-registry": "0.2.1-rc.3",
|
|
150
151
|
"@deepseek-ai/dsh-api-gateway": "0.2.1-rc.3",
|
|
151
152
|
"@deepseek-ai/dsh-api-session-controller": "0.2.1-rc.3",
|
|
@@ -164,6 +165,7 @@
|
|
|
164
165
|
"@deepseek-ai/dsh-permission-presets": "0.2.1-rc.3",
|
|
165
166
|
"@deepseek-ai/dsh-scope": "0.2.1-rc.3",
|
|
166
167
|
"@deepseek-ai/dsh-session": "0.2.1-rc.3",
|
|
168
|
+
"@deepseek-ai/dsh-session-projection": "0.2.1-rc.3",
|
|
167
169
|
"@deepseek-ai/dsh-settings": "0.2.1-rc.3",
|
|
168
170
|
"@deepseek-ai/dsh-skill": "0.2.1-rc.3",
|
|
169
171
|
"@deepseek-ai/dsh-system-prompt": "0.2.1-rc.3",
|
|
@@ -177,7 +179,7 @@
|
|
|
177
179
|
"@types/node": "^26.4.0",
|
|
178
180
|
"@types/react": "18.3.28",
|
|
179
181
|
"@types/react-dom": "18.3.7",
|
|
180
|
-
"@vitest/coverage-v8": "^4.1.
|
|
182
|
+
"@vitest/coverage-v8": "^4.1.12",
|
|
181
183
|
"eslint": "10.9.1",
|
|
182
184
|
"jsdom": "^26.1.0",
|
|
183
185
|
"katex": "^0.18.2",
|
|
@@ -186,7 +188,7 @@
|
|
|
186
188
|
"react-dom": "18.3.1",
|
|
187
189
|
"tsdown": "^0.22.14",
|
|
188
190
|
"typescript": "^7.0.2",
|
|
189
|
-
"vitest": "^4.1.
|
|
191
|
+
"vitest": "^4.1.12",
|
|
190
192
|
"@yadsh/dsh-config": "^0.0.0",
|
|
191
193
|
"@yadsh/dsh-plugin-scripts": "^0.0.0"
|
|
192
194
|
},
|