gz-research-assistant 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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recorder-Da1VSLid.js","names":[],"sources":["../src/privacy.ts","../src/performance.ts","../src/runtime.ts","../src/snapshot.ts","../src/automation/recorder.ts"],"sourcesContent":["const secretKey =\n /password|passwd|pwd|token|authorization|cookie|secret|credential|session|api[-_]?key|身份证|手机号|银行卡|证件|phone|mobile|email|idcard|bankcard/i;\n\nexport function safeText(value: string, limit = 600): string {\n return value\n .slice(0, 12000)\n .replace(/Bearer\\s+[^\\s,;\"']+/gi, 'Bearer [已脱敏]')\n .replace(/\\beyJ[\\w-]+\\.[\\w-]+\\.[\\w-]+\\b/g, '[令牌已脱敏]')\n .replace(\n /((?:password|passwd|pwd|token|secret|authorization|cookie|session(?:id)?|api[-_]?key)[\"']?\\s*[=:]\\s*[\"']?)[^\"'\\s,;&]+/gi,\n '$1[已脱敏]',\n )\n .replace(/\\b1[3-9]\\d{9}\\b/g, '[手机号已脱敏]')\n .replace(/\\b\\d{17}[\\dXx]\\b/g, '[证件号已脱敏]')\n .replace(/[\\w.+-]+@[\\w.-]+\\.[a-z]{2,}/gi, '[邮箱已脱敏]')\n .slice(0, limit);\n}\n\nexport function safeUrl(value: string): string {\n try {\n const url = new URL(value, location.origin);\n if (!['http:', 'https:'].includes(url.protocol)) return '[' + url.protocol + ']';\n const keys = [...new Set(url.searchParams.keys())].slice(0, 20);\n // Query and fragment values can carry auth state or business identifiers.\n return (\n safeText(url.origin + url.pathname, 300) +\n (keys.length\n ? '?' + keys.map((key) => encodeURIComponent(safeText(key, 40)) + '=[已脱敏]').join('&')\n : '') +\n (url.hash ? '#[已省略]' : '')\n );\n } catch {\n return '[无效地址]';\n }\n}\n\nexport function sanitize(value: unknown, depth = 0, seen = new WeakSet<object>()): unknown {\n if (depth > 5) return '[层级已截断]';\n if (typeof value === 'string') return safeText(value);\n if (value === null || typeof value === 'number' || typeof value === 'boolean') return value;\n if (value instanceof Error)\n return {\n name: safeText(value.name),\n message: safeText(value.message),\n stack: safeText(value.stack ?? '', 1800),\n };\n if (typeof value !== 'object') return String(value).slice(0, 80);\n if (seen.has(value)) return '[循环引用]';\n seen.add(value);\n if (Array.isArray(value))\n return value.slice(0, 30).map((item) => sanitize(item, depth + 1, seen));\n return Object.fromEntries(\n Object.entries(value)\n .slice(0, 50)\n .map(([key, item]) => [\n safeText(key, 80),\n secretKey.test(key) ? '[已脱敏]' : sanitize(item, depth + 1, seen),\n ]),\n );\n}\n\nexport function bodyPreview(body: unknown): unknown {\n if (typeof body !== 'string') return body == null ? null : '[非文本正文未采集]';\n if (body.length > 16000) return '[正文超过 16 KB,未采集]';\n try {\n return sanitize(JSON.parse(body));\n } catch {\n return '[非 JSON 正文未采集]';\n }\n}\n\nexport function privateEndpoint(url: string): boolean {\n return /\\/(?:login|logininfo|logout|auth|oauth|token|password|session)(?:\\/|\\?|$)/i.test(url);\n}\n","export interface HeapSample {\n time: number;\n used: number;\n limit: number;\n}\nexport interface PerformanceEvidence {\n heapSamples: HeapSample[];\n longTasks: { time: number; duration: number }[];\n}\nexport interface PerformanceIssue {\n id: string;\n severity: 'warning' | 'error';\n title: string;\n evidence: string;\n rule: string;\n suggestions: string[];\n url: string;\n}\nexport const emptyPerformance = (): PerformanceEvidence => ({ heapSamples: [], longTasks: [] });\nexport const megabytes = (bytes: number) => `${(bytes / 1048576).toFixed(1)} MB`;\n\n/** Local heuristics: heap growth is evidence to investigate, never proof of a leak. */\nexport function diagnosePerformance(\n metrics: Record<string, number>,\n data: PerformanceEvidence,\n now: number,\n): PerformanceIssue[] {\n const issues: PerformanceIssue[] = [];\n if (metrics.LCP > 2500)\n issues.push({\n id: 'lcp',\n severity: metrics.LCP > 4000 ? 'error' : 'warning',\n title: '主要内容显示偏慢',\n evidence: `本次页面加载 LCP 为 ${Math.round(metrics.LCP)} ms`,\n rule: 'LCP > 2.5 秒需改进,> 4 秒较差;此处为单次页面观测,不代表站点分位数。',\n suggestions: [\n '在 DevTools Performance 中录制页面加载,定位 LCP 元素。',\n '检查关键图片大小、资源优先级与接口等待,减少阻塞渲染的脚本。',\n ],\n url: 'https://web.dev/articles/lcp',\n });\n if (metrics.CLS > 0.1)\n issues.push({\n id: 'cls',\n severity: metrics.CLS > 0.25 ? 'error' : 'warning',\n title: '页面布局存在明显跳动',\n evidence: `本次页面生命周期 CLS 为 ${metrics.CLS.toFixed(3)}`,\n rule: 'CLS > 0.1 需改进,> 0.25 较差;采用布局偏移会话窗口统计。',\n suggestions: [\n '在 DevTools Performance 的 Layout shifts 轨道查看发生偏移的元素。',\n '为图片、表格和异步内容预留空间,检查字体替换和顶部动态插入内容。',\n ],\n url: 'https://web.dev/articles/optimize-cls',\n });\n const tasks = data.longTasks.filter((task) => task.time <= now && now - task.time <= 30000);\n const total = tasks.reduce((sum, task) => sum + task.duration, 0);\n const longest = Math.max(0, ...tasks.map((task) => task.duration));\n if (longest >= 200 || total >= 1000)\n issues.push({\n id: 'long-task',\n severity: longest >= 1000 ? 'error' : 'warning',\n title: '主线程可能出现卡顿',\n evidence: `最近 30 秒 ${tasks.length} 次长任务,最长 ${Math.round(longest)} ms,累计 ${Math.round(total)} ms`,\n rule: '本地告警规则:单次 ≥ 200 ms,或 30 秒累计 ≥ 1,000 ms;长任务采集门槛为 50 ms。',\n suggestions: [\n '在 DevTools Performance 中录制卡顿操作,展开 Main 轨道中的长任务。',\n '检查大循环、重复渲染和同步 JSON 处理;拆分任务,长列表使用虚拟滚动。',\n ],\n url: 'https://developer.chrome.com/docs/devtools/performance',\n });\n // Require consecutive visible, unpaused samples. Gaps must not imply steady growth.\n const samples: HeapSample[] = [];\n for (const sample of data.heapSamples) {\n if (sample.time > now || now - sample.time > 90000) continue;\n if (samples.length && sample.time - samples[samples.length - 1].time > 10000)\n samples.length = 0;\n samples.push(sample);\n }\n const last = samples.at(-1);\n if (!last || now - last.time > 10000) return issues;\n const recent = samples.slice(-3);\n if (recent.length === 3 && recent.every((s) => s.limit > 0 && s.used / s.limit >= 0.8))\n issues.push({\n id: 'heap-pressure',\n severity: 'error',\n title: 'JS 堆内存压力偏高',\n evidence: `当前 ${megabytes(last.used)} / 堆上限 ${megabytes(last.limit)}(${Math.round((last.used / last.limit) * 100)}%)`,\n rule: '本地告警规则:连续 3 次采样 ≥ 浏览器 JS 堆上限的 80%。',\n suggestions: [\n '在 Chrome 任务管理器核对内存占用,并在 Memory 中比较堆快照。',\n '检查大数组、缓存和未释放的对象;按实际设备验证内存预算。',\n ],\n url: 'https://developer.chrome.com/docs/devtools/memory-problems',\n });\n if (samples.length >= 13 && last.time - samples[0].time >= 60000) {\n const size = Math.floor(samples.length / 3);\n const floor = (values: HeapSample[]) => Math.min(...values.map((s) => s.used));\n const first = floor(samples.slice(0, size));\n const middle = floor(samples.slice(size, size * 2));\n const end = floor(samples.slice(size * 2));\n const growth = end - first;\n if (\n first > 0 &&\n growth >= 20 * 1048576 &&\n growth / first >= 0.3 &&\n middle > first &&\n end > middle\n )\n issues.push({\n id: 'heap-growth',\n severity: 'warning',\n title: '内存持续增长,建议排查泄漏',\n evidence: `${Math.round((last.time - samples[0].time) / 1000)} 秒内,分段内存低点增加 ${megabytes(growth)}(${Math.round((growth / first) * 100)}%)`,\n rule: '本地风险规则:至少连续 60 秒、13 次采样,三段低点依次增长,增量 ≥ 20 MB 且 ≥ 30%。这不是泄漏结论。',\n suggestions: [\n '重复进入、退出同一业务页面,再静置观察内存是否回落。',\n '在 DevTools Memory 手动回收垃圾后分别拍摄堆快照,用 Comparison 比较持续保留的对象。',\n '检查 Detached DOM、事件监听器、定时器、订阅和缓存的清理;用 Allocation instrumentation 定位分配来源。',\n ],\n url: 'https://developer.chrome.com/docs/devtools/memory-problems',\n });\n }\n return issues;\n}\n","import { bodyPreview, privateEndpoint, safeText, safeUrl, sanitize } from './privacy';\nimport { diagnosePerformance, emptyPerformance, type PerformanceEvidence } from './performance';\nimport { describeControl, privateInput, controls, excluded } from 'gz-laya-pilot/browser';\n\nexport interface AssistantOptions {\n /** Business response codes belong to the host, not the generic recorder. */\n isBusinessFailure?: (body: unknown) => boolean;\n ignoreRequest?: (url: URL) => boolean;\n}\n\nexport type EventKind = 'route' | 'click' | 'change' | 'request' | 'error' | 'performance';\nexport interface TraceEvent {\n id: number;\n time: number;\n kind: EventKind;\n title: string;\n page: string;\n actionId?: number;\n detail?: unknown;\n}\nexport interface NetworkRecord {\n id: number;\n time: number;\n actionId?: number;\n method: string;\n url: string;\n status: number;\n duration: number;\n failed: boolean;\n source: 'fetch' | 'xhr';\n request?: unknown;\n response?: unknown;\n resourceCode?: string;\n message?: string;\n}\nexport interface Snapshot {\n schema: 'zhidao-research-assistant';\n version: 1;\n capturedAt: string;\n reason: string;\n feedback?: string;\n page: ReturnType<typeof pageState>;\n environment: ReturnType<typeof environment>;\n metrics: Record<string, number>;\n performance?: PerformanceEvidence;\n events: TraceEvent[];\n requests: NetworkRecord[];\n limits: { events: number; requests: number; retentionMinutes: number };\n}\ninterface RuntimeState {\n events: TraceEvent[];\n requests: NetworkRecord[];\n metrics: Record<string, number>;\n performance: PerformanceEvidence;\n performanceUpdatedAt: number;\n paused: boolean;\n frozen: Snapshot | null;\n}\nconst MAX_EVENTS = 300,\n MAX_REQUESTS = 60,\n RETENTION = 15 * 60 * 1000;\nlet state: RuntimeState = {\n events: [],\n requests: [],\n metrics: {},\n performance: emptyPerformance(),\n performanceUpdatedAt: Date.now(),\n paused: false,\n frozen: null,\n};\nlet activePerformanceIssues = new Set<string>();\nlet sequence = 0,\n actionId: number | undefined,\n active = false,\n generation = 0;\nlet notifyTimer: ReturnType<typeof setTimeout> | undefined;\nconst subscribers = new Set<() => void>();\nlet dispose: (() => void) | undefined;\n\nfunction publish() {\n if (notifyTimer) return;\n notifyTimer = setTimeout(() => {\n notifyTimer = undefined;\n subscribers.forEach((fn) => fn());\n }, 150);\n}\nfunction prune() {\n const after = Date.now() - RETENTION;\n state = {\n ...state,\n events: state.events.filter((e) => e.time >= after).slice(-MAX_EVENTS),\n requests: state.requests.filter((e) => e.time >= after).slice(-MAX_REQUESTS),\n performanceUpdatedAt: Date.now(),\n };\n}\nfunction add(\n kind: EventKind,\n title: string,\n detail?: unknown,\n time = Date.now(),\n relatedAction = actionId,\n) {\n if (!active || state.paused) return;\n const event: TraceEvent = {\n id: ++sequence,\n time,\n kind,\n title: safeText(title, 180),\n page: safeUrl(location.href),\n actionId: relatedAction,\n detail: sanitize(detail),\n };\n if (kind === 'click' || kind === 'change' || kind === 'route') actionId = event.id;\n state = { ...state, events: [...state.events, event] };\n prune();\n publish();\n}\nfunction elementLabel(element: Element | null) {\n if (!element) return '';\n return privateInput(element) ? '[敏感控件]' : safeText(describeControl(element).label, 70);\n}\nfunction pageState() {\n return {\n url: safeUrl(location.href),\n title: safeText(document.title, 100),\n viewport: { width: innerWidth, height: innerHeight, pixelRatio: devicePixelRatio },\n scroll: { x: scrollX, y: scrollY },\n visibility: document.visibilityState,\n focusedControl: elementLabel(document.activeElement),\n headings: [...document.querySelectorAll('h1,h2,h3')]\n .filter((e) => !e.closest('[data-research-assistant]'))\n .slice(0, 12)\n .map((e) => safeText(e.textContent ?? '', 80)),\n domNodes: document.getElementsByTagName('*').length,\n iframeCount: document.querySelectorAll('iframe').length,\n };\n}\nfunction storageKeys(store: 'localStorage' | 'sessionStorage') {\n try {\n return Array.from({ length: Math.min(window[store].length, 60) }, (_, i) =>\n safeText(window[store].key(i) ?? '', 100),\n );\n } catch {\n return ['[浏览器禁止访问]'];\n }\n}\nexport function environment() {\n const performanceWithMemory = performance as Performance & {\n memory?: { usedJSHeapSize: number; totalJSHeapSize: number; jsHeapSizeLimit: number };\n };\n const nav = navigator as Navigator & {\n deviceMemory?: number;\n connection?: { effectiveType?: string; downlink?: number; rtt?: number; saveData?: boolean };\n };\n let cookies: string[] = [];\n try {\n cookies = document.cookie\n .split(';')\n .filter((v) => v.trim())\n .slice(0, 60)\n .map((v) => safeText(v.split('=')[0].trim(), 100));\n } catch {\n cookies = ['[浏览器禁止访问]'];\n }\n return {\n userAgent: safeText(navigator.userAgent, 300),\n language: navigator.language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n online: navigator.onLine,\n cpuThreads: navigator.hardwareConcurrency,\n deviceMemoryGB: nav.deviceMemory ?? null,\n heap: performanceWithMemory.memory\n ? {\n ...{\n usedJSHeapSize: performanceWithMemory.memory.usedJSHeapSize,\n totalJSHeapSize: performanceWithMemory.memory.totalJSHeapSize,\n jsHeapSizeLimit: performanceWithMemory.memory.jsHeapSizeLimit,\n },\n }\n : null,\n connection: nav.connection\n ? {\n effectiveType: nav.connection.effectiveType,\n downlinkMbps: nav.connection.downlink,\n rttMs: nav.connection.rtt,\n saveData: nav.connection.saveData,\n }\n : null,\n cookies,\n localStorageKeys: storageKeys('localStorage'),\n sessionStorageKeys: storageKeys('sessionStorage'),\n coverage: '仅当前窗口;跨域 iframe 未接入。Cookie 不包含 HttpOnly,所有存储值均不采集。',\n };\n}\nexport function captureSnapshot(reason = '手动截取现场'): Snapshot {\n prune();\n return structuredClone({\n schema: 'zhidao-research-assistant',\n version: 1,\n capturedAt: new Date().toISOString(),\n reason: safeText(reason),\n page: pageState(),\n environment: environment(),\n metrics: state.metrics,\n performance: state.performance,\n events: state.events,\n requests: state.requests,\n limits: { events: MAX_EVENTS, requests: MAX_REQUESTS, retentionMinutes: RETENTION / 60000 },\n });\n}\nexport function freezeSnapshot(reason?: string) {\n state = { ...state, frozen: captureSnapshot(reason) };\n publish();\n}\nexport function reportError(title: string, detail?: unknown) {\n if (!active || state.paused) return;\n add('error', title, detail);\n freezeSnapshot(title);\n}\nexport const assistantRuntime = {\n subscribe(fn: () => void) {\n subscribers.add(fn);\n return () => {\n subscribers.delete(fn);\n };\n },\n getState: () => state,\n pause(paused: boolean) {\n generation++;\n state = { ...state, paused, performance: emptyPerformance() };\n activePerformanceIssues.clear();\n publish();\n },\n clear() {\n generation++;\n actionId = undefined;\n state = {\n ...state,\n events: [],\n requests: [],\n metrics: {},\n performance: emptyPerformance(),\n frozen: null,\n };\n activePerformanceIssues.clear();\n publish();\n },\n};\nfunction finishNetwork(record: NetworkRecord, session: number) {\n if (!active || state.paused || generation !== session) return;\n state = { ...state, requests: [...state.requests, record].slice(-MAX_REQUESTS) };\n add(\n 'request',\n `${record.method} ${record.url} · ${record.status || '网络错误'} · ${Math.round(record.duration)} ms`,\n { requestId: record.id, failed: record.failed },\n record.time,\n record.actionId,\n );\n if (record.failed)\n reportError('接口调用失败', {\n requestId: record.id,\n url: record.url,\n status: record.status,\n message: record.message,\n });\n}\nasync function readResponse(response: Response) {\n if (!response.headers.get('content-type')?.includes('json')) return '[非 JSON 响应未采集]';\n if (Number(response.headers.get('content-length')) > 16000) return '[响应超过 16 KB,未采集]';\n const clone = response.clone();\n const reader = clone.body?.getReader();\n if (!reader) return null;\n let text = '',\n size = 0;\n const decoder = new TextDecoder();\n let timedOut = false;\n const timeout = setTimeout(() => {\n timedOut = true;\n void reader.cancel().catch(() => {});\n }, 2500);\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n size += value.byteLength;\n if (size > 16000) {\n void reader.cancel().catch(() => {});\n return '[响应超过 16 KB,已截断]';\n }\n text += decoder.decode(value, { stream: true });\n }\n return timedOut ? '[响应预览超时,未采集]' : bodyPreview(text + decoder.decode());\n } finally {\n clearTimeout(timeout);\n reader.releaseLock();\n }\n}\nexport function startAssistant(options: AssistantOptions = {}): () => void {\n if (dispose) return dispose;\n const businessFailure = (value: unknown) => {\n try {\n return options.isBusinessFailure?.(value) === true;\n } catch {\n return false;\n }\n };\n active = true;\n const cleanups: (() => void)[] = [];\n const listen = (target: EventTarget, type: string, listener: EventListener, capture = false) => {\n target.addEventListener(type, listener, capture);\n cleanups.push(() => target.removeEventListener(type, listener, capture));\n };\n listen(\n document,\n 'click',\n (e) => {\n const element = e.target instanceof Element ? e.target : null;\n if (element?.closest(excluded)) return;\n const control = element?.closest(controls);\n if (control && !privateInput(control))\n add('click', '点击:' + elementLabel(control), { target: describeControl(control) });\n },\n true,\n );\n listen(\n document,\n 'change',\n (e) => {\n const element = e.target instanceof Element ? e.target : null;\n if (!element || element.closest(excluded) || privateInput(element)) return;\n add('change', '修改字段:' + elementLabel(element), {\n target: describeControl(element),\n value: '[不采集输入值]',\n });\n },\n true,\n );\n const route = () => add('route', '进入页面', { url: safeUrl(location.href) });\n for (const method of ['pushState', 'replaceState'] as const) {\n const original = history[method];\n const wrapper: History[typeof method] = function (this: History, ...args) {\n const result = original.apply(this, args);\n route();\n return result;\n };\n history[method] = wrapper;\n cleanups.push(() => {\n if (history[method] === wrapper) history[method] = original;\n });\n }\n listen(window, 'popstate', route);\n listen(window, 'hashchange', route);\n listen(\n window,\n 'error',\n (event) => {\n if (event instanceof ErrorEvent) reportError(event.message || '运行错误', event.error);\n else if (event.target instanceof Element)\n reportError('资源加载失败', {\n tag: event.target.tagName,\n url: safeUrl(event.target.getAttribute('src') || event.target.getAttribute('href') || ''),\n });\n },\n true,\n );\n listen(window, 'unhandledrejection', (e) =>\n reportError('未处理的 Promise 错误', (e as PromiseRejectionEvent).reason),\n );\n const originalFetch = window.fetch;\n const wrappedFetch: typeof fetch = async function (this: Window, input, init) {\n if (state.paused || !active) return originalFetch.call(this, input, init);\n const session = generation,\n started = performance.now(),\n time = Date.now();\n const rawUrl =\n typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;\n // Local runner polling and case contents are not business diagnostics.\n if (\n new URL(rawUrl, location.href).pathname.startsWith('/__laya-pilot/') ||\n options.ignoreRequest?.(new URL(rawUrl, location.href))\n )\n return originalFetch.call(this, input, init);\n const sensitive = privateEndpoint(rawUrl);\n const record: NetworkRecord = {\n id: ++sequence,\n time,\n actionId,\n source: 'fetch',\n method: (init?.method ?? (input instanceof Request ? input.method : 'GET')).toUpperCase(),\n url: safeUrl(rawUrl),\n status: 0,\n duration: 0,\n failed: false,\n };\n try {\n record.request = sensitive ? '[认证接口正文未采集]' : bodyPreview(init?.body);\n const headers = new Headers(\n init?.headers ?? (input instanceof Request ? input.headers : undefined),\n );\n record.resourceCode = safeText(headers.get('X-Resrc-Code') ?? '', 80);\n } catch {\n /* Diagnostics must never block the request. */\n }\n try {\n const response = await originalFetch.call(this, input, init);\n record.status = response.status;\n record.duration = performance.now() - started;\n record.failed = !response.ok;\n // Run asynchronously; original response and stream remain owned by the app.\n void (async () => {\n try {\n record.response = sensitive ? '[认证接口正文未采集]' : await readResponse(response);\n record.failed ||= businessFailure(record.response);\n } catch {\n record.response = '[响应不可读取]';\n }\n finishNetwork(record, session);\n })();\n return response;\n } catch (error) {\n record.duration = performance.now() - started;\n record.failed = true;\n record.message = safeText(error instanceof Error ? error.message : String(error));\n finishNetwork(record, session);\n throw error;\n }\n };\n window.fetch = wrappedFetch;\n cleanups.push(() => {\n if (window.fetch === wrappedFetch) window.fetch = originalFetch;\n });\n\n // Axios in internal deployments can use XHR; keep the native instance and semantics.\n const xhrOpen = XMLHttpRequest.prototype.open,\n xhrSend = XMLHttpRequest.prototype.send,\n xhrHeader = XMLHttpRequest.prototype.setRequestHeader;\n const xhrRecords = new WeakMap<\n XMLHttpRequest,\n { method: string; url: string; resourceCode?: string }\n >();\n const open: typeof xhrOpen = function (\n this: XMLHttpRequest,\n method: string,\n url: string | URL,\n async: boolean = true,\n username?: string | null,\n password?: string | null,\n ) {\n xhrRecords.set(this, { method, url: String(url) });\n return xhrOpen.call(this, method, url, async, username, password);\n };\n const setHeader: typeof xhrHeader = function (this: XMLHttpRequest, name, value) {\n const result = xhrHeader.call(this, name, value);\n const meta = xhrRecords.get(this);\n if (meta && name.toLowerCase() === 'x-resrc-code') meta.resourceCode = safeText(value, 80);\n return result;\n };\n const send: typeof xhrSend = function (this: XMLHttpRequest, body) {\n const meta = xhrRecords.get(this);\n if (!meta || !active || state.paused) return xhrSend.call(this, body);\n const session = generation,\n started = performance.now();\n const sensitive = privateEndpoint(meta.url);\n const record: NetworkRecord = {\n id: ++sequence,\n time: Date.now(),\n actionId,\n method: meta.method.toUpperCase(),\n url: safeUrl(meta.url),\n source: 'xhr',\n resourceCode: meta.resourceCode,\n status: 0,\n duration: 0,\n failed: false,\n request: sensitive ? '[认证接口正文未采集]' : bodyPreview(body),\n };\n const done = () => {\n record.duration = performance.now() - started;\n record.status = this.status;\n record.failed = this.status === 0 || this.status >= 400;\n try {\n record.response = sensitive\n ? '[认证接口正文未采集]'\n : this.responseType === 'json'\n ? sanitize(this.response)\n : this.responseType === '' || this.responseType === 'text'\n ? bodyPreview(this.responseText)\n : '[非文本响应未采集]';\n record.failed ||= businessFailure(record.response);\n } catch {\n record.response = '[响应不可读取]';\n }\n finishNetwork(record, session);\n };\n this.addEventListener('loadend', done, { once: true });\n try {\n return xhrSend.call(this, body);\n } catch (error) {\n this.removeEventListener('loadend', done);\n throw error;\n }\n };\n XMLHttpRequest.prototype.open = open;\n XMLHttpRequest.prototype.send = send;\n XMLHttpRequest.prototype.setRequestHeader = setHeader;\n cleanups.push(() => {\n if (XMLHttpRequest.prototype.open === open) XMLHttpRequest.prototype.open = xhrOpen;\n if (XMLHttpRequest.prototype.send === send) XMLHttpRequest.prototype.send = xhrSend;\n if (XMLHttpRequest.prototype.setRequestHeader === setHeader)\n XMLHttpRequest.prototype.setRequestHeader = xhrHeader;\n });\n const observe = (type: string, callback: (entry: PerformanceEntry) => void) => {\n try {\n const observer = new PerformanceObserver((list) => {\n if (active && !state.paused) {\n list.getEntries().forEach(callback);\n state = { ...state, metrics: { ...state.metrics } };\n updatePerformanceIssues();\n publish();\n }\n });\n observer.observe({ type, buffered: true });\n cleanups.push(() => observer.disconnect());\n } catch {\n /* Unsupported browser metric stays absent. */\n }\n };\n observe('navigation', (e) => {\n const n = e as PerformanceNavigationTiming;\n state.metrics.TTFB = n.responseStart;\n state.metrics.DOMContentLoaded = n.domContentLoadedEventEnd;\n state.metrics.load = n.loadEventEnd;\n });\n observe('paint', (e) => {\n if (e.name === 'first-contentful-paint') state.metrics.FCP = e.startTime;\n });\n observe('largest-contentful-paint', (e) => {\n state.metrics.LCP = e.startTime;\n });\n observe('longtask', (e) => {\n state.metrics.longTasks = (state.metrics.longTasks ?? 0) + 1;\n state.metrics.longTaskDuration = (state.metrics.longTaskDuration ?? 0) + e.duration;\n const now = Date.now();\n state = {\n ...state,\n performance: {\n ...state.performance,\n longTasks: [\n ...state.performance.longTasks.filter((task) => now - task.time <= 30000),\n { time: performance.timeOrigin + e.startTime, duration: e.duration },\n ].slice(-200),\n },\n };\n if (e.duration > 200) add('performance', '主线程长任务', { duration: Math.round(e.duration) });\n });\n let clsStart = 0,\n clsLast = 0,\n clsWindow = 0;\n observe('layout-shift', (e) => {\n const shift = e as PerformanceEntry & { hadRecentInput: boolean; value: number };\n if (shift.hadRecentInput) return;\n if (e.startTime - clsLast > 1000 || e.startTime - clsStart > 5000) {\n clsStart = e.startTime;\n clsWindow = 0;\n }\n clsLast = e.startTime;\n clsWindow += shift.value;\n state.metrics.CLS = Math.max(state.metrics.CLS ?? 0, clsWindow);\n });\n const pruneTimer = setInterval(() => {\n prune();\n publish();\n }, 10000);\n cleanups.push(() => clearInterval(pruneTimer));\n const sampleMemory = () => {\n if (!active || state.paused || document.visibilityState === 'hidden') return;\n const memory = (\n performance as Performance & { memory?: { usedJSHeapSize: number; jsHeapSizeLimit: number } }\n ).memory;\n const now = Date.now();\n const sample =\n memory &&\n Number.isFinite(memory.usedJSHeapSize) &&\n memory.usedJSHeapSize >= 0 &&\n Number.isFinite(memory.jsHeapSizeLimit) &&\n memory.jsHeapSizeLimit > 0\n ? [{ time: now, used: memory.usedJSHeapSize, limit: memory.jsHeapSizeLimit }]\n : [];\n state = {\n ...state,\n performance: {\n heapSamples: [...state.performance.heapSamples, ...sample]\n .filter((s) => now - s.time <= RETENTION)\n .slice(-180),\n longTasks: state.performance.longTasks.filter((task) => now - task.time <= 30000),\n },\n };\n updatePerformanceIssues();\n publish();\n };\n const memoryTimer = setInterval(sampleMemory, 5000);\n cleanups.push(() => clearInterval(memoryTimer));\n sampleMemory();\n route();\n dispose = () => {\n active = false;\n generation++;\n cleanups.reverse().forEach((fn) => fn());\n if (notifyTimer) clearTimeout(notifyTimer);\n notifyTimer = undefined;\n dispose = undefined;\n };\n return dispose;\n}\n\nfunction updatePerformanceIssues() {\n state = { ...state, performanceUpdatedAt: Date.now() };\n const issues = diagnosePerformance(state.metrics, state.performance, state.performanceUpdatedAt);\n const current = new Set(issues.map((issue) => issue.id));\n for (const issue of issues) {\n if (!activePerformanceIssues.has(issue.id))\n add('performance', issue.title, { evidence: issue.evidence, rule: issue.rule });\n }\n activePerformanceIssues = current;\n}\n","import { safeText, safeUrl, sanitize } from './privacy';\nimport type { Snapshot } from './runtime';\n\n/** Offline import accepts only this version and bounded collections; never executes file content. */\nexport function parseSnapshot(text: string): Snapshot {\n if (text.length > 2 * 1024 * 1024) throw Error('快照不能超过 2 MB');\n const value = JSON.parse(text) as Snapshot;\n if (\n !value ||\n value.schema !== 'zhidao-research-assistant' ||\n value.version !== 1 ||\n typeof value.capturedAt !== 'string' ||\n !Number.isFinite(Date.parse(value.capturedAt)) ||\n typeof value.reason !== 'string' ||\n typeof value.page?.url !== 'string' ||\n !value.environment ||\n typeof value.environment !== 'object' ||\n !Array.isArray(value.events) ||\n value.events.length > 300 ||\n !Array.isArray(value.requests) ||\n value.requests.length > 60 ||\n !value.metrics ||\n typeof value.metrics !== 'object'\n )\n throw Error('不是受支持的研发小蜜快照');\n const kinds = ['route', 'click', 'change', 'request', 'error', 'performance'];\n for (const e of value.events) {\n if (\n !e ||\n !kinds.includes(e.kind) ||\n !Number.isFinite(e.id) ||\n !Number.isFinite(e.time) ||\n typeof e.title !== 'string' ||\n typeof e.page !== 'string'\n )\n throw Error('时间线数据格式错误');\n }\n for (const r of value.requests) {\n if (\n !r ||\n !Number.isFinite(r.id) ||\n !Number.isFinite(r.time) ||\n typeof r.url !== 'string' ||\n typeof r.method !== 'string' ||\n !Number.isFinite(r.duration) ||\n !Number.isFinite(r.status)\n )\n throw Error('接口数据格式错误');\n }\n if (value.performance) {\n const { heapSamples, longTasks } = value.performance;\n if (\n !Array.isArray(heapSamples) ||\n heapSamples.length > 180 ||\n !Array.isArray(longTasks) ||\n longTasks.length > 200 ||\n heapSamples.some(\n (s, i) =>\n !s ||\n !Number.isFinite(s.time) ||\n !Number.isFinite(s.used) ||\n s.used < 0 ||\n !Number.isFinite(s.limit) ||\n s.limit <= 0 ||\n (i > 0 && s.time <= heapSamples[i - 1].time),\n ) ||\n longTasks.some(\n (s) => !s || !Number.isFinite(s.time) || !Number.isFinite(s.duration) || s.duration < 0,\n )\n )\n throw Error('性能采样数据格式错误');\n }\n return {\n schema: value.schema,\n version: 1,\n capturedAt: value.capturedAt,\n reason: safeText(value.reason),\n feedback: typeof value.feedback === 'string' ? safeText(value.feedback, 1000) : undefined,\n page: { ...(sanitize(value.page) as Snapshot['page']), url: safeUrl(value.page.url) },\n environment: {\n ...(sanitize(value.environment) as Snapshot['environment']),\n // These are explicitly name lists, not cookie/session values.\n ...Object.fromEntries(\n ['cookies', 'localStorageKeys', 'sessionStorageKeys'].map((key) => {\n const list = value.environment[key as keyof Snapshot['environment']];\n return [\n key,\n Array.isArray(list)\n ? list\n .slice(0, 60)\n .filter((item) => typeof item === 'string')\n .map((item) => safeText(item, 100))\n : [],\n ];\n }),\n ),\n },\n metrics: Object.fromEntries(\n Object.entries(value.metrics)\n .filter(([, v]) => typeof v === 'number' && Number.isFinite(v))\n .slice(0, 30),\n ),\n ...(value.performance\n ? {\n performance: {\n heapSamples: value.performance.heapSamples.map(({ time, used, limit }) => ({\n time,\n used,\n limit,\n })),\n longTasks: value.performance.longTasks.map(({ time, duration }) => ({\n time,\n duration,\n })),\n },\n }\n : {}),\n events: value.events.map((e) => ({ ...(sanitize(e) as typeof e), page: safeUrl(e.page) })),\n requests: value.requests.map((r) => ({ ...(sanitize(r) as typeof r), url: safeUrl(r.url) })),\n limits: { events: 300, requests: 60, retentionMinutes: 15 },\n };\n}\n\nexport function downloadSnapshot(snapshot: Snapshot, description: string) {\n const json = JSON.stringify(\n { ...snapshot, feedback: safeText(description || snapshot.feedback || '', 1000) },\n null,\n 2,\n );\n const blob = new Blob([json], { type: 'application/json;charset=utf-8' });\n const url = URL.createObjectURL(blob),\n link = document.createElement('a');\n link.href = url;\n link.download = `研发小蜜快照_${new Date().toISOString().replace(/[:.]/g, '-')}.json`;\n document.body.append(link);\n link.click();\n link.remove();\n setTimeout(() => URL.revokeObjectURL(url), 30000);\n}\n","import type { Step, TestCase } from './schema';\nimport { excluded, controls, privateInput, locate } from 'gz-laya-pilot/browser';\nexport { privateInput, locate } from 'gz-laya-pilot/browser';\n\ntype State = { recording: boolean; draft: TestCase; saved: TestCase | null };\nconst empty = (): TestCase => ({\n schema: 'zhidao-recorded-case',\n version: 1,\n name: '页面操作录制',\n path: typeof location === 'undefined' ? '/' : location.pathname,\n steps: [],\n});\nlet state: State = { recording: false, draft: empty(), saved: null };\nconst subscribers = new Set<() => void>();\nlet dispose = () => {};\nfunction publish(next: Partial<State>) {\n state = { ...state, ...next };\n subscribers.forEach((fn) => fn());\n}\nfunction append(step: Step) {\n if (state.draft.steps.length >= 100) {\n recorder.stop();\n return;\n }\n const steps = [...state.draft.steps];\n // Consecutive typing in one field becomes one fill; clicks flush the boundary.\n const last = steps.at(-1);\n if (\n step.kind === 'fill' &&\n last?.kind === 'fill' &&\n last.target?.selector === step.target?.selector\n )\n steps.pop();\n steps.push(step);\n publish({ draft: { ...state.draft, steps } });\n}\nexport const recorder = {\n subscribe(fn: () => void) {\n subscribers.add(fn);\n return () => {\n subscribers.delete(fn);\n };\n },\n getState: () => state,\n start() {\n dispose();\n publish({ recording: true, draft: empty() });\n let enterAt = -Infinity;\n const handle = (event: Event) => {\n if (!event.isTrusted || !(event.target instanceof Element) || event.target.closest(excluded))\n return;\n // Enter on an input can synthesize a submit-button click. Replaying both\n // would submit twice, so retain the key and omit its native click.\n if (\n event instanceof MouseEvent &&\n event.type === 'click' &&\n event.detail === 0 &&\n event.timeStamp - enterAt < 500\n )\n return;\n const element = event.target.closest(controls);\n if (!element) return;\n if (privateInput(element)) {\n if (event.type === 'input') {\n const last = state.draft.steps.at(-1);\n if (last?.kind !== 'unsupported' || last.value !== '敏感字段输入未录制')\n append({ kind: 'unsupported', value: '敏感字段输入未录制' });\n }\n return;\n }\n const target = locate(element);\n if (\n element instanceof HTMLInputElement &&\n ['file', 'date', 'datetime-local', 'range', 'color'].includes(element.type)\n ) {\n if (event.type === 'change')\n append({ kind: 'unsupported', value: `${target.label}:该控件需要手动适配` });\n return;\n }\n if (\n event.type === 'input' &&\n (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement)\n ) {\n if (!['checkbox', 'radio'].includes((element as HTMLInputElement).type))\n append({ kind: 'fill', target, value: element.value });\n } else if (event.type === 'change' && element instanceof HTMLSelectElement) {\n append({ kind: 'select', target, value: element.value });\n } else if (\n event.type === 'change' &&\n element instanceof HTMLInputElement &&\n ['checkbox', 'radio'].includes(element.type)\n ) {\n append({ kind: 'check', target, checked: element.checked });\n } else if (\n event.type === 'click' &&\n !(element instanceof HTMLSelectElement) &&\n !(element instanceof HTMLInputElement && ['checkbox', 'radio'].includes(element.type))\n ) {\n append({ kind: 'click', target });\n } else if (event instanceof KeyboardEvent && ['Enter', 'Escape', 'Tab'].includes(event.key)) {\n // Button Enter already produces a click event.\n if (event.key === 'Enter' && element.matches('button,[role=\"button\"]')) return;\n if (event.key === 'Enter') enterAt = event.timeStamp;\n append({ kind: 'press', target, value: event.key });\n }\n };\n for (const type of ['click', 'input', 'change', 'keydown'])\n document.addEventListener(type, handle, true);\n dispose = () => {\n for (const type of ['click', 'input', 'change', 'keydown'])\n document.removeEventListener(type, handle, true);\n };\n },\n stop() {\n dispose();\n publish({ recording: false });\n },\n edit(draft: TestCase) {\n publish({ draft });\n },\n loadDraft(draft: TestCase) {\n if (state.recording) throw Error('请先结束主动录制,再生成时间线草稿');\n publish({ draft: structuredClone(draft) });\n },\n checkpoint(text: string) {\n append({ kind: 'assert-text', value: text });\n },\n save(value: TestCase) {\n publish({ saved: structuredClone(value), draft: value });\n },\n clear() {\n dispose();\n publish({ recording: false, draft: empty(), saved: null });\n },\n};\n"],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ import { type PerformanceEvidence } from './performance';
2
+ export interface AssistantOptions {
3
+ /** Business response codes belong to the host, not the generic recorder. */
4
+ isBusinessFailure?: (body: unknown) => boolean;
5
+ ignoreRequest?: (url: URL) => boolean;
6
+ }
7
+ export type EventKind = 'route' | 'click' | 'change' | 'request' | 'error' | 'performance';
8
+ export interface TraceEvent {
9
+ id: number;
10
+ time: number;
11
+ kind: EventKind;
12
+ title: string;
13
+ page: string;
14
+ actionId?: number;
15
+ detail?: unknown;
16
+ }
17
+ export interface NetworkRecord {
18
+ id: number;
19
+ time: number;
20
+ actionId?: number;
21
+ method: string;
22
+ url: string;
23
+ status: number;
24
+ duration: number;
25
+ failed: boolean;
26
+ source: 'fetch' | 'xhr';
27
+ request?: unknown;
28
+ response?: unknown;
29
+ resourceCode?: string;
30
+ message?: string;
31
+ }
32
+ export interface Snapshot {
33
+ schema: 'zhidao-research-assistant';
34
+ version: 1;
35
+ capturedAt: string;
36
+ reason: string;
37
+ feedback?: string;
38
+ page: ReturnType<typeof pageState>;
39
+ environment: ReturnType<typeof environment>;
40
+ metrics: Record<string, number>;
41
+ performance?: PerformanceEvidence;
42
+ events: TraceEvent[];
43
+ requests: NetworkRecord[];
44
+ limits: {
45
+ events: number;
46
+ requests: number;
47
+ retentionMinutes: number;
48
+ };
49
+ }
50
+ interface RuntimeState {
51
+ events: TraceEvent[];
52
+ requests: NetworkRecord[];
53
+ metrics: Record<string, number>;
54
+ performance: PerformanceEvidence;
55
+ performanceUpdatedAt: number;
56
+ paused: boolean;
57
+ frozen: Snapshot | null;
58
+ }
59
+ declare function pageState(): {
60
+ url: string;
61
+ title: string;
62
+ viewport: {
63
+ width: number;
64
+ height: number;
65
+ pixelRatio: number;
66
+ };
67
+ scroll: {
68
+ x: number;
69
+ y: number;
70
+ };
71
+ visibility: DocumentVisibilityState;
72
+ focusedControl: string;
73
+ headings: string[];
74
+ domNodes: number;
75
+ iframeCount: number;
76
+ };
77
+ export declare function environment(): {
78
+ userAgent: string;
79
+ language: string;
80
+ timezone: string;
81
+ online: boolean;
82
+ cpuThreads: number;
83
+ deviceMemoryGB: number | null;
84
+ heap: {
85
+ usedJSHeapSize: number;
86
+ totalJSHeapSize: number;
87
+ jsHeapSizeLimit: number;
88
+ } | null;
89
+ connection: {
90
+ effectiveType: string | undefined;
91
+ downlinkMbps: number | undefined;
92
+ rttMs: number | undefined;
93
+ saveData: boolean | undefined;
94
+ } | null;
95
+ cookies: string[];
96
+ localStorageKeys: string[];
97
+ sessionStorageKeys: string[];
98
+ coverage: string;
99
+ };
100
+ export declare function captureSnapshot(reason?: string): Snapshot;
101
+ export declare function freezeSnapshot(reason?: string): void;
102
+ export declare function reportError(title: string, detail?: unknown): void;
103
+ export declare const assistantRuntime: {
104
+ subscribe(fn: () => void): () => void;
105
+ getState: () => RuntimeState;
106
+ pause(paused: boolean): void;
107
+ clear(): void;
108
+ };
109
+ export declare function startAssistant(options?: AssistantOptions): () => void;
110
+ export {};
package/dist/sdk.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { type ResearchAssistantProps } from './ResearchAssistant';
2
+ import { type AssistantOptions } from './runtime';
3
+ /** One assistant per page. The caller owns authentication and removes it on logout. */
4
+ export declare function mountAssistant(container: HTMLElement, props?: ResearchAssistantProps, options?: AssistantOptions): () => void;
package/dist/sdk.js ADDED
@@ -0,0 +1,15 @@
1
+ import { t as e } from "./ResearchAssistant-DAsgcwcG.js";
2
+ import { i as t, l as n, t as r } from "./recorder-Da1VSLid.js";
3
+ import { jsx as i } from "react/jsx-runtime";
4
+ import { createRoot as a } from "react-dom/client";
5
+ //#region src/sdk.tsx
6
+ function o(o, s = {}, c = {}) {
7
+ let l = n(c), u = a(o);
8
+ return u.render(/* @__PURE__ */ i(e, { ...s })), () => {
9
+ u.unmount(), l(), t.clear(), r.clear();
10
+ };
11
+ }
12
+ //#endregion
13
+ export { o as mountAssistant };
14
+
15
+ //# sourceMappingURL=sdk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk.js","names":[],"sources":["../src/sdk.tsx"],"sourcesContent":["import { createRoot } from 'react-dom/client';\nimport ResearchAssistant, { type ResearchAssistantProps } from './ResearchAssistant';\nimport { startAssistant, assistantRuntime, type AssistantOptions } from './runtime';\nimport { recorder } from './automation/recorder';\n\n/** One assistant per page. The caller owns authentication and removes it on logout. */\nexport function mountAssistant(\n container: HTMLElement,\n props: ResearchAssistantProps = {},\n options: AssistantOptions = {},\n) {\n const stop = startAssistant(options);\n const root = createRoot(container);\n root.render(<ResearchAssistant {...props} />);\n return () => {\n root.unmount();\n stop();\n assistantRuntime.clear();\n recorder.clear();\n };\n}\n"],"mappings":";;;;;AAMA,SAAgB,EACd,GACA,IAAgC,CAAC,GACjC,IAA4B,CAAC,GAC7B;CACA,IAAM,IAAO,EAAe,CAAO,GAC7B,IAAO,EAAW,CAAS;CAEjC,OADA,EAAK,OAAO,kBAAC,GAAD,EAAmB,GAAI,EAAQ,CAAA,CAAC,SAC/B;EAIX,AAHA,EAAK,QAAQ,GACb,EAAK,GACL,EAAiB,MAAM,GACvB,EAAS,MAAM;CACjB;AACF"}
@@ -0,0 +1,4 @@
1
+ import type { Snapshot } from './runtime';
2
+ /** Offline import accepts only this version and bounded collections; never executes file content. */
3
+ export declare function parseSnapshot(text: string): Snapshot;
4
+ export declare function downloadSnapshot(snapshot: Snapshot, description: string): void;
package/dist/style.css ADDED
@@ -0,0 +1,11 @@
1
+ /*!
2
+ * OverlayScrollbars
3
+ * Version: 2.16.0
4
+ *
5
+ * Copyright (c) Rene Haas | KingSora.
6
+ * https://github.com/KingSora
7
+ *
8
+ * Released under the MIT license.
9
+ */
10
+ .os-size-observer,.os-size-observer-listener{direction:inherit;pointer-events:none;visibility:hidden;box-sizing:border-box;overflow:hidden;scroll-behavior:auto!important}.os-size-observer,.os-size-observer-listener,.os-size-observer-listener-item,.os-size-observer-listener-item-final{writing-mode:horizontal-tb;position:absolute;top:0;left:0}.os-size-observer{z-index:-1;contain:strict;padding:inherit;border:inherit;box-sizing:inherit;flex-flow:row;margin:-133px;display:flex;inset:0;transform:scale(.1)}.os-size-observer:before{content:"";box-sizing:inherit;flex:none;width:10px;height:10px;padding:10px}.os-size-observer-appear{animation:1ms forwards os-size-observer-appear-animation}.os-size-observer-listener{box-sizing:border-box;padding:inherit;border:inherit;flex:auto;margin:-133px;position:relative;transform:scale(10)}.os-size-observer-listener.ltr{margin-left:0;margin-right:-266px}.os-size-observer-listener.rtl{margin-left:-266px;margin-right:0}.os-size-observer-listener:empty:before{content:"";width:100%;height:100%}.os-size-observer-listener:empty:before,.os-size-observer-listener>.os-size-observer-listener-item{padding:inherit;border:inherit;box-sizing:content-box;flex:auto;display:block;position:relative}.os-size-observer-listener-scroll{box-sizing:border-box;display:flex}.os-size-observer-listener-item{direction:ltr;flex:none;bottom:0;right:0;overflow:hidden}.os-size-observer-listener-item-final{transition:none}@keyframes os-size-observer-appear-animation{0%{cursor:auto}to{cursor:none}}.os-trinsic-observer{box-sizing:border-box;z-index:-1;contain:strict;border:none;flex:none;max-width:0;height:0;max-height:1px;margin:0;padding:0;position:relative;top:calc(100% + 1px);overflow:hidden}.os-trinsic-observer:not(:empty){height:calc(100% + 1px);top:-1px}.os-trinsic-observer:not(:empty)>.os-size-observer{width:1000%;min-width:1px;height:1000%;min-height:1px}html[data-overlayscrollbars-body]{overflow:hidden}html[data-overlayscrollbars-body],html[data-overlayscrollbars-body]>body{width:100%;height:100%;margin:0}html[data-overlayscrollbars-body]>body{margin:0;overflow:visible}[data-overlayscrollbars]{position:relative}[data-overlayscrollbars~=host],[data-overlayscrollbars-padding]{display:flex;scroll-behavior:auto!important;flex-flow:row!important;align-items:stretch!important}[data-overlayscrollbars-padding],[data-overlayscrollbars-viewport]:not([data-overlayscrollbars]){box-sizing:inherit;z-index:0;border:none;flex:auto;width:100%;min-width:0;height:auto;margin:0;padding:0;position:relative}[data-overlayscrollbars-viewport]:not([data-overlayscrollbars]){--os-vaw:0;--os-vah:0;outline:none}[data-overlayscrollbars-viewport]:not([data-overlayscrollbars]):focus{outline:none}[data-overlayscrollbars-viewport][data-overlayscrollbars-viewport~=arrange]:before{content:"";pointer-events:none;z-index:-1;min-width:1px;min-height:1px;width:var(--os-vaw);height:var(--os-vah);position:absolute}[data-overlayscrollbars~=host],[data-overlayscrollbars-padding]{overflow:hidden!important}[data-overlayscrollbars~=host][data-overlayscrollbars~=noClipping],[data-overlayscrollbars-padding~=noClipping]{overflow:visible!important}[data-overlayscrollbars-viewport]{--os-viewport-overflow-x:hidden;--os-viewport-overflow-y:hidden;overflow-x:var(--os-viewport-overflow-x);overflow-y:var(--os-viewport-overflow-y)}[data-overlayscrollbars-viewport~=overflowXVisible]{--os-viewport-overflow-x:visible}[data-overlayscrollbars-viewport~=overflowXHidden]{--os-viewport-overflow-x:hidden}[data-overlayscrollbars-viewport~=overflowXScroll]{--os-viewport-overflow-x:scroll}[data-overlayscrollbars-viewport~=overflowYVisible]{--os-viewport-overflow-y:visible}[data-overlayscrollbars-viewport~=overflowYHidden]{--os-viewport-overflow-y:hidden}[data-overlayscrollbars-viewport~=overflowYScroll]{--os-viewport-overflow-y:scroll}[data-overlayscrollbars-viewport~=overflowImportant]{overflow-x:var(--os-viewport-overflow-x)!important;overflow-y:var(--os-viewport-overflow-y)!important}[data-overlayscrollbars-viewport~=noContent]:not(#osFakeId){font-size:0!important;line-height:0!important}[data-overlayscrollbars-viewport~=noContent]:not(#osFakeId):before,[data-overlayscrollbars-viewport~=noContent]:not(#osFakeId):after,[data-overlayscrollbars-viewport~=noContent]:not(#osFakeId)>:not(#osFakeId){clip:rect(0, 0, 0, 0)!important;white-space:nowrap!important;border-width:0!important;width:1px!important;height:1px!important;margin:-1px!important;padding:0!important;display:none!important;position:absolute!important;overflow:hidden!important}[data-overlayscrollbars-viewport~=measuring],[data-overlayscrollbars-viewport~=scrolling]{scroll-behavior:auto!important;scroll-snap-type:none!important}[data-overlayscrollbars-viewport~=measuring][data-overlayscrollbars-viewport~=overflowXVisible]{overflow-x:hidden!important}[data-overlayscrollbars-viewport~=measuring][data-overlayscrollbars-viewport~=overflowYVisible]{overflow-y:hidden!important}[data-overlayscrollbars-content]{box-sizing:inherit}[data-overlayscrollbars-contents]:not(#osFakeId):not([data-overlayscrollbars-padding]):not([data-overlayscrollbars-viewport]):not([data-overlayscrollbars-content]){display:contents}[data-overlayscrollbars-grid],[data-overlayscrollbars-grid] [data-overlayscrollbars-padding]{grid-template:1fr/1fr;display:grid}[data-overlayscrollbars-grid]>[data-overlayscrollbars-padding],[data-overlayscrollbars-grid]>[data-overlayscrollbars-viewport],[data-overlayscrollbars-grid]>[data-overlayscrollbars-padding]>[data-overlayscrollbars-viewport]{width:auto!important;height:auto!important}@property --os-scroll-percent{syntax:"<number>";inherits:true;initial-value:0}@property --os-viewport-percent{syntax:"<number>";inherits:true;initial-value:0}.os-scrollbar{--os-viewport-percent:0;--os-scroll-percent:0;--os-scroll-direction:0;--os-scroll-percent-directional:calc(var(--os-scroll-percent) - (var(--os-scroll-percent) + (1 - var(--os-scroll-percent)) * -1) * var(--os-scroll-direction));contain:size layout;contain:size layout style;pointer-events:none;opacity:0;visibility:hidden;transition:opacity .15s,visibility .15s,top .15s,right .15s,bottom .15s,left .15s;position:absolute}body>.os-scrollbar{z-index:99999;position:fixed}.os-scrollbar-transitionless{transition:none!important}.os-scrollbar-track{position:relative;border:none!important;padding:0!important}.os-scrollbar-handle{position:absolute}.os-scrollbar-track,.os-scrollbar-handle{pointer-events:none;width:100%;height:100%}.os-scrollbar.os-scrollbar-track-interactive .os-scrollbar-track,.os-scrollbar.os-scrollbar-handle-interactive .os-scrollbar-handle{pointer-events:auto;touch-action:none}.os-scrollbar-horizontal{bottom:0;left:0}.os-scrollbar-vertical{top:0;right:0}.os-scrollbar-rtl.os-scrollbar-horizontal{right:0}.os-scrollbar-rtl.os-scrollbar-vertical{left:0;right:auto}.os-scrollbar-visible{opacity:1;visibility:visible}.os-scrollbar-auto-hide.os-scrollbar-auto-hide-hidden{opacity:0;visibility:hidden}.os-scrollbar-interaction.os-scrollbar-visible{opacity:1;visibility:visible}.os-scrollbar-unusable,.os-scrollbar-unusable *,.os-scrollbar-wheel,.os-scrollbar-wheel *{pointer-events:none!important}.os-scrollbar-unusable .os-scrollbar-handle{opacity:0!important;transition:none!important}.os-scrollbar-horizontal .os-scrollbar-handle{bottom:0;left:calc(var(--os-scroll-percent-directional) * 100%);transform:translateX(calc(var(--os-scroll-percent-directional) * -100%));width:calc(var(--os-viewport-percent) * 100%)}.os-scrollbar-vertical .os-scrollbar-handle{right:0;top:calc(var(--os-scroll-percent-directional) * 100%);transform:translateY(calc(var(--os-scroll-percent-directional) * -100%));height:calc(var(--os-viewport-percent) * 100%)}@supports (container-type:size){.os-scrollbar-track{container-type:size}.os-scrollbar-horizontal .os-scrollbar-handle{transform:translateX(calc(var(--os-scroll-percent-directional) * 100cqw + var(--os-scroll-percent-directional) * -100%));left:auto}.os-scrollbar-vertical .os-scrollbar-handle{transform:translateY(calc(var(--os-scroll-percent-directional) * 100cqh + var(--os-scroll-percent-directional) * -100%));top:auto}.os-scrollbar-rtl.os-scrollbar-horizontal .os-scrollbar-handle{left:0;right:auto}}.os-scrollbar-rtl.os-scrollbar-vertical .os-scrollbar-handle{left:0;right:auto}.os-scrollbar.os-scrollbar-horizontal.os-scrollbar-cornerless,.os-scrollbar.os-scrollbar-horizontal.os-scrollbar-cornerless.os-scrollbar-rtl{left:0;right:0}.os-scrollbar.os-scrollbar-vertical.os-scrollbar-cornerless,.os-scrollbar.os-scrollbar-vertical.os-scrollbar-cornerless.os-scrollbar-rtl{top:0;bottom:0}@media print{.os-scrollbar{display:none}}.os-scrollbar{--os-size:0;--os-padding-perpendicular:0;--os-padding-axis:0;--os-track-border-radius:0;--os-track-bg:none;--os-track-bg-hover:none;--os-track-bg-active:none;--os-track-border:none;--os-track-border-hover:none;--os-track-border-active:none;--os-handle-border-radius:0;--os-handle-bg:none;--os-handle-bg-hover:none;--os-handle-bg-active:none;--os-handle-border:none;--os-handle-border-hover:none;--os-handle-border-active:none;--os-handle-min-size:33px;--os-handle-max-size:none;--os-handle-perpendicular-size:100%;--os-handle-perpendicular-size-hover:100%;--os-handle-perpendicular-size-active:100%;--os-handle-interactive-area-offset:0}.os-scrollbar-track{border:var(--os-track-border);border-radius:var(--os-track-border-radius);background:var(--os-track-bg);transition:opacity .15s,background-color .15s,border-color .15s}.os-scrollbar-track:hover{border:var(--os-track-border-hover);background:var(--os-track-bg-hover)}.os-scrollbar-track:active{border:var(--os-track-border-active);background:var(--os-track-bg-active)}.os-scrollbar-handle{border:var(--os-handle-border);border-radius:var(--os-handle-border-radius);background:var(--os-handle-bg)}.os-scrollbar-handle:hover{border:var(--os-handle-border-hover);background:var(--os-handle-bg-hover)}.os-scrollbar-handle:active{border:var(--os-handle-border-active);background:var(--os-handle-bg-active)}.os-scrollbar-track:before,.os-scrollbar-handle:before{content:"";display:block;position:absolute;inset:0}.os-scrollbar-horizontal{padding:var(--os-padding-perpendicular) var(--os-padding-axis);right:var(--os-size);height:var(--os-size)}.os-scrollbar-horizontal.os-scrollbar-rtl{left:var(--os-size);right:0}.os-scrollbar-horizontal .os-scrollbar-track:before{top:calc(var(--os-padding-perpendicular) * -1);bottom:calc(var(--os-padding-perpendicular) * -1)}.os-scrollbar-horizontal .os-scrollbar-handle{min-width:var(--os-handle-min-size);max-width:var(--os-handle-max-size);height:var(--os-handle-perpendicular-size);transition:opacity .15s,background-color .15s,border-color .15s,height .15s}.os-scrollbar-horizontal .os-scrollbar-handle:before{top:calc((var(--os-padding-perpendicular) + var(--os-handle-interactive-area-offset)) * -1);bottom:calc(var(--os-padding-perpendicular) * -1)}.os-scrollbar-horizontal:hover .os-scrollbar-handle{height:var(--os-handle-perpendicular-size-hover)}.os-scrollbar-horizontal:active .os-scrollbar-handle{height:var(--os-handle-perpendicular-size-active)}.os-scrollbar-vertical{padding:var(--os-padding-axis) var(--os-padding-perpendicular);bottom:var(--os-size);width:var(--os-size)}.os-scrollbar-vertical .os-scrollbar-track:before{left:calc(var(--os-padding-perpendicular) * -1);right:calc(var(--os-padding-perpendicular) * -1)}.os-scrollbar-vertical .os-scrollbar-handle{min-height:var(--os-handle-min-size);max-height:var(--os-handle-max-size);width:var(--os-handle-perpendicular-size);transition:opacity .15s,background-color .15s,border-color .15s,width .15s}.os-scrollbar-vertical .os-scrollbar-handle:before{left:calc((var(--os-padding-perpendicular) + var(--os-handle-interactive-area-offset)) * -1);right:calc(var(--os-padding-perpendicular) * -1)}.os-scrollbar-vertical.os-scrollbar-rtl .os-scrollbar-handle:before{right:calc((var(--os-padding-perpendicular) + var(--os-handle-interactive-area-offset)) * -1);left:calc(var(--os-padding-perpendicular) * -1)}.os-scrollbar-vertical:hover .os-scrollbar-handle{width:var(--os-handle-perpendicular-size-hover)}.os-scrollbar-vertical:active .os-scrollbar-handle{width:var(--os-handle-perpendicular-size-active)}[data-overlayscrollbars-viewport~=measuring]>.os-scrollbar,.os-theme-none.os-scrollbar{display:none!important}.os-theme-dark,.os-theme-light{box-sizing:border-box;--os-size:10px;--os-padding-perpendicular:2px;--os-padding-axis:2px;--os-track-border-radius:10px;--os-handle-interactive-area-offset:4px;--os-handle-border-radius:10px}.os-theme-dark{--os-handle-bg:#00000070;--os-handle-bg-hover:#0000008c;--os-handle-bg-active:#000000a8}.os-theme-light{--os-handle-bg:#ffffff70;--os-handle-bg-hover:#ffffff8c;--os-handle-bg-active:#ffffffa8}[data-overlayscrollbars-initialize]:not([data-overlayscrollbars-viewport]),[data-overlayscrollbars-viewport~=scrollbarHidden],html[data-overlayscrollbars-viewport~=scrollbarHidden]>body{scrollbar-width:none!important}[data-overlayscrollbars-initialize]:not([data-overlayscrollbars-viewport])::-webkit-scrollbar{appearance:none!important;width:0!important;height:0!important;display:none!important}[data-overlayscrollbars-initialize]:not([data-overlayscrollbars-viewport])::-webkit-scrollbar-corner{appearance:none!important;width:0!important;height:0!important;display:none!important}[data-overlayscrollbars-viewport~=scrollbarHidden]::-webkit-scrollbar{appearance:none!important;width:0!important;height:0!important;display:none!important}[data-overlayscrollbars-viewport~=scrollbarHidden]::-webkit-scrollbar-corner{appearance:none!important;width:0!important;height:0!important;display:none!important}html[data-overlayscrollbars-viewport~=scrollbarHidden]>body::-webkit-scrollbar{appearance:none!important;width:0!important;height:0!important;display:none!important}html[data-overlayscrollbars-viewport~=scrollbarHidden]>body::-webkit-scrollbar-corner{appearance:none!important;width:0!important;height:0!important;display:none!important}[data-overlayscrollbars-initialize]:not([data-overlayscrollbars]):not(html):not(body){overflow:auto}.research-assistant__avatar{color:#b5f0d4;background:#244b40;border-radius:15px;flex:none;place-items:center;width:44px;height:44px;display:grid;box-shadow:inset 0 0 0 1px #b5f0d422}.research-assistant__avatar svg{width:26px;height:26px}.research-assistant__dock{z-index:990;align-items:center;display:flex;position:fixed;bottom:24px;right:24px}.research-assistant__dock[hidden]{display:none}.research-assistant__launcher.ant-btn{border-radius:50%;width:52px;height:52px;padding:0;box-shadow:0 5px 20px #0002}.research-assistant__launcher.ant-btn .research-assistant__avatar{border-radius:50%;width:48px;height:48px}.research-assistant__sr-only{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.research-assistant__window{--ra-space-sm:8px;--ra-space-md:16px;--ra-space-lg:24px;z-index:991;box-sizing:border-box;border:1px solid var(--app-color-border,#e0e5e4);background:var(--app-color-bg-container,#fff);color:var(--app-color-text-primary,#20332d);isolation:isolate;border-radius:20px;flex-direction:column;font-family:inherit;display:flex;position:fixed;overflow:hidden;box-shadow:0 24px 80px #0003,0 4px 16px #0002;container:research-assistant/inline-size}.research-assistant__window[hidden]{display:none}.research-assistant__window:focus{outline:none}.research-assistant__window.is-expanded{width:min(1180px,100vw - 24px);height:calc(100dvh - 24px);margin:auto;inset:12px}.research-assistant__window.is-moving{-webkit-user-select:none;user-select:none}.research-assistant__window button:focus-visible,.research-assistant__window [tabindex="0"]:focus-visible{outline:2px solid var(--app-color-primary,#237956);outline-offset:-3px}.research-assistant .os-scrollbar{--os-size:8px;--os-handle-bg:#687b7480;--os-handle-bg-hover:#687b74b0}.research-assistant [data-overlayscrollbars]{position:relative}.research-assistant__header{border-bottom:1px solid var(--app-color-border,#e0e5e4);background:linear-gradient(110deg,#71b6960b,#0000 65%);flex:none;justify-content:space-between;align-items:center;gap:8px;padding:14px 16px 12px 20px;display:flex}.research-assistant__drag{cursor:grab;touch-action:none;-webkit-user-select:none;user-select:none;flex:1;align-items:center;gap:12px;min-width:0;display:flex}.research-assistant__drag:active{cursor:grabbing}.research-assistant__drag h2{margin:0;font-size:16px;font-weight:600}.research-assistant__drag h2 span{color:var(--app-color-text-secondary,#60746b);background:var(--app-color-bg-item,#f6f8f7);border:1px solid var(--app-color-border,#e0e5e4);vertical-align:middle;border-radius:5px;margin-left:6px;padding:2px 6px;font-size:10px;font-weight:400}.research-assistant__drag p{color:var(--app-color-text-tertiary,#87968f);margin:6px 0 0;font-size:11px}.research-assistant__window-actions{gap:4px;display:flex}.research-assistant__window-actions button{width:30px;height:30px;color:var(--app-color-text-secondary,#60746b);cursor:pointer;background:0 0;border:0;border-radius:8px}.research-assistant__window-actions button:hover{background:var(--app-color-bg-item-hover,#eef3f0);color:var(--app-color-text-primary,#20332d)}.research-assistant__body{flex-direction:column;flex:1;min-height:0;display:flex;overflow:auto}.research-assistant__toolbar{color:var(--app-color-text-secondary,#60746b);flex-wrap:wrap;flex:none;justify-content:space-between;align-items:center;gap:8px;padding:8px 20px;font-size:11px;display:flex}.research-assistant__toolbar>span{align-items:center;gap:7px;display:flex}.research-assistant__toolbar i{background:#64ad8b;border-radius:50%;width:6px;height:6px}.research-assistant__toolbar i.paused{background:#d99b35}.research-assistant__toolbar .ant-btn{color:var(--app-color-text-secondary,#60746b);font-size:11px}.research-assistant__sources{align-items:center;gap:var(--ra-space-sm);flex-wrap:wrap;flex:none;padding:0 24px 16px;display:flex}.research-assistant__sources .ant-btn{border-radius:6px;font-size:11px}.research-assistant__body>.ant-alert{flex:none;margin:0 20px 10px;font-size:12px}.research-assistant__main-tabs{flex:1;min-height:0}.research-assistant__main-tabs>.ant-tabs-nav{flex:none;margin:0;padding:0 16px}.research-assistant__main-tabs>.ant-tabs-nav .ant-tabs-tab{flex:1;justify-content:center;min-width:0;margin:0;padding:12px 0;font-size:13px}.research-assistant__main-tabs>.ant-tabs-nav .ant-tabs-nav-list{gap:8px;width:100%}.research-assistant__main-tabs>.ant-tabs-nav .ant-tabs-tab-btn{justify-content:center;align-items:center;gap:8px;display:flex}.research-assistant__main-tabs>.ant-tabs-nav .ant-tabs-tab-icon{margin:0}.research-assistant__main-tabs>.ant-tabs-content-holder,.research-assistant__main-tabs>.ant-tabs-body-holder{overscroll-behavior:contain;overflow:auto}.research-assistant__diagnostic-tabs>.ant-tabs-nav{margin:0;padding:16px 24px 0}.research-assistant__diagnostic-tabs>.ant-tabs-nav:before{border:0}.research-assistant__diagnostic-tabs>.ant-tabs-nav .ant-tabs-tab{border-radius:7px;flex:1;justify-content:center;padding:8px;font-size:12px;margin:0!important}.research-assistant__diagnostic-tabs>.ant-tabs-nav .ant-tabs-tab-active{background:var(--app-color-bg-item-hover,#eef3f0)}.research-assistant__diagnostic-tabs>.ant-tabs-nav .ant-tabs-ink-bar{display:none}.research-assistant__diagnostic-tabs>.ant-tabs-nav .ant-tabs-nav-list{gap:8px;width:100%}.research-assistant__diagnostic-tabs>.ant-tabs-nav .ant-tabs-tab-btn{align-items:center;gap:6px;display:flex}.research-assistant__diagnostic-tabs>.ant-tabs-nav .ant-tabs-tab-icon{margin:0}.research-assistant__section{align-items:stretch;gap:var(--ra-space-lg);padding:var(--ra-space-lg);flex-direction:column;min-width:0;display:flex}.research-assistant__section>*{min-width:0}.research-assistant__section h3{margin:0;font-size:14px}.research-assistant__section details{margin:0}.research-assistant__section summary{cursor:pointer;color:var(--app-color-text-secondary,#60746b);font-size:12px}.research-assistant__section .ant-alert{border-radius:10px;font-size:12px}.research-assistant__section .ant-alert-description{font-size:12px;line-height:1.8}.research-assistant__section>label{font-size:12px}.research-assistant__intro{flex-direction:column;gap:8px;display:flex}.research-assistant__intro>span{letter-spacing:-.5px;font-size:23px;font-weight:600}.research-assistant__intro p{color:var(--app-color-text-secondary,#60746b);margin:0;font-size:12px}.research-assistant__eyebrow{color:var(--app-color-text-tertiary,#87968f);align-items:center;gap:6px;margin:0;font-size:11px;display:flex}.research-assistant__label{margin:20px 0 10px;font-weight:500;display:block}.research-assistant__actions .ant-btn{border-radius:8px;height:36px}.research-assistant__hint{color:var(--app-color-text-secondary,#60746b);margin:0;font-size:12px;line-height:1.8}.research-assistant__stats{gap:var(--ra-space-sm);flex-wrap:wrap;margin:0;display:flex}.research-assistant__stats>div{min-width:0;padding:var(--ra-space-md);border:1px solid var(--app-color-border,#e0e5e4);background:var(--app-color-bg-item,#f6f8f7);color:var(--app-color-text-secondary,#60746b);border-radius:12px;flex:88px;font-size:11px}.research-assistant__stats strong{font-variant-numeric:tabular-nums;color:var(--app-color-text-primary,#20332d);align-items:baseline;gap:5px;margin-bottom:5px;font-size:25px;font-weight:500;line-height:1.2;display:flex}.research-assistant__stats small{color:var(--app-color-text-tertiary,#87968f);font-size:10px;font-weight:400}.research-assistant__stats .has-errors strong{color:#cd805e}.research-assistant__json{border:1px solid var(--app-color-border,#e0e5e4);background:var(--app-color-bg-layout,#f6f8f7);max-height:380px;color:var(--app-color-text-primary,#20332d);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px;margin:12px 0;padding:14px;font:12px/1.8 Consolas,monospace;overflow:auto}.research-assistant__filters{gap:var(--ra-space-sm);flex-wrap:wrap;display:flex}.research-assistant__filters>.ant-input-affix-wrapper{flex:180px;min-width:0}.research-assistant__filters select{border:1px solid var(--app-color-border,#e0e5e4);min-height:32px;color:var(--app-color-text-primary,#20332d);background:var(--app-color-bg-container,#fff);border-radius:6px;flex:0 128px;padding:4px 8px}.research-assistant__timeline{margin:0;padding:0 0 0 12px;list-style:none}.research-assistant__timeline>li{border-left:2px solid var(--app-color-border,#e0e5e4);flex-direction:column;gap:8px;padding:0 0 24px 16px;display:flex;position:relative}.research-assistant__timeline>li:before{content:"";background:#73ac98;border-radius:50%;width:8px;height:8px;position:absolute;top:8px;left:-5px}.research-assistant__timeline>li.is-error:before{background:#d98775}.research-assistant__timeline>li>strong{overflow-wrap:anywhere;margin:0;font-size:13px;display:block}.research-assistant__timeline time,.research-assistant__timeline small{color:var(--app-color-text-secondary,#60746b);margin:0;font-size:12px}.research-assistant__timeline details{margin:0;font-size:12px}.research-assistant__request{border:1px solid var(--app-color-border,#e0e5e4);border-radius:10px;padding:16px}.research-assistant__request summary{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.research-assistant__request summary:before{content:"›";font-size:18px;transition:transform .15s}.research-assistant__request[open] summary:before{transform:rotate(90deg)}.research-assistant__request summary::-webkit-details-marker{display:none}.research-assistant__request .research-assistant__request-url{overflow-wrap:anywhere;flex:1 0 100%;min-width:0;margin:0;font:12px/1.8 Consolas,monospace}.research-assistant__metrics{gap:var(--ra-space-md);flex-wrap:wrap;display:flex}.research-assistant__metrics>div{border:1px solid var(--app-color-border,#e0e5e4);border-radius:10px;flex:180px;min-width:0;padding:16px}.research-assistant__metrics span{color:var(--app-color-text-secondary,#60746b);font-size:12px;display:block}.research-assistant__metrics strong{margin-top:8px;font-size:20px;font-weight:500;display:block}.research-assistant__footer{border-top:1px solid var(--app-color-border,#e0e5e4);color:var(--app-color-text-tertiary,#87968f);flex:none;justify-content:space-between;gap:10px;padding:10px 24px 10px 20px;font-size:10px;display:flex}.research-assistant__footer>span:first-child{align-items:center;gap:6px;display:flex}.research-assistant__footer i{background:#64ad8b;border-radius:50%;width:5px;height:5px}.research-assistant__resize{cursor:nwse-resize;touch-action:none;background:repeating-linear-gradient(135deg, transparent, transparent 3px, var(--app-color-text-tertiary,#87968f) 3px, var(--app-color-text-tertiary,#87968f) 4px) 6px 6px / 10px 10px no-repeat;width:26px;height:26px;position:absolute;bottom:3px;right:3px}.research-assistant__case-steps{gap:var(--ra-space-md);flex-direction:column;max-height:440px;margin:0;padding:0;list-style:none;display:flex;overflow:auto}.research-assistant__case-steps:empty{display:none}.research-assistant__case-steps>li{border:1px solid var(--app-color-border,#e0e5e4);background:var(--app-color-bg-layout,#f6f8f7);border-radius:8px;flex-direction:column;flex:none;gap:12px;padding:16px;display:flex}.research-assistant__case-steps code{overflow-wrap:anywhere;font-size:11px}.research-assistant__case-steps .ant-input{margin:0}.research-assistant__section input[type=number]{border:1px solid var(--app-color-border,#e0e5e4);width:90px;color:var(--app-color-text-primary,#20332d);background:var(--app-color-bg-layout,#f6f8f7);border-radius:6px;padding:4px 8px}.research-assistant__button-row,.research-assistant__event-meta,.research-assistant__step-heading,.research-assistant__card-heading,.research-assistant__request-meta,.research-assistant__stat-label,.research-assistant__subheading{align-items:center;gap:var(--ra-space-sm);flex-wrap:wrap;min-width:0;display:flex}.research-assistant__button-row .ant-tag,.research-assistant__event-meta .ant-tag,.research-assistant__step-heading .ant-tag,.research-assistant__card-heading .ant-tag,.research-assistant__request-meta .ant-tag,.research-assistant__stat-label .ant-tag,.research-assistant__subheading .ant-tag{margin:0}.research-assistant__button-row>.ant-btn{white-space:normal;flex:0 auto;max-width:100%;height:auto;min-height:32px;padding-block:5px;font-size:13px}.research-assistant__toolbar-actions{gap:4px;margin-left:auto}.research-assistant__section-heading{align-items:center;gap:12px;display:flex}.research-assistant__section-heading>div{flex:1;min-width:0}.research-assistant__section-heading h3{font-size:15px;font-weight:600;line-height:1.5}.research-assistant__section-heading p{color:var(--app-color-text-secondary,#60746b);margin:4px 0 0;font-size:12px;line-height:1.6}.research-assistant__section-heading>.ant-tag{margin:0}.research-assistant__heading-icon{border:1px solid var(--app-color-border,#e0e5e4);background:var(--app-color-bg-item,#f6f8f7);width:36px;height:36px;color:var(--app-color-primary,#237956);border-radius:10px;flex:0 0 36px;justify-content:center;align-items:center;font-size:17px;display:flex}.research-assistant__field,.research-assistant__form-stack{gap:var(--ra-space-sm);flex-direction:column;min-width:0;display:flex}.research-assistant__field>label,.research-assistant__form-stack>label{color:var(--app-color-text-secondary,#60746b);align-items:center;gap:8px;font-size:12px;font-weight:500;display:flex}.research-assistant__field .ant-input-textarea-show-count,.research-assistant__form-stack .ant-input-textarea-show-count{margin-bottom:16px}.research-assistant__form-stack{gap:var(--ra-space-md)}.research-assistant__automation-layout{align-items:stretch;gap:var(--ra-space-md);flex-direction:column;min-width:0;display:flex}.research-assistant__card{gap:var(--ra-space-md);padding:var(--ra-space-md);box-sizing:border-box;border:1px solid var(--app-color-border,#e0e5e4);background:var(--app-color-bg-item,#f6f8f7);border-radius:12px;flex-direction:column;min-width:0;display:flex}.research-assistant__card p{overflow-wrap:anywhere}.research-assistant__card h3{align-items:center;gap:8px;font-size:14px;display:flex}.research-assistant__card .ant-tag{margin:0}.research-assistant__card-heading{justify-content:space-between}.research-assistant__card-heading>span{color:var(--app-color-text-tertiary,#87968f);font-size:12px}.research-assistant__card-heading h3>.anticon{color:var(--app-color-primary,#237956)}.research-assistant__card-actions{border-top:1px solid var(--app-color-border,#e0e5e4);padding-top:16px}.research-assistant__checkpoint-row{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.research-assistant__checkpoint-row>.ant-input{flex:168px;min-width:0}.research-assistant__checkpoint-row>.ant-btn{flex:none}.research-assistant__delay-row{color:var(--app-color-text-secondary,#60746b);align-items:center;gap:8px;font-size:12px;display:flex}.research-assistant__step-heading>strong{overflow-wrap:anywhere;flex:120px;min-width:0;font-size:13px}.research-assistant__step-number{color:var(--app-color-text-tertiary,#87968f);font:12px Consolas,monospace}.research-assistant__step-actions{padding-top:4px}.research-assistant__saved-case{color:var(--app-color-text-secondary,#60746b);flex-wrap:wrap;align-items:center;gap:8px;margin:0;font-size:12px;display:flex}.research-assistant__help summary,.research-assistant__supplement summary{line-height:1.7}.research-assistant__help summary .anticon,.research-assistant__supplement summary .anticon{margin-right:8px}.research-assistant__help>.research-assistant__hint,.research-assistant__supplement>.research-assistant__hint{margin-top:8px}.research-assistant__help>.research-assistant__form-stack,.research-assistant__supplement>.research-assistant__form-stack{margin-top:16px}.research-assistant__empty-steps{border:1px dashed var(--app-color-border,#e0e5e4);color:var(--app-color-text-secondary,#60746b);border-radius:8px;flex-direction:column;align-items:center;gap:8px;padding:24px 16px;font-size:12px;display:flex}.research-assistant__empty-steps>.anticon{color:var(--app-color-text-tertiary,#87968f);font-size:24px}.research-assistant__empty-steps p{color:var(--app-color-text-tertiary,#87968f);margin:0;font-size:11px}.research-assistant__request-meta{flex:1}.research-assistant__request-meta>span:last-child{color:var(--app-color-text-tertiary,#87968f);align-items:center;gap:4px;margin-left:auto;display:flex}.research-assistant.is-expanded .research-assistant__section{max-width:1040px;margin-inline:auto}.research-assistant.is-expanded .research-assistant__json,.research-assistant.is-expanded .research-assistant__case-steps{max-height:none}@media (width<=600px){.research-assistant__dock{bottom:12px;right:12px}.research-assistant__header{padding:12px}.research-assistant__drag{gap:8px}.research-assistant__drag h2 span{display:none}.research-assistant__drag p{font-size:10px}.research-assistant__toolbar{flex-wrap:wrap;gap:4px;padding-inline:12px}.research-assistant__sources{padding-inline:12px}.research-assistant__section{padding:16px}.research-assistant__footer{padding-left:12px}.research-assistant__footer>span:last-child{display:none}.research-assistant__main-tabs>.ant-tabs-nav{padding-inline:12px}.research-assistant__main-tabs>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab{margin-left:0}}@container research-assistant (width<=420px){.research-assistant__section{gap:16px;padding:16px}.research-assistant__sources{padding-inline:16px}.research-assistant__stats>div{padding:12px}.research-assistant__stat-label{gap:4px}.research-assistant__main-tabs>.ant-tabs-nav .ant-tabs-tab-btn{flex-direction:column;gap:4px;font-size:12px}.research-assistant__main-tabs>.ant-tabs-nav .ant-tabs-tab{padding-block:8px}.research-assistant__diagnostic-tabs>.ant-tabs-nav{padding-inline:16px}.research-assistant__diagnostic-tabs>.ant-tabs-nav .ant-tabs-nav-list{gap:4px}.research-assistant__diagnostic-tabs>.ant-tabs-nav .ant-tabs-tab-btn{flex-direction:column;gap:4px;font-size:11px}.research-assistant__diagnostic-tabs>.ant-tabs-nav .ant-tabs-tab{padding-inline:4px}}@media (prefers-reduced-motion:reduce){.research-assistant__dock,.research-assistant__scroll-thumb{transition:none}}.research-assistant__automation-layout>.research-assistant__card{box-sizing:border-box;flex:none;width:100%;min-width:0}.research-assistant__issue-list{flex-direction:column;gap:12px;display:flex}.research-assistant__performance-issue p{margin:0;line-height:1.7}.research-assistant__performance-issue summary{cursor:pointer;color:var(--app-color-primary,#237956)}.research-assistant__performance-issue ol{padding-left:22px;line-height:1.8}.research-assistant__memory-chart{width:100%;height:100px;color:var(--app-color-primary,#237956);display:block}.research-assistant__assertion-area,.research-assistant__assertion-results,.research-assistant__assertion-result{flex-direction:column;gap:12px;min-width:0;display:flex}.research-assistant__assertion-area{border-top:1px solid var(--app-color-border,#e0e5e4);padding-top:16px}.research-assistant__assertion-area>.ant-btn{align-self:flex-start}.research-assistant__assertion-editor,.research-assistant__assertion-result{border:1px solid var(--app-color-border,#e0e5e4);background:var(--app-color-bg-layout,#f6f8f7);border-radius:8px;padding:16px}.research-assistant__assertion-editor .ant-select,.research-assistant__assertion-result .ant-select{width:100%;min-width:0}.research-assistant__assertion-editor .ant-input-number,.research-assistant__assertion-result .ant-input-number{width:100%}.research-assistant__assertion-fields,.research-assistant__assertion-summary{flex-wrap:wrap;gap:12px;min-width:0;display:flex}.research-assistant__assertion-fields>.research-assistant__field,.research-assistant__assertion-summary>.research-assistant__field{flex:160px}.research-assistant__assertion-fields code,.research-assistant__assertion-summary code{overflow-wrap:anywhere;flex:100%}.research-assistant__assertion-result dl{flex-direction:column;gap:4px;margin:0;display:flex}.research-assistant__assertion-result dl dt{color:var(--app-color-text-secondary,#60746b);font-size:12px}.research-assistant__assertion-result dl dd{overflow-wrap:anywhere;white-space:pre-wrap;margin:0 0 8px}
11
+ /*$vite$:1*/
@@ -0,0 +1,4 @@
1
+ import { type RefObject } from 'react';
2
+ import 'overlayscrollbars/overlayscrollbars.css';
3
+ /** React owns content; OverlayScrollbars owns only its overlay handles and listeners. */
4
+ export declare function useOverlayScrollbars(rootRef: RefObject<HTMLElement | null>, open: boolean): void;
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "gz-research-assistant",
3
+ "version": "0.1.0",
4
+ "description": "Research assistant with diagnostics, recording and declarative browser assertions",
5
+ "type": "module",
6
+ "license": "UNLICENSED",
7
+ "files": [
8
+ "dist",
9
+ "README.md"
10
+ ],
11
+ "sideEffects": [
12
+ "**/*.css"
13
+ ],
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js"
18
+ },
19
+ "./core": {
20
+ "types": "./dist/core.d.ts",
21
+ "import": "./dist/core.js"
22
+ },
23
+ "./sdk": {
24
+ "types": "./dist/sdk.d.ts",
25
+ "import": "./dist/sdk.js"
26
+ },
27
+ "./style.css": "./dist/style.css"
28
+ },
29
+ "scripts": {
30
+ "build": "vite build && tsc -p tsconfig.json",
31
+ "prepack": "npm run build"
32
+ },
33
+ "dependencies": {
34
+ "gz-laya-pilot": "0.1.0",
35
+ "overlayscrollbars": "^2.16.0"
36
+ },
37
+ "peerDependencies": {
38
+ "@ant-design/icons": "^6.1.0",
39
+ "@chenhui996/gg-ui": "0.1.6",
40
+ "antd": "^6.3.3",
41
+ "react": "^19.2.4",
42
+ "react-dom": "^19.2.4"
43
+ },
44
+ "devDependencies": {
45
+ "@types/react": "^19.2.14",
46
+ "@types/react-dom": "^19.2.3",
47
+ "less": "^4.6.4",
48
+ "typescript": "~5.9.3",
49
+ "vite": "^8.0.0"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public",
53
+ "registry": "https://registry.npmjs.org/"
54
+ }
55
+ }