@yadsh/dsh-qa-surface 0.1.1 → 0.3.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/CHANGELOG.md +151 -0
- package/README.md +239 -16
- package/SPEC-dsh-qa-surface.md +600 -96
- package/capability-policy.json +5 -0
- package/compatibility.json +18 -4
- package/cordis.patch.yml +11 -0
- package/docs/ARCHITECTURE.md +50 -8
- package/docs/COMPATIBILITY.md +5 -4
- package/docs/CONFIGURATION.md +184 -3
- package/docs/SOURCES-MIGRATION.md +28 -0
- package/docs/SOURCES-PROVENANCE-AUDIT.md +88 -0
- package/docs/SPEC-dsh-qa-surface-accounts.md +219 -0
- package/docs/SPEC-dsh-qa-surface-sources-provenance.md +1692 -0
- package/lib/accounts/index.js +2 -0
- package/lib/accounts/index.js.map +1 -0
- package/lib/accounts/store.js +478 -0
- package/lib/accounts/store.js.map +1 -0
- package/lib/attestation.js +10 -0
- package/lib/attestation.js.map +1 -0
- package/lib/cli.js +143 -0
- package/lib/cli.js.map +1 -0
- package/lib/client/QaAccountsController.js +329 -0
- package/lib/client/QaAccountsController.js.map +1 -0
- package/lib/client/QaConfigController.js +111 -4
- package/lib/client/QaConfigController.js.map +1 -1
- package/lib/client/QaSessionController.js +621 -163
- package/lib/client/QaSessionController.js.map +1 -1
- package/lib/client/QaSurface.js +303 -24
- package/lib/client/QaSurface.js.map +1 -1
- package/lib/client/QaTranscriptAdapter.js +324 -49
- package/lib/client/QaTranscriptAdapter.js.map +1 -1
- package/lib/client/attestation.js +66 -0
- package/lib/client/attestation.js.map +1 -0
- package/lib/client/chat-index.js +86 -0
- package/lib/client/chat-index.js.map +1 -0
- package/lib/client/components/Markdown.js +124 -13
- package/lib/client/components/Markdown.js.map +1 -1
- package/lib/client/components/QaAgentsDrawer.js +40 -0
- package/lib/client/components/QaAgentsDrawer.js.map +1 -0
- package/lib/client/components/QaAuthGate.js +40 -0
- package/lib/client/components/QaAuthGate.js.map +1 -0
- package/lib/client/components/QaChangelog.js +112 -0
- package/lib/client/components/QaChangelog.js.map +1 -0
- package/lib/client/components/QaComposer.js +132 -15
- package/lib/client/components/QaComposer.js.map +1 -1
- package/lib/client/components/QaMessage.js +214 -10
- package/lib/client/components/QaMessage.js.map +1 -1
- package/lib/client/components/QaSidebar.js +167 -0
- package/lib/client/components/QaSidebar.js.map +1 -0
- package/lib/client/components/QaSourcesDrawer.js +127 -0
- package/lib/client/components/QaSourcesDrawer.js.map +1 -0
- package/lib/client/components/QaTurnRail.js +281 -0
- package/lib/client/components/QaTurnRail.js.map +1 -0
- package/lib/client/components/QaWelcomeNotice.js +125 -0
- package/lib/client/components/QaWelcomeNotice.js.map +1 -0
- package/lib/client/components/QaWidthHandle.js +142 -0
- package/lib/client/components/QaWidthHandle.js.map +1 -0
- package/lib/client/components/QaWorkGroup.js +135 -0
- package/lib/client/components/QaWorkGroup.js.map +1 -0
- package/lib/client/components/VariantSwitcher.js +29 -0
- package/lib/client/components/VariantSwitcher.js.map +1 -0
- package/lib/client/components/format.js +48 -0
- package/lib/client/components/format.js.map +1 -0
- package/lib/client/components/source-refs.js +78 -0
- package/lib/client/components/source-refs.js.map +1 -0
- package/lib/client/create-session.js +51 -0
- package/lib/client/create-session.js.map +1 -0
- package/lib/client/index.js +166 -35
- package/lib/client/index.js.map +1 -1
- package/lib/client/project-session-state.js +78 -0
- package/lib/client/project-session-state.js.map +1 -0
- package/lib/client/session-admission.js +38 -0
- package/lib/client/session-admission.js.map +1 -0
- package/lib/client/session-assets.js +52 -0
- package/lib/client/session-assets.js.map +1 -0
- package/lib/client/session-sources.js +61 -0
- package/lib/client/session-sources.js.map +1 -0
- package/lib/client/settlement.js +24 -0
- package/lib/client/settlement.js.map +1 -0
- package/lib/client/styles.js +450 -43
- package/lib/client/styles.js.map +1 -1
- package/lib/client/tool-presentation.js +102 -0
- package/lib/client/tool-presentation.js.map +1 -0
- package/lib/client/turn-sources.js +98 -0
- package/lib/client/turn-sources.js.map +1 -0
- package/lib/client/types.js +15 -0
- package/lib/client/types.js.map +1 -0
- package/lib/client/use-session-ui-state.js +68 -0
- package/lib/client/use-session-ui-state.js.map +1 -0
- package/lib/client/use-transcript-view.js +44 -0
- package/lib/client/use-transcript-view.js.map +1 -0
- package/lib/client/wait-for.js +49 -0
- package/lib/client/wait-for.js.map +1 -0
- package/lib/client.js +12551 -918
- package/lib/client.js.map +1 -1
- package/lib/config.js +226 -58
- package/lib/config.js.map +1 -1
- package/lib/entry-redirect.js +44 -0
- package/lib/entry-redirect.js.map +1 -0
- package/lib/host-route.js +25 -1
- package/lib/host-route.js.map +1 -1
- package/lib/index.js +354 -72
- package/lib/index.js.map +1 -1
- package/lib/launch-token.js +42 -0
- package/lib/launch-token.js.map +1 -0
- package/lib/lockdown-policy.js +20 -0
- package/lib/lockdown-policy.js.map +1 -0
- package/lib/provenance/collector.js +40 -0
- package/lib/provenance/collector.js.map +1 -0
- package/lib/provenance/connectors.js +147 -0
- package/lib/provenance/connectors.js.map +1 -0
- package/lib/provenance/dedupe.js +89 -0
- package/lib/provenance/dedupe.js.map +1 -0
- package/lib/provenance/extractors.js +340 -0
- package/lib/provenance/extractors.js.map +1 -0
- package/lib/provenance/file-preview.js +39 -0
- package/lib/provenance/file-preview.js.map +1 -0
- package/lib/provenance/host-store.js +387 -0
- package/lib/provenance/host-store.js.map +1 -0
- package/lib/provenance/index.js +9 -0
- package/lib/provenance/index.js.map +1 -0
- package/lib/provenance/normalize.js +128 -0
- package/lib/provenance/normalize.js.map +1 -0
- package/lib/provenance/reported.js +53 -0
- package/lib/provenance/reported.js.map +1 -0
- package/lib/provenance/types.js +2 -0
- package/lib/provenance/types.js.map +1 -0
- package/lib/resolve-config.js +283 -10
- package/lib/resolve-config.js.map +1 -1
- package/lib/secure-session.js +212 -0
- package/lib/secure-session.js.map +1 -0
- package/lib/typert.host.d.ts +3 -0
- package/lib/typert.host.js +784 -0
- package/lib/typert.remote-client.d.ts +40 -0
- package/lib/typert.remote-client.js +597 -0
- package/lib/types/accounts/index.d.ts +2 -0
- package/lib/types/accounts/store.d.ts +121 -0
- package/lib/types/attestation.d.ts +17 -0
- package/lib/types/cli.d.ts +9 -0
- package/lib/types/client/QaAccountsController.d.ts +95 -0
- package/lib/types/client/QaConfigController.d.ts +35 -3
- package/lib/types/client/QaSessionController.d.ts +146 -20
- package/lib/types/client/QaSurface.d.ts +11 -5
- package/lib/types/client/QaTranscriptAdapter.d.ts +13 -3
- package/lib/types/client/attestation.d.ts +25 -0
- package/lib/types/client/chat-index.d.ts +28 -0
- package/lib/types/client/components/Markdown.d.ts +17 -3
- package/lib/types/client/components/QaAgentsDrawer.d.ts +25 -0
- package/lib/types/client/components/QaAuthGate.d.ts +15 -0
- package/lib/types/client/components/QaChangelog.d.ts +21 -0
- package/lib/types/client/components/QaComposer.d.ts +12 -2
- package/lib/types/client/components/QaMessage.d.ts +22 -2
- package/lib/types/client/components/QaSidebar.d.ts +69 -0
- package/lib/types/client/components/QaSourcesDrawer.d.ts +20 -0
- package/lib/types/client/components/QaTurnRail.d.ts +59 -0
- package/lib/types/client/components/QaWelcomeNotice.d.ts +27 -0
- package/lib/types/client/components/QaWidthHandle.d.ts +36 -0
- package/lib/types/client/components/QaWorkGroup.d.ts +19 -0
- package/lib/types/client/components/VariantSwitcher.d.ts +19 -0
- package/lib/types/client/components/format.d.ts +9 -0
- package/lib/types/client/components/source-refs.d.ts +16 -0
- package/lib/types/client/create-session.d.ts +16 -0
- package/lib/types/client/index.d.ts +2 -5
- package/lib/types/client/project-session-state.d.ts +30 -0
- package/lib/types/client/session-admission.d.ts +23 -0
- package/lib/types/client/session-assets.d.ts +20 -0
- package/lib/types/client/session-sources.d.ts +28 -0
- package/lib/types/client/settlement.d.ts +6 -0
- package/lib/types/client/tool-presentation.d.ts +6 -0
- package/lib/types/client/turn-sources.d.ts +14 -0
- package/lib/types/client/types.d.ts +93 -0
- package/lib/types/client/use-session-ui-state.d.ts +35 -0
- package/lib/types/client/use-transcript-view.d.ts +20 -0
- package/lib/types/client/wait-for.d.ts +11 -0
- package/lib/types/entry-redirect.d.ts +20 -0
- package/lib/types/host-route.d.ts +14 -1
- package/lib/types/index.d.ts +67 -7
- package/lib/types/launch-token.d.ts +21 -0
- package/lib/types/lockdown-policy.d.ts +18 -0
- package/lib/types/provenance/collector.d.ts +26 -0
- package/lib/types/provenance/connectors.d.ts +11 -0
- package/lib/types/provenance/dedupe.d.ts +6 -0
- package/lib/types/provenance/extractors.d.ts +14 -0
- package/lib/types/provenance/file-preview.d.ts +10 -0
- package/lib/types/provenance/host-store.d.ts +54 -0
- package/lib/types/provenance/index.d.ts +10 -0
- package/lib/types/provenance/normalize.d.ts +13 -0
- package/lib/types/provenance/reported.d.ts +5 -0
- package/lib/types/provenance/types.d.ts +78 -0
- package/lib/types/secure-session.d.ts +31 -0
- package/lib/types/types.d.ts +304 -1
- package/package.json +70 -27
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { QaAccountRole, QaAccountSession, QaAccountUserPublic, QaClaimResult, QaOwnershipEntry, QaWhoamiResult } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Coarse, wire-safe account failure codes. They ride the `(reason: <code>)`
|
|
4
|
+
* marker pattern the attestation path established; the browser maps them to
|
|
5
|
+
* audience-safe copy and the precise cause stays in the Host logs.
|
|
6
|
+
*/
|
|
7
|
+
export type QaAccountsErrorReason = "auth-required" | "admin-required" | "invalid-credentials" | "account-disabled" | "email-taken" | "invalid-email" | "invalid-display-name" | "invalid-role" | "weak-password" | "registration-disabled" | "rate-limited" | "session-owned-elsewhere";
|
|
8
|
+
export declare class QaAccountsError extends Error {
|
|
9
|
+
readonly reason: QaAccountsErrorReason;
|
|
10
|
+
constructor(reason: QaAccountsErrorReason, message: string);
|
|
11
|
+
}
|
|
12
|
+
interface StoredUser {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
readonly email: string;
|
|
15
|
+
readonly displayName: string;
|
|
16
|
+
readonly role: QaAccountRole;
|
|
17
|
+
/** scrypt material: hex salt + hex hash. */
|
|
18
|
+
readonly passwordHash: {
|
|
19
|
+
readonly salt: string;
|
|
20
|
+
readonly hash: string;
|
|
21
|
+
};
|
|
22
|
+
readonly createdAt: string;
|
|
23
|
+
lastLoginAt: string | null;
|
|
24
|
+
/** Disabled accounts are refused at login and lose their live tokens. */
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Bumped to invalidate every token ever issued to the account: the value
|
|
28
|
+
* rides the token payload and must match at verification time.
|
|
29
|
+
*/
|
|
30
|
+
tokenVersion?: number;
|
|
31
|
+
}
|
|
32
|
+
export interface QaAccountsOptions {
|
|
33
|
+
readonly sessionTtlDays: number;
|
|
34
|
+
readonly allowRegistration: boolean;
|
|
35
|
+
/** Login/registration attempts accepted per rolling minute, store-wide. */
|
|
36
|
+
readonly maxAuthAttemptsPerMinute?: number;
|
|
37
|
+
}
|
|
38
|
+
/** The accounts file lives next to the DSH home the launcher exports. */
|
|
39
|
+
export declare function defaultAccountsFilePath(): string;
|
|
40
|
+
/**
|
|
41
|
+
* Host authority for QA accounts: the file-backed user list, the session
|
|
42
|
+
* ownership map and the HMAC account tokens. All mutations are synchronous
|
|
43
|
+
* and persisted atomically (temp file + rename); LAN scale keeps this trivial.
|
|
44
|
+
*/
|
|
45
|
+
export declare class QaAccounts {
|
|
46
|
+
readonly filePath: string;
|
|
47
|
+
private file;
|
|
48
|
+
private readonly authAttempts;
|
|
49
|
+
private readonly maxAuthAttemptsPerMinute;
|
|
50
|
+
private readonly sessionTtlDays;
|
|
51
|
+
private readonly allowRegistration;
|
|
52
|
+
/** mtime+size of the file as of the last load; the external-change probe. */
|
|
53
|
+
private lastLoadStamp;
|
|
54
|
+
constructor(filePath: string | undefined, options: QaAccountsOptions);
|
|
55
|
+
/**
|
|
56
|
+
* The qa-accounts CLI runs in its own process against the same file. Re-read
|
|
57
|
+
* it whenever it changed on disk, before every read or read-modify-write:
|
|
58
|
+
* without this a running Host would keep honoring tokens the CLI revoked
|
|
59
|
+
* and its next save would resurrect the CLI's change from a stale snapshot.
|
|
60
|
+
* One file, one writer at a time remains the deployment's discipline; LAN
|
|
61
|
+
* scale keeps the stat per operation trivial.
|
|
62
|
+
*/
|
|
63
|
+
private reloadIfChanged;
|
|
64
|
+
private load;
|
|
65
|
+
private persist;
|
|
66
|
+
private save;
|
|
67
|
+
private pruneAuthAttempts;
|
|
68
|
+
private assertAuthBudget;
|
|
69
|
+
private userByEmail;
|
|
70
|
+
register(email: string, password: string, displayName?: string): QaAccountSession;
|
|
71
|
+
login(email: string, password: string): QaAccountSession;
|
|
72
|
+
whoami(token: string): QaWhoamiResult;
|
|
73
|
+
/** Resolve a token to its user, or null for absent/invalid/expired ones. */
|
|
74
|
+
verifyToken(token: string): string | null;
|
|
75
|
+
private mintToken;
|
|
76
|
+
/** The account behind a token, or an auth-required refusal. */
|
|
77
|
+
requireUser(token: string): StoredUser;
|
|
78
|
+
/**
|
|
79
|
+
* Ownership gate for one session: claim unowned sessions for the requesting
|
|
80
|
+
* user (first come, first served — the pre-accounts migration path), refuse
|
|
81
|
+
* foreign sessions unless the caller administers the deployment.
|
|
82
|
+
*/
|
|
83
|
+
ensureSessionAccess(token: string, sessionId: string): QaAccountUserPublic;
|
|
84
|
+
/** Bulk-claim a browser's local chat index; foreign ids come back as conflicts. */
|
|
85
|
+
claimSessions(token: string, sessionIds: readonly string[]): QaClaimResult;
|
|
86
|
+
/** Session ids owned by the token's user, most recently claimed first. */
|
|
87
|
+
ownedSessionIds(token: string): readonly string[];
|
|
88
|
+
/**
|
|
89
|
+
* Every ownership entry with the owner's display name resolved at read
|
|
90
|
+
* time, oldest claim first. Admin-only: this is the cross-user view the
|
|
91
|
+
* admin sidebar groups chats by; ordinary accounts get a dedicated refusal.
|
|
92
|
+
*/
|
|
93
|
+
listOwnership(token: string): readonly QaOwnershipEntry[];
|
|
94
|
+
/** Every account, file order; for `qa-accounts list`. */
|
|
95
|
+
listUsers(): readonly {
|
|
96
|
+
readonly email: string;
|
|
97
|
+
readonly displayName: string;
|
|
98
|
+
readonly role: QaAccountRole;
|
|
99
|
+
readonly disabled: boolean;
|
|
100
|
+
readonly createdAt: string;
|
|
101
|
+
readonly lastLoginAt: string | null;
|
|
102
|
+
}[];
|
|
103
|
+
/** Create an account outside the self-registration gate. */
|
|
104
|
+
addUser(email: string, password: string, options?: {
|
|
105
|
+
displayName?: string;
|
|
106
|
+
role?: QaAccountRole;
|
|
107
|
+
}): QaAccountUserPublic;
|
|
108
|
+
private editUser;
|
|
109
|
+
/** Grant or revoke the admin role. */
|
|
110
|
+
setUserRole(email: string, role: QaAccountRole): QaAccountUserPublic;
|
|
111
|
+
/**
|
|
112
|
+
* Disable an account: future logins are refused and every live token is
|
|
113
|
+
* invalidated (the token version bumps). `enable` does not resurrect old
|
|
114
|
+
* tokens — the account signs in again.
|
|
115
|
+
*/
|
|
116
|
+
setUserDisabled(email: string, disabled: boolean): QaAccountUserPublic;
|
|
117
|
+
/** Invalidate every token of the account (password-leak response). */
|
|
118
|
+
revokeTokens(email: string): QaAccountUserPublic;
|
|
119
|
+
}
|
|
120
|
+
export {};
|
|
121
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable, coarse reason codes for QA policy attestation rejections.
|
|
3
|
+
*
|
|
4
|
+
* The RPC carrier folds a thrown Host error into `{ code, message, details }`
|
|
5
|
+
* and always empties `details`, so the wire message is the only channel back
|
|
6
|
+
* to the browser. The message therefore carries a `(reason: <code>)` marker:
|
|
7
|
+
* coarse enough to reveal nothing about the deployment policy to the QA
|
|
8
|
+
* audience, precise enough for an operator reading the browser console to
|
|
9
|
+
* know which class of mismatch to look for in the Host logs.
|
|
10
|
+
*/
|
|
11
|
+
export type QaAttestationReason = "agent-unavailable" | "workspace-unavailable" | "composition-mismatch" | "permission-preset" | "adoption-refused" | "unknown-tools" | "auth-required" | "session-owned-elsewhere" | "attestation-failed";
|
|
12
|
+
/** Host rejection whose wire message carries the coarse reason marker. */
|
|
13
|
+
export declare class QaAttestationError extends Error {
|
|
14
|
+
readonly reason: QaAttestationReason;
|
|
15
|
+
constructor(reason: QaAttestationReason, message: string);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=attestation.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export interface CliIo {
|
|
3
|
+
out(line: string): void;
|
|
4
|
+
err(line: string): void;
|
|
5
|
+
}
|
|
6
|
+
/** Execute one management command; returns the process exit code. */
|
|
7
|
+
export declare function run(argv: readonly string[], io: CliIo, readPassword?: () => string): number;
|
|
8
|
+
export declare function main(argv: readonly string[], io?: CliIo, readPassword?: () => string): number;
|
|
9
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { QaAccountUserPublic, QaOwnershipEntry, ResolvedQaSurfaceConfig } from "../types.js";
|
|
2
|
+
import type { QaAccountsApi, StorageLike } from "./types.js";
|
|
3
|
+
export type QaAccountsSnapshot = {
|
|
4
|
+
readonly stage: "checking";
|
|
5
|
+
} | {
|
|
6
|
+
readonly stage: "gate";
|
|
7
|
+
readonly mode: "login" | "register";
|
|
8
|
+
readonly busy: boolean;
|
|
9
|
+
readonly error: string | null;
|
|
10
|
+
} | {
|
|
11
|
+
readonly stage: "authed";
|
|
12
|
+
readonly user: QaAccountUserPublic;
|
|
13
|
+
/**
|
|
14
|
+
* Server-known chat ids; the sidebar list authority. Own chats always,
|
|
15
|
+
* plus every mapped chat for an admin (the cross-user grouping view).
|
|
16
|
+
*/
|
|
17
|
+
readonly ownedIds: readonly string[];
|
|
18
|
+
/**
|
|
19
|
+
* The full ownership map; admins only, empty for ordinary accounts and
|
|
20
|
+
* whenever the admin listing was refused or unavailable.
|
|
21
|
+
*/
|
|
22
|
+
readonly ownership: readonly QaOwnershipEntry[];
|
|
23
|
+
/** Bumped whenever ownedIds or ownership changes; re-projects lists. */
|
|
24
|
+
readonly ownedRevision: number;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Audience-safe copy for the coarse account refusal codes; anything unknown
|
|
28
|
+
* falls back to the generic line.
|
|
29
|
+
*/
|
|
30
|
+
export declare function accountsErrorMessage(code: string | null): string;
|
|
31
|
+
/** Extract the coarse account reason code from a Host wire failure. */
|
|
32
|
+
export declare function accountsReasonOf(failure: unknown): string | null;
|
|
33
|
+
export interface QaAccountsControllerOptions {
|
|
34
|
+
readonly remote: QaAccountsApi;
|
|
35
|
+
readonly storage: StorageLike | undefined;
|
|
36
|
+
/** Config snapshot getter; the token key follows the deployment identity. */
|
|
37
|
+
readonly config: () => ResolvedQaSurfaceConfig;
|
|
38
|
+
/**
|
|
39
|
+
* The legacy per-browser chat index at login time, for the one-shot
|
|
40
|
+
* ownership migration; conflicts are dropped through {@link forgetChat}.
|
|
41
|
+
*/
|
|
42
|
+
readonly legacyChatIds?: () => readonly string[];
|
|
43
|
+
readonly forgetChat?: (sessionId: string) => void;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Browser-side account lifecycle: token persistence, the checking → gate →
|
|
47
|
+
* authed state machine, and the ownership bookkeeping the sidebar list is
|
|
48
|
+
* built from. Anonymous/failed identity never blocks a deployment with
|
|
49
|
+
* accounts disabled — the caller simply does not mount this controller.
|
|
50
|
+
*/
|
|
51
|
+
export declare class QaAccountsController {
|
|
52
|
+
private readonly options;
|
|
53
|
+
private readonly listeners;
|
|
54
|
+
private snapshot;
|
|
55
|
+
private tokenValue;
|
|
56
|
+
private disposed;
|
|
57
|
+
constructor(options: QaAccountsControllerOptions);
|
|
58
|
+
getSnapshot: () => QaAccountsSnapshot;
|
|
59
|
+
subscribe: (listener: () => void) => (() => void);
|
|
60
|
+
dispose(): void;
|
|
61
|
+
/** The bearer token threaded into gated remotes; null while anonymous. */
|
|
62
|
+
/** The bearer token threaded into gated remotes; null while anonymous. */
|
|
63
|
+
token(): string | null;
|
|
64
|
+
/** Server-owned chat ids (empty until authed); falls back to nothing. */
|
|
65
|
+
ownedIds(): readonly string[];
|
|
66
|
+
/** Boot probe: restore the stored token and ask the Host who it is. */
|
|
67
|
+
start(): Promise<void>;
|
|
68
|
+
login(email: string, password: string): Promise<void>;
|
|
69
|
+
register(email: string, password: string): Promise<void>;
|
|
70
|
+
setMode(mode: "login" | "register"): void;
|
|
71
|
+
/** Drop the token and return to the gate (logout or expired identity). */
|
|
72
|
+
signOut(): void;
|
|
73
|
+
/** Claim one freshly created chat so the ownership map stays current. */
|
|
74
|
+
claimNewSession(sessionId: string): Promise<void>;
|
|
75
|
+
private authenticate;
|
|
76
|
+
/** Own the account, migrate the legacy index, then project authed. */
|
|
77
|
+
private enterSession;
|
|
78
|
+
/** Refresh the owned list after index changes; cheap enough to re-pull. */
|
|
79
|
+
refreshOwned(): Promise<void>;
|
|
80
|
+
/** The admin cross-user ownership view; failures degrade to an empty map. */
|
|
81
|
+
private fetchOwnership;
|
|
82
|
+
/** Session id → owner display name; empty unless an admin is signed in. */
|
|
83
|
+
ownerNames(): ReadonlyMap<string, string>;
|
|
84
|
+
/**
|
|
85
|
+
* The chat owner's display name for author labels: admins see it on
|
|
86
|
+
* foreign chats only; the owner themself and ordinary accounts see none.
|
|
87
|
+
*/
|
|
88
|
+
messageAuthorOf(sessionId: string): string | undefined;
|
|
89
|
+
private readStoredToken;
|
|
90
|
+
private saveStoredToken;
|
|
91
|
+
private clearStoredToken;
|
|
92
|
+
private tokenKey;
|
|
93
|
+
private publish;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=QaAccountsController.d.ts.map
|
|
@@ -1,21 +1,53 @@
|
|
|
1
|
-
import type { SettingsScope } from "@deepseek-ai/dsh-client-
|
|
1
|
+
import type { SettingsScope } from "@deepseek-ai/dsh-client-ui-settings/client";
|
|
2
2
|
import type { QaSurfaceConfig, ResolvedQaSurfaceConfig } from "../types.js";
|
|
3
3
|
export interface QaConfigSnapshot {
|
|
4
4
|
readonly status: "loading" | "ready" | "unavailable" | "error";
|
|
5
5
|
readonly config: ResolvedQaSurfaceConfig;
|
|
6
6
|
readonly error: string | null;
|
|
7
7
|
}
|
|
8
|
-
/**
|
|
8
|
+
/** Reads the effective Host configuration when the settings namespace cannot. */
|
|
9
|
+
export type QaConfigFallback = () => Promise<ResolvedQaSurfaceConfig>;
|
|
10
|
+
/**
|
|
11
|
+
* Browser projection of the Host-owned qa-surface settings namespace.
|
|
12
|
+
*
|
|
13
|
+
* The DSH gateway pins settings RPCs to loopback, so a browser served over the
|
|
14
|
+
* LAN always sees the namespace as `unavailable`. When the caller supplies the
|
|
15
|
+
* `qaSurface/describe` Remote as a fallback, that channel answers instead: the
|
|
16
|
+
* projection waits in `loading` until it settles, then reports the Host-owned
|
|
17
|
+
* configuration as `ready`. A rejected fallback returns the projection to
|
|
18
|
+
* `unavailable`, exactly as when no fallback exists.
|
|
19
|
+
*/
|
|
9
20
|
export declare class QaConfigController {
|
|
10
21
|
private readonly scope;
|
|
11
22
|
private readonly listeners;
|
|
12
23
|
private snapshot;
|
|
13
24
|
private readonly unsubscribe;
|
|
14
|
-
|
|
25
|
+
private readonly fallback;
|
|
26
|
+
private fallbackState;
|
|
27
|
+
private fallbackConfig;
|
|
28
|
+
private disposed;
|
|
29
|
+
constructor(scope: SettingsScope<QaSurfaceConfig>, fallback?: QaConfigFallback);
|
|
15
30
|
getSnapshot: () => QaConfigSnapshot;
|
|
16
31
|
subscribe: (listener: () => void) => (() => void);
|
|
17
32
|
dispose(): void;
|
|
18
33
|
private project;
|
|
19
34
|
private refresh;
|
|
35
|
+
/**
|
|
36
|
+
* Re-read the Host configuration after a Host reconnect. Without this, an
|
|
37
|
+
* open page keeps the configuration it fetched at load time: after the Host
|
|
38
|
+
* restarts with a changed deployment config, the next attestation compares
|
|
39
|
+
* its proof against the stale client copy and refuses. While re-reading,
|
|
40
|
+
* the previous answer stays projected — no loading flicker; the snapshot
|
|
41
|
+
* updates only when the answer actually changed.
|
|
42
|
+
*/
|
|
43
|
+
refreshFallback(): void;
|
|
44
|
+
/**
|
|
45
|
+
* The fallback trigger rides every refresh: the scope flips to
|
|
46
|
+
* `unavailable` whenever the browser is served over the LAN, which a
|
|
47
|
+
* constructor-time check can miss. The state guard makes repeats a no-op,
|
|
48
|
+
* so one fetch runs per controller lifetime; the recursive refresh lets the
|
|
49
|
+
* pending state surface before the first notification pass.
|
|
50
|
+
*/
|
|
51
|
+
private requestFallbackIfNeeded;
|
|
20
52
|
}
|
|
21
53
|
//# sourceMappingURL=QaConfigController.d.ts.map
|
|
@@ -1,59 +1,185 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import type { ConnectionGenerationState } from "@deepseek-ai/dsh-client-connection/client";
|
|
2
|
+
import type { QaImageDraft, QaSessionState, ResolvedQaSurfaceConfig } from "../types.js";
|
|
3
|
+
import type { QaConversation, QaSecureSession, QaSessions, QaSessionsApi, QaSourceApi, StorageLike } from "./types.js";
|
|
4
|
+
export interface QaAccountsFacade {
|
|
5
|
+
/** The account bearer token, or null while anonymous. */
|
|
6
|
+
readonly token: () => string | null;
|
|
7
|
+
/** Server-owned chat ids; the list authority while accounts are on. */
|
|
8
|
+
readonly ownedIds: () => readonly string[];
|
|
9
|
+
/**
|
|
10
|
+
* The chat owner's display name for author labels; admins see it on
|
|
11
|
+
* foreign chats only, everyone else gets undefined.
|
|
12
|
+
*/
|
|
13
|
+
readonly messageAuthorOf: (sessionId: string) => string | undefined;
|
|
14
|
+
/** Called after a new chat binds, so ownership stays current. */
|
|
15
|
+
readonly onSessionCreated: (sessionId: string) => void;
|
|
16
|
+
/** Called when the Host refuses with auth-required (expired/rotated). */
|
|
17
|
+
readonly onAuthRequired: () => void;
|
|
9
18
|
}
|
|
10
19
|
export interface QaSessionControllerOptions {
|
|
11
|
-
readonly sessions:
|
|
20
|
+
readonly sessions: QaSessions;
|
|
12
21
|
readonly api: QaSessionsApi;
|
|
13
|
-
|
|
22
|
+
/** Conversation assembly feeding the transcript projection. */
|
|
23
|
+
readonly conversation: QaConversation;
|
|
24
|
+
readonly connection: ConnectionGenerationState;
|
|
14
25
|
readonly config: ResolvedQaSurfaceConfig;
|
|
26
|
+
readonly secureSession: QaSecureSession;
|
|
27
|
+
readonly sourceApi?: QaSourceApi;
|
|
15
28
|
readonly storage?: StorageLike;
|
|
29
|
+
/** Present while the deployment gates QA users with accounts. */
|
|
30
|
+
readonly accounts?: QaAccountsFacade;
|
|
16
31
|
readonly timeoutMs?: number;
|
|
32
|
+
/**
|
|
33
|
+
* Minimum spacing between projections of a running turn's stream frames.
|
|
34
|
+
* The host runtime already batches deltas to one notification per
|
|
35
|
+
* animation frame; this ceiling keeps the render path flat on long
|
|
36
|
+
* transcripts and weak hardware. Zero disables the spacing.
|
|
37
|
+
*/
|
|
38
|
+
readonly streamIntervalMs?: number;
|
|
17
39
|
}
|
|
18
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* The only module that couples QA behavior to DSH Session/client APIs. It owns
|
|
42
|
+
* the chat lifecycle state machine; the observable wait, browser-local chat
|
|
43
|
+
* bookkeeping and policy-attestation details live in their own modules.
|
|
44
|
+
*/
|
|
19
45
|
export declare class QaSessionController {
|
|
20
46
|
private readonly listeners;
|
|
21
47
|
private readonly sessions;
|
|
22
48
|
private readonly api;
|
|
49
|
+
private readonly conversation;
|
|
23
50
|
private readonly connection;
|
|
24
51
|
private readonly config;
|
|
25
|
-
private readonly
|
|
52
|
+
private readonly secureSessionRemote;
|
|
53
|
+
private readonly sourceApi;
|
|
54
|
+
private readonly chats;
|
|
55
|
+
private readonly accounts;
|
|
56
|
+
/** Per-chat attachment URL cache; blob URLs die with the chat binding. */
|
|
57
|
+
private readonly assets;
|
|
26
58
|
private readonly timeoutMs;
|
|
59
|
+
private readonly streamIntervalMs;
|
|
27
60
|
private state;
|
|
28
61
|
private session;
|
|
62
|
+
private conversationBinding;
|
|
29
63
|
private unsubscribeSession;
|
|
64
|
+
private unsubscribeChat;
|
|
30
65
|
private readonly unsubscribeConnection;
|
|
31
66
|
private ensuring;
|
|
67
|
+
private materializing;
|
|
32
68
|
private operationError;
|
|
33
69
|
private admissionPending;
|
|
70
|
+
private policyReady;
|
|
71
|
+
private drafting;
|
|
72
|
+
private streamFlushTimer;
|
|
73
|
+
/** The chat session to return to when a subagent view closes. */
|
|
74
|
+
private chatSessionId;
|
|
75
|
+
private viewingSubagent;
|
|
34
76
|
private connectedOnce;
|
|
35
77
|
private disposed;
|
|
36
78
|
private generation;
|
|
79
|
+
private chatsRevision;
|
|
80
|
+
/** Host-side provenance of the bound chat, merged into the projection. */
|
|
81
|
+
private readonly hostSources;
|
|
37
82
|
constructor(options: QaSessionControllerOptions);
|
|
38
83
|
getSnapshot: () => QaSessionState;
|
|
39
84
|
subscribe: (listener: () => void) => (() => void);
|
|
40
85
|
ensureSession(): Promise<void>;
|
|
41
|
-
send(text: string): Promise<boolean>;
|
|
86
|
+
send(text: string, images?: readonly QaImageDraft[]): Promise<boolean>;
|
|
87
|
+
/**
|
|
88
|
+
* Ask for a fresh variant of the previous answer. The session has no
|
|
89
|
+
* truncation seam, so this sends the hidden regeneration instruction as an
|
|
90
|
+
* ordinary prompt: the model produces a follow-up turn, the projection
|
|
91
|
+
* hides the marker message, and the consecutive turns read as variants of
|
|
92
|
+
* the original question (switched in the surface).
|
|
93
|
+
*/
|
|
94
|
+
regenerate(): Promise<boolean>;
|
|
42
95
|
stop(): Promise<void>;
|
|
43
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Enter the "new chat" draft: show an empty composer without creating any
|
|
98
|
+
* session. Nothing appears in the chat list and no Host session is spent
|
|
99
|
+
* until the first prompt is actually sent, which materializes the session
|
|
100
|
+
* lazily ({@link materializeDraft}). Fixed-policy deployments cannot draft.
|
|
101
|
+
*/
|
|
102
|
+
startDraft(): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Turn the current draft into a real attested session. Runs inside the
|
|
105
|
+
* send flow; concurrent sends share one materialization. A refusal here is
|
|
106
|
+
* reported at once — a fresh session's first attestation is the
|
|
107
|
+
* deployment's only chance to learn the reason.
|
|
108
|
+
*/
|
|
109
|
+
private materializeDraft;
|
|
110
|
+
/**
|
|
111
|
+
* Open one of this browser's indexed chats. The id must be present in the
|
|
112
|
+
* host session list and pass policy attestation; an unknown id is forgotten
|
|
113
|
+
* from the index. Fixed-policy deployments cannot switch.
|
|
114
|
+
*/
|
|
115
|
+
switchTo(sessionId: string): Promise<void>;
|
|
116
|
+
/**
|
|
117
|
+
* Watch a subagent's transcript live. The binding is read-only by
|
|
118
|
+
* construction: no attestation runs (attestation admits sending, and the
|
|
119
|
+
* composer stays disabled here), the chat index is untouched, and
|
|
120
|
+
* {@link closeSubagent} returns to the chat the panel was opened from.
|
|
121
|
+
*/
|
|
122
|
+
viewSubagent(id: string, title: string): Promise<void>;
|
|
123
|
+
/** Leave the subagent transcript and re-open the chat it was launched from. */
|
|
124
|
+
closeSubagent(): Promise<void>;
|
|
125
|
+
/** This browser's chat ids: the owned list when accounts are on, else the
|
|
126
|
+
* local index. Both intersect the host session list at projection time. */
|
|
127
|
+
chatIds(): readonly string[];
|
|
128
|
+
/** The bound session id, or null while no chat is bound. */
|
|
129
|
+
activeSessionId(): string | null;
|
|
130
|
+
/**
|
|
131
|
+
* Resolve one durable image attachment of the bound session into a
|
|
132
|
+
* browser-usable URL. Resolutions are cached per chat in the asset
|
|
133
|
+
* repository (attachment ids repeat across chats) and revoked when the chat
|
|
134
|
+
* is unbound; failures surface as broken views and retry on demand.
|
|
135
|
+
*/
|
|
136
|
+
readImage(attachmentId: string): Promise<string>;
|
|
137
|
+
private readAttachmentUrl;
|
|
138
|
+
/**
|
|
139
|
+
* Remove one chat from this browser's index. Deleting the chat that is
|
|
140
|
+
* currently open also forgets the persisted id and starts a fresh attested
|
|
141
|
+
* session (when the deployment allows session resets); the Host-side
|
|
142
|
+
* session itself is not touched — no host deletion seam exists.
|
|
143
|
+
*/
|
|
144
|
+
deleteChat(id: string): Promise<void>;
|
|
145
|
+
/** Drop one chat id from this browser's index. */
|
|
146
|
+
forgetChat(sessionId: string): void;
|
|
44
147
|
dispose(): void;
|
|
45
148
|
private ensureSessionNow;
|
|
46
|
-
|
|
149
|
+
/**
|
|
150
|
+
* Recovery ladder after a refused send-time attestation. The prompt was
|
|
151
|
+
* never admitted, so nothing here can duplicate it. Step 1 re-opens the
|
|
152
|
+
* session: a Host that idled the agent out dismantles its tool view, and
|
|
153
|
+
* re-opening re-materializes it. Step 2 — when that refused session is
|
|
154
|
+
* still blank (it never received the prompt, so there is nothing to lose) —
|
|
155
|
+
* starts a fresh attested session instead. A session with history is left
|
|
156
|
+
* alone: recreating it would silently drop the conversation. Returns the
|
|
157
|
+
* attested session id, or null when nothing was attested.
|
|
158
|
+
*/
|
|
159
|
+
private recoverForSend;
|
|
47
160
|
private bind;
|
|
48
161
|
private unbind;
|
|
49
162
|
private waitForConnection;
|
|
163
|
+
/**
|
|
164
|
+
* Project one session notification. A running turn's frames arrive at
|
|
165
|
+
* animation-frame cadence, so re-projections are spaced at least
|
|
166
|
+
* {@link streamIntervalMs} apart: the first frame of a window projects at
|
|
167
|
+
* once and further frames are absorbed (the memoized render path replays
|
|
168
|
+
* nothing, so absorbing a frame only defers it). Everything outside a
|
|
169
|
+
* running turn - phase flips, errors, turn completion - projects
|
|
170
|
+
* immediately.
|
|
171
|
+
*/
|
|
172
|
+
private publishSessionUpdate;
|
|
173
|
+
private clearStreamFlush;
|
|
50
174
|
private publish;
|
|
51
175
|
private fail;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
176
|
+
/**
|
|
177
|
+
* Attest the currently bound session. `ok` carries the session id the proof
|
|
178
|
+
* was issued for; `stale` means the binding changed while the request was
|
|
179
|
+
* in flight, so nothing was written — the newer binding manages its own
|
|
180
|
+
* attestation; `refused` is a genuine admission refusal of this binding.
|
|
181
|
+
*/
|
|
182
|
+
private attestPolicy;
|
|
56
183
|
private emit;
|
|
57
184
|
}
|
|
58
|
-
export type { SessionListState };
|
|
59
185
|
//# sourceMappingURL=QaSessionController.d.ts.map
|
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { ISessions } from "@deepseek-ai/dsh-client-runtime/client";
|
|
1
|
+
import type { ConnectionGenerationState } from "@deepseek-ai/dsh-client-connection/client";
|
|
3
2
|
import type { InjectFace, PropsRuntime } from "@deepseek-ai/dsh-client-ui-slots";
|
|
4
3
|
import type { QaConfigController } from "./QaConfigController.js";
|
|
5
4
|
import type { QaRouteController } from "./QaRouteController.js";
|
|
5
|
+
import type { QaAccountsController } from "./QaAccountsController.js";
|
|
6
|
+
import type { QaConversation, QaSecureSession, QaSessions, QaSessionsApi, QaSourceApi } from "./types.js";
|
|
6
7
|
export interface QaSurfaceFace {
|
|
7
8
|
readonly route: QaRouteController;
|
|
8
9
|
readonly config: QaConfigController;
|
|
9
|
-
readonly sessions:
|
|
10
|
-
readonly
|
|
11
|
-
readonly
|
|
10
|
+
readonly sessions: QaSessions;
|
|
11
|
+
readonly conversation: QaConversation;
|
|
12
|
+
readonly api: QaSessionsApi;
|
|
13
|
+
readonly connection: ConnectionGenerationState;
|
|
14
|
+
readonly secureSession: QaSecureSession;
|
|
15
|
+
readonly sourceApi: QaSourceApi;
|
|
16
|
+
/** Present when the deployment mounts the QA account gate. */
|
|
17
|
+
readonly accounts?: QaAccountsController;
|
|
12
18
|
}
|
|
13
19
|
type QaSurfaceProps = PropsRuntime<"shell.overlay"> & InjectFace<QaSurfaceFace>;
|
|
14
20
|
export declare function QaSurface(props: QaSurfaceProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
import type { ConversationSnapshot } from "@deepseek-ai/dsh-client-
|
|
1
|
+
import type { ConversationSnapshot } from "@deepseek-ai/dsh-client-ui-conversation/client";
|
|
2
2
|
import type { QaMessage } from "../types.js";
|
|
3
|
-
/**
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* The hidden regeneration prompt. Regenerate sends this as an ordinary
|
|
5
|
+
* prompt — the session has no truncation seam, so a "variant" is a real
|
|
6
|
+
* follow-up turn — and the projection drops it from the visible transcript,
|
|
7
|
+
* leaving the consecutive answer turns to read as variants of one question.
|
|
8
|
+
*/
|
|
9
|
+
export declare const QA_REGENERATE_MARKER = "\u041F\u0435\u0440\u0435\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u0443\u0439 \u0441\u0432\u043E\u0439 \u043F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0438\u0439 \u043E\u0442\u0432\u0435\u0442 \u2014 \u0434\u0430\u0439 \u043D\u043E\u0432\u044B\u0439 \u0432\u0430\u0440\u0438\u0430\u043D\u0442, \u043D\u0435 \u043F\u043E\u0432\u0442\u043E\u0440\u044F\u044F \u043F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0438\u0439.";
|
|
10
|
+
/** Project end-user messages plus optional operator-approved work detail. */
|
|
11
|
+
export declare function projectTranscript(snapshot: ConversationSnapshot | undefined, options?: {
|
|
12
|
+
/** Live turn lifecycle from the bound Session (drives running-row status). */
|
|
13
|
+
readonly running?: boolean;
|
|
5
14
|
readonly showToolActivity?: boolean;
|
|
15
|
+
readonly showReasoning?: boolean;
|
|
6
16
|
}): readonly QaMessage[];
|
|
7
17
|
//# sourceMappingURL=QaTranscriptAdapter.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { QaLockdownProof, ResolvedQaSurfaceConfig } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Browser-side reading of Host policy attestation: one error type the session
|
|
4
|
+
* lifecycle branches on, plus pure diagnostics for the console. The specific
|
|
5
|
+
* mismatch facts stay in the Host logs; a refusal only reveals the coarse
|
|
6
|
+
* reason class and an operator hint.
|
|
7
|
+
*/
|
|
8
|
+
export declare class QaPolicyAttestationError extends Error {
|
|
9
|
+
constructor();
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Extract the coarse attestation reason code from a Host wire failure, if the
|
|
13
|
+
* failure carries the marker.
|
|
14
|
+
*/
|
|
15
|
+
export declare function attestationReasonOf(failure: {
|
|
16
|
+
readonly message?: string;
|
|
17
|
+
} | undefined | null): string | null;
|
|
18
|
+
export declare function attestationHint(reason: string | null): string;
|
|
19
|
+
/**
|
|
20
|
+
* Whether a Host proof answers the deployment lockdown config this browser
|
|
21
|
+
* holds. Every field must match; the allow-list is compared as exact JSON so
|
|
22
|
+
* order differences refuse too, mirroring the Host's pinned list.
|
|
23
|
+
*/
|
|
24
|
+
export declare function proofMatchesConfig(proof: QaLockdownProof, lockdown: ResolvedQaSurfaceConfig["lockdown"], sessionId: string): boolean;
|
|
25
|
+
//# sourceMappingURL=attestation.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { StorageLike } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Browser-local chat bookkeeping: a most-recently-used index of chat ids for
|
|
4
|
+
* the sidebar plus the id of the chat this browser reopens on load. Both live
|
|
5
|
+
* under the deployment's storage key and route path, and every access
|
|
6
|
+
* tolerates a denied or broken store — persistence must never prevent a real
|
|
7
|
+
* DSH session.
|
|
8
|
+
*/
|
|
9
|
+
export declare class QaChatIndex {
|
|
10
|
+
private readonly storage;
|
|
11
|
+
private readonly sessionKey;
|
|
12
|
+
private readonly chatKey;
|
|
13
|
+
constructor(storage: StorageLike | undefined, prefix: string);
|
|
14
|
+
/** This browser's indexed chat ids, most recently used first. */
|
|
15
|
+
chatIds(): readonly string[];
|
|
16
|
+
/**
|
|
17
|
+
* Add one chat to the index without reordering anything. Display order is
|
|
18
|
+
* the host's `updatedAt`, so merely opening a chat must not move it — the
|
|
19
|
+
* index is membership only.
|
|
20
|
+
*/
|
|
21
|
+
addChat(sessionId: string): void;
|
|
22
|
+
forgetChat(sessionId: string): void;
|
|
23
|
+
/** The persisted chat id this browser reopens on load, or null. */
|
|
24
|
+
activeId(): string | null;
|
|
25
|
+
saveActive(sessionId: string): void;
|
|
26
|
+
clearActive(): void;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=chat-index.d.ts.map
|
|
@@ -1,5 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import type { QaSource } from "../../types.js";
|
|
2
|
+
import { type QaSourceRefs } from "./source-refs.js";
|
|
3
|
+
/** Inline source awareness handed down from the owning assistant message. */
|
|
4
|
+
export interface MarkdownSourceContext {
|
|
5
|
+
readonly refs?: QaSourceRefs;
|
|
6
|
+
/** Open a path-backed source in the sources drawer's detail view. */
|
|
7
|
+
readonly onSourceOpen?: (source: QaSource) => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Deliberately small, HTML-free Markdown renderer for assistant-visible text.
|
|
11
|
+
* Memoized on the text value: stream updates re-render only the message whose
|
|
12
|
+
* text actually changed, so committed history is never re-parsed.
|
|
13
|
+
*/
|
|
14
|
+
export declare const Markdown: import("react").MemoExoticComponent<({ text, sourceRefs, onSourceOpen, }: {
|
|
3
15
|
readonly text: string;
|
|
4
|
-
|
|
16
|
+
readonly sourceRefs?: QaSourceRefs;
|
|
17
|
+
readonly onSourceOpen?: (source: QaSource) => void;
|
|
18
|
+
}) => import("react/jsx-runtime").JSX.Element>;
|
|
5
19
|
//# sourceMappingURL=Markdown.d.ts.map
|