@yadsh/dsh-qa-surface 0.10.0 → 0.11.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 +251 -12
- package/lib/access/service.js +49 -10
- package/lib/access/service.js.map +1 -1
- package/lib/account-remotes.js +41 -0
- package/lib/account-remotes.js.map +1 -1
- package/lib/accounts/database.js +140 -0
- package/lib/accounts/database.js.map +1 -1
- package/lib/accounts/errors.js.map +1 -1
- package/lib/accounts/service-token.js +103 -0
- package/lib/accounts/service-token.js.map +1 -0
- package/lib/accounts/store.js +291 -5
- package/lib/accounts/store.js.map +1 -1
- package/lib/admin/conversation-log.js +14 -8
- package/lib/admin/conversation-log.js.map +1 -1
- package/lib/admin/permissions.js +5 -0
- package/lib/admin/permissions.js.map +1 -1
- package/lib/admin/quality-store.js +4 -0
- package/lib/admin/quality-store.js.map +1 -1
- package/lib/admin/service.js +173 -0
- package/lib/admin/service.js.map +1 -1
- package/lib/admin/session-log.js +39 -8
- package/lib/admin/session-log.js.map +1 -1
- package/lib/attachment-rules.js +39 -6
- package/lib/attachment-rules.js.map +1 -1
- package/lib/cli.js +83 -1
- package/lib/cli.js.map +1 -1
- package/lib/client/QaAccountsController.js +213 -4
- package/lib/client/QaAccountsController.js.map +1 -1
- package/lib/client/QaSessionController.js +37 -21
- package/lib/client/QaSessionController.js.map +1 -1
- package/lib/client/QaSurface.js +28 -4
- package/lib/client/QaSurface.js.map +1 -1
- package/lib/client/admin/QaAdmin.js +9 -1
- package/lib/client/admin/QaAdmin.js.map +1 -1
- package/lib/client/admin/pages/SkillFiles.js +78 -0
- package/lib/client/admin/pages/SkillFiles.js.map +1 -0
- package/lib/client/admin/pages/Users.js +65 -1
- package/lib/client/admin/pages/Users.js.map +1 -1
- package/lib/client/admin/routes.js +8 -1
- package/lib/client/admin/routes.js.map +1 -1
- package/lib/client/admin/styles.js +2 -0
- package/lib/client/admin/styles.js.map +1 -1
- package/lib/client/attachments.js +41 -11
- package/lib/client/attachments.js.map +1 -1
- package/lib/client/components/QaAuthGate.js +19 -10
- package/lib/client/components/QaAuthGate.js.map +1 -1
- package/lib/client/components/QaChangelog.js +27 -0
- package/lib/client/components/QaChangelog.js.map +1 -1
- package/lib/client/index.js +13 -0
- package/lib/client/index.js.map +1 -1
- package/lib/client/lineage.js +64 -0
- package/lib/client/lineage.js.map +1 -1
- package/lib/client/settings/sections/attachments.js +6 -5
- package/lib/client/settings/sections/attachments.js.map +1 -1
- package/lib/client/settings/sections/notes.js +22 -4
- package/lib/client/settings/sections/notes.js.map +1 -1
- package/lib/client/styles.js +9 -0
- package/lib/client/styles.js.map +1 -1
- package/lib/client/types.js.map +1 -1
- package/lib/client/user-settings/IntegrationTokensPage.js +150 -0
- package/lib/client/user-settings/IntegrationTokensPage.js.map +1 -0
- package/lib/client/user-settings/PasswordSettingsPage.js +48 -0
- package/lib/client/user-settings/PasswordSettingsPage.js.map +1 -0
- package/lib/client/user-settings/SkillCatalog.js +2 -2
- package/lib/client/user-settings/SkillCatalog.js.map +1 -1
- package/lib/client/user-settings/UserSettingsDialog.js +17 -2
- package/lib/client/user-settings/UserSettingsDialog.js.map +1 -1
- package/lib/client/user-settings/copy.js +20 -0
- package/lib/client/user-settings/copy.js.map +1 -1
- package/lib/client.js +2466 -137
- package/lib/client.js.map +1 -1
- package/lib/config-resolvers/attachments.js +6 -5
- package/lib/config-resolvers/attachments.js.map +1 -1
- package/lib/config-resolvers/defaults.js +23 -2
- package/lib/config-resolvers/defaults.js.map +1 -1
- package/lib/config-resolvers/integration.js +94 -0
- package/lib/config-resolvers/integration.js.map +1 -0
- package/lib/config-resolvers/notes.js +2 -0
- package/lib/config-resolvers/notes.js.map +1 -1
- package/lib/config.js +72 -0
- package/lib/config.js.map +1 -1
- package/lib/index.js +197 -2
- package/lib/index.js.map +1 -1
- package/lib/integration/answer.js +100 -0
- package/lib/integration/answer.js.map +1 -0
- package/lib/integration/attachments.js +231 -0
- package/lib/integration/attachments.js.map +1 -0
- package/lib/integration/contract.js +53 -0
- package/lib/integration/contract.js.map +1 -0
- package/lib/integration/host-runner.js +243 -0
- package/lib/integration/host-runner.js.map +1 -0
- package/lib/integration/http.js +538 -0
- package/lib/integration/http.js.map +1 -0
- package/lib/integration/service.js +331 -0
- package/lib/integration/service.js.map +1 -0
- package/lib/integration/transcript-reader.js +202 -0
- package/lib/integration/transcript-reader.js.map +1 -0
- package/lib/integration/transcript.js +148 -0
- package/lib/integration/transcript.js.map +1 -0
- package/lib/personal-skills/index.js +2 -2
- package/lib/personal-skills/index.js.map +1 -1
- package/lib/personal-skills/paths.js +14 -8
- package/lib/personal-skills/paths.js.map +1 -1
- package/lib/personal-skills/provider.js +16 -4
- package/lib/personal-skills/provider.js.map +1 -1
- package/lib/personal-skills/service.js +240 -30
- package/lib/personal-skills/service.js.map +1 -1
- package/lib/prompt-notes.js +58 -0
- package/lib/prompt-notes.js.map +1 -1
- package/lib/provenance/document-preview.js +10 -1
- package/lib/provenance/document-preview.js.map +1 -1
- package/lib/qa-tools/catalog.js +12 -1
- package/lib/qa-tools/catalog.js.map +1 -1
- package/lib/qa-tools/docs-tools.js +563 -0
- package/lib/qa-tools/docs-tools.js.map +1 -0
- package/lib/resolve-config.js +4 -0
- package/lib/resolve-config.js.map +1 -1
- package/lib/secure-session.js +83 -3
- package/lib/secure-session.js.map +1 -1
- package/lib/shared/integration-tokens.js +23 -0
- package/lib/shared/integration-tokens.js.map +1 -0
- package/lib/typert.host.js +1176 -213
- package/lib/typert.remote-client.d.ts +27 -1
- package/lib/typert.remote-client.js +911 -69
- package/lib/types/access/service.d.ts +33 -2
- package/lib/types/account-remotes.d.ts +30 -1
- package/lib/types/accounts/database.d.ts +53 -0
- package/lib/types/accounts/errors.d.ts +5 -1
- package/lib/types/accounts/service-token.d.ts +70 -0
- package/lib/types/accounts/store.d.ts +131 -1
- package/lib/types/admin/conversation-log.d.ts +12 -0
- package/lib/types/admin/service.d.ts +56 -1
- package/lib/types/admin/session-log.d.ts +21 -0
- package/lib/types/attachment-rules.d.ts +26 -3
- package/lib/types/client/QaAccountsController.d.ts +64 -5
- package/lib/types/client/QaSessionController.d.ts +24 -2
- package/lib/types/client/admin/pages/SkillFiles.d.ts +17 -0
- package/lib/types/client/admin/routes.d.ts +2 -0
- package/lib/types/client/attachments.d.ts +21 -4
- package/lib/types/client/lineage.d.ts +42 -0
- package/lib/types/client/settings/sections/notes.d.ts +5 -3
- package/lib/types/client/types.d.ts +71 -1
- package/lib/types/client/user-settings/IntegrationTokensPage.d.ts +21 -0
- package/lib/types/client/user-settings/PasswordSettingsPage.d.ts +19 -0
- package/lib/types/client/user-settings/UserSettingsDialog.d.ts +11 -2
- package/lib/types/client/user-settings/copy.d.ts +10 -1
- package/lib/types/config-resolvers/integration.d.ts +47 -0
- package/lib/types/config.d.ts +10 -0
- package/lib/types/index.d.ts +73 -1
- package/lib/types/integration/answer.d.ts +65 -0
- package/lib/types/integration/attachments.d.ts +85 -0
- package/lib/types/integration/contract.d.ts +196 -0
- package/lib/types/integration/host-runner.d.ts +44 -0
- package/lib/types/integration/http.d.ts +79 -0
- package/lib/types/integration/service.d.ts +120 -0
- package/lib/types/integration/transcript-reader.d.ts +100 -0
- package/lib/types/integration/transcript.d.ts +59 -0
- package/lib/types/personal-skills/index.d.ts +2 -2
- package/lib/types/personal-skills/paths.d.ts +15 -3
- package/lib/types/personal-skills/provider.d.ts +14 -2
- package/lib/types/personal-skills/service.d.ts +89 -14
- package/lib/types/prompt-notes.d.ts +28 -0
- package/lib/types/provenance/document-preview.d.ts +4 -0
- package/lib/types/qa-tools/catalog.d.ts +1 -1
- package/lib/types/qa-tools/docs-tools.d.ts +160 -0
- package/lib/types/secure-session.d.ts +52 -1
- package/lib/types/shared/integration-tokens.d.ts +24 -0
- package/lib/types/types.d.ts +170 -2
- package/package.json +4 -4
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import type { ToolDefinition } from "@deepseek-ai/dsh-tools";
|
|
2
|
+
/**
|
|
3
|
+
* `docs_search` and `docs_read` — the documentation surface of the QA catalog.
|
|
4
|
+
*
|
|
5
|
+
* A QA chat answers questions from the stand's documentation, and until now the
|
|
6
|
+
* model had no tool that said where that documentation is: the path in a
|
|
7
|
+
* reviewer's remark (`docs/platform/3.8/…`) was something the model had to
|
|
8
|
+
* guess its way to with a glob sweep, and a miss read as "the document does
|
|
9
|
+
* not exist" rather than "wrong tree". These two tools make the tree a
|
|
10
|
+
* first-class surface. Both are read-only, both are fenced to the
|
|
11
|
+
* documentation directory inside the calling chat's workspace
|
|
12
|
+
* (`<session cwd>/docs`, the directory the stand publishes its documentation
|
|
13
|
+
* into), and both name the documentation as what they search, so the tool
|
|
14
|
+
* description itself answers "where do I look for documentation?".
|
|
15
|
+
*
|
|
16
|
+
* The tree is read as a shallow layout convention, not a schema: hits carry
|
|
17
|
+
* the `version` and `module` parsed out of the path (`docs/<module>/<version>/…`)
|
|
18
|
+
* so the model can stay inside one edition of one module, and the same two
|
|
19
|
+
* names are accepted as filters. A path the convention does not describe is
|
|
20
|
+
* still searched and still read — it simply carries no identity.
|
|
21
|
+
*
|
|
22
|
+
* Nothing here is destructive and building it registers nothing: like the rest
|
|
23
|
+
* of the catalog these are side-effect-free definitions, and the workspace root
|
|
24
|
+
* is read from `exec.agent` at call time.
|
|
25
|
+
*/
|
|
26
|
+
/** The documentation directory inside a chat workspace. */
|
|
27
|
+
export declare const QA_DOCS_DIRECTORY = "docs";
|
|
28
|
+
/** Search defaults and budgets, all fixed: a chat cannot raise them. */
|
|
29
|
+
export declare const QA_DOCS_SEARCH_DEFAULT_LIMIT = 8;
|
|
30
|
+
export declare const QA_DOCS_SEARCH_MAX_LIMIT = 40;
|
|
31
|
+
export declare const QA_DOCS_SEARCH_BYTE_BUDGET = 4000;
|
|
32
|
+
export declare const QA_DOCS_READ_DEFAULT_LINES = 120;
|
|
33
|
+
export declare const QA_DOCS_READ_MAX_LINES = 400;
|
|
34
|
+
/** Why a documentation tool refused a call. */
|
|
35
|
+
export type QaDocsRefusal = "workspace-unavailable" | "docs-unavailable" | "invalid-request" | "outside-docs" | "symlink-escape" | "not-found" | "not-a-file" | "not-text";
|
|
36
|
+
/**
|
|
37
|
+
* A typed refusal of one documentation call.
|
|
38
|
+
*
|
|
39
|
+
* The message is what the model reads. It names the reason in words and never
|
|
40
|
+
* echoes an absolute host path, so a refusal cannot leak the deployment's
|
|
41
|
+
* layout into the conversation.
|
|
42
|
+
*/
|
|
43
|
+
export declare class QaDocsError extends Error {
|
|
44
|
+
readonly code: QaDocsRefusal;
|
|
45
|
+
constructor(code: QaDocsRefusal, message: string, options?: ErrorOptions);
|
|
46
|
+
}
|
|
47
|
+
/** The slice of the execution record these tool bodies read. */
|
|
48
|
+
interface QaDocsExecution {
|
|
49
|
+
readonly agent?: {
|
|
50
|
+
readonly session: {
|
|
51
|
+
readonly header: {
|
|
52
|
+
readonly cwd?: string;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** The resolved documentation root of one call. */
|
|
58
|
+
export interface QaDocsRoot {
|
|
59
|
+
/** Canonical workspace root of the calling chat. */
|
|
60
|
+
readonly workspace: string;
|
|
61
|
+
/** Canonical `<workspace>/docs`. */
|
|
62
|
+
readonly docs: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Module/version identity parsed out of a documentation path.
|
|
66
|
+
*
|
|
67
|
+
* Both are optional and, when a path does not carry one, genuinely absent: the
|
|
68
|
+
* catalog's output schema is read with `exactOptionalPropertyTypes`, so an
|
|
69
|
+
* identity is spread into a report rather than written as `undefined`.
|
|
70
|
+
*/
|
|
71
|
+
export interface QaDocsIdentity {
|
|
72
|
+
readonly version?: string;
|
|
73
|
+
readonly module?: string;
|
|
74
|
+
}
|
|
75
|
+
/** One documentation match. */
|
|
76
|
+
export interface QaDocsHit extends QaDocsIdentity {
|
|
77
|
+
/** Workspace-relative path, starting at `docs/`, with forward slashes. */
|
|
78
|
+
readonly path: string;
|
|
79
|
+
/** 1-based line number inside the file. */
|
|
80
|
+
readonly line: number;
|
|
81
|
+
/** The matched line, trimmed and bounded. */
|
|
82
|
+
readonly text: string;
|
|
83
|
+
}
|
|
84
|
+
/** The outcome of one documentation search. */
|
|
85
|
+
export interface QaDocsSearchResult extends QaDocsIdentity {
|
|
86
|
+
readonly query: string;
|
|
87
|
+
/** The directory documentation is read from, relative to the workspace. */
|
|
88
|
+
readonly root: string;
|
|
89
|
+
readonly hits: QaDocsHit[];
|
|
90
|
+
readonly truncated: boolean;
|
|
91
|
+
readonly filesScanned: number;
|
|
92
|
+
readonly skipped: number;
|
|
93
|
+
}
|
|
94
|
+
/** The outcome of one documentation read. */
|
|
95
|
+
export interface QaDocsReadResult extends QaDocsIdentity {
|
|
96
|
+
readonly path: string;
|
|
97
|
+
readonly from: number;
|
|
98
|
+
readonly to: number;
|
|
99
|
+
readonly totalLines: number;
|
|
100
|
+
readonly truncated: boolean;
|
|
101
|
+
readonly text: string;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Identity of one documentation path, read relative to the documentation root.
|
|
105
|
+
*
|
|
106
|
+
* The documented layout is `docs/<module>/<version>/…`: the version is the
|
|
107
|
+
* first directory segment that parses as one (`3.8`, `v2`, `2024.1`), and the
|
|
108
|
+
* module is the directory segment immediately before it. A path with no
|
|
109
|
+
* version segment keeps its first directory segment as the module; a file
|
|
110
|
+
* directly in `docs/` carries neither, and is still searched and read.
|
|
111
|
+
*/
|
|
112
|
+
export declare function docsIdentityOf(pathFromDocsRoot: string): QaDocsIdentity;
|
|
113
|
+
/**
|
|
114
|
+
* The canonical documentation root of one call.
|
|
115
|
+
*
|
|
116
|
+
* The root is a real directory inside the canonical workspace: a `docs` entry
|
|
117
|
+
* that is a link or a file is refused rather than followed, because the fence
|
|
118
|
+
* is the point of the tool and a link is how a fence is left.
|
|
119
|
+
*/
|
|
120
|
+
export declare function docsRootOf(exec: QaDocsExecution): Promise<QaDocsRoot>;
|
|
121
|
+
export interface QaDocsSearchRequest {
|
|
122
|
+
readonly query: string;
|
|
123
|
+
readonly version?: string | undefined;
|
|
124
|
+
readonly module?: string | undefined;
|
|
125
|
+
readonly path?: string | undefined;
|
|
126
|
+
readonly limit?: number | undefined;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Search the documentation tree of one chat workspace.
|
|
130
|
+
*
|
|
131
|
+
* Matching is a case-insensitive substring test, line by line: a hit is a
|
|
132
|
+
* line, not a file, so the caller can cite it. The result is bounded twice —
|
|
133
|
+
* by `limit` hits and by the byte budget of the rendered report — and reports
|
|
134
|
+
* which bound cut it short instead of silently dropping matches.
|
|
135
|
+
* @throws QaDocsError when the tree is missing, the scope path is wrong, or the query is empty.
|
|
136
|
+
*/
|
|
137
|
+
export declare function searchDocumentation(root: QaDocsRoot, request: QaDocsSearchRequest): Promise<QaDocsSearchResult>;
|
|
138
|
+
export interface QaDocsReadRequest {
|
|
139
|
+
readonly path: string;
|
|
140
|
+
readonly from?: number | undefined;
|
|
141
|
+
readonly lines?: number | undefined;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Read one window of one documentation file of a chat workspace.
|
|
145
|
+
* @throws QaDocsError when the path is outside the tree, missing, a directory, or not text.
|
|
146
|
+
*/
|
|
147
|
+
export declare function readDocumentation(root: QaDocsRoot, request: QaDocsReadRequest): Promise<QaDocsReadResult>;
|
|
148
|
+
/**
|
|
149
|
+
* `docs_search` — the catalog's documentation search.
|
|
150
|
+
*
|
|
151
|
+
* The description is part of the tool's job: it states that documentation is
|
|
152
|
+
* read here, from `docs/`, and that memory is not a documentation source. The
|
|
153
|
+
* version/module facets exist so a model that has been told "3.8" stops
|
|
154
|
+
* sweeping the whole tree.
|
|
155
|
+
*/
|
|
156
|
+
export declare function createDocsSearchTool(): ToolDefinition;
|
|
157
|
+
/** `docs_read` — open one documentation file at a bounded window of lines. */
|
|
158
|
+
export declare function createDocsReadTool(): ToolDefinition;
|
|
159
|
+
export {};
|
|
160
|
+
//# sourceMappingURL=docs-tools.d.ts.map
|
|
@@ -14,6 +14,13 @@ export interface QaAccountsGate {
|
|
|
14
14
|
readonly id: string;
|
|
15
15
|
} | undefined;
|
|
16
16
|
userWorkspace(userId: string, registeredWorkspacePath: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* The account an ownership record names, for callers that authenticated by
|
|
19
|
+
* another credential (the integration API's service token). Absent records
|
|
20
|
+
* and a changed owner both resolve to undefined. Only read by that path: the
|
|
21
|
+
* token-shaped entry above remains the browser's only door.
|
|
22
|
+
*/
|
|
23
|
+
ownerIdOf(sessionId: string): string | undefined;
|
|
17
24
|
}
|
|
18
25
|
/**
|
|
19
26
|
* Host-side QA policy admission boundary — the only browser-callable operation
|
|
@@ -48,6 +55,11 @@ export declare class QaPolicyAdmission {
|
|
|
48
55
|
*/
|
|
49
56
|
private readonly attested;
|
|
50
57
|
private readonly workspaceAccess;
|
|
58
|
+
/**
|
|
59
|
+
* Removers of the document input roots granted per session, so a grant lives
|
|
60
|
+
* exactly as long as the workspace access that justified it.
|
|
61
|
+
*/
|
|
62
|
+
private readonly documentInputRoots;
|
|
51
63
|
/**
|
|
52
64
|
* Every name reachable anywhere in one QA conversation, keyed by session id.
|
|
53
65
|
*
|
|
@@ -67,7 +79,9 @@ export declare class QaPolicyAdmission {
|
|
|
67
79
|
*/
|
|
68
80
|
dynamicToolNames?: (agent: Agent) => readonly string[],
|
|
69
81
|
/** Resolve and freeze the session's subrole policy after its agent exists. */
|
|
70
|
-
capabilityPolicy?: ((
|
|
82
|
+
capabilityPolicy?: ((owner: {
|
|
83
|
+
readonly id: string;
|
|
84
|
+
} | undefined, sessionId: string, agent: Agent) => Promise<QaResolvedSessionPolicy | undefined>) | undefined,
|
|
71
85
|
/** Scope-local catalog entries may be known before they are activated. */
|
|
72
86
|
knownDynamicToolNames?: () => readonly string[]);
|
|
73
87
|
/**
|
|
@@ -92,6 +106,20 @@ export declare class QaPolicyAdmission {
|
|
|
92
106
|
* Source preview asks for the same root, so one upload is readable by both.
|
|
93
107
|
*/
|
|
94
108
|
attachmentRoot(): string | undefined;
|
|
109
|
+
/**
|
|
110
|
+
* Carry the fence's attachment exemption into the document pipeline.
|
|
111
|
+
*
|
|
112
|
+
* The guard above lets a single-file read reach the mounted store: an upload
|
|
113
|
+
* is content-addressed, immutable, outside every workspace, and the prompt
|
|
114
|
+
* hands the model exactly that path. The document pipeline keeps its own
|
|
115
|
+
* read scope and knew nothing about the store, so `document_*` refused the
|
|
116
|
+
* very file the model was allowed to read — the panel's own Word preview hit
|
|
117
|
+
* the same wall. The grant is the missing hand-over, made where the access it
|
|
118
|
+
* mirrors is made: per admitted session, and revoked with it.
|
|
119
|
+
*/
|
|
120
|
+
private grantDocumentInputRoots;
|
|
121
|
+
/** Drop one session's document grant, if the pipeline still holds it. */
|
|
122
|
+
private revokeDocumentInputRoots;
|
|
95
123
|
/**
|
|
96
124
|
* The live agent for one session, resuming a Session the Host has not
|
|
97
125
|
* materialized in this process.
|
|
@@ -127,6 +155,29 @@ export declare class QaPolicyAdmission {
|
|
|
127
155
|
*/
|
|
128
156
|
private accessOwner;
|
|
129
157
|
secureSession(token: string, sessionId: string): Promise<QaLockdownProof>;
|
|
158
|
+
/**
|
|
159
|
+
* The same admission for a caller whose account was already authenticated by
|
|
160
|
+
* another credential — the integration API, which has a service token and no
|
|
161
|
+
* browser session.
|
|
162
|
+
*
|
|
163
|
+
* Everything after identity is shared with {@link secureSession}: the
|
|
164
|
+
* policy pins, the tool allow-list, the QA tool attachment and the
|
|
165
|
+
* attestation record are one code path, because a second copy of admission
|
|
166
|
+
* would be a second place for a QA chat to be admitted without them.
|
|
167
|
+
*
|
|
168
|
+
* @param userId - the account the credential resolved to.
|
|
169
|
+
* @param sessionId - the session to attest.
|
|
170
|
+
* @returns the sanitized proof, as the browser path receives it.
|
|
171
|
+
*/
|
|
172
|
+
secureSessionForUser(userId: string, sessionId: string): Promise<QaLockdownProof>;
|
|
173
|
+
/**
|
|
174
|
+
* The account behind one session, taken from the ownership record rather
|
|
175
|
+
* than from a token. The record is the same authority the token path reads:
|
|
176
|
+
* a chat belongs to exactly one account, and a service token may only ever
|
|
177
|
+
* reach the chats of its own.
|
|
178
|
+
*/
|
|
179
|
+
private ownerById;
|
|
180
|
+
private secureSessionAs;
|
|
130
181
|
/**
|
|
131
182
|
* Mask one agent down to the policy's tool names, for the account-free path
|
|
132
183
|
* (a capability policy installs its own mask through its grants).
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { QaServiceTokenScope } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The integration-token vocabulary and its bounds, on the browser side too.
|
|
4
|
+
*
|
|
5
|
+
* Minting lives in `accounts/service-token.ts`, which is Host-only (it hashes a
|
|
6
|
+
* secret before storing it); the profile page has to name the same scopes and
|
|
7
|
+
* enforce the same limits without importing that. Dependency-free like every
|
|
8
|
+
* `src/shared` module, so both bundles inline it and there is exactly one copy
|
|
9
|
+
* of the numbers the two halves have to agree on.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* What an integration token may do. Scopes are checked per request rather than
|
|
13
|
+
* per deployment: the same bridge token that asks questions carries no
|
|
14
|
+
* permission to read back a conversation catalog it was not given.
|
|
15
|
+
*/
|
|
16
|
+
export declare const QA_SERVICE_TOKEN_SCOPES: readonly QaServiceTokenScope[];
|
|
17
|
+
/** A token that carries no scope is useless; `ask` is what the API is for. */
|
|
18
|
+
export declare const QA_SERVICE_TOKEN_DEFAULT_SCOPES: readonly QaServiceTokenScope[];
|
|
19
|
+
/** Bounds the caller's label; it is a note to the operator, not a document. */
|
|
20
|
+
export declare const QA_SERVICE_TOKEN_LABEL_MAX = 80;
|
|
21
|
+
/** Bounds on a token's life; zero or a negative TTL would mint a dead token. */
|
|
22
|
+
export declare const QA_SERVICE_TOKEN_TTL_DAYS_MIN = 1;
|
|
23
|
+
export declare const QA_SERVICE_TOKEN_TTL_DAYS_MAX = 3650;
|
|
24
|
+
//# sourceMappingURL=integration-tokens.d.ts.map
|
package/lib/types/types.d.ts
CHANGED
|
@@ -42,7 +42,9 @@ export interface QaQuestionAnswerItem {
|
|
|
42
42
|
*/
|
|
43
43
|
export type QaAccountRole = "user" | "reviewer" | "admin";
|
|
44
44
|
/** Administrative permissions a role grants; see `admin/permissions.ts`. */
|
|
45
|
-
export type QaPermission = "users.read" | "users.manage" | "roles.read" | "roles.manage" | "conversations.read.all" | "conversations.read.own" | "conversations.delete" | "reviews.read" | "reviews.write" | "analytics.read" | "audit.read" | "settings.manage"
|
|
45
|
+
export type QaPermission = "users.read" | "users.manage" | "roles.read" | "roles.manage" | "conversations.read.all" | "conversations.read.own" | "conversations.delete" | "reviews.read" | "reviews.write" | "analytics.read" | "audit.read" | "settings.manage"
|
|
46
|
+
/** Write access to skill files, personal and deployment-wide. */
|
|
47
|
+
| "skills.manage";
|
|
46
48
|
/**
|
|
47
49
|
* Tools split by how they become available. `always` is visible from the first
|
|
48
50
|
* model step; `skillGrantable` is a ceiling — the tool only appears once an
|
|
@@ -342,6 +344,21 @@ export interface QaAccountSession {
|
|
|
342
344
|
readonly token: string;
|
|
343
345
|
readonly user: QaAccountUserPublic;
|
|
344
346
|
}
|
|
347
|
+
/**
|
|
348
|
+
* One forgotten-password request waiting for an operator. The address and name
|
|
349
|
+
* travel with it so the console can show who is locked out without a second
|
|
350
|
+
* lookup; the count makes repeated taps visible instead of silent.
|
|
351
|
+
*/
|
|
352
|
+
export interface QaPasswordResetRequest {
|
|
353
|
+
readonly userId: string;
|
|
354
|
+
readonly email: string;
|
|
355
|
+
readonly displayName: string;
|
|
356
|
+
readonly requestedAt: string;
|
|
357
|
+
readonly lastRequestedAt: string;
|
|
358
|
+
readonly requestCount: number;
|
|
359
|
+
/** True when the account is disabled: a reset will not let it sign in. */
|
|
360
|
+
readonly disabled: boolean;
|
|
361
|
+
}
|
|
345
362
|
export type QaWhoamiResult = {
|
|
346
363
|
readonly authenticated: false;
|
|
347
364
|
} | {
|
|
@@ -354,6 +371,45 @@ export interface QaClaimResult {
|
|
|
354
371
|
/** Ids already owned by a different user; the browser drops them. */
|
|
355
372
|
readonly conflicts: readonly string[];
|
|
356
373
|
}
|
|
374
|
+
/**
|
|
375
|
+
* What an integration token may do. The credential a non-browser application
|
|
376
|
+
* presents to the QA HTTP API carries its own scopes, so a bridge that asks
|
|
377
|
+
* questions cannot read back conversations it was never given.
|
|
378
|
+
*/
|
|
379
|
+
export type QaServiceTokenScope = "ask" | "sessions:read";
|
|
380
|
+
/**
|
|
381
|
+
* What an account asks a new integration token to be. The credential is always
|
|
382
|
+
* issued to the caller: nothing a browser sends may name another account, so
|
|
383
|
+
* this shape has no owner field and the administrative path keeps its own.
|
|
384
|
+
*/
|
|
385
|
+
export interface QaServiceTokenCreateInput {
|
|
386
|
+
/** A note the operator's list shows; empty becomes a generic label. */
|
|
387
|
+
readonly label?: string;
|
|
388
|
+
/** Requested scopes; unknown ones are dropped, empty falls back to `ask`. */
|
|
389
|
+
readonly scopes?: readonly string[];
|
|
390
|
+
/** How long the token lives, in days; bounded server-side. */
|
|
391
|
+
readonly ttlDays?: number;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* One integration token as a list shows it. The plaintext is deliberately not
|
|
395
|
+
* part of this shape: a secret is shown once, when it is minted, and a list
|
|
396
|
+
* that could repeat it would be a list that leaks it.
|
|
397
|
+
*/
|
|
398
|
+
export interface QaServiceTokenSummary {
|
|
399
|
+
readonly id: string;
|
|
400
|
+
readonly label: string;
|
|
401
|
+
readonly scopes: readonly QaServiceTokenScope[];
|
|
402
|
+
readonly createdAt: string;
|
|
403
|
+
readonly expiresAt: string;
|
|
404
|
+
readonly lastUsedAt: string | null;
|
|
405
|
+
readonly revokedAt: string | null;
|
|
406
|
+
readonly useCount: number;
|
|
407
|
+
}
|
|
408
|
+
/** One freshly minted token: the plaintext is here and nowhere else, ever. */
|
|
409
|
+
export interface QaIssuedServiceToken extends QaServiceTokenSummary {
|
|
410
|
+
/** The credential to hand to the integration. Never recoverable later. */
|
|
411
|
+
readonly token: string;
|
|
412
|
+
}
|
|
357
413
|
/**
|
|
358
414
|
* One chat-ownership entry as the admin views see it: the session, its owner
|
|
359
415
|
* and the owner's display name resolved at read time (a disabled account
|
|
@@ -388,6 +444,44 @@ export type QaSkillJsonValue = string | number | boolean | null | readonly QaSki
|
|
|
388
444
|
readonly [key: string]: QaSkillJsonValue;
|
|
389
445
|
};
|
|
390
446
|
/** One personal skill as the catalog list renders it. */
|
|
447
|
+
/**
|
|
448
|
+
* One administrator write to a skill somebody else owns.
|
|
449
|
+
*
|
|
450
|
+
* The record exists so a personal skill cannot be changed behind its owner's
|
|
451
|
+
* back: it is written beside the skill and reported on every read, and the
|
|
452
|
+
* owner sees the badge in their own catalog.
|
|
453
|
+
*/
|
|
454
|
+
export interface QaSkillAdminEdit {
|
|
455
|
+
/** Administrator account id; the owner is told a role, not a colleague. */
|
|
456
|
+
readonly actorId: string;
|
|
457
|
+
/** ISO timestamp of that write. */
|
|
458
|
+
readonly at: string;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Which skill store an administrator is editing: the deployment-wide shared
|
|
462
|
+
* root every account may read, or one account's own directory.
|
|
463
|
+
*/
|
|
464
|
+
export type QaAdminSkillScope = {
|
|
465
|
+
readonly kind: "shared";
|
|
466
|
+
} | {
|
|
467
|
+
readonly kind: "user";
|
|
468
|
+
readonly userId: string;
|
|
469
|
+
};
|
|
470
|
+
/** The account a personal skill scope belongs to, for the console's header. */
|
|
471
|
+
export interface QaAdminSkillOwner {
|
|
472
|
+
readonly userId: string;
|
|
473
|
+
readonly email: string;
|
|
474
|
+
readonly displayName: string;
|
|
475
|
+
}
|
|
476
|
+
/** One scope's catalog plus the facts the console names it by. */
|
|
477
|
+
export interface QaAdminSkillsView {
|
|
478
|
+
readonly scope: QaAdminSkillScope;
|
|
479
|
+
/** The account of a personal scope; null for the shared root. */
|
|
480
|
+
readonly owner: QaAdminSkillOwner | null;
|
|
481
|
+
readonly skills: readonly QaSkillSummary[];
|
|
482
|
+
/** Absolute directory this scope reads and writes, rendered read-only. */
|
|
483
|
+
readonly rootPath: string;
|
|
484
|
+
}
|
|
391
485
|
export interface QaSkillSummary {
|
|
392
486
|
readonly name: string;
|
|
393
487
|
readonly description: string;
|
|
@@ -405,6 +499,13 @@ export interface QaSkillSummary {
|
|
|
405
499
|
readonly updatedAt: string | null;
|
|
406
500
|
/** sha256 of the stored bytes; an update must echo the revision it read. */
|
|
407
501
|
readonly revision: string;
|
|
502
|
+
/**
|
|
503
|
+
* The administrator write that produced the stored revision, or null. A
|
|
504
|
+
* record whose revision no longer matches is stale and reports as null: the
|
|
505
|
+
* badge answers "did an administrator write what I am looking at", not
|
|
506
|
+
* "was this skill ever touched by an administrator".
|
|
507
|
+
*/
|
|
508
|
+
readonly adminEdit: QaSkillAdminEdit | null;
|
|
408
509
|
}
|
|
409
510
|
/** One personal skill with everything the editor needs. */
|
|
410
511
|
export interface QaSkillDocument extends QaSkillSummary {
|
|
@@ -528,6 +629,16 @@ export interface QaNotesConfig {
|
|
|
528
629
|
readonly enabled?: boolean;
|
|
529
630
|
readonly template?: string;
|
|
530
631
|
};
|
|
632
|
+
/** Which reader an attached office document belongs to; no placeholders. */
|
|
633
|
+
readonly documents?: {
|
|
634
|
+
readonly enabled?: boolean;
|
|
635
|
+
readonly template?: string;
|
|
636
|
+
};
|
|
637
|
+
/** Where an answer should come from; no placeholders. */
|
|
638
|
+
readonly sourcePriority?: {
|
|
639
|
+
readonly enabled?: boolean;
|
|
640
|
+
readonly template?: string;
|
|
641
|
+
};
|
|
531
642
|
}
|
|
532
643
|
export interface QaSurfaceConfig {
|
|
533
644
|
readonly enabled?: boolean;
|
|
@@ -710,6 +821,42 @@ export interface QaSurfaceConfig {
|
|
|
710
821
|
readonly sources?: QaSourcesConfig;
|
|
711
822
|
readonly attachments?: QaAttachmentsConfig;
|
|
712
823
|
readonly notes?: QaNotesConfig;
|
|
824
|
+
readonly integration?: QaIntegrationConfig;
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* The HTTP API an external application (the ticket bridge) uses to ask
|
|
828
|
+
* questions and read its own conversations back: `POST {basePath}/ask`,
|
|
829
|
+
* `GET {basePath}/session` and `GET {basePath}/health`, authenticated with an
|
|
830
|
+
* account's integration token. Off unless a deployment asks for it.
|
|
831
|
+
*/
|
|
832
|
+
export interface QaIntegrationConfig {
|
|
833
|
+
/** Serve the API at all. Requires accounts; off by default. */
|
|
834
|
+
readonly enabled?: boolean;
|
|
835
|
+
/** Route namespace; the endpoints all hang off it. */
|
|
836
|
+
readonly basePath?: string;
|
|
837
|
+
/** Default lifetime of a minted integration token, in days. */
|
|
838
|
+
readonly tokenTtlDays?: number;
|
|
839
|
+
/**
|
|
840
|
+
* Wall-clock budget for one question. The endpoint answers within it — with
|
|
841
|
+
* an escalation when the turn is still running — because the caller's own
|
|
842
|
+
* timeout is a fixed part of the contract.
|
|
843
|
+
*/
|
|
844
|
+
readonly requestTimeoutMs?: number;
|
|
845
|
+
/** Questions answered at the same time, deployment wide. */
|
|
846
|
+
readonly maxConcurrent?: number;
|
|
847
|
+
/** Requests one token may make per rolling minute. */
|
|
848
|
+
readonly requestsPerMinute?: number;
|
|
849
|
+
/** Ceiling on one request body, in bytes. */
|
|
850
|
+
readonly maxRequestBytes?: number;
|
|
851
|
+
/** Ceiling on one inline image attachment, in bytes. */
|
|
852
|
+
readonly maxAttachmentBytes?: number;
|
|
853
|
+
/**
|
|
854
|
+
* Ceiling on the published answer, in characters. The caller posts it into a
|
|
855
|
+
* ticket comment, whose own budget is smaller than a model's answer, and a
|
|
856
|
+
* cut made here at a paragraph boundary is readable where the caller's own
|
|
857
|
+
* silent truncation is not.
|
|
858
|
+
*/
|
|
859
|
+
readonly maxAnswerCharacters?: number;
|
|
713
860
|
}
|
|
714
861
|
/** What a QA visitor may attach to one message. */
|
|
715
862
|
export interface QaAttachmentsConfig {
|
|
@@ -913,6 +1060,25 @@ export interface ResolvedQaSurfaceConfig {
|
|
|
913
1060
|
readonly enabled: boolean;
|
|
914
1061
|
readonly template: string;
|
|
915
1062
|
};
|
|
1063
|
+
readonly documents: {
|
|
1064
|
+
readonly enabled: boolean;
|
|
1065
|
+
readonly template: string;
|
|
1066
|
+
};
|
|
1067
|
+
readonly sourcePriority: {
|
|
1068
|
+
readonly enabled: boolean;
|
|
1069
|
+
readonly template: string;
|
|
1070
|
+
};
|
|
1071
|
+
};
|
|
1072
|
+
readonly integration: {
|
|
1073
|
+
readonly enabled: boolean;
|
|
1074
|
+
readonly basePath: string;
|
|
1075
|
+
readonly tokenTtlDays: number;
|
|
1076
|
+
readonly requestTimeoutMs: number;
|
|
1077
|
+
readonly maxConcurrent: number;
|
|
1078
|
+
readonly requestsPerMinute: number;
|
|
1079
|
+
readonly maxRequestBytes: number;
|
|
1080
|
+
readonly maxAttachmentBytes: number;
|
|
1081
|
+
readonly maxAnswerCharacters: number;
|
|
916
1082
|
};
|
|
917
1083
|
}
|
|
918
1084
|
/** Which native registry one unified entry came from. */
|
|
@@ -1444,7 +1610,9 @@ export interface QaReviewQueueItem {
|
|
|
1444
1610
|
readonly feedbackId?: string;
|
|
1445
1611
|
}
|
|
1446
1612
|
/** Administrative actions recorded in the audit trail. */
|
|
1447
|
-
export type QaAdminAuditAction = "user.created" | "user.updated" | "user.enabled" | "user.disabled"
|
|
1613
|
+
export type QaAdminAuditAction = "user.created" | "user.updated" | "user.enabled" | "user.disabled"
|
|
1614
|
+
/** An operator set a new password for an account that had requested one. */
|
|
1615
|
+
| "user.password-reset" | "authorization.changed" | "subrole.assignment.changed" | "subrole.created" | "subrole.updated" | "subrole.deleted" | "common_capabilities.updated" | "conversation.reviewed" | "conversation.deleted" | "review.updated" | "review.queued" | "admin.settings.updated" | "skill.created" | "skill.updated" | "skill.deleted";
|
|
1448
1616
|
export interface QaAdminAuditEvent {
|
|
1449
1617
|
readonly id: string;
|
|
1450
1618
|
readonly timestamp: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yadsh/dsh-qa-surface",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "A focused end-user QA surface backed by native DeepSeek Harness sessions",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -135,9 +135,9 @@
|
|
|
135
135
|
"zod": "^4.4.3",
|
|
136
136
|
"@yadsh/dsh-audit-core": "^0.1.0",
|
|
137
137
|
"@yadsh/dsh-audit-ui": "^0.1.0",
|
|
138
|
-
"@yadsh/dsh-documents": "^0.
|
|
139
|
-
"@yadsh/dsh-plugin-
|
|
140
|
-
"@yadsh/dsh-plugin-
|
|
138
|
+
"@yadsh/dsh-documents": "^0.5.0",
|
|
139
|
+
"@yadsh/dsh-plugin-log": "^0.4.0",
|
|
140
|
+
"@yadsh/dsh-plugin-kit": "^0.3.0"
|
|
141
141
|
},
|
|
142
142
|
"devDependencies": {
|
|
143
143
|
"@deepseek-ai/cordis": "4.0.2",
|