@yadsh/dsh-qa-surface 0.1.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 +10 -0
- package/LICENSE +21 -0
- package/README.md +135 -0
- package/SPEC-dsh-qa-surface.md +1921 -0
- package/compatibility.json +15 -0
- package/cordis.patch.yml +9 -0
- package/docs/ARCHITECTURE.md +24 -0
- package/docs/COMPATIBILITY.md +13 -0
- package/docs/CONFIGURATION.md +18 -0
- package/docs/EMBEDDING.md +13 -0
- package/lib/client/QaConfigController.js +65 -0
- package/lib/client/QaConfigController.js.map +1 -0
- package/lib/client/QaRouteController.js +109 -0
- package/lib/client/QaRouteController.js.map +1 -0
- package/lib/client/QaSessionController.js +366 -0
- package/lib/client/QaSessionController.js.map +1 -0
- package/lib/client/QaSurface.js +109 -0
- package/lib/client/QaSurface.js.map +1 -0
- package/lib/client/QaTranscriptAdapter.js +92 -0
- package/lib/client/QaTranscriptAdapter.js.map +1 -0
- package/lib/client/components/Markdown.js +102 -0
- package/lib/client/components/Markdown.js.map +1 -0
- package/lib/client/components/QaComposer.js +33 -0
- package/lib/client/components/QaComposer.js.map +1 -0
- package/lib/client/components/QaMessage.js +14 -0
- package/lib/client/components/QaMessage.js.map +1 -0
- package/lib/client/index.js +46 -0
- package/lib/client/index.js.map +1 -0
- package/lib/client/styles.js +58 -0
- package/lib/client/styles.js.map +1 -0
- package/lib/client.js +1131 -0
- package/lib/client.js.map +1 -0
- package/lib/config.js +83 -0
- package/lib/config.js.map +1 -0
- package/lib/host-route.js +27 -0
- package/lib/host-route.js.map +1 -0
- package/lib/index.js +83 -0
- package/lib/index.js.map +1 -0
- package/lib/navigation-marker.js +3 -0
- package/lib/navigation-marker.js.map +1 -0
- package/lib/resolve-config.js +143 -0
- package/lib/resolve-config.js.map +1 -0
- package/lib/types/client/QaConfigController.d.ts +21 -0
- package/lib/types/client/QaRouteController.d.ts +43 -0
- package/lib/types/client/QaSessionController.d.ts +59 -0
- package/lib/types/client/QaSurface.d.ts +16 -0
- package/lib/types/client/QaTranscriptAdapter.d.ts +7 -0
- package/lib/types/client/components/Markdown.d.ts +5 -0
- package/lib/types/client/components/QaComposer.d.ts +11 -0
- package/lib/types/client/components/QaMessage.d.ts +8 -0
- package/lib/types/client/index.d.ts +19 -0
- package/lib/types/client/styles.d.ts +2 -0
- package/lib/types/config.d.ts +5 -0
- package/lib/types/host-route.d.ts +9 -0
- package/lib/types/index.d.ts +29 -0
- package/lib/types/navigation-marker.d.ts +3 -0
- package/lib/types/resolve-config.d.ts +6 -0
- package/lib/types/types.d.ts +114 -0
- package/lib/types.js +2 -0
- package/lib/types.js.map +1 -0
- package/package.json +137 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","names":["useState","useRef","Fragment","useSyncExternalStore","useState","useRef"],"sources":["../src/resolve-config.ts","../src/client/QaConfigController.ts","../src/navigation-marker.ts","../src/client/QaRouteController.ts","../src/client/QaTranscriptAdapter.ts","../src/client/QaSessionController.ts","../src/client/components/QaComposer.tsx","../src/client/components/Markdown.tsx","../src/client/components/QaMessage.tsx","../src/client/QaSurface.tsx","../src/client/styles.ts","../src/client/index.tsx"],"sourcesContent":["import type { QaSurfaceConfig, ResolvedQaSurfaceConfig } from \"./types.js\";\n\nexport const DEFAULT_QA_SURFACE_CONFIG: ResolvedQaSurfaceConfig = Object.freeze(\n {\n enabled: true,\n route: Object.freeze({ path: \"/qa\", matchChildren: true }),\n branding: Object.freeze({\n title: \"Assistant\",\n subtitle: \"\",\n welcomeMessage: \"How can I help?\",\n placeholder: \"Ask a question...\",\n logoUrl: null,\n }),\n session: Object.freeze({\n policy: \"browser-persistent\",\n storageKey: \"dsh-qa-surface\",\n workspaceId: null,\n fixedSessionId: null,\n agentPreset: null,\n provider: null,\n model: null,\n reasoningEffort: null,\n }),\n ui: Object.freeze({\n showHeader: true,\n showReset: true,\n showStop: true,\n showTimestamps: false,\n showToolActivity: false,\n showReasoning: false,\n renderMarkdown: true,\n maxContentWidth: 900,\n }),\n suggestedQuestions: Object.freeze([]),\n interaction: Object.freeze({\n approvals: \"blocked\",\n questions: \"unsupported\",\n }),\n embedding: Object.freeze({ frameAncestors: null }),\n },\n);\n\nfunction optionalText(value: string | null | undefined): string | null {\n const trimmed = value?.trim() ?? \"\";\n return trimmed === \"\" ? null : trimmed;\n}\n\nexport function normalizeRoutePath(value: string): string {\n const trimmed = value.trim();\n if (trimmed === \"\" || !trimmed.startsWith(\"/\")) {\n throw new TypeError(\"dsh-qa-surface: route.path must start with /\");\n }\n const path = trimmed.length > 1 ? trimmed.replace(/\\/+$/u, \"\") : trimmed;\n if (path === \"/\") {\n throw new TypeError(\n \"dsh-qa-surface: route.path cannot replace the operator root\",\n );\n }\n if (path === \"/api\" || path.startsWith(\"/api/\")) {\n throw new TypeError(\"dsh-qa-surface: route.path cannot claim /api\");\n }\n if (path === \"/plugins\" || path.startsWith(\"/plugins/\")) {\n throw new TypeError(\"dsh-qa-surface: route.path cannot claim /plugins\");\n }\n return path;\n}\n\nfunction uniqueQuestions(values: readonly string[]): readonly string[] {\n const questions = [\n ...new Set(values.map((value) => value.trim()).filter(Boolean)),\n ];\n if (questions.some((value) => value.length > 500)) {\n throw new TypeError(\n \"dsh-qa-surface: suggested questions must be at most 500 characters\",\n );\n }\n return Object.freeze(questions);\n}\n\n/** Materialize defaults and enforce route/session/model safety constraints. */\nexport function resolveConfig(\n input: QaSurfaceConfig = {},\n): ResolvedQaSurfaceConfig {\n const routePath = normalizeRoutePath(\n input.route?.path ?? DEFAULT_QA_SURFACE_CONFIG.route.path,\n );\n const policy =\n input.session?.policy ?? DEFAULT_QA_SURFACE_CONFIG.session.policy;\n const fixedSessionId = optionalText(input.session?.fixedSessionId);\n if (policy === \"fixed\" && fixedSessionId === null) {\n throw new TypeError(\n \"dsh-qa-surface: session.fixedSessionId is required for fixed policy\",\n );\n }\n const provider = optionalText(input.session?.provider);\n const model = optionalText(input.session?.model);\n if ((provider === null) !== (model === null)) {\n throw new TypeError(\n \"dsh-qa-surface: session.provider and session.model must be set together\",\n );\n }\n const storageKey =\n input.session?.storageKey?.trim() ??\n DEFAULT_QA_SURFACE_CONFIG.session.storageKey;\n if (storageKey === \"\") {\n throw new TypeError(\"dsh-qa-surface: session.storageKey cannot be empty\");\n }\n const maxContentWidth =\n input.ui?.maxContentWidth ?? DEFAULT_QA_SURFACE_CONFIG.ui.maxContentWidth;\n if (\n !Number.isSafeInteger(maxContentWidth) ||\n maxContentWidth < 480 ||\n maxContentWidth > 1600\n ) {\n throw new TypeError(\n \"dsh-qa-surface: ui.maxContentWidth must be an integer from 480 to 1600\",\n );\n }\n if (input.ui?.showReasoning === true) {\n throw new TypeError(\n \"dsh-qa-surface: ui.showReasoning is not supported by the safe MVP surface\",\n );\n }\n\n return Object.freeze({\n enabled: input.enabled ?? DEFAULT_QA_SURFACE_CONFIG.enabled,\n route: Object.freeze({\n path: routePath,\n matchChildren:\n input.route?.matchChildren ??\n DEFAULT_QA_SURFACE_CONFIG.route.matchChildren,\n }),\n branding: Object.freeze({\n title:\n input.branding?.title?.trim() ||\n DEFAULT_QA_SURFACE_CONFIG.branding.title,\n subtitle: input.branding?.subtitle?.trim() ?? \"\",\n welcomeMessage:\n input.branding?.welcomeMessage?.trim() ??\n DEFAULT_QA_SURFACE_CONFIG.branding.welcomeMessage,\n placeholder:\n input.branding?.placeholder?.trim() ||\n DEFAULT_QA_SURFACE_CONFIG.branding.placeholder,\n logoUrl: optionalText(input.branding?.logoUrl),\n }),\n session: Object.freeze({\n policy,\n storageKey,\n workspaceId: optionalText(input.session?.workspaceId),\n fixedSessionId,\n agentPreset: optionalText(input.session?.agentPreset),\n provider,\n model,\n reasoningEffort: optionalText(input.session?.reasoningEffort),\n }),\n ui: Object.freeze({\n showHeader:\n input.ui?.showHeader ?? DEFAULT_QA_SURFACE_CONFIG.ui.showHeader,\n showReset: input.ui?.showReset ?? DEFAULT_QA_SURFACE_CONFIG.ui.showReset,\n showStop: input.ui?.showStop ?? DEFAULT_QA_SURFACE_CONFIG.ui.showStop,\n showTimestamps:\n input.ui?.showTimestamps ?? DEFAULT_QA_SURFACE_CONFIG.ui.showTimestamps,\n showToolActivity:\n input.ui?.showToolActivity ??\n DEFAULT_QA_SURFACE_CONFIG.ui.showToolActivity,\n showReasoning: false,\n renderMarkdown:\n input.ui?.renderMarkdown ?? DEFAULT_QA_SURFACE_CONFIG.ui.renderMarkdown,\n maxContentWidth,\n }),\n suggestedQuestions: uniqueQuestions(input.suggestedQuestions ?? []),\n interaction: Object.freeze({\n approvals: \"blocked\",\n questions: \"unsupported\",\n }),\n embedding: Object.freeze({\n frameAncestors: optionalText(input.embedding?.frameAncestors),\n }),\n });\n}\n","import type { SettingsScope } from \"@deepseek-ai/dsh-client-runtime/client\";\nimport { DEFAULT_QA_SURFACE_CONFIG, resolveConfig } from \"../resolve-config.js\";\nimport type { QaSurfaceConfig, ResolvedQaSurfaceConfig } from \"../types.js\";\n\nexport interface QaConfigSnapshot {\n readonly status: \"loading\" | \"ready\" | \"unavailable\" | \"error\";\n readonly config: ResolvedQaSurfaceConfig;\n readonly error: string | null;\n}\n\n/** Browser projection of the Host-owned qa-surface settings namespace. */\nexport class QaConfigController {\n private readonly listeners = new Set<() => void>();\n private snapshot: QaConfigSnapshot;\n private readonly unsubscribe: () => void;\n\n constructor(private readonly scope: SettingsScope<QaSurfaceConfig>) {\n this.snapshot = this.project();\n this.unsubscribe = scope.subscribe(() => this.refresh());\n }\n\n getSnapshot = (): QaConfigSnapshot => this.snapshot;\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n dispose(): void {\n this.unsubscribe();\n this.listeners.clear();\n }\n\n private project(): QaConfigSnapshot {\n const settings = this.scope.getSnapshot();\n if (settings.status === \"loading\") {\n return {\n status: \"loading\",\n config: DEFAULT_QA_SURFACE_CONFIG,\n error: null,\n };\n }\n if (settings.status === \"unavailable\") {\n return {\n status: \"unavailable\",\n config: DEFAULT_QA_SURFACE_CONFIG,\n error: null,\n };\n }\n try {\n return {\n status: \"ready\",\n config: resolveConfig(settings.value ?? {}),\n error: null,\n };\n } catch {\n return {\n status: \"error\",\n config: DEFAULT_QA_SURFACE_CONFIG,\n error: \"The assistant configuration is unavailable.\",\n };\n }\n }\n\n private refresh(): void {\n const next = this.project();\n if (\n next.status === this.snapshot.status &&\n next.config === this.snapshot.config &&\n next.error === this.snapshot.error\n ) {\n return;\n }\n this.snapshot = next;\n for (const listener of this.listeners) listener();\n }\n}\n","/** Query hand-off used only by the Host navigation compatibility redirect. */\nexport const QA_NAVIGATION_MARKER = \"__dsh_qa_route\";\n","import type { ResolvedQaSurfaceConfig } from \"../types.js\";\nimport { QA_NAVIGATION_MARKER } from \"../navigation-marker.js\";\n\nexport interface QaRouteSnapshot {\n readonly pathname: string;\n readonly active: boolean;\n}\n\ninterface NavigationHistory {\n pushState(data: unknown, unused: string, url?: string | URL | null): void;\n replaceState(data: unknown, unused: string, url?: string | URL | null): void;\n}\n\ninterface NavigationWindow {\n readonly location: { readonly pathname: string; readonly search?: string };\n readonly history: NavigationHistory;\n addEventListener(type: \"popstate\", listener: () => void): void;\n removeEventListener(type: \"popstate\", listener: () => void): void;\n}\n\nexport function matchesQaRoute(\n pathname: string,\n route: ResolvedQaSurfaceConfig[\"route\"],\n): boolean {\n if (pathname === route.path || pathname === `${route.path}/`) return true;\n if (route.path === \"/\") return route.matchChildren;\n if (!route.matchChildren) return false;\n return pathname.startsWith(`${route.path}/`);\n}\n\n/** Observable route matcher with reversible History API instrumentation. */\nexport class QaRouteController {\n private readonly listeners = new Set<() => void>();\n private route: ResolvedQaSurfaceConfig[\"route\"] = {\n path: \"/qa\",\n matchChildren: true,\n };\n private enabled = false;\n private snapshot: QaRouteSnapshot;\n private readonly originalPushState: NavigationHistory[\"pushState\"];\n private readonly originalReplaceState: NavigationHistory[\"replaceState\"];\n private readonly wrappedPushState: NavigationHistory[\"pushState\"];\n private readonly wrappedReplaceState: NavigationHistory[\"replaceState\"];\n private disposed = false;\n\n constructor(private readonly target: NavigationWindow = window) {\n this.originalPushState = target.history.pushState;\n this.originalReplaceState = target.history.replaceState;\n this.restoreRedirectedPath();\n this.snapshot = this.project();\n const refresh = () => this.refresh();\n const history = target.history;\n const originalPushState = this.originalPushState;\n const originalReplaceState = this.originalReplaceState;\n this.wrappedPushState = function (\n ...args: Parameters<NavigationHistory[\"pushState\"]>\n ) {\n Reflect.apply(originalPushState, history, args);\n refresh();\n };\n this.wrappedReplaceState = function (\n ...args: Parameters<NavigationHistory[\"replaceState\"]>\n ) {\n Reflect.apply(originalReplaceState, history, args);\n refresh();\n };\n target.history.pushState = this.wrappedPushState;\n target.history.replaceState = this.wrappedReplaceState;\n target.addEventListener(\"popstate\", refresh);\n this.removePopstate = () => target.removeEventListener(\"popstate\", refresh);\n }\n\n private readonly removePopstate: () => void;\n\n getSnapshot = (): QaRouteSnapshot => this.snapshot;\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n configure(config: ResolvedQaSurfaceConfig, ready = true): void {\n this.route = config.route;\n this.enabled = ready && config.enabled;\n this.refresh();\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.removePopstate();\n if (this.target.history.pushState === this.wrappedPushState) {\n this.target.history.pushState = this.originalPushState;\n }\n if (this.target.history.replaceState === this.wrappedReplaceState) {\n this.target.history.replaceState = this.originalReplaceState;\n }\n this.listeners.clear();\n }\n\n private project(): QaRouteSnapshot {\n const pathname = this.target.location.pathname;\n return {\n pathname,\n active: this.enabled && matchesQaRoute(pathname, this.route),\n };\n }\n\n private restoreRedirectedPath(): void {\n const search = this.target.location.search;\n if (search === undefined || search === \"\") return;\n const requested = new URLSearchParams(search).get(QA_NAVIGATION_MARKER);\n if (\n requested === null ||\n !requested.startsWith(\"/\") ||\n requested.startsWith(\"//\")\n ) {\n return;\n }\n Reflect.apply(this.originalReplaceState, this.target.history, [\n null,\n \"\",\n requested,\n ]);\n }\n\n private refresh(): void {\n if (this.disposed) return;\n const next = this.project();\n if (\n next.pathname === this.snapshot.pathname &&\n next.active === this.snapshot.active\n ) {\n return;\n }\n this.snapshot = next;\n for (const listener of this.listeners) listener();\n }\n}\n","import type { ConversationSnapshot } from \"@deepseek-ai/dsh-client-runtime/client\";\nimport type { QaMessage } from \"../types.js\";\n\nfunction visibleContentText(content: readonly unknown[]): string {\n return content\n .flatMap((block) => {\n if (typeof block !== \"object\" || block === null) return [];\n return Reflect.get(block, \"type\") === \"text\" &&\n typeof Reflect.get(block, \"text\") === \"string\"\n ? [Reflect.get(block, \"text\") as string]\n : [];\n })\n .join(\"\");\n}\n\nfunction visibleAssistantText(\n blocks: readonly { readonly kind: string; readonly text?: string }[],\n): string {\n return blocks\n .filter(\n (block): block is { readonly kind: \"text\"; readonly text: string } =>\n block.kind === \"text\" && typeof block.text === \"string\",\n )\n .map((block) => block.text)\n .join(\"\");\n}\n\n/** Project only end-user-safe text from the public DSH conversation snapshot. */\nexport function projectTranscript(\n snapshot: ConversationSnapshot,\n options: { readonly showToolActivity?: boolean } = {},\n): readonly QaMessage[] {\n const messages: QaMessage[] = [];\n for (const node of snapshot.nodes) {\n if (node.kind === \"user\" || node.kind === \"steering\") {\n const text = visibleContentText(node.content);\n if (text !== \"\") {\n messages.push({\n id: `${node.kind}:${node.seq}`,\n role: \"user\",\n text,\n status: \"committed\",\n timestamp: node.time,\n });\n }\n continue;\n }\n if (node.kind === \"assistant\") {\n const text = visibleAssistantText(node.blocks);\n if (text !== \"\") {\n messages.push({\n id: `assistant:${node.messageId ?? node.seq}`,\n role: \"assistant\",\n text,\n status: \"committed\",\n timestamp: node.time,\n });\n }\n continue;\n }\n if (node.kind === \"turn-error\") {\n messages.push({\n id: `turn-error:${node.seq}`,\n role: \"system\",\n text: \"The assistant could not complete this response.\",\n status: \"error\",\n timestamp: node.time,\n });\n continue;\n }\n if (node.kind === \"turn-max-tokens\") {\n messages.push({\n id: `turn-max-tokens:${node.seq}`,\n role: \"system\",\n text: \"The response reached its length limit.\",\n status: \"info\",\n timestamp: node.time,\n });\n }\n }\n\n if (snapshot.partial !== null) {\n const text = visibleAssistantText(snapshot.partial.blocks);\n if (text !== \"\") {\n messages.push({\n id: `assistant:partial:${snapshot.partial.turn}:${snapshot.partial.step}`,\n role: \"assistant\",\n text,\n status: \"streaming\",\n });\n }\n }\n if (\n options.showToolActivity === true &&\n snapshot.runningCalls.length > 0 &&\n snapshot.partial === null\n ) {\n messages.push({\n id: \"tool-activity\",\n role: \"system\",\n text: \"Working…\",\n status: \"info\",\n });\n }\n return messages;\n}\n","import type {\n HostDescriptionSource,\n IApiClient,\n SessionId,\n WorkspaceId,\n} from \"@deepseek-ai/dsh-client-connection/client\";\nimport type {\n ISessions,\n SessionFace,\n SessionListState,\n} from \"@deepseek-ai/dsh-client-runtime/client\";\nimport type { QaSessionState, ResolvedQaSurfaceConfig } from \"../types.js\";\nimport { projectTranscript } from \"./QaTranscriptAdapter.js\";\n\ntype QaSessionsApi = Pick<IApiClient[\"sessions\"], \"create\" | \"selectModel\">;\n\nexport interface StorageLike {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n}\n\nexport interface QaSessionControllerOptions {\n readonly sessions: ISessions;\n readonly api: QaSessionsApi;\n readonly connection: HostDescriptionSource;\n readonly config: ResolvedQaSurfaceConfig;\n readonly storage?: StorageLike;\n readonly timeoutMs?: number;\n}\n\nconst EMPTY_STATE: QaSessionState = Object.freeze({\n phase: \"idle\",\n sessionId: null,\n messages: Object.freeze([]),\n error: null,\n canSend: false,\n canStop: false,\n});\n\nfunction waitFor<T>(\n source: {\n getSnapshot(): T;\n subscribe(listener: () => void): () => void;\n },\n predicate: (value: T) => boolean,\n timeoutMs: number,\n): Promise<T> {\n const current = source.getSnapshot();\n if (predicate(current)) return Promise.resolve(current);\n return new Promise<T>((resolve, reject) => {\n let settled = false;\n const timeout: { id?: ReturnType<typeof setTimeout> } = {};\n let unsubscribe: () => void = () => undefined;\n const finish = (value: T) => {\n if (settled) return;\n settled = true;\n if (timeout.id !== undefined) clearTimeout(timeout.id);\n unsubscribe();\n resolve(value);\n };\n unsubscribe = source.subscribe(() => {\n const next = source.getSnapshot();\n if (predicate(next)) finish(next);\n });\n // Tolerate observable implementations that notify synchronously while a\n // subscriber is being installed, and close that subscription afterward.\n if (settled) {\n unsubscribe();\n return;\n }\n const afterSubscribe = source.getSnapshot();\n if (predicate(afterSubscribe)) {\n finish(afterSubscribe);\n return;\n }\n timeout.id = setTimeout(() => {\n if (settled) return;\n settled = true;\n unsubscribe();\n reject(new Error(\"Timed out waiting for the DSH runtime.\"));\n }, timeoutMs);\n });\n}\n\n/** The only module that couples QA behavior to DSH Session/client APIs. */\nexport class QaSessionController {\n private readonly listeners = new Set<() => void>();\n private readonly sessions: ISessions;\n private readonly api: QaSessionsApi;\n private readonly connection: HostDescriptionSource;\n private readonly config: ResolvedQaSurfaceConfig;\n private readonly storage: StorageLike | undefined;\n private readonly timeoutMs: number;\n private state: QaSessionState = EMPTY_STATE;\n private session: SessionFace | undefined;\n private unsubscribeSession: (() => void) | undefined;\n private readonly unsubscribeConnection: () => void;\n private ensuring: Promise<void> | undefined;\n private operationError: string | null = null;\n private admissionPending = false;\n private connectedOnce: boolean;\n private disposed = false;\n private generation = 0;\n\n constructor(options: QaSessionControllerOptions) {\n this.sessions = options.sessions;\n this.api = options.api;\n this.connection = options.connection;\n this.config = options.config;\n this.storage = options.storage;\n this.timeoutMs = options.timeoutMs ?? 15_000;\n this.connectedOnce = this.connection.getSnapshot() !== undefined;\n this.unsubscribeConnection = this.connection.subscribe(() => {\n if (this.connection.getSnapshot() !== undefined)\n this.connectedOnce = true;\n this.publish();\n });\n }\n\n getSnapshot = (): QaSessionState => this.state;\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n ensureSession(): Promise<void> {\n if (this.ensuring !== undefined) return this.ensuring;\n const operation = this.ensureSessionNow().finally(() => {\n if (this.ensuring === operation) this.ensuring = undefined;\n });\n this.ensuring = operation;\n return operation;\n }\n\n async send(text: string): Promise<boolean> {\n const prompt = text.trim();\n if (prompt === \"\" || this.session === undefined || !this.state.canSend) {\n return false;\n }\n if (prompt.startsWith(\"/\")) {\n this.operationError =\n \"Slash commands are not available in this assistant view.\";\n this.publish();\n return false;\n }\n this.operationError = null;\n this.admissionPending = true;\n this.publish();\n try {\n const result = await this.session.prompt(\n [{ type: \"text\", text: prompt }],\n \"queue\",\n );\n if (!result.ok) {\n this.admissionPending = false;\n this.operationError = \"Your message could not be sent.\";\n this.publish();\n return false;\n }\n this.publish();\n return true;\n } catch (error) {\n this.admissionPending = false;\n console.error(\"dsh-qa-surface: prompt failed\", error);\n this.operationError = \"Your message could not be sent.\";\n this.publish();\n return false;\n }\n }\n\n async stop(): Promise<void> {\n if (this.session === undefined || !this.state.canStop) return;\n try {\n const result = await this.session.cancel();\n if (!result.ok)\n this.operationError = \"The response could not be stopped.\";\n } catch (error) {\n console.error(\"dsh-qa-surface: stop failed\", error);\n this.operationError = \"The response could not be stopped.\";\n }\n this.publish();\n }\n\n async reset(): Promise<void> {\n if (this.config.session.policy === \"fixed\") return;\n const previous = this.session;\n if (previous?.getSnapshot().running === true) {\n try {\n await previous.cancel();\n } catch (error) {\n console.error(\"dsh-qa-surface: stop before reset failed\", error);\n }\n }\n const operation = ++this.generation;\n this.unbind();\n this.operationError = null;\n this.admissionPending = false;\n this.state = { ...EMPTY_STATE, phase: \"creating\" };\n this.emit();\n try {\n await this.waitForConnection();\n const id = await this.createSession();\n if (this.disposed || operation !== this.generation) return;\n this.persist(id);\n await this.bind(id);\n } catch (error) {\n this.fail(\"Unable to start a new chat.\", error);\n }\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.generation += 1;\n this.unsubscribeConnection();\n this.unbind();\n this.listeners.clear();\n }\n\n private async ensureSessionNow(): Promise<void> {\n const operation = ++this.generation;\n this.state = { ...EMPTY_STATE, phase: \"creating\" };\n this.emit();\n try {\n await this.waitForConnection();\n const list = await waitFor(\n this.sessions.list,\n (snapshot) => snapshot.phase === \"ready\",\n this.timeoutMs,\n );\n let id: string | null = null;\n if (this.config.session.policy === \"fixed\") {\n id = this.config.session.fixedSessionId;\n if (id === null || !Object.hasOwn(list.byId, id)) {\n throw new Error(\"Configured fixed session is unavailable.\");\n }\n } else if (this.config.session.policy === \"browser-persistent\") {\n const stored = this.readPersisted();\n if (stored !== null && Object.hasOwn(list.byId, stored)) {\n id = stored;\n } else if (stored !== null) {\n this.clearPersisted();\n }\n }\n if (id === null) {\n id = await this.createSession();\n if (this.config.session.policy === \"browser-persistent\")\n this.persist(id);\n }\n if (this.disposed || operation !== this.generation) return;\n await this.bind(id);\n } catch (error) {\n this.fail(\"Unable to start a chat.\", error);\n }\n }\n\n private async createSession(): Promise<string> {\n const response = await this.api.create({\n ...(this.config.session.workspaceId === null\n ? {}\n : { workspaceId: this.config.session.workspaceId as WorkspaceId }),\n ...(this.config.session.agentPreset === null\n ? {}\n : { agentPreset: this.config.session.agentPreset }),\n });\n if (!response.result.ok) throw new Error(response.result.error.code);\n const id = String(response.result.value.sessionId);\n await waitFor(\n this.sessions.list,\n (snapshot) => Object.hasOwn(snapshot.byId, id),\n this.timeoutMs,\n );\n if (\n this.config.session.provider !== null &&\n this.config.session.model !== null\n ) {\n const selected = await this.api.selectModel({\n sessionId: id as SessionId,\n provider: this.config.session.provider,\n model: this.config.session.model,\n ...(this.config.session.reasoningEffort === null\n ? {}\n : { reasoningEffort: this.config.session.reasoningEffort }),\n });\n if (!selected.result.ok) throw new Error(selected.result.error.code);\n }\n return id;\n }\n\n private async bind(id: string): Promise<void> {\n this.sessions.open(id as SessionId);\n let binding = this.sessions.binding(id as SessionId);\n if (binding === undefined) {\n await waitFor(\n this.sessions.list,\n (snapshot) => Object.hasOwn(snapshot.byId, id),\n this.timeoutMs,\n );\n binding = this.sessions.binding(id as SessionId);\n }\n if (binding === undefined)\n throw new Error(\"Session binding is unavailable.\");\n this.unbind();\n this.session = binding.session;\n this.unsubscribeSession = binding.session.subscribe(() => {\n this.admissionPending = false;\n this.operationError = null;\n this.publish();\n });\n this.publish();\n }\n\n private unbind(): void {\n this.unsubscribeSession?.();\n this.unsubscribeSession = undefined;\n this.session = undefined;\n this.admissionPending = false;\n }\n\n private waitForConnection(): Promise<unknown> {\n return waitFor(\n this.connection,\n (description) => description !== undefined,\n this.timeoutMs,\n );\n }\n\n private publish(): void {\n if (this.disposed) return;\n const connected = this.connection.getSnapshot() !== undefined;\n if (this.session === undefined) {\n this.state = {\n ...this.state,\n phase:\n !connected && this.connectedOnce ? \"reconnecting\" : this.state.phase,\n error: this.operationError ?? this.state.error,\n };\n this.emit();\n return;\n }\n const snapshot = this.session.getSnapshot();\n const blocked = snapshot.pending.length > 0;\n const error =\n this.operationError ??\n (blocked\n ? \"This request requires an interaction that is not available in this assistant view.\"\n : snapshot.removed || snapshot.openState === \"error\"\n ? \"This chat is no longer available.\"\n : null);\n const phase = !connected\n ? \"reconnecting\"\n : blocked\n ? \"blocked\"\n : snapshot.removed || snapshot.openState === \"error\"\n ? \"error\"\n : snapshot.openState !== \"open\"\n ? \"creating\"\n : snapshot.running || this.admissionPending\n ? \"running\"\n : \"ready\";\n this.state = {\n phase,\n sessionId: String(this.session.sessionId),\n messages: projectTranscript(snapshot, {\n showToolActivity: this.config.ui.showToolActivity,\n }),\n error,\n canSend: connected && phase === \"ready\",\n canStop:\n connected && snapshot.running && this.config.ui.showStop && !blocked,\n };\n this.emit();\n }\n\n private fail(message: string, error: unknown): void {\n console.error(\"dsh-qa-surface: session operation failed\", error);\n if (this.disposed) return;\n this.operationError = message;\n this.state = {\n ...EMPTY_STATE,\n phase: \"error\",\n error: message,\n };\n this.emit();\n }\n\n private storageKey(): string {\n return `${this.config.session.storageKey}:v1:${this.config.route.path}:session`;\n }\n\n private readPersisted(): string | null {\n try {\n const value = this.storage?.getItem(this.storageKey())?.trim() ?? \"\";\n return value === \"\" ? null : value;\n } catch {\n return null;\n }\n }\n\n private persist(id: string): void {\n try {\n this.storage?.setItem(this.storageKey(), id);\n } catch {\n // A denied localStorage write must not prevent a real DSH session.\n }\n }\n\n private clearPersisted(): void {\n try {\n this.storage?.removeItem(this.storageKey());\n } catch {\n // A denied localStorage removal is harmless; the id is revalidated later.\n }\n }\n\n private emit(): void {\n for (const listener of this.listeners) listener();\n }\n}\n\nexport type { SessionListState };\n","import { useEffect, useRef, useState } from \"react\";\n\nexport interface QaComposerProps {\n readonly placeholder: string;\n readonly canSend: boolean;\n readonly canStop: boolean;\n readonly running: boolean;\n readonly showStop: boolean;\n readonly onSend: (text: string) => Promise<boolean>;\n readonly onStop: () => Promise<void>;\n}\n\nexport function QaComposer(props: QaComposerProps) {\n const [draft, setDraft] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const textarea = useRef<HTMLTextAreaElement>(null);\n const send = async () => {\n if (submitting || draft.trim() === \"\" || !props.canSend) return;\n setSubmitting(true);\n try {\n if (await props.onSend(draft)) setDraft(\"\");\n } finally {\n setSubmitting(false);\n textarea.current?.focus();\n }\n };\n\n useEffect(() => {\n if (!props.running) textarea.current?.focus();\n }, [props.running]);\n\n return (\n <div className=\"dsh-qa-composer\">\n <label className=\"dsh-qa-sr-only\" htmlFor=\"dsh-qa-prompt\">\n Ask a question\n </label>\n <textarea\n ref={textarea}\n id=\"dsh-qa-prompt\"\n rows={1}\n value={draft}\n placeholder={props.placeholder}\n disabled={!props.canSend && !props.running}\n onChange={(event) => setDraft(event.currentTarget.value)}\n onKeyDown={(event) => {\n if (\n event.key === \"Enter\" &&\n !event.shiftKey &&\n !event.nativeEvent.isComposing\n ) {\n event.preventDefault();\n void send();\n }\n }}\n />\n {props.running && props.showStop ? (\n <button\n type=\"button\"\n className=\"dsh-qa-button dsh-qa-button--stop\"\n disabled={!props.canStop}\n onClick={() => void props.onStop()}\n >\n Stop\n </button>\n ) : (\n <button\n type=\"button\"\n className=\"dsh-qa-button dsh-qa-button--send\"\n disabled={!props.canSend || submitting || draft.trim() === \"\"}\n onClick={() => void send()}\n >\n Send\n </button>\n )}\n </div>\n );\n}\n","import { Fragment, type ReactNode } from \"react\";\n\nconst INLINE = /(\\[[^\\]]+\\]\\([^\\s)]+\\)|`[^`]+`|\\*\\*[^*]+\\*\\*|\\*[^*]+\\*)/gu;\n\nfunction safeHref(value: string): string | undefined {\n try {\n const url = new URL(value, window.location.origin);\n return [\"http:\", \"https:\", \"mailto:\"].includes(url.protocol)\n ? value\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction inline(text: string, keyPrefix: string): ReactNode[] {\n const nodes: ReactNode[] = [];\n let offset = 0;\n for (const match of text.matchAll(INLINE)) {\n const index = match.index;\n if (index > offset) nodes.push(text.slice(offset, index));\n const token = match[0];\n const key = `${keyPrefix}:${index}`;\n if (token.startsWith(\"[\")) {\n const parts = /^\\[([^\\]]+)\\]\\(([^\\s)]+)\\)$/u.exec(token);\n const href = parts?.[2] === undefined ? undefined : safeHref(parts[2]);\n nodes.push(\n href === undefined ? (\n token\n ) : (\n <a key={key} href={href} target=\"_blank\" rel=\"noreferrer\">\n {parts?.[1]}\n </a>\n ),\n );\n } else if (token.startsWith(\"`\")) {\n nodes.push(<code key={key}>{token.slice(1, -1)}</code>);\n } else if (token.startsWith(\"**\")) {\n nodes.push(<strong key={key}>{token.slice(2, -2)}</strong>);\n } else {\n nodes.push(<em key={key}>{token.slice(1, -1)}</em>);\n }\n offset = index + token.length;\n }\n if (offset < text.length) nodes.push(text.slice(offset));\n return nodes;\n}\n\n/** Deliberately small, HTML-free Markdown renderer for assistant-visible text. */\nexport function Markdown({ text }: { readonly text: string }) {\n const lines = text.replace(/\\r\\n?/gu, \"\\n\").split(\"\\n\");\n const blocks: ReactNode[] = [];\n for (let index = 0; index < lines.length;) {\n const line = lines[index] ?? \"\";\n if (line.startsWith(\"```\")) {\n const language = line.slice(3).trim();\n const code: string[] = [];\n index += 1;\n while (index < lines.length && !(lines[index] ?? \"\").startsWith(\"```\")) {\n code.push(lines[index] ?? \"\");\n index += 1;\n }\n if (index < lines.length) index += 1;\n blocks.push(\n <pre key={`code:${index}`}>\n <code data-language={language || undefined}>{code.join(\"\\n\")}</code>\n </pre>,\n );\n continue;\n }\n const heading = /^(#{1,3})\\s+(.+)$/u.exec(line);\n if (heading !== null) {\n const content = inline(heading[2] ?? \"\", `heading:${index}`);\n const key = `heading:${index}`;\n blocks.push(\n heading[1]?.length === 1 ? (\n <h2 key={key}>{content}</h2>\n ) : heading[1]?.length === 2 ? (\n <h3 key={key}>{content}</h3>\n ) : (\n <h4 key={key}>{content}</h4>\n ),\n );\n index += 1;\n continue;\n }\n if (/^[-*]\\s+/u.test(line)) {\n const items: ReactNode[] = [];\n while (index < lines.length && /^[-*]\\s+/u.test(lines[index] ?? \"\")) {\n const content = (lines[index] ?? \"\").replace(/^[-*]\\s+/u, \"\");\n items.push(\n <li key={`item:${index}`}>{inline(content, `item:${index}`)}</li>,\n );\n index += 1;\n }\n blocks.push(<ul key={`list:${index}`}>{items}</ul>);\n continue;\n }\n if (line.startsWith(\"> \")) {\n blocks.push(\n <blockquote key={`quote:${index}`}>\n {inline(line.slice(2), `quote:${index}`)}\n </blockquote>,\n );\n index += 1;\n continue;\n }\n if (line.trim() === \"\") {\n index += 1;\n continue;\n }\n const paragraph = [line];\n index += 1;\n while (\n index < lines.length &&\n (lines[index] ?? \"\").trim() !== \"\" &&\n !/^(#{1,3})\\s+|^```|^[-*]\\s+|^>\\s/u.test(lines[index] ?? \"\")\n ) {\n paragraph.push(lines[index] ?? \"\");\n index += 1;\n }\n blocks.push(\n <p key={`paragraph:${index}`}>\n {paragraph.map((part, partIndex) => (\n <Fragment key={`line:${partIndex}`}>\n {partIndex === 0 ? null : <br />}\n {inline(part, `paragraph:${index}:${partIndex}`)}\n </Fragment>\n ))}\n </p>,\n );\n }\n return <>{blocks}</>;\n}\n","import type { QaMessage as QaMessageModel } from \"../../types.js\";\nimport { Markdown } from \"./Markdown.js\";\n\nexport interface QaMessageProps {\n readonly message: QaMessageModel;\n readonly renderMarkdown: boolean;\n readonly showTimestamp: boolean;\n}\n\nexport function QaMessage({\n message,\n renderMarkdown,\n showTimestamp,\n}: QaMessageProps) {\n const label =\n message.role === \"assistant\"\n ? \"Assistant\"\n : message.role === \"user\"\n ? \"You\"\n : \"Status\";\n return (\n <article\n className={`dsh-qa-message dsh-qa-message--${message.role}`}\n data-status={message.status}\n >\n <div className=\"dsh-qa-message__meta\">\n <span>{label}</span>\n {showTimestamp && message.timestamp !== undefined ? (\n <time dateTime={new Date(message.timestamp).toISOString()}>\n {new Date(message.timestamp).toLocaleTimeString([], {\n hour: \"2-digit\",\n minute: \"2-digit\",\n })}\n </time>\n ) : null}\n </div>\n <div className=\"dsh-qa-message__content\">\n {message.role === \"assistant\" && renderMarkdown ? (\n <Markdown text={message.text} />\n ) : (\n message.text\n )}\n {message.status === \"streaming\" ? (\n <span className=\"dsh-qa-message__cursor\" aria-hidden=\"true\" />\n ) : null}\n </div>\n </article>\n );\n}\n","import {\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n useSyncExternalStore,\n type KeyboardEvent,\n} from \"react\";\nimport type {\n HostDescriptionSource,\n IApiClient,\n} from \"@deepseek-ai/dsh-client-connection/client\";\nimport type { ISessions } from \"@deepseek-ai/dsh-client-runtime/client\";\nimport type {\n InjectFace,\n PropsRuntime,\n} from \"@deepseek-ai/dsh-client-ui-slots\";\nimport type { QaSessionState } from \"../types.js\";\nimport type { QaConfigController } from \"./QaConfigController.js\";\nimport type { QaRouteController } from \"./QaRouteController.js\";\nimport { QaSessionController } from \"./QaSessionController.js\";\nimport { QaComposer } from \"./components/QaComposer.js\";\nimport { QaMessage } from \"./components/QaMessage.js\";\n\nconst INACTIVE_STATE: QaSessionState = Object.freeze({\n phase: \"idle\",\n sessionId: null,\n messages: Object.freeze([]),\n error: null,\n canSend: false,\n canStop: false,\n});\nconst noopSubscribe = () => () => undefined;\n\nexport interface QaSurfaceFace {\n readonly route: QaRouteController;\n readonly config: QaConfigController;\n readonly sessions: ISessions;\n readonly api: Pick<IApiClient[\"sessions\"], \"create\" | \"selectModel\">;\n readonly connection: HostDescriptionSource;\n}\n\ntype QaSurfaceProps = PropsRuntime<\"shell.overlay\"> & InjectFace<QaSurfaceFace>;\n\nfunction focusable(root: HTMLElement): HTMLElement[] {\n return [\n ...root.querySelectorAll<HTMLElement>(\n \"button:not([disabled]), textarea:not([disabled]), a[href], [tabindex]:not([tabindex='-1'])\",\n ),\n ].filter((element) => !element.hidden);\n}\n\nfunction trapKeys(event: KeyboardEvent<HTMLElement>): void {\n event.stopPropagation();\n if (event.key !== \"Tab\") return;\n const items = focusable(event.currentTarget);\n if (items.length === 0) {\n event.preventDefault();\n event.currentTarget.focus();\n return;\n }\n const first = items[0];\n const last = items.at(-1);\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last?.focus();\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first?.focus();\n }\n}\n\nfunction statusText(state: QaSessionState): string | null {\n if (state.phase === \"creating\") return \"Connecting…\";\n if (state.phase === \"reconnecting\") return \"Connection lost. Reconnecting…\";\n if (state.phase === \"running\") return \"Assistant is responding…\";\n return null;\n}\n\nexport function QaSurface(props: QaSurfaceProps) {\n const route = useSyncExternalStore(\n props.route.subscribe,\n props.route.getSnapshot,\n props.route.getSnapshot,\n );\n const configState = useSyncExternalStore(\n props.config.subscribe,\n props.config.getSnapshot,\n props.config.getSnapshot,\n );\n const config = configState.config;\n const [controller, setController] = useState<QaSessionController>();\n const transcript = useRef<HTMLDivElement>(null);\n const nearBottom = useRef(true);\n\n useEffect(() => {\n if (!route.active) {\n setController(undefined);\n return;\n }\n const next = new QaSessionController({\n sessions: props.sessions,\n api: props.api,\n connection: props.connection,\n config,\n storage: window.localStorage,\n });\n setController(next);\n void next.ensureSession();\n return () => next.dispose();\n }, [config, props.api, props.connection, props.sessions, route.active]);\n\n const state = useSyncExternalStore(\n controller?.subscribe ?? noopSubscribe,\n controller?.getSnapshot ?? (() => INACTIVE_STATE),\n controller?.getSnapshot ?? (() => INACTIVE_STATE),\n );\n\n useEffect(() => {\n if (!route.active) return;\n const previousBodyOverflow = document.body.style.overflow;\n const previousHtmlOverflow = document.documentElement.style.overflow;\n document.body.dataset.dshQaSurface = \"active\";\n document.body.style.overflow = \"hidden\";\n document.documentElement.style.overflow = \"hidden\";\n const frame = requestAnimationFrame(() => {\n document.querySelector<HTMLTextAreaElement>(\"#dsh-qa-prompt\")?.focus();\n });\n return () => {\n cancelAnimationFrame(frame);\n delete document.body.dataset.dshQaSurface;\n document.body.style.overflow = previousBodyOverflow;\n document.documentElement.style.overflow = previousHtmlOverflow;\n };\n }, [route.active]);\n\n useLayoutEffect(() => {\n const element = transcript.current;\n if (element !== null && nearBottom.current) {\n element.scrollTop = element.scrollHeight;\n }\n }, [state.messages]);\n\n if (!route.active) return null;\n\n const status = statusText(state);\n const empty = state.messages.length === 0;\n return (\n <main\n className=\"dsh-qa-surface\"\n aria-label={config.branding.title}\n tabIndex={-1}\n onKeyDown={trapKeys}\n >\n {config.ui.showHeader ? (\n <header className=\"dsh-qa-header\">\n <div\n className=\"dsh-qa-header__inner\"\n style={{ maxWidth: config.ui.maxContentWidth }}\n >\n {config.branding.logoUrl === null ? null : (\n <img\n className=\"dsh-qa-header__logo\"\n src={config.branding.logoUrl}\n alt=\"\"\n />\n )}\n <div className=\"dsh-qa-header__text\">\n <h1>{config.branding.title}</h1>\n {config.branding.subtitle === \"\" ? null : (\n <p>{config.branding.subtitle}</p>\n )}\n </div>\n {config.ui.showReset && config.session.policy !== \"fixed\" ? (\n <button\n type=\"button\"\n className=\"dsh-qa-button dsh-qa-button--secondary\"\n disabled={\n controller === undefined || state.phase === \"creating\"\n }\n onClick={() => void controller?.reset()}\n >\n New chat\n </button>\n ) : null}\n </div>\n </header>\n ) : null}\n\n <div\n ref={transcript}\n className=\"dsh-qa-transcript\"\n onScroll={(event) => {\n const element = event.currentTarget;\n nearBottom.current =\n element.scrollHeight - element.scrollTop - element.clientHeight <\n 96;\n }}\n >\n <div\n className=\"dsh-qa-transcript__inner\"\n style={{ maxWidth: config.ui.maxContentWidth }}\n >\n {empty ? (\n <section\n className=\"dsh-qa-welcome\"\n aria-labelledby=\"dsh-qa-welcome-title\"\n >\n <h2 id=\"dsh-qa-welcome-title\">\n {config.branding.welcomeMessage}\n </h2>\n {config.suggestedQuestions.length > 0 ? (\n <div\n className=\"dsh-qa-suggestions\"\n aria-label=\"Suggested questions\"\n >\n {config.suggestedQuestions.map((question) => (\n <button\n type=\"button\"\n key={question}\n disabled={!state.canSend}\n onClick={() => void controller?.send(question)}\n >\n {question}\n </button>\n ))}\n </div>\n ) : null}\n </section>\n ) : (\n state.messages.map((message) => (\n <QaMessage\n key={message.id}\n message={message}\n renderMarkdown={config.ui.renderMarkdown}\n showTimestamp={config.ui.showTimestamps}\n />\n ))\n )}\n {state.error === null ? null : (\n <div className=\"dsh-qa-error\" role=\"alert\">\n <span>{state.error}</span>\n {state.phase === \"error\" ? (\n <button\n type=\"button\"\n onClick={() => void controller?.ensureSession()}\n >\n Retry\n </button>\n ) : null}\n </div>\n )}\n </div>\n </div>\n\n <footer className=\"dsh-qa-footer\">\n <div\n className=\"dsh-qa-footer__inner\"\n style={{ maxWidth: config.ui.maxContentWidth }}\n >\n <div className=\"dsh-qa-status\" aria-live=\"polite\" aria-atomic=\"true\">\n {status}\n </div>\n <QaComposer\n placeholder={config.branding.placeholder}\n canSend={state.canSend}\n canStop={state.canStop}\n running={state.phase === \"running\"}\n showStop={config.ui.showStop}\n onSend={(text) => controller?.send(text) ?? Promise.resolve(false)}\n onStop={() => controller?.stop() ?? Promise.resolve()}\n />\n </div>\n </footer>\n </main>\n );\n}\n","export const QA_SURFACE_STYLES = String.raw`\n.dsh-qa-surface{position:fixed;inset:0;z-index:2147483000;pointer-events:auto;display:flex;flex-direction:column;min-width:0;height:100vh;height:100dvh;overflow:hidden;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font-family:inherit}\n.dsh-qa-surface *{box-sizing:border-box}\n.dsh-qa-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n.dsh-qa-header{flex:none;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2)}\n.dsh-qa-header__inner,.dsh-qa-footer__inner,.dsh-qa-transcript__inner{width:100%;margin:0 auto}\n.dsh-qa-header__inner{min-height:72px;display:flex;align-items:center;gap:12px;padding:12px 24px}\n.dsh-qa-header__logo{width:36px;height:36px;object-fit:contain;border-radius:9px;flex:none}\n.dsh-qa-header__text{flex:1;min-width:0}\n.dsh-qa-header h1{margin:0;color:var(--dsw-alias-label-primary);font-size:17px;font-weight:650;line-height:1.35}\n.dsh-qa-header p{margin:2px 0 0;color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.4}\n.dsh-qa-transcript{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-gutter:stable}\n.dsh-qa-transcript__inner{min-height:100%;padding:32px 24px 24px}\n.dsh-qa-welcome{min-height:100%;display:flex;flex-direction:column;justify-content:center;align-items:center;text-align:center;padding:40px 0}\n.dsh-qa-welcome h2{max-width:620px;margin:0;color:var(--dsw-alias-label-primary);font-size:clamp(24px,4vw,34px);font-weight:600;line-height:1.25}\n.dsh-qa-suggestions{display:flex;flex-wrap:wrap;justify-content:center;gap:8px;margin-top:24px}\n.dsh-qa-suggestions button{max-width:360px;padding:9px 13px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-secondary);font:inherit;font-size:13px;line-height:1.35;cursor:pointer}\n.dsh-qa-suggestions button:hover:not(:disabled){border-color:var(--dsw-alias-label-dimmed);color:var(--dsw-alias-label-primary)}\n.dsh-qa-suggestions button:disabled{opacity:.5;cursor:default}\n.dsh-qa-message{display:flex;flex-direction:column;max-width:min(82%,720px);margin:0 0 24px}\n.dsh-qa-message--user{align-items:flex-end;margin-left:auto}\n.dsh-qa-message--assistant{align-items:flex-start;margin-right:auto}\n.dsh-qa-message--system{align-items:center;max-width:100%;margin-left:auto;margin-right:auto}\n.dsh-qa-message__meta{display:flex;gap:8px;margin:0 4px 6px;color:var(--dsw-alias-label-tertiary);font-size:11px;font-weight:600;line-height:1.3}\n.dsh-qa-message__content{max-width:100%;white-space:pre-wrap;overflow-wrap:anywhere;border:1px solid var(--dsw-alias-border-l2);border-radius:14px;padding:11px 14px;background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font-size:15px;line-height:1.62}\n.dsh-qa-message--user .dsh-qa-message__content{background:var(--dsw-alias-bg-module-platform)}\n.dsh-qa-message--system .dsh-qa-message__content{padding:7px 11px;border-radius:9px;color:var(--dsw-alias-label-secondary);font-size:13px}\n.dsh-qa-message[data-status=\"error\"] .dsh-qa-message__content{border-color:var(--dsw-alias-status-error)}\n.dsh-qa-message__content p,.dsh-qa-message__content ul,.dsh-qa-message__content blockquote,.dsh-qa-message__content pre{margin:0 0 10px}\n.dsh-qa-message__content :last-child{margin-bottom:0}\n.dsh-qa-message__content h2,.dsh-qa-message__content h3,.dsh-qa-message__content h4{margin:14px 0 7px;line-height:1.35}\n.dsh-qa-message__content h2{font-size:18px}.dsh-qa-message__content h3{font-size:16px}.dsh-qa-message__content h4{font-size:15px}\n.dsh-qa-message__content ul{padding-left:22px}.dsh-qa-message__content a{color:var(--dsw-alias-brand-primary)}\n.dsh-qa-message__content code{border-radius:5px;padding:1px 4px;background:var(--dsw-alias-bg-layer-2);font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:.9em}\n.dsh-qa-message__content pre{overflow-x:auto;border-radius:9px;padding:12px;background:var(--dsw-alias-bg-layer-2)}\n.dsh-qa-message__content pre code{padding:0;background:transparent}\n.dsh-qa-message__content blockquote{border-left:3px solid var(--dsw-alias-border-l2);padding-left:12px;color:var(--dsw-alias-label-secondary)}\n.dsh-qa-message__cursor{display:inline-block;width:7px;height:1em;margin-left:3px;vertical-align:-2px;background:var(--dsw-alias-label-secondary);animation:dsh-qa-blink 1s steps(2,start) infinite}\n@keyframes dsh-qa-blink{50%{opacity:0}}\n.dsh-qa-error{display:flex;align-items:center;justify-content:center;gap:10px;margin:16px auto;padding:10px 12px;border:1px solid var(--dsw-alias-status-error);border-radius:10px;color:var(--dsw-alias-label-primary);font-size:13px}\n.dsh-qa-error button{border:0;background:transparent;color:var(--dsw-alias-brand-primary);font:inherit;font-weight:600;cursor:pointer}\n.dsh-qa-footer{flex:none;border-top:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);padding:0 24px max(14px,env(safe-area-inset-bottom))}\n.dsh-qa-footer__inner{position:relative;padding-top:14px}\n.dsh-qa-status{min-height:18px;margin-bottom:5px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}\n.dsh-qa-composer{display:flex;align-items:flex-end;gap:10px;border:1px solid var(--dsw-alias-border-l2);border-radius:14px;padding:7px;background:var(--dsw-alias-bg-layer-3);transition:border-color .16s}\n.dsh-qa-composer:focus-within{border-color:var(--dsw-alias-brand-primary)}\n.dsh-qa-composer textarea{flex:1;min-width:0;max-height:160px;resize:none;overflow-y:auto;border:0;outline:0;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:15px;line-height:22px;padding:7px 9px}\n.dsh-qa-composer textarea::placeholder{color:var(--dsw-alias-label-tertiary)}\n.dsh-qa-button{appearance:none;flex:none;border:1px solid transparent;border-radius:9px;padding:8px 13px;font:inherit;font-size:13px;font-weight:600;line-height:18px;cursor:pointer}\n.dsh-qa-button:focus-visible,.dsh-qa-suggestions button:focus-visible,.dsh-qa-error button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}\n.dsh-qa-button:disabled{opacity:.45;cursor:default}\n.dsh-qa-button--send{background:var(--dsw-alias-brand-primary);color:var(--dsw-alias-label-on-primary)}\n.dsh-qa-button--stop,.dsh-qa-button--secondary{border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-secondary)}\n@media (max-width:600px){.dsh-qa-header__inner{min-height:60px;padding:9px 14px}.dsh-qa-header__logo{width:32px;height:32px}.dsh-qa-header p{display:none}.dsh-qa-transcript__inner{padding:22px 14px 16px}.dsh-qa-message{max-width:90%;margin-bottom:18px}.dsh-qa-message__content{font-size:14px;padding:10px 12px}.dsh-qa-footer{padding-left:10px;padding-right:10px}.dsh-qa-button{padding-left:11px;padding-right:11px}}\n@media (max-height:480px) and (orientation:landscape){.dsh-qa-header__inner{min-height:48px;padding-top:6px;padding-bottom:6px}.dsh-qa-header p{display:none}.dsh-qa-transcript__inner{padding-top:14px}.dsh-qa-footer__inner{padding-top:7px}.dsh-qa-status{position:absolute;right:0;top:-18px}}\n@media (prefers-reduced-motion:reduce){.dsh-qa-message__cursor{animation:none}}\n`;\n","import type { Context } from \"@deepseek-ai/cordis\";\nimport type { ConnectionHandle } from \"@deepseek-ai/dsh-client-connection/client\";\nimport type { ISessions } from \"@deepseek-ai/dsh-client-runtime/client\";\nimport type { SettingsScopeBinder } from \"@deepseek-ai/dsh-client-ui-settings/client\";\nimport type {} from \"@deepseek-ai/dsh-client-ui-layout/client\";\nimport type {} from \"@deepseek-ai/dsh-client-ui-settings/client\";\nimport { QaConfigController } from \"./QaConfigController.js\";\nimport { QaRouteController } from \"./QaRouteController.js\";\nimport { QaSurface } from \"./QaSurface.js\";\nimport { QA_SURFACE_STYLES } from \"./styles.js\";\nimport type { QaSurfaceConfig } from \"../types.js\";\n\nconst SETTINGS_NAMESPACE = \"qa-surface\";\n\ndeclare module \"@deepseek-ai/cordis\" {\n interface Context {\n connection: ConnectionHandle;\n sessions: ISessions;\n settingsScope: SettingsScopeBinder;\n }\n}\n\nexport const inject = [\"slots\", \"sessions\", \"connection\", \"settingsScope\"];\n\n/** Register the route-aware, full-frame QA entry in the additive overlay slot. */\nexport function apply(ctx: Context): void {\n const route = new QaRouteController();\n const config = new QaConfigController(\n ctx.settingsScope.bind<QaSurfaceConfig>({ namespace: SETTINGS_NAMESPACE }),\n );\n const syncRoute = () => {\n const snapshot = config.getSnapshot();\n route.configure(\n snapshot.config,\n snapshot.status === \"ready\" || snapshot.status === \"unavailable\",\n );\n };\n syncRoute();\n const unsubscribeConfig = config.subscribe(syncRoute);\n\n ctx.effect(() => {\n const style = document.createElement(\"style\");\n style.dataset.dshQaSurface = \"styles\";\n style.textContent = QA_SURFACE_STYLES;\n document.head.append(style);\n return () => style.remove();\n }, \"dsh-qa-surface: styles\");\n\n ctx.effect(\n () => () => {\n unsubscribeConfig();\n config.dispose();\n route.dispose();\n },\n \"dsh-qa-surface: controllers\",\n );\n\n ctx.slots.inject(\"shell.overlay\", () =>\n ctx.slots.register(\n {\n name: \"shell.overlay\",\n id: \"dsh-qa-surface\",\n order: -10_000,\n inject: () => ({\n route,\n config,\n sessions: ctx.sessions,\n api: ctx.connection.api.sessions,\n connection: ctx.connection.hostDescription,\n }),\n },\n QaSurface,\n ),\n );\n}\n\nexport { QaConfigController } from \"./QaConfigController.js\";\nexport { QaRouteController, matchesQaRoute } from \"./QaRouteController.js\";\nexport { QaSessionController } from \"./QaSessionController.js\";\nexport { projectTranscript } from \"./QaTranscriptAdapter.js\";\n"],"mappings":"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"}
|
package/lib/config.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import z from "@deepseek-ai/schemastery";
|
|
2
|
+
const nullableString = z.union([z.string(), z.const(null)]);
|
|
3
|
+
const configSchema = z.object({
|
|
4
|
+
enabled: z.boolean().default(true),
|
|
5
|
+
route: z
|
|
6
|
+
.object({
|
|
7
|
+
path: z.string().default("/qa"),
|
|
8
|
+
matchChildren: z.boolean().default(true),
|
|
9
|
+
})
|
|
10
|
+
.default({ path: "/qa", matchChildren: true }),
|
|
11
|
+
branding: z
|
|
12
|
+
.object({
|
|
13
|
+
title: z.string().default("Assistant"),
|
|
14
|
+
subtitle: z.string().default(""),
|
|
15
|
+
welcomeMessage: z.string().default("How can I help?"),
|
|
16
|
+
placeholder: z.string().default("Ask a question..."),
|
|
17
|
+
logoUrl: nullableString.default(null),
|
|
18
|
+
})
|
|
19
|
+
.default({
|
|
20
|
+
title: "Assistant",
|
|
21
|
+
subtitle: "",
|
|
22
|
+
welcomeMessage: "How can I help?",
|
|
23
|
+
placeholder: "Ask a question...",
|
|
24
|
+
logoUrl: null,
|
|
25
|
+
}),
|
|
26
|
+
session: z
|
|
27
|
+
.object({
|
|
28
|
+
policy: z
|
|
29
|
+
.union(["browser-persistent", "new-on-load", "fixed"])
|
|
30
|
+
.default("browser-persistent"),
|
|
31
|
+
storageKey: z.string().default("dsh-qa-surface"),
|
|
32
|
+
workspaceId: nullableString.default(null),
|
|
33
|
+
fixedSessionId: nullableString.default(null),
|
|
34
|
+
agentPreset: nullableString.default(null),
|
|
35
|
+
provider: nullableString.default(null),
|
|
36
|
+
model: nullableString.default(null),
|
|
37
|
+
reasoningEffort: nullableString.default(null),
|
|
38
|
+
})
|
|
39
|
+
.default({
|
|
40
|
+
policy: "browser-persistent",
|
|
41
|
+
storageKey: "dsh-qa-surface",
|
|
42
|
+
workspaceId: null,
|
|
43
|
+
fixedSessionId: null,
|
|
44
|
+
agentPreset: null,
|
|
45
|
+
provider: null,
|
|
46
|
+
model: null,
|
|
47
|
+
reasoningEffort: null,
|
|
48
|
+
}),
|
|
49
|
+
ui: z
|
|
50
|
+
.object({
|
|
51
|
+
showHeader: z.boolean().default(true),
|
|
52
|
+
showReset: z.boolean().default(true),
|
|
53
|
+
showStop: z.boolean().default(true),
|
|
54
|
+
showTimestamps: z.boolean().default(false),
|
|
55
|
+
showToolActivity: z.boolean().default(false),
|
|
56
|
+
showReasoning: z.boolean().default(false),
|
|
57
|
+
renderMarkdown: z.boolean().default(true),
|
|
58
|
+
maxContentWidth: z.number().step(1).min(480).max(1600).default(900),
|
|
59
|
+
})
|
|
60
|
+
.default({
|
|
61
|
+
showHeader: true,
|
|
62
|
+
showReset: true,
|
|
63
|
+
showStop: true,
|
|
64
|
+
showTimestamps: false,
|
|
65
|
+
showToolActivity: false,
|
|
66
|
+
showReasoning: false,
|
|
67
|
+
renderMarkdown: true,
|
|
68
|
+
maxContentWidth: 900,
|
|
69
|
+
}),
|
|
70
|
+
suggestedQuestions: z.array(z.string()).default([]),
|
|
71
|
+
interaction: z
|
|
72
|
+
.object({
|
|
73
|
+
approvals: z.union(["blocked"]).default("blocked"),
|
|
74
|
+
questions: z.union(["unsupported"]).default("unsupported"),
|
|
75
|
+
})
|
|
76
|
+
.default({ approvals: "blocked", questions: "unsupported" }),
|
|
77
|
+
embedding: z
|
|
78
|
+
.object({ frameAncestors: nullableString.default(null) })
|
|
79
|
+
.default({ frameAncestors: null }),
|
|
80
|
+
});
|
|
81
|
+
export const ConfigSchema = configSchema;
|
|
82
|
+
export { DEFAULT_QA_SURFACE_CONFIG, normalizeRoutePath, resolveConfig, } from "./resolve-config.js";
|
|
83
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,0BAA0B,CAAC;AAGzC,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAE5D,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAClC,KAAK,EAAE,CAAC;SACL,MAAM,CAAC;QACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;QAC/B,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;KACzC,CAAC;SACD,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;IAChD,QAAQ,EAAE,CAAC;SACR,MAAM,CAAC;QACN,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC;QACtC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,iBAAiB,CAAC;QACrD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC;QACpD,OAAO,EAAE,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC;KACtC,CAAC;SACD,OAAO,CAAC;QACP,KAAK,EAAE,WAAW;QAClB,QAAQ,EAAE,EAAE;QACZ,cAAc,EAAE,iBAAiB;QACjC,WAAW,EAAE,mBAAmB;QAChC,OAAO,EAAE,IAAI;KACd,CAAC;IACJ,OAAO,EAAE,CAAC;SACP,MAAM,CAAC;QACN,MAAM,EAAE,CAAC;aACN,KAAK,CAAC,CAAC,oBAAoB,EAAE,aAAa,EAAE,OAAO,CAAU,CAAC;aAC9D,OAAO,CAAC,oBAAoB,CAAC;QAChC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC;QAChD,WAAW,EAAE,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC;QACzC,cAAc,EAAE,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC;QAC5C,WAAW,EAAE,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC;QACzC,QAAQ,EAAE,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC;QACtC,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC;QACnC,eAAe,EAAE,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC;KAC9C,CAAC;SACD,OAAO,CAAC;QACP,MAAM,EAAE,oBAAoB;QAC5B,UAAU,EAAE,gBAAgB;QAC5B,WAAW,EAAE,IAAI;QACjB,cAAc,EAAE,IAAI;QACpB,WAAW,EAAE,IAAI;QACjB,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,IAAI;QACX,eAAe,EAAE,IAAI;KACtB,CAAC;IACJ,EAAE,EAAE,CAAC;SACF,MAAM,CAAC;QACN,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;QACrC,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;QACpC,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;QACnC,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;QAC1C,gBAAgB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;QAC5C,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;QACzC,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;QACzC,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;KACpE,CAAC;SACD,OAAO,CAAC;QACP,UAAU,EAAE,IAAI;QAChB,SAAS,EAAE,IAAI;QACf,QAAQ,EAAE,IAAI;QACd,cAAc,EAAE,KAAK;QACrB,gBAAgB,EAAE,KAAK;QACvB,aAAa,EAAE,KAAK;QACpB,cAAc,EAAE,IAAI;QACpB,eAAe,EAAE,GAAG;KACrB,CAAC;IACJ,kBAAkB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACnD,WAAW,EAAE,CAAC;SACX,MAAM,CAAC;QACN,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAU,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;QAC3D,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAU,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;KACpE,CAAC;SACD,OAAO,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC;IAC9D,SAAS,EAAE,CAAC;SACT,MAAM,CAAC,EAAE,cAAc,EAAE,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;SACxD,OAAO,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC;CACrC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,YAA6C,CAAC;AAC1E,OAAO,EACL,yBAAyB,EACzB,kBAAkB,EAClB,aAAa,GACd,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { QA_NAVIGATION_MARKER } from "./navigation-marker.js";
|
|
2
|
+
/**
|
|
3
|
+
* DSH 0.1.1 static hosting returns 404 for missing paths. Redirect a browser
|
|
4
|
+
* navigation through its canonical index entry; the client restores the
|
|
5
|
+
* requested pathname before activating the QA overlay.
|
|
6
|
+
*/
|
|
7
|
+
export function registerQaNavigationRoute(webServer, config) {
|
|
8
|
+
return webServer.register({
|
|
9
|
+
kind: config.route.matchChildren ? "prefix" : "exact",
|
|
10
|
+
path: config.route.path,
|
|
11
|
+
handler: (request, response) => {
|
|
12
|
+
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
13
|
+
response.writeHead(405, { allow: "GET, HEAD" });
|
|
14
|
+
response.end();
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const requested = request.url ?? config.route.path;
|
|
18
|
+
const location = `/?${QA_NAVIGATION_MARKER}=${encodeURIComponent(requested)}`;
|
|
19
|
+
response.writeHead(302, {
|
|
20
|
+
location,
|
|
21
|
+
"cache-control": "no-store",
|
|
22
|
+
});
|
|
23
|
+
response.end();
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=host-route.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-route.js","sourceRoot":"","sources":["../src/host-route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CACvC,SAAsC,EACtC,MAA+B;IAE/B,OAAO,SAAS,CAAC,QAAQ,CAAC;QACxB,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO;QACrD,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI;QACvB,OAAO,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE;YAC7B,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC1D,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;gBAChD,QAAQ,CAAC,GAAG,EAAE,CAAC;gBACf,OAAO;YACT,CAAC;YACD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;YACnD,MAAM,QAAQ,GAAG,KAAK,oBAAoB,IAAI,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9E,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE;gBACtB,QAAQ;gBACR,eAAe,EAAE,UAAU;aAC5B,CAAC,CAAC;YACH,QAAQ,CAAC,GAAG,EAAE,CAAC;QACjB,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Service } from "@deepseek-ai/cordis";
|
|
2
|
+
import { installSettingsSection, settingsNamespace, } from "@deepseek-ai/dsh-settings";
|
|
3
|
+
import { createHostLoggerSink, getPluginLogger, } from "@yadsh/dsh-plugin-log";
|
|
4
|
+
import { ConfigSchema, resolveConfig } from "./config.js";
|
|
5
|
+
import { registerQaNavigationRoute } from "./host-route.js";
|
|
6
|
+
export const name = "qa-surface";
|
|
7
|
+
export const inject = [];
|
|
8
|
+
export const QA_SURFACE_SETTINGS_NAMESPACE = settingsNamespace("qa-surface");
|
|
9
|
+
export const Config = ConfigSchema;
|
|
10
|
+
/** Small Host companion: validates config and exposes it through DSH settings. */
|
|
11
|
+
export class QaSurface extends Service {
|
|
12
|
+
static inject = inject;
|
|
13
|
+
static Config = ConfigSchema;
|
|
14
|
+
source;
|
|
15
|
+
logger;
|
|
16
|
+
webServer;
|
|
17
|
+
disposeRoute;
|
|
18
|
+
routeKey;
|
|
19
|
+
constructor(ctx, entry = {}) {
|
|
20
|
+
super(ctx, "qaSurface");
|
|
21
|
+
const resolvedEntry = resolveConfig(entry);
|
|
22
|
+
this.source = () => resolvedEntry;
|
|
23
|
+
this.logger = getPluginLogger({
|
|
24
|
+
pluginId: "dsh-qa-surface",
|
|
25
|
+
consoleSink: createHostLoggerSink(ctx.logger),
|
|
26
|
+
});
|
|
27
|
+
ctx.effect(() => async () => this.logger.close(), "dsh-qa-surface.logger");
|
|
28
|
+
installSettingsSection(ctx, QA_SURFACE_SETTINGS_NAMESPACE, ConfigSchema, entry, {
|
|
29
|
+
setSource: (source) => {
|
|
30
|
+
this.source = source;
|
|
31
|
+
},
|
|
32
|
+
onChange: () => {
|
|
33
|
+
const config = this.getConfig();
|
|
34
|
+
this.refreshRoute();
|
|
35
|
+
this.logger.info("config.updated", {
|
|
36
|
+
enabled: config.enabled,
|
|
37
|
+
route: config.route.path,
|
|
38
|
+
sessionPolicy: config.session.policy,
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
validate: (value) => {
|
|
42
|
+
resolveConfig(value);
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
ctx.inject(["webServer"], (webContext) => {
|
|
46
|
+
this.webServer = webContext.webServer;
|
|
47
|
+
this.refreshRoute();
|
|
48
|
+
webContext.effect(() => () => {
|
|
49
|
+
this.disposeRoute?.();
|
|
50
|
+
this.disposeRoute = undefined;
|
|
51
|
+
this.routeKey = undefined;
|
|
52
|
+
this.webServer = undefined;
|
|
53
|
+
}, "dsh-qa-surface.navigation-route");
|
|
54
|
+
});
|
|
55
|
+
this.logger.info("plugin.ready", {
|
|
56
|
+
enabled: resolvedEntry.enabled,
|
|
57
|
+
route: resolvedEntry.route.path,
|
|
58
|
+
sessionPolicy: resolvedEntry.session.policy,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
getConfig() {
|
|
62
|
+
return resolveConfig(this.source());
|
|
63
|
+
}
|
|
64
|
+
refreshRoute() {
|
|
65
|
+
const config = this.getConfig();
|
|
66
|
+
const key = config.enabled
|
|
67
|
+
? `${config.route.path}:${config.route.matchChildren}`
|
|
68
|
+
: undefined;
|
|
69
|
+
if (key === this.routeKey)
|
|
70
|
+
return;
|
|
71
|
+
this.disposeRoute?.();
|
|
72
|
+
this.disposeRoute = undefined;
|
|
73
|
+
this.routeKey = undefined;
|
|
74
|
+
if (key === undefined || this.webServer === undefined)
|
|
75
|
+
return;
|
|
76
|
+
this.disposeRoute = registerQaNavigationRoute(this.webServer, config);
|
|
77
|
+
this.routeKey = key;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export { ConfigSchema, DEFAULT_QA_SURFACE_CONFIG, normalizeRoutePath, resolveConfig, } from "./config.js";
|
|
81
|
+
export { registerQaNavigationRoute } from "./host-route.js";
|
|
82
|
+
export default QaSurface;
|
|
83
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation-marker.js","sourceRoot":"","sources":["../src/navigation-marker.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,MAAM,CAAC,MAAM,oBAAoB,GAAG,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
export const DEFAULT_QA_SURFACE_CONFIG = Object.freeze({
|
|
2
|
+
enabled: true,
|
|
3
|
+
route: Object.freeze({ path: "/qa", matchChildren: true }),
|
|
4
|
+
branding: Object.freeze({
|
|
5
|
+
title: "Assistant",
|
|
6
|
+
subtitle: "",
|
|
7
|
+
welcomeMessage: "How can I help?",
|
|
8
|
+
placeholder: "Ask a question...",
|
|
9
|
+
logoUrl: null,
|
|
10
|
+
}),
|
|
11
|
+
session: Object.freeze({
|
|
12
|
+
policy: "browser-persistent",
|
|
13
|
+
storageKey: "dsh-qa-surface",
|
|
14
|
+
workspaceId: null,
|
|
15
|
+
fixedSessionId: null,
|
|
16
|
+
agentPreset: null,
|
|
17
|
+
provider: null,
|
|
18
|
+
model: null,
|
|
19
|
+
reasoningEffort: null,
|
|
20
|
+
}),
|
|
21
|
+
ui: Object.freeze({
|
|
22
|
+
showHeader: true,
|
|
23
|
+
showReset: true,
|
|
24
|
+
showStop: true,
|
|
25
|
+
showTimestamps: false,
|
|
26
|
+
showToolActivity: false,
|
|
27
|
+
showReasoning: false,
|
|
28
|
+
renderMarkdown: true,
|
|
29
|
+
maxContentWidth: 900,
|
|
30
|
+
}),
|
|
31
|
+
suggestedQuestions: Object.freeze([]),
|
|
32
|
+
interaction: Object.freeze({
|
|
33
|
+
approvals: "blocked",
|
|
34
|
+
questions: "unsupported",
|
|
35
|
+
}),
|
|
36
|
+
embedding: Object.freeze({ frameAncestors: null }),
|
|
37
|
+
});
|
|
38
|
+
function optionalText(value) {
|
|
39
|
+
const trimmed = value?.trim() ?? "";
|
|
40
|
+
return trimmed === "" ? null : trimmed;
|
|
41
|
+
}
|
|
42
|
+
export function normalizeRoutePath(value) {
|
|
43
|
+
const trimmed = value.trim();
|
|
44
|
+
if (trimmed === "" || !trimmed.startsWith("/")) {
|
|
45
|
+
throw new TypeError("dsh-qa-surface: route.path must start with /");
|
|
46
|
+
}
|
|
47
|
+
const path = trimmed.length > 1 ? trimmed.replace(/\/+$/u, "") : trimmed;
|
|
48
|
+
if (path === "/") {
|
|
49
|
+
throw new TypeError("dsh-qa-surface: route.path cannot replace the operator root");
|
|
50
|
+
}
|
|
51
|
+
if (path === "/api" || path.startsWith("/api/")) {
|
|
52
|
+
throw new TypeError("dsh-qa-surface: route.path cannot claim /api");
|
|
53
|
+
}
|
|
54
|
+
if (path === "/plugins" || path.startsWith("/plugins/")) {
|
|
55
|
+
throw new TypeError("dsh-qa-surface: route.path cannot claim /plugins");
|
|
56
|
+
}
|
|
57
|
+
return path;
|
|
58
|
+
}
|
|
59
|
+
function uniqueQuestions(values) {
|
|
60
|
+
const questions = [
|
|
61
|
+
...new Set(values.map((value) => value.trim()).filter(Boolean)),
|
|
62
|
+
];
|
|
63
|
+
if (questions.some((value) => value.length > 500)) {
|
|
64
|
+
throw new TypeError("dsh-qa-surface: suggested questions must be at most 500 characters");
|
|
65
|
+
}
|
|
66
|
+
return Object.freeze(questions);
|
|
67
|
+
}
|
|
68
|
+
/** Materialize defaults and enforce route/session/model safety constraints. */
|
|
69
|
+
export function resolveConfig(input = {}) {
|
|
70
|
+
const routePath = normalizeRoutePath(input.route?.path ?? DEFAULT_QA_SURFACE_CONFIG.route.path);
|
|
71
|
+
const policy = input.session?.policy ?? DEFAULT_QA_SURFACE_CONFIG.session.policy;
|
|
72
|
+
const fixedSessionId = optionalText(input.session?.fixedSessionId);
|
|
73
|
+
if (policy === "fixed" && fixedSessionId === null) {
|
|
74
|
+
throw new TypeError("dsh-qa-surface: session.fixedSessionId is required for fixed policy");
|
|
75
|
+
}
|
|
76
|
+
const provider = optionalText(input.session?.provider);
|
|
77
|
+
const model = optionalText(input.session?.model);
|
|
78
|
+
if ((provider === null) !== (model === null)) {
|
|
79
|
+
throw new TypeError("dsh-qa-surface: session.provider and session.model must be set together");
|
|
80
|
+
}
|
|
81
|
+
const storageKey = input.session?.storageKey?.trim() ??
|
|
82
|
+
DEFAULT_QA_SURFACE_CONFIG.session.storageKey;
|
|
83
|
+
if (storageKey === "") {
|
|
84
|
+
throw new TypeError("dsh-qa-surface: session.storageKey cannot be empty");
|
|
85
|
+
}
|
|
86
|
+
const maxContentWidth = input.ui?.maxContentWidth ?? DEFAULT_QA_SURFACE_CONFIG.ui.maxContentWidth;
|
|
87
|
+
if (!Number.isSafeInteger(maxContentWidth) ||
|
|
88
|
+
maxContentWidth < 480 ||
|
|
89
|
+
maxContentWidth > 1600) {
|
|
90
|
+
throw new TypeError("dsh-qa-surface: ui.maxContentWidth must be an integer from 480 to 1600");
|
|
91
|
+
}
|
|
92
|
+
if (input.ui?.showReasoning === true) {
|
|
93
|
+
throw new TypeError("dsh-qa-surface: ui.showReasoning is not supported by the safe MVP surface");
|
|
94
|
+
}
|
|
95
|
+
return Object.freeze({
|
|
96
|
+
enabled: input.enabled ?? DEFAULT_QA_SURFACE_CONFIG.enabled,
|
|
97
|
+
route: Object.freeze({
|
|
98
|
+
path: routePath,
|
|
99
|
+
matchChildren: input.route?.matchChildren ??
|
|
100
|
+
DEFAULT_QA_SURFACE_CONFIG.route.matchChildren,
|
|
101
|
+
}),
|
|
102
|
+
branding: Object.freeze({
|
|
103
|
+
title: input.branding?.title?.trim() ||
|
|
104
|
+
DEFAULT_QA_SURFACE_CONFIG.branding.title,
|
|
105
|
+
subtitle: input.branding?.subtitle?.trim() ?? "",
|
|
106
|
+
welcomeMessage: input.branding?.welcomeMessage?.trim() ??
|
|
107
|
+
DEFAULT_QA_SURFACE_CONFIG.branding.welcomeMessage,
|
|
108
|
+
placeholder: input.branding?.placeholder?.trim() ||
|
|
109
|
+
DEFAULT_QA_SURFACE_CONFIG.branding.placeholder,
|
|
110
|
+
logoUrl: optionalText(input.branding?.logoUrl),
|
|
111
|
+
}),
|
|
112
|
+
session: Object.freeze({
|
|
113
|
+
policy,
|
|
114
|
+
storageKey,
|
|
115
|
+
workspaceId: optionalText(input.session?.workspaceId),
|
|
116
|
+
fixedSessionId,
|
|
117
|
+
agentPreset: optionalText(input.session?.agentPreset),
|
|
118
|
+
provider,
|
|
119
|
+
model,
|
|
120
|
+
reasoningEffort: optionalText(input.session?.reasoningEffort),
|
|
121
|
+
}),
|
|
122
|
+
ui: Object.freeze({
|
|
123
|
+
showHeader: input.ui?.showHeader ?? DEFAULT_QA_SURFACE_CONFIG.ui.showHeader,
|
|
124
|
+
showReset: input.ui?.showReset ?? DEFAULT_QA_SURFACE_CONFIG.ui.showReset,
|
|
125
|
+
showStop: input.ui?.showStop ?? DEFAULT_QA_SURFACE_CONFIG.ui.showStop,
|
|
126
|
+
showTimestamps: input.ui?.showTimestamps ?? DEFAULT_QA_SURFACE_CONFIG.ui.showTimestamps,
|
|
127
|
+
showToolActivity: input.ui?.showToolActivity ??
|
|
128
|
+
DEFAULT_QA_SURFACE_CONFIG.ui.showToolActivity,
|
|
129
|
+
showReasoning: false,
|
|
130
|
+
renderMarkdown: input.ui?.renderMarkdown ?? DEFAULT_QA_SURFACE_CONFIG.ui.renderMarkdown,
|
|
131
|
+
maxContentWidth,
|
|
132
|
+
}),
|
|
133
|
+
suggestedQuestions: uniqueQuestions(input.suggestedQuestions ?? []),
|
|
134
|
+
interaction: Object.freeze({
|
|
135
|
+
approvals: "blocked",
|
|
136
|
+
questions: "unsupported",
|
|
137
|
+
}),
|
|
138
|
+
embedding: Object.freeze({
|
|
139
|
+
frameAncestors: optionalText(input.embedding?.frameAncestors),
|
|
140
|
+
}),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=resolve-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-config.js","sourceRoot":"","sources":["../src/resolve-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { SettingsScope } from "@deepseek-ai/dsh-client-runtime/client";
|
|
2
|
+
import type { QaSurfaceConfig, ResolvedQaSurfaceConfig } from "../types.js";
|
|
3
|
+
export interface QaConfigSnapshot {
|
|
4
|
+
readonly status: "loading" | "ready" | "unavailable" | "error";
|
|
5
|
+
readonly config: ResolvedQaSurfaceConfig;
|
|
6
|
+
readonly error: string | null;
|
|
7
|
+
}
|
|
8
|
+
/** Browser projection of the Host-owned qa-surface settings namespace. */
|
|
9
|
+
export declare class QaConfigController {
|
|
10
|
+
private readonly scope;
|
|
11
|
+
private readonly listeners;
|
|
12
|
+
private snapshot;
|
|
13
|
+
private readonly unsubscribe;
|
|
14
|
+
constructor(scope: SettingsScope<QaSurfaceConfig>);
|
|
15
|
+
getSnapshot: () => QaConfigSnapshot;
|
|
16
|
+
subscribe: (listener: () => void) => (() => void);
|
|
17
|
+
dispose(): void;
|
|
18
|
+
private project;
|
|
19
|
+
private refresh;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=QaConfigController.d.ts.map
|