@sparkelf/dsh-artifact-app 0.0.0-stage → 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/README.md +56 -2
- package/cordis.patch.yml +3 -0
- package/lib/client.js +824 -0
- package/lib/client.js.map +1 -0
- package/lib/index.d.ts +638 -0
- package/lib/index.js +2154 -0
- package/package.json +82 -3
- package/skills/artifact-app-authoring/SKILL.md +157 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","names":["useRef","useState","useState","useCallback","useMemo","useState"],"sources":["../src/client/CockpitViewer.tsx","../src/client/CockpitTab.tsx","../src/client/ArtifactFileViewer.tsx","../src/client/index.tsx"],"sourcesContent":["/**\n * Sandboxed cockpit viewer.\n *\n * The iframe is served by the plugin's render route and runs with\n * `sandbox=\"allow-scripts allow-same-origin\"` (opaque origin). The workspace token reaches it only\n * through postMessage, and only after this parent verified the message source.\n *\n * @module client/CockpitViewer\n */\n\nimport { useEffect, useRef, useState, type CSSProperties } from 'react'\n\n/** Addresses resolved from the host config route. */\ninterface ViewerConfig {\n renderBaseUrl: string\n gatewayBaseUrl: string\n dataopsWebBaseUrl: string\n}\n\n/** Message the runtime posts to its parent. */\ninterface RuntimeMessage {\n source?: string\n type?: string\n resourceRef?: string\n}\n\nconst frameStyle: CSSProperties = {\n width: '100%',\n height: '100%',\n // 宿主侧栏的 tab 容器不一定是可伸展的 flex 父级,只写 height:100% 会被压到 ~140px\n // (实测 clientHeight=142,画布被裁成一条)。给一个下限,让驾驶舱在任何容器里都能看。\n minHeight: '520px',\n border: '0',\n display: 'block',\n background: '#060a14',\n}\n\n/**\n * Render one cockpit in a sandboxed iframe and keep its bootstrap config fed.\n * @param props.artifactId - cockpit (or preview draft) id.\n * @param props.refreshKey - changing it reloads the iframe, used by \"updated\" events.\n * @param props.reloadToken - bump from outside to force a reload.\n */\nexport function CockpitViewer({ artifactId, reloadToken }: { artifactId: string; reloadToken?: number }) {\n const frameRef = useRef<HTMLIFrameElement | null>(null)\n /** iframe 加载完成后重发一次引导配置:`hello` 可能在监听器挂上之前就发出去了。 */\n const resendRef = useRef<(() => void) | null>(null)\n const [config, setConfig] = useState<ViewerConfig | null>(null)\n const [token, setToken] = useState<string | null>(null)\n const [error, setError] = useState<string | null>(null)\n\n useEffect(() => {\n let alive = true\n void (async () => {\n try {\n const [configResponse, tokenResponse] = await Promise.all([\n fetch('/dsh-artifact-app/config', { headers: { accept: 'application/json' } }),\n fetch('/dsh-artifact-app/token', { headers: { accept: 'application/json' } }),\n ])\n const configPayload = await configResponse.json() as ViewerConfig & { error?: string }\n const tokenPayload = await tokenResponse.json() as { token?: string; error?: string }\n if (!configResponse.ok) throw new Error(configPayload.error ?? '读取驾驶舱配置失败')\n if (!tokenResponse.ok || typeof tokenPayload.token !== 'string') throw new Error(tokenPayload.error ?? '读取 DataOps 登录凭证失败')\n if (alive) {\n setConfig(configPayload)\n setToken(tokenPayload.token)\n }\n } catch (cause) {\n if (alive) setError(cause instanceof Error ? cause.message : String(cause))\n }\n })()\n return () => { alive = false }\n }, [])\n\n useEffect(() => {\n if (config === null || token === null) return undefined\n /** 把引导配置推给 iframe;`hello` 与 iframe 的 load 事件都会触发它。 */\n const sendConfig = (): void => {\n frameRef.current?.contentWindow?.postMessage({\n source: 'dataops-artifact-host',\n type: 'config',\n payload: {\n artifactId,\n token,\n gatewayBaseUrl: config.gatewayBaseUrl,\n refreshIntervalSeconds: 300,\n keepConnection: false,\n locale: 'zh-CN',\n theme: 'dark',\n },\n }, '*')\n }\n const onMessage = (event: MessageEvent): void => {\n const frame = frameRef.current\n if (frame === null || event.source !== frame.contentWindow) return\n const data = event.data as RuntimeMessage | null\n if (data === null || typeof data !== 'object' || data.source !== 'dataops-artifact-app') return\n if (data.type === 'request-access') {\n const target = config.dataopsWebBaseUrl.replace(/\\/+$/u, '')\n window.open(target, '_blank', 'noopener,noreferrer')\n return\n }\n if (data.type !== 'hello' && data.type !== 'ready' && data.type !== 'token:expired') return\n sendConfig()\n }\n resendRef.current = sendConfig\n window.addEventListener('message', onMessage)\n return () => { resendRef.current = null; window.removeEventListener('message', onMessage) }\n }, [artifactId, config, token])\n\n if (error !== null) {\n return <div role=\"alert\" style={{ padding: 18, color: '#b91c1c', fontSize: 12 }}>{error}</div>\n }\n if (config === null || token === null) {\n return <div style={{ padding: 18, color: 'var(--dsw-alias-label-secondary, #6b7280)', fontSize: 12 }}>正在准备驾驶舱…</div>\n }\n const src = config.renderBaseUrl.replace(/\\/+$/u, '') + '/' + encodeURIComponent(artifactId) + (reloadToken === undefined ? '' : '?r=' + String(reloadToken))\n return (\n <iframe\n ref={frameRef}\n title=\"驾驶舱\"\n src={src}\n sandbox=\"allow-scripts allow-same-origin\"\n allow=\"fullscreen\"\n onLoad={() => resendRef.current?.()}\n style={frameStyle}\n data-artifact-viewer={artifactId}\n />\n )\n}","/**\n * The `dataops-artifact-apps` right-sidebar tab.\n *\n * One pane holds the cockpit list and, once a card is opened, the sandboxed\n * viewer. The list is proxied by the host so the browser holds no DataOps token\n * for reads.\n *\n * @module client/CockpitTab\n */\n\nimport { useCallback, useEffect, useMemo, useState, type CSSProperties } from 'react'\nimport { CockpitViewer } from './CockpitViewer.tsx'\n\n/** Minimal tab record Better Sidebar passes. */\ninterface TabRecord {\n meta?: unknown\n title?: string\n}\n\n/** Props this tab consumes. */\nexport interface CockpitTabProps {\n tab: TabRecord\n scope?: { sessionId?: string }\n visible?: boolean\n}\n\ninterface AppRow {\n id: string\n name: string\n description?: string | null\n catalog?: string | null\n status: string\n currentVersion: number\n publishedVersion: number\n updatedAt: string\n}\n\nconst readMeta = (value: unknown): { cockpitId?: string; cockpitName?: string; nonce?: string } => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return {}\n const record = value as Record<string, unknown>\n return {\n cockpitId: typeof record.cockpitId === 'string' ? record.cockpitId : undefined,\n cockpitName: typeof record.cockpitName === 'string' ? record.cockpitName : undefined,\n nonce: typeof record.nonce === 'string' ? record.nonce : undefined,\n }\n}\n\nconst cardStyle: CSSProperties = {\n display: 'grid',\n gap: 4,\n width: '100%',\n minWidth: 0,\n textAlign: 'left',\n padding: '10px 12px',\n borderRadius: 10,\n border: '1px solid var(--dsw-alias-border-l1, #e5e7eb)',\n background: 'var(--dsw-alias-bg-layer-1, #ffffff)',\n color: 'inherit',\n cursor: 'pointer',\n}\n\nconst muted: CSSProperties = { fontSize: 10, color: 'var(--dsw-alias-label-secondary, #6b7280)' }\n\n/** Cockpit list plus viewer. */\nexport function CockpitTab({ tab }: CockpitTabProps) {\n const meta = readMeta(tab.meta)\n const [apps, setApps] = useState<AppRow[]>([])\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<string | null>(null)\n const [selected, setSelected] = useState<{ id: string; name: string } | null>(\n meta.cockpitId === undefined ? null : { id: meta.cockpitId, name: meta.cockpitName ?? '驾驶舱' },\n )\n const [reloadToken, setReloadToken] = useState(0)\n\n const load = useCallback(async () => {\n setLoading(true)\n setError(null)\n try {\n const response = await fetch('/dsh-artifact-app/apps?pageSize=50', { headers: { accept: 'application/json' } })\n const payload = await response.json() as { items?: AppRow[]; error?: string }\n if (!response.ok) throw new Error(payload.error ?? 'HTTP ' + String(response.status))\n setApps(payload.items ?? [])\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : String(cause))\n } finally {\n setLoading(false)\n }\n }, [])\n\n useEffect(() => { void load() }, [load])\n\n useEffect(() => {\n if (meta.cockpitId === undefined) return\n setSelected({ id: meta.cockpitId, name: meta.cockpitName ?? '驾驶舱' })\n setReloadToken((value) => value + 1)\n }, [meta.cockpitId, meta.cockpitName, meta.nonce])\n\n const catalogs = useMemo(() => [...new Set(apps.map((app) => app.catalog).filter((value): value is string => typeof value === 'string' && value !== ''))], [apps])\n\n /**\n * 导出一份可脱离 DSH 单独分发的 HTML:服务端返回的 HTML 已烧死 appId 与网关地址,\n * 这里再把运行时与 ECharts 内联进去,产物双击即可打开(地址栏加 #token=… 取数)。\n */\n const [exporting, setExporting] = useState(false)\n const exportHtml = async (): Promise<void> => {\n if (selected === null || exporting) return\n setExporting(true)\n try {\n const base = '/dsh-artifact-app/gateway/api/artifact-apps'\n const [htmlResponse, runtimeResponse, echartsResponse] = await Promise.all([\n fetch(base.replace(/\\/+$/u, '') + '/' + encodeURIComponent(selected.id) + '/html', { headers: { accept: 'application/json' } }),\n fetch(base.replace(/\\/+$/u, '') + '/runtime.js'),\n fetch(base.replace(/\\/+$/u, '') + '/echarts.js'),\n ])\n if (!htmlResponse.ok) throw new Error('读取驾驶舱 HTML 失败')\n const payload = await htmlResponse.json() as { html?: string }\n const runtime = runtimeResponse.ok ? await runtimeResponse.text() : ''\n const echarts = echartsResponse.ok ? await echartsResponse.text() : ''\n const inline = (runtime === '' ? '' : '<script>' + runtime + '<\\/script>') + (echarts === '' ? '' : '<script>' + echarts + '<\\/script>')\n const html = (payload.html ?? '').replace('</body>', inline + '</body>')\n const blob = new Blob([html], { type: 'text/html;charset=utf-8' })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = (selected.name || 'cockpit') + '.html'\n document.body.appendChild(link)\n link.click()\n link.remove()\n URL.revokeObjectURL(url)\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : String(cause))\n } finally {\n setExporting(false)\n }\n }\n\n if (selected !== null) {\n return (\n <div style={{ display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0 }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 10px', borderBottom: '1px solid var(--dsw-alias-border-l1, #e5e7eb)' }}>\n <button type=\"button\" onClick={() => setSelected(null)} style={{ border: 'none', background: 'transparent', color: 'inherit', cursor: 'pointer', fontSize: 12, padding: 0 }}>← 列表</button>\n <div style={{ flex: 1, minWidth: 0, fontSize: 12, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{selected.name}</div>\n <button\n type=\"button\"\n title=\"刷新\"\n aria-label=\"刷新\"\n onClick={() => setReloadToken((value) => value + 1)}\n style={{ border: 'none', background: 'transparent', color: 'inherit', cursor: 'pointer', display: 'grid', placeItems: 'center', width: 26, height: 26, borderRadius: 6 }}\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.9\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M21 12a9 9 0 1 1-3-6.7\" />\n <path d=\"M21 4v5h-5\" />\n </svg>\n </button>\n <button\n type=\"button\"\n title=\"全屏查看\"\n aria-label=\"全屏查看\"\n onClick={() => {\n const host = document.querySelector('[data-artifact-fullscreen-host]') as HTMLElement | null\n const target = host ?? document.querySelector('iframe[data-artifact-viewer]')?.parentElement ?? null\n if (target === null) return\n if (document.fullscreenElement !== null) void document.exitFullscreen()\n else void target.requestFullscreen?.().catch(() => undefined)\n }}\n style={{ border: 'none', background: 'transparent', color: 'inherit', cursor: 'pointer', display: 'grid', placeItems: 'center', width: 26, height: 26, borderRadius: 6 }}\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.9\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M4 9V4h5\" /><path d=\"M20 9V4h-5\" /><path d=\"M4 15v5h5\" /><path d=\"M20 15v5h-5\" />\n </svg>\n </button>\n <button\n type=\"button\"\n title=\"导出 HTML\"\n aria-label=\"导出 HTML\"\n disabled={exporting}\n onClick={() => void exportHtml()}\n style={{ border: 'none', background: 'transparent', color: 'inherit', cursor: exporting ? 'progress' : 'pointer', display: 'grid', placeItems: 'center', width: 26, height: 26, borderRadius: 6, opacity: exporting ? 0.5 : 1 }}\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.9\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M12 3v12\" />\n <path d=\"M7 10l5 5 5-5\" />\n <path d=\"M4 21h16\" />\n </svg>\n </button>\n </div>\n <div data-artifact-fullscreen-host style={{ flex: 1, minHeight: 0 }}>\n <CockpitViewer artifactId={selected.id} reloadToken={reloadToken} />\n </div>\n </div>\n )\n }\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0 }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '10px 12px', borderBottom: '1px solid var(--dsw-alias-border-l1, #e5e7eb)' }}>\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ fontSize: 12, fontWeight: 600 }}>驾驶舱</div>\n <div style={muted}>DataOps 驾驶舱资产 · {apps.length} 个{catalogs.length > 0 ? ' · ' + catalogs.join(' / ') : ''}</div>\n </div>\n <button type=\"button\" onClick={() => void load()} style={{ border: 'none', background: 'transparent', color: 'inherit', cursor: 'pointer', fontSize: 12 }}>刷新</button>\n </div>\n <div style={{ flex: 1, minHeight: 0, overflowY: 'auto', padding: 10, display: 'grid', gap: 8, alignContent: 'start' }}>\n {loading ? <div style={{ ...muted, textAlign: 'center', padding: 18 }}>正在加载驾驶舱…</div> : null}\n {error !== null ? <div role=\"alert\" style={{ padding: '8px 10px', borderRadius: 8, background: '#fef2f2', color: '#b91c1c', fontSize: 11 }}>{error}</div> : null}\n {!loading && error === null && apps.length === 0 ? <div style={{ ...muted, textAlign: 'center', padding: 18 }}>暂无驾驶舱</div> : null}\n {apps.map((app) => (\n <button\n key={app.id}\n type=\"button\"\n style={cardStyle}\n onClick={() => setSelected({ id: app.id, name: app.name })}\n data-cockpit-id={app.id}\n >\n <span style={{ display: 'flex', alignItems: 'center', gap: 6, minWidth: 0 }}>\n <span style={{ flex: 1, minWidth: 0, fontSize: 12, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{app.name}</span>\n <span style={{ ...muted, flex: 'none' }}>{app.status === 'PUBLISHED' ? '已发布' : '草稿'}</span>\n </span>\n {app.description ? <span style={{ ...muted, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{app.description}</span> : null}\n <span style={muted}>{app.catalog ?? '未分类'} · v{app.publishedVersion || app.currentVersion}</span>\n </button>\n ))}\n </div>\n </div>\n )\n}","/**\n * HTML file viewer for cockpit files.\n *\n * The descriptor only matches `/artifact-apps/**` HTML carrying the\n * `artifact-app` meta marker. Opening such a file creates or updates one draft\n * through the host and renders it exactly like a published cockpit, so the file\n * on disk is the draft.\n *\n * @module client/ArtifactFileViewer\n */\n\nimport { useEffect, useState } from 'react'\nimport { CockpitViewer } from './CockpitViewer.tsx'\n\n/** Props the Better Sidebar file viewer passes. */\nexport interface ArtifactFileViewerProps {\n path: string\n title?: string\n content?: string\n largeFile?: { size: number }\n}\n\n/** Marker the file must carry for this viewer to claim it. */\nexport const ARTIFACT_FILE_MARKER = /<meta[^>]+name=[\"']artifact-app[\"'][^>]*>/iu\n\n/**\n * Whether a file is a cockpit document.\n * @param path - workspace path.\n * @param head - the first bytes the viewer sniffed.\n */\nexport const isArtifactFile = (path: string, head: Uint8Array | string): boolean => {\n if (!/\\/artifact-apps\\/[^/]+\\.html?$/iu.test(path)) return false\n const text = typeof head === 'string' ? head : new TextDecoder().decode(head)\n return ARTIFACT_FILE_MARKER.test(text)\n}\n\n/** Create/update the preview draft, then render it. */\nexport function ArtifactFileViewer({ path, content, largeFile }: ArtifactFileViewerProps) {\n const [artifactId, setArtifactId] = useState<string | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [busy, setBusy] = useState(false)\n const [attempt, setAttempt] = useState(0)\n\n useEffect(() => {\n if (content === undefined) return undefined\n let alive = true\n setBusy(true)\n setError(null)\n void (async () => {\n try {\n const response = await fetch('/dsh-artifact-app/preview', {\n method: 'POST',\n headers: { 'content-type': 'application/json', accept: 'application/json' },\n body: JSON.stringify({ path, html: content }),\n })\n const payload = await response.json() as { artifactId?: string; error?: string }\n if (!response.ok || typeof payload.artifactId !== 'string') {\n throw new Error(payload.error ?? 'HTTP ' + String(response.status))\n }\n if (alive) setArtifactId(payload.artifactId)\n } catch (cause) {\n if (alive) setError(cause instanceof Error ? cause.message : String(cause))\n } finally {\n if (alive) setBusy(false)\n }\n })()\n return () => { alive = false }\n }, [path, content, attempt])\n\n if (largeFile !== undefined) {\n return <div style={{ padding: 18, fontSize: 12, color: 'var(--dsw-alias-label-secondary, #6b7280)' }}>文件过大({Math.round(largeFile.size / 1024)} KB),请缩小后再预览驾驶舱。</div>\n }\n if (error !== null) {\n return (\n <div role=\"alert\" style={{ padding: 12, margin: 12, borderRadius: 8, background: '#fef2f2', color: '#b91c1c', fontSize: 12, display: 'grid', gap: 8 }}>\n <span style={{ whiteSpace: 'pre-wrap' }}>{error}</span>\n <button type=\"button\" onClick={() => setAttempt((value) => value + 1)} style={{ justifySelf: 'start', border: '1px solid #fca5a5', background: 'transparent', color: '#b91c1c', borderRadius: 6, padding: '3px 10px', cursor: 'pointer', fontSize: 11 }}>重试</button>\n </div>\n )\n }\n if (busy || artifactId === null) {\n return <div style={{ padding: 18, fontSize: 12, color: 'var(--dsw-alias-label-secondary, #6b7280)' }}>正在生成驾驶舱预览…</div>\n }\n return <CockpitViewer artifactId={artifactId} />\n}","/**\n * Client half of the artifact-app plugin.\n *\n * Registers the `dataops-artifact-apps` right-sidebar tab, the cockpit HTML file\n * viewer, and the SSE bridge that lets `cockpit_open` drive the sidebar. All three\n * are optional when a profile has no Better Sidebar: the host routes and tools keep\n * working without a browser surface.\n *\n * @module @sparkelf/dsh-artifact-app/client\n */\n\nimport { useEffect } from 'react'\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport { CockpitTab } from './CockpitTab.tsx'\nimport { ArtifactFileViewer, isArtifactFile } from './ArtifactFileViewer.tsx'\n\n/** Client services this plugin reads; `slots` owns the always-mounted bridge seat. */\nexport const inject = ['slots']\n\n/** Tab id shared by registration, the bridge and the tools. */\nexport const ARTIFACT_TAB_TYPE = 'dataops-artifact-apps'\n/** File viewer id. */\nexport const ARTIFACT_VIEWER_ID = 'artifact-app:cockpit'\n\n/** The part of Better Sidebar this plugin uses. */\ninterface BetterSidebarLike {\n registerTab?(descriptor: Record<string, unknown>): () => void\n registerFileViewer?(descriptor: Record<string, unknown>): () => void\n openTab?(seed: { type: string; id?: string; title?: string; meta?: unknown }, scope?: { sessionId?: string }): void\n updateTab?(tabId: string, patch: { title?: string; meta?: unknown }, sessionId?: string): void\n}\n\ninterface OpenEvent {\n type: 'open_cockpit'\n cockpitId: string\n cockpitName: string | null\n mode: string\n nonce: string\n requestId: string\n}\n\ninterface UpdatedEvent {\n type: 'cockpit_updated'\n cockpitId: string\n nonce: string\n}\n\n/** Invisible bridge: SSE navigation events become Better Sidebar calls. */\nfunction OpenCockpitBridge({ service, scope }: { service: BetterSidebarLike; scope?: { sessionId?: string } }) {\n useEffect(() => {\n if (typeof EventSource !== 'function') return undefined\n const source = new EventSource('/dsh-artifact-app/open/events')\n const open = (event: MessageEvent): void => {\n let parsed: OpenEvent\n try { parsed = JSON.parse(String(event.data)) as OpenEvent } catch { return }\n if (parsed.type !== 'open_cockpit' || typeof parsed.cockpitId !== 'string') return\n const meta = { cockpitId: parsed.cockpitId, cockpitName: parsed.cockpitName, nonce: parsed.nonce, mode: parsed.mode }\n service.openTab?.({ type: ARTIFACT_TAB_TYPE, id: ARTIFACT_TAB_TYPE, title: '驾驶舱', meta }, scope)\n service.updateTab?.(ARTIFACT_TAB_TYPE, { title: '驾驶舱', meta }, scope?.sessionId)\n }\n const updated = (event: MessageEvent): void => {\n let parsed: UpdatedEvent\n try { parsed = JSON.parse(String(event.data)) as UpdatedEvent } catch { return }\n if (parsed.type !== 'cockpit_updated' || typeof parsed.cockpitId !== 'string') return\n service.updateTab?.(ARTIFACT_TAB_TYPE, {\n title: '驾驶舱',\n meta: { cockpitId: parsed.cockpitId, nonce: parsed.nonce },\n }, scope?.sessionId)\n }\n source.addEventListener('dataops-open-cockpit', open as EventListener)\n source.addEventListener('dataops-cockpit-updated', updated as EventListener)\n return () => {\n source.removeEventListener('dataops-open-cockpit', open as EventListener)\n source.removeEventListener('dataops-cockpit-updated', updated as EventListener)\n source.close()\n }\n }, [service, scope])\n return null\n}\n\n/**\n * Register the tab, the file viewer and the bridge.\n * @param ctx - DSH client context.\n */\nexport function apply(ctx: ClientContext): void {\n try {\n ctx.effect(() => {\n let disposeTab: (() => void) | undefined\n let disposeViewer: (() => void) | undefined\n let disposeBridge: (() => void) | undefined\n let betterSidebarService: BetterSidebarLike | undefined\n const inject = (ctx as unknown as {\n inject?: (names: readonly string[], callback: (injected: { betterSidebar?: BetterSidebarLike }) => void) => unknown\n }).inject\n inject?.(['betterSidebar'], (injected) => {\n const service = injected.betterSidebar\n if (service?.registerTab === undefined) return\n betterSidebarService = service\n disposeTab = service.registerTab({\n id: ARTIFACT_TAB_TYPE,\n title: '驾驶舱',\n icon: (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M4 18a8 8 0 1 1 16 0\" />\n <path d=\"M12 18l4.2-5\" />\n <circle cx=\"12\" cy=\"18\" r=\"1.4\" />\n </svg>\n ),\n\n description: 'DataOps 驾驶舱资产、预览与发布',\n order: 62,\n single: true,\n component: ((props: Record<string, unknown>) => CockpitTab(props as never)) as never,\n })\n disposeViewer = service.registerFileViewer?.({\n id: ARTIFACT_VIEWER_ID,\n title: '驾驶舱预览',\n // Detection is the only claim. Better Sidebar 0.29 still falls through\n // to `exts.includes(ext)` after a failed `detect`, so a non-empty list\n // here would capture every `.html` in the workspace and run it through\n // the cockpit template contract — plain pages then fail with\n // TEMPLATE_CONTRACT_MISSING instead of opening in the normal preview.\n exts: [],\n priority: 60,\n fetchStrategy: 'fsRead',\n detect: (path: string, head: Uint8Array) => isArtifactFile(path, head),\n component: ((props: Record<string, unknown>) => ArtifactFileViewer(props as never)) as never,\n })\n })\n const slots = (ctx as unknown as {\n slots: {\n inject(name: string, factory: () => () => void): () => void\n register(options: Record<string, unknown>, component: (props: never) => unknown): () => void\n }\n }).slots\n disposeBridge = slots.inject('sidebar.footer.action', () => slots.register({\n name: 'sidebar.footer.action',\n id: 'artifact-app-bridge',\n order: 96,\n }, ((props: { scope?: { sessionId?: string } }) => (betterSidebarService === undefined\n ? null\n : OpenCockpitBridge({ service: betterSidebarService, scope: props?.scope }))) as never))\n return () => {\n disposeBridge?.()\n disposeBridge = undefined\n disposeViewer?.()\n disposeViewer = undefined\n disposeTab?.()\n disposeTab = undefined\n }\n }, 'artifact-app: sidebar tab, file viewer and open bridge')\n } catch (error) {\n console.error('[artifact-app] apply failed', error)\n throw error\n }\n}"],"mappings":"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"}
|