dsh-update-status 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/LICENSE +21 -0
- package/README.md +149 -0
- package/README.zh.md +149 -0
- package/assets/update-panel.png +0 -0
- package/cordis.patch.yml +5 -0
- package/docs/RELEASING.md +114 -0
- package/lib/client.js +1416 -0
- package/lib/client.js.map +1 -0
- package/lib/index.d.ts +93 -0
- package/lib/index.js +511 -0
- package/package.json +101 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","names":["PLUGIN_ID","PLUGIN_ID"],"sources":["../src/shared/channels.ts","../src/shared/types.ts","../src/shared/semver.ts","../src/shared/preview-guidance.ts","../src/client/i18n.ts","../src/client/react.ts","../src/client/components.tsx","../src/client/contract.ts","../src/client/stores.ts","../src/client/styles.ts","../src/client/index.ts"],"sourcesContent":["import type { ChannelRelease, UpdateStatus } from './types.ts'\n\nconst CHANNEL_ORDER = { latest: 0, next: 1, alpha: 2 } as const\n\n/**\n * Reduce raw dist-tags to user-meaningful choices without losing Host facts.\n * The selected channel and stable return path are mandatory; other rows must\n * represent a version that differs from both the running DSH and earlier rows.\n */\nexport function visibleChannelReleases(status: Pick<UpdateStatus, 'currentVersion' | 'channel' | 'channels'>): ChannelRelease[] {\n const ordered = [...status.channels].sort((left, right) => CHANNEL_ORDER[left.channel] - CHANNEL_ORDER[right.channel])\n const mandatory = new Set(['latest', status.channel])\n const visible = ordered.filter(release => mandatory.has(release.channel))\n const seenVersions = new Set(visible.map(release => release.version).filter((version): version is string => version !== null))\n\n for (const release of ordered) {\n if (mandatory.has(release.channel) || release.version === null || release.version === status.currentVersion) continue\n if (seenVersions.has(release.version)) continue\n visible.push(release)\n seenVersions.add(release.version)\n }\n\n return visible.sort((left, right) => CHANNEL_ORDER[left.channel] - CHANNEL_ORDER[right.channel])\n}\n","/**\n * JSON-only contract shared by the Host and Web halves.\n *\n * The static package uses the authenticated Connection RPC channel because\n * `harness.handle` / `host.call` are dynamic-Cordis-only closure APIs in DSH\n * 0.1.2-rc.1. The endpoint vocabulary remains deliberately small and private\n * to this plugin channel.\n */\n\nexport const PLUGIN_ID = 'dsh-update-status'\nexport const PACKAGE_NAME = '@deepseek-ai/dsh'\nexport const UPDATE_STATUS_CHANNEL = '/dsh-update-status'\nexport const RELEASES_URL = 'https://github.com/deepseek-ai/deepseek-harness/releases'\n/** Exact DSH release this Phase-1 bundle declares compatible in package.json. */\nexport const STATIC_COMPATIBLE_VERSION = '0.1.2-rc.1'\nexport const RELEASE_CHANNELS = ['latest', 'next', 'alpha'] as const\nexport const DEFAULT_CACHE_TTL_MINUTES = 360\nexport const MIN_CACHE_TTL_MINUTES = 30\nexport const MAX_CACHE_TTL_MINUTES = 1_440\n\nexport function isCacheTtlMinutes(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value)\n && value >= MIN_CACHE_TTL_MINUTES && value <= MAX_CACHE_TTL_MINUTES\n}\n\nexport const UPDATE_ENDPOINTS = {\n getStatus: 'get-status',\n checkUpdate: 'check-update',\n} as const\n\nexport type UpdateEndpoint = (typeof UPDATE_ENDPOINTS)[keyof typeof UPDATE_ENDPOINTS]\nexport type ReleaseChannel = (typeof RELEASE_CHANNELS)[number]\nexport type ReleaseCompatibility = 'verified' | 'unverified' | 'incompatible'\nexport type InstallKind = 'npm-global' | 'pnpm-global' | 'source-checkout' | 'unknown'\n\nexport function isReleaseChannel(value: unknown): value is ReleaseChannel {\n return value === 'latest' || value === 'next' || value === 'alpha'\n}\n\nexport interface ChannelRelease {\n channel: ReleaseChannel\n version: string | null\n publishedAt: string | null\n compatibility: ReleaseCompatibility\n}\n\n/** Arguments accepted by either read/check endpoint. */\nexport interface CheckUpdateRequest {\n force?: boolean\n channel?: ReleaseChannel\n /** User preference, bounded by the Host before it affects cache expiry. */\n cacheTtlMinutes?: number\n}\n\n/**\n * A lossless, JSON-serializable snapshot used by both browser surfaces.\n * Nulls are intentional: a failed first check must still render a truthful\n * current-version card instead of an empty or malformed UI.\n */\nexport interface UpdateStatus {\n currentVersion: string\n latestVersion: string | null\n hasUpdate: boolean\n cached: boolean\n checkedAt: string | null\n warning: string | null\n installKind: InstallKind\n upgradeCommand: string\n releaseUrl: string\n changelogUrl: string\n publishedAt: string | null\n packageName: string\n /** Selected npm dist-tag used for comparison and command generation. */\n channel: ReleaseChannel\n /** All supported dist-tags returned by the same cached registry request. */\n channels: ChannelRelease[]\n /** Phase 1 is informational only; the GUI must never apply an update. */\n canApplyInPlace: false\n}\n\n/** Persisted browser preference served through the ordinary DSH settings seam. */\nexport interface UpdateStatusSettings {\n sidebarEnabled: boolean\n channel: ReleaseChannel\n /** On-demand npm-registry cache duration. This never starts a browser timer. */\n cacheTtlMinutes: number\n}\n","/**\n * Small, dependency-free SemVer 2.0 comparator for the host check path.\n * It intentionally accepts the common leading `v` used by release tags while\n * preserving prerelease precedence (`0.1.2-rc.1 < 0.1.2`).\n */\n\nexport interface ParsedSemver {\n major: number\n minor: number\n patch: number\n prerelease: readonly string[]\n}\n\nconst SEMVER = /^(?:v)?(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$/\nconst NUMERIC_IDENTIFIER = /^(0|[1-9]\\d*)$/\n\nexport function parseSemver(value: string): ParsedSemver | undefined {\n const match = SEMVER.exec(value.trim())\n if (match === null) return undefined\n const major = Number(match[1])\n const minor = Number(match[2])\n const patch = Number(match[3])\n if (!Number.isSafeInteger(major) || !Number.isSafeInteger(minor) || !Number.isSafeInteger(patch)) return undefined\n const prerelease = match[4] === undefined ? [] : match[4].split('.')\n return { major, minor, patch, prerelease }\n}\n\nfunction compareIdentifier(left: string, right: string): number {\n const leftNumeric = NUMERIC_IDENTIFIER.test(left)\n const rightNumeric = NUMERIC_IDENTIFIER.test(right)\n if (leftNumeric && rightNumeric) return Number(left) - Number(right)\n if (leftNumeric) return -1\n if (rightNumeric) return 1\n return left < right ? -1 : left > right ? 1 : 0\n}\n\n/** Returns a negative number when left is older; undefined means unparsable. */\nexport function compareSemver(leftValue: string, rightValue: string): number | undefined {\n const left = parseSemver(leftValue)\n const right = parseSemver(rightValue)\n if (left === undefined || right === undefined) return undefined\n\n for (const key of ['major', 'minor', 'patch'] as const) {\n if (left[key] !== right[key]) return left[key] - right[key]\n }\n\n const leftStable = left.prerelease.length === 0\n const rightStable = right.prerelease.length === 0\n if (leftStable && rightStable) return 0\n if (leftStable) return 1\n if (rightStable) return -1\n\n const length = Math.max(left.prerelease.length, right.prerelease.length)\n for (let index = 0; index < length; index += 1) {\n const leftPart = left.prerelease[index]\n const rightPart = right.prerelease[index]\n if (leftPart === undefined) return -1\n if (rightPart === undefined) return 1\n const comparison = compareIdentifier(leftPart, rightPart)\n if (comparison !== 0) return comparison\n }\n return 0\n}\n\n/** False rather than a guess when either version is not valid SemVer. */\nexport function hasSemverUpdate(currentVersion: string, latestVersion: string): boolean {\n const comparison = compareSemver(currentVersion, latestVersion)\n return comparison !== undefined && comparison < 0\n}\n","import type { UpdateStatus } from './types.ts'\nimport { PACKAGE_NAME } from './types.ts'\nimport { parseSemver } from './semver.ts'\n\n/** Pinned guidance only: never execute a command or mutate the followed channel. */\nexport function previewCommand(status: UpdateStatus, version: string | null): string | null {\n if (version === null || version.trim() !== version || parseSemver(version) === undefined) return null\n if (status.installKind === 'npm-global') return `npm install -g ${PACKAGE_NAME}@${version}`\n if (status.installKind === 'pnpm-global') return `pnpm add -g ${PACKAGE_NAME}@${version}`\n return null\n}\n","/** Tiny bilingual dictionary kept local to avoid changing the host locale tree. */\n\nexport type Language = 'zh' | 'en'\n\ntype Entry = { zh: string; en: string }\n\nconst DICTIONARY: Record<string, Entry> = {\n 'brand.status': { zh: 'DSH 版本状态', en: 'DSH version status' },\n 'brand.checking': { zh: '正在检查版本', en: 'Checking version' },\n 'brand.update': { zh: '有可用更新', en: 'Update available' },\n 'brand.current': { zh: '已是最新或尚未发现更新', en: 'Up to date or no update found' },\n 'brand.problem': { zh: '检查遇到问题', en: 'Check encountered a problem' },\n 'footer.status': { zh: '打开 DSH 版本状态', en: 'Open DSH version status' },\n 'panel.title': { zh: 'DSH 更新状态', en: 'DSH update status' },\n 'panel.close': { zh: '关闭', en: 'Close' },\n 'panel.cacheDuration': { zh: '缓存时长', en: 'Cache duration' },\n 'panel.minutes': { zh: '分钟', en: 'minutes' },\n 'panel.cacheHint': { zh: '到期后在下次打开或读取状态时检查;不会后台轮询。点击“检查更新”会立即检查。', en: 'After expiry, DSH checks only on the next status read; there is no background polling. “Check for updates” checks immediately.' },\n 'panel.cacheReadonly': { zh: '此连接的缓存设置为只读。', en: 'This connection’s cache setting is read-only.' },\n 'panel.current': { zh: '当前运行版本', en: 'Current running version' },\n 'panel.latest': { zh: '所选通道版本', en: 'Selected channel version' },\n 'panel.channels': { zh: '可用发布通道', en: 'Available release channels' },\n 'panel.compatVerified': { zh: '已验证兼容', en: 'Verified compatible' },\n 'panel.compatUnverified': { zh: '尚未验证兼容', en: 'Compatibility unverified' },\n 'panel.compatIncompatible': { zh: '已知不兼容', en: 'Known incompatible' },\n 'panel.selectChannel': { zh: '选择此通道', en: 'Select channel' },\n 'panel.selectedChannel': { zh: '已选择', en: 'Selected' },\n 'panel.notChecked': { zh: '尚未取得', en: 'Not available yet' },\n 'panel.available': { zh: '发现新版本', en: 'Update available' },\n 'panel.currentState': { zh: '未发现可用更新', en: 'No update found' },\n 'panel.cached': { zh: '来自 Host 缓存', en: 'From Host cache' },\n 'panel.live': { zh: '刚从 npm registry 检查', en: 'Checked npm registry now' },\n 'panel.checkedAt': { zh: '上次检查', en: 'Last checked' },\n 'panel.publishedAt': { zh: '发布时间', en: 'Published' },\n 'panel.check': { zh: '检查更新', en: 'Check for updates' },\n 'panel.checking': { zh: '检查中…', en: 'Checking…' },\n 'panel.switchingChannel': { zh: '正在切换通道…', en: 'Switching channel…' },\n 'panel.releaseNotes': { zh: '发布说明', en: 'Release notes' },\n 'panel.command': { zh: '升级命令', en: 'Upgrade command' },\n 'panel.copy': { zh: '复制命令', en: 'Copy command' },\n 'panel.copied': { zh: '已复制', en: 'Copied' },\n 'panel.copyFallback': { zh: '浏览器未允许复制;已选中文本,请长按或复制。', en: 'Clipboard unavailable; the command is selected for long-press or copy.' },\n 'panel.commandNote': { zh: '仅复制,不会执行。请在运行 DSH 的那台电脑的终端执行;完成后由你自行重启 DSH。', en: 'Copy only — nothing runs here. Execute it in a terminal on the computer running DSH, then restart DSH yourself.' },\n 'panel.readOnly': { zh: '阶段 1 仅提示:本插件不会安装、重启、回滚或替换任何文件。', en: 'Phase 1 is advisory only: this plugin never installs, restarts, rolls back, or replaces files.' },\n 'panel.error': { zh: '检查提示', en: 'Check notice' },\n 'panel.static': { zh: '此连接只显示静态版本;请在运行 DSH 的本机打开侧栏查看完整更新信息。', en: 'This connection shows only the static version. Open the sidebar on the computer running DSH for full update details.' },\n 'preview.open': { zh: '查看预览版升级方式', en: 'View preview upgrade instructions' },\n 'preview.close': { zh: '收起升级说明', en: 'Hide upgrade instructions' },\n 'preview.follow': { zh: '关注通道只影响检查结果,不代表已安装或已切换版本。', en: 'Following a channel only changes update checks, not the installed version.' },\n 'preview.target': { zh: '目标版本', en: 'Target version' },\n 'preview.risk': { zh: '预览版本可能不稳定,插件兼容性尚需确认。执行前请保存工作、备份配置并结束运行中的任务;安装后需手动重启 DSH。此页面不会安装或重启。', en: 'Preview builds may be unstable and plugin compatibility needs checking. Save work, back up configuration and finish active tasks before executing. Restart DSH manually afterwards. This page never installs or restarts.' },\n 'preview.unavailable': { zh: '暂无可确认的预览目标,请先检查更新。', en: 'No confirmed preview target. Check for updates first.' },\n 'preview.manual': { zh: '当前安装方式无法安全生成命令,请先确认安装来源;源码安装需按其构建说明操作。', en: 'Cannot safely generate a command for this installation. Confirm its source; source checkouts require their build instructions.' },\n 'preview.same': { zh: '此目标与当前运行版本相同,无需重复安装。', en: 'This target is already running; no reinstall is needed.' },\n 'settings.title': { zh: '版本与更新', en: 'Version & updates' },\n 'settings.sidebar': { zh: '在侧栏显示版本状态入口', en: 'Show the version-status entry in the sidebar' },\n 'settings.sidebarHint': { zh: '关闭后不再渲染品牌 Badge 和收起轨道兜底入口。不会执行或安排升级。', en: 'When off, the brand badge and collapsed-rail fallback are not rendered. No update is run or scheduled.' },\n 'settings.channel': { zh: '关注发布通道', en: 'Release channel to follow' },\n 'settings.channelLatest': { zh: '稳定版(latest,推荐)', en: 'Stable (latest, recommended)' },\n 'settings.channelNext': { zh: '候选版(next)', en: 'Release candidate (next)' },\n 'settings.channelAlpha': { zh: '预览版(alpha)', en: 'Preview (alpha)' },\n 'settings.channelHint': { zh: '预览通道可能包含未稳定接口或插件兼容性变化。这里只检查并生成命令,不会安装。', en: 'Preview channels may contain unstable APIs or plugin compatibility changes. This only checks and generates a command; it never installs.' },\n 'settings.readonly': { zh: '此连接的设置为只读;显示状态不受影响。', en: 'Settings are read-only on this connection; status display is unchanged.' },\n}\n\nexport function languageOf(): Language {\n try {\n return navigator.language.toLowerCase().startsWith('zh') ? 'zh' : 'en'\n } catch {\n return 'en'\n }\n}\n\nexport function t(key: keyof typeof DICTIONARY): string {\n const entry = DICTIONARY[key]\n if (entry === undefined) return key\n return entry[languageOf()] ?? entry.en\n}\n","/** React arrives from DSH's frozen browser module table at client materialization. */\nimport type * as ReactNS from 'react'\n\n// eslint/oxlint would normally discourage require; DSH's closure factory makes\n// this the supported runtime import path for a third-party client bundle.\nexport const React: typeof ReactNS = require('react') as typeof ReactNS\nexport const h = React.createElement\n","/** Sidebar replacement, collapsed-rail fallback, overlay detail panel, and settings page. */\n\nimport type * as ReactNS from 'react'\nimport { visibleChannelReleases } from '../shared/channels.ts'\nimport { previewCommand } from '../shared/preview-guidance.ts'\nimport { MAX_CACHE_TTL_MINUTES, MIN_CACHE_TTL_MINUTES, isCacheTtlMinutes, type ReleaseChannel, type ReleaseCompatibility, type UpdateStatus } from '../shared/types.ts'\nimport type { PreferencesStore, PanelStore, StatusStore } from './stores.ts'\nimport { t } from './i18n.ts'\nimport { React, h } from './react.ts'\n\nfunction useObservable<T>(store: { subscribe(listener: () => void): () => void; getSnapshot(): T }): T {\n return React.useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot)\n}\n\nfunction timeText(value: string | null): string | null {\n if (value === null) return null\n try {\n return new Intl.DateTimeFormat(undefined, { dateStyle: 'medium', timeStyle: 'short' }).format(new Date(value))\n } catch {\n return value\n }\n}\n\nfunction shortVersion(value: string): string {\n if (value.length <= 16) return value\n return value.slice(0, 15) + '…'\n}\n\nfunction channelLabel(channel: ReleaseChannel): string {\n if (channel === 'latest') return t('settings.channelLatest')\n if (channel === 'next') return t('settings.channelNext')\n return t('settings.channelAlpha')\n}\n\nfunction compatibilityLabel(value: ReleaseCompatibility): string {\n if (value === 'verified') return t('panel.compatVerified')\n if (value === 'incompatible') return t('panel.compatIncompatible')\n return t('panel.compatUnverified')\n}\n\n/** Persists a cache policy only; it never schedules a browser or Host timer. */\nfunction CacheTtlControl({ preferences }: { preferences: PreferencesStore }): ReactNS.ReactElement {\n const snapshot = useObservable(preferences)\n const [draft, setDraft] = React.useState(String(snapshot.cacheTtlMinutes))\n React.useEffect(() => { setDraft(String(snapshot.cacheTtlMinutes)) }, [snapshot.cacheTtlMinutes])\n const save = (): void => {\n const value = Number(draft)\n if (isCacheTtlMinutes(value)) preferences.setCacheTtlMinutes(value)\n else setDraft(String(snapshot.cacheTtlMinutes))\n }\n return (\n <div className=\"dus-cache-setting\">\n <label className=\"dus-cache-field\">\n <span>{t('panel.cacheDuration')}</span>\n <span className=\"dus-cache-input-wrap\">\n <input\n className=\"dus-cache-input\"\n type=\"number\"\n inputMode=\"numeric\"\n min={MIN_CACHE_TTL_MINUTES}\n max={MAX_CACHE_TTL_MINUTES}\n step={1}\n value={draft}\n disabled={!snapshot.writable}\n aria-describedby=\"dus-cache-hint\"\n onChange={(event) => { setDraft(event.currentTarget.value) }}\n onBlur={save}\n onKeyDown={(event) => {\n if (event.key === 'Enter') { event.currentTarget.blur() }\n if (event.key === 'Escape') { setDraft(String(snapshot.cacheTtlMinutes)); event.currentTarget.blur() }\n }}\n />\n <span>{t('panel.minutes')}</span>\n </span>\n </label>\n <p className=\"dus-cache-hint\" id=\"dus-cache-hint\">{t('panel.cacheHint')}</p>\n {!snapshot.writable && <p className=\"dus-cache-hint\">{t('panel.cacheReadonly')}</p>}\n </div>\n )\n}\n\ntype VisualState = 'loading' | 'update' | 'current' | 'problem'\n\nfunction visualState(status: UpdateStatus | null, loading: boolean, error: string | null): VisualState {\n if (loading) return 'loading'\n if (error !== null || status?.warning !== null) return status?.hasUpdate === true ? 'update' : 'problem'\n return status?.hasUpdate === true ? 'update' : 'current'\n}\n\nfunction badgeLabel(status: UpdateStatus | null, loading: boolean, error: string | null): string {\n const state = visualState(status, loading, error)\n if (state === 'loading') return t('brand.checking')\n if (state === 'update') return t('brand.update')\n if (state === 'problem') return t('brand.problem')\n return t('brand.current')\n}\n\nexport interface SharedUi {\n status: StatusStore\n preferences: PreferencesStore\n panel: PanelStore\n canManage: boolean\n}\n\n/** Occupies ONLY sidebar.brand.name; the official fish mark stays untouched. */\nexport function BrandName({ ui }: { ui: SharedUi }): ReactNS.ReactElement | null {\n const preferences = useObservable(ui.preferences)\n const snapshot = useObservable(ui.status)\n if (!preferences.sidebarEnabled) return null\n\n const state = visualState(snapshot.status, snapshot.loading, snapshot.error)\n const version = snapshot.status?.currentVersion ?? '…'\n const activate = (event: ReactNS.SyntheticEvent): void => {\n // The surrounding sidebar brand is an existing New Session <button>. This\n // non-button interaction prevents a nested button and stops its click.\n event.preventDefault()\n event.stopPropagation()\n // The official brand identity ancestor is aria-hidden. Do not leave focus\n // inside it while the modal dialog is open (Chrome otherwise warns).\n const target = event.currentTarget\n if (target instanceof HTMLElement) target.blur()\n if (ui.canManage) ui.panel.toggle('brand')\n }\n const onKeyDown = (event: ReactNS.KeyboardEvent<HTMLSpanElement>): void => {\n if (event.key !== 'Enter' && event.key !== ' ') return\n activate(event)\n }\n\n return (\n <span className=\"dus-brand-name\">\n {/* No handler: clicking this still bubbles to the shell's New Session button. */}\n <span className=\"dus-brand-deepseek\">DeepSeek</span>\n <span\n className=\"dus-badge\"\n data-update={snapshot.status?.hasUpdate === true || undefined}\n data-error={state === 'problem' || undefined}\n role={ui.canManage ? 'button' : undefined}\n tabIndex={ui.canManage ? 0 : undefined}\n aria-label={badgeLabel(snapshot.status, snapshot.loading, snapshot.error)}\n aria-disabled={ui.canManage ? undefined : true}\n title={badgeLabel(snapshot.status, snapshot.loading, snapshot.error)}\n onClick={ui.canManage ? activate : undefined}\n onKeyDown={ui.canManage ? onKeyDown : undefined}\n >\n <span className=\"dus-badge-version\">{shortVersion(version)}</span>\n <span className=\"dus-dot\" data-update={snapshot.status?.hasUpdate === true || undefined} data-loading={snapshot.loading || undefined} aria-hidden=\"true\" />\n </span>\n </span>\n )\n}\n\n/** List-slot fallback: it deliberately disappears while the name badge is wide. */\nexport function FooterAction({ wide, ui }: { wide?: unknown; ui: SharedUi }): ReactNS.ReactElement | null {\n const preferences = useObservable(ui.preferences)\n const snapshot = useObservable(ui.status)\n if (wide === true || !preferences.sidebarEnabled) return null\n const state = visualState(snapshot.status, snapshot.loading, snapshot.error)\n const label = badgeLabel(snapshot.status, snapshot.loading, snapshot.error)\n return (\n <button\n className=\"dus-footer-button\"\n type=\"button\"\n aria-label={t('footer.status')}\n title={label}\n disabled={!ui.canManage}\n onClick={() => { ui.panel.toggle('rail') }}\n >\n <span className=\"dus-footer-icon\" aria-hidden=\"true\">↟</span>\n <span className=\"dus-dot dus-footer-dot\" data-update={snapshot.status?.hasUpdate === true || undefined} data-loading={state === 'loading' || undefined} />\n </button>\n )\n}\n\nfunction statusSummary(status: UpdateStatus | null, loading: boolean, error: string | null): { kind: 'update' | 'ok' | 'warning' | 'error'; text: string } {\n if (loading && status === null) return { kind: 'warning', text: t('brand.checking') }\n if (error !== null) return { kind: 'error', text: error }\n if (status?.hasUpdate === true) return { kind: 'update', text: t('panel.available') }\n if (status?.warning !== null && status?.warning !== undefined) return { kind: 'warning', text: status.warning }\n return { kind: 'ok', text: t('panel.currentState') }\n}\n\nfunction selectCommand(element: HTMLElement | null): void {\n if (element === null) return\n try {\n const selection = window.getSelection()\n if (selection === null) return\n const range = document.createRange()\n range.selectNodeContents(element)\n selection.removeAllRanges()\n selection.addRange(range)\n element.focus()\n } catch {\n // The command remains ordinary selectable text even when selection fails.\n }\n}\n\n/** Full detail is only opened from a loopback/local DSH UI surface. */\nexport function UpdatePanel({ ui }: { ui: SharedUi }): ReactNS.ReactElement | null {\n const panel = useObservable(ui.panel)\n const preferences = useObservable(ui.preferences)\n const snapshot = useObservable(ui.status)\n const commandRef = React.useRef<HTMLElement | null>(null)\n const dialogRef = React.useRef<HTMLDialogElement | null>(null)\n const [copyMessage, setCopyMessage] = React.useState<string | null>(null)\n const visible = panel.open && preferences.sidebarEnabled && ui.canManage\n\n React.useLayoutEffect(() => {\n if (!visible) return undefined\n const dialog = dialogRef.current\n if (dialog === null) return undefined\n try {\n if (!dialog.open) dialog.showModal()\n } catch {\n // Older embedded Chromium still receives a visible non-top-layer dialog.\n dialog.setAttribute('open', '')\n }\n return () => {\n if (dialog.open) dialog.close()\n }\n }, [visible])\n\n React.useEffect(() => {\n if (!panel.open) return undefined\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') ui.panel.close()\n }\n window.addEventListener('keydown', onKeyDown)\n return () => { window.removeEventListener('keydown', onKeyDown) }\n }, [panel.open, ui.panel])\n\n if (!visible) return null\n const status = snapshot.status\n const summary = statusSummary(status, snapshot.loading, snapshot.error)\n const switchingChannel = status !== null && status.channel !== preferences.channel\n const command = switchingChannel ? t('panel.switchingChannel') : status?.upgradeCommand ?? '—'\n\n const copy = async (): Promise<void> => {\n setCopyMessage(null)\n try {\n if (!navigator.clipboard?.writeText) throw new Error('Clipboard API unavailable')\n await navigator.clipboard.writeText(command)\n setCopyMessage(t('panel.copied'))\n } catch {\n selectCommand(commandRef.current)\n setCopyMessage(t('panel.copyFallback'))\n }\n }\n\n return (\n <dialog\n ref={dialogRef}\n className=\"dus-overlay-root\"\n aria-label={t('panel.title')}\n onCancel={(event) => {\n event.preventDefault()\n ui.panel.close()\n }}\n >\n <div className=\"dus-backdrop\" onClick={() => { ui.panel.close() }} />\n <section className=\"dus-panel\" data-origin={panel.origin} role=\"dialog\" aria-modal=\"true\" aria-label={t('panel.title')} onClick={(event) => { event.stopPropagation() }}>\n <div className=\"dus-panel-head\">\n <span className=\"dus-panel-title\">{t('panel.title')}</span>\n <button className=\"dus-close\" type=\"button\" aria-label={t('panel.close')} onClick={() => { ui.panel.close() }}>×</button>\n </div>\n\n <CacheTtlControl preferences={ui.preferences} />\n <p className=\"dus-state\" data-kind={summary.kind}>{summary.text}</p>\n\n <div className=\"dus-metadata\">\n <div className=\"dus-metadata-row\">\n <span className=\"dus-meta-label\">{t('panel.current')}</span>\n <code className=\"dus-meta-value\">{status?.currentVersion ?? '…'}</code>\n </div>\n <div className=\"dus-metadata-row\">\n <span className=\"dus-meta-label\">{t('panel.latest')} · {status === null ? 'latest' : channelLabel(status.channel)}</span>\n <code className=\"dus-meta-value\">{status?.latestVersion ?? t('panel.notChecked')}</code>\n {status?.publishedAt !== null && status?.publishedAt !== undefined && <span className=\"dus-meta-sub\">{t('panel.publishedAt')}: {timeText(status.publishedAt)}</span>}\n </div>\n {status?.checkedAt !== null && status?.checkedAt !== undefined && <div className=\"dus-metadata-row\">\n <span className=\"dus-meta-label\">{t('panel.checkedAt')}</span>\n <span className=\"dus-meta-value\">{timeText(status.checkedAt)}</span>\n <span className=\"dus-meta-sub\">{status.cached ? t('panel.cached') : t('panel.live')}</span>\n </div>}\n </div>\n\n {status !== null && <div className=\"dus-channel-list\" aria-label={t('panel.channels')}>\n <p className=\"dus-command-label\">{t('panel.channels')}</p>\n {visibleChannelReleases(status).map(release => {\n const selected = release.channel === preferences.channel\n return <div className=\"dus-channel-row\" data-selected={selected || undefined} key={release.channel}>\n <span>{channelLabel(release.channel)}</span>\n <code>{release.version ?? '—'}</code>\n <span className=\"dus-channel-compat\" data-compatibility={release.compatibility}>{compatibilityLabel(release.compatibility)}</span>\n <button\n className=\"dus-channel-action\"\n type=\"button\"\n disabled={selected || !preferences.writable || release.version === null}\n aria-label={`${selected ? t('panel.selectedChannel') : t('panel.selectChannel')}: ${channelLabel(release.channel)}`}\n onClick={() => { ui.preferences.setChannel(release.channel) }}\n >{selected ? t('panel.selectedChannel') : t('panel.selectChannel')}</button>\n </div>\n })}\n </div>}\n\n {status?.warning !== null && status?.warning !== undefined && <p className=\"dus-warning\">{t('panel.error')}: {status.warning}</p>}\n {snapshot.error !== null && <p className=\"dus-warning\">{t('panel.error')}: {snapshot.error}</p>}\n\n <div className=\"dus-actions\">\n <button className=\"dus-action\" type=\"button\" disabled={snapshot.loading} onClick={() => { void ui.status.refresh(undefined, preferences.cacheTtlMinutes) }}>\n {snapshot.loading ? t('panel.checking') : t('panel.check')}\n </button>\n {status !== null && <a className=\"dus-action\" href={status.changelogUrl} target=\"_blank\" rel=\"noreferrer\">{t('panel.releaseNotes')}</a>}\n <button className=\"dus-action\" type=\"button\" disabled={switchingChannel || status === null} onClick={() => { void copy() }}>{t('panel.copy')}</button>\n </div>\n\n <p className=\"dus-command-label\">{t('panel.command')}</p>\n <code ref={commandRef} className=\"dus-command\" tabIndex={0}>{command}</code>\n {copyMessage !== null && <p className=\"dus-copy-message\" role=\"status\">{copyMessage}</p>}\n <p className=\"dus-note\">{t('panel.commandNote')}</p>\n <p className=\"dus-note\">{t('panel.readOnly')}</p>\n </section>\n </dialog>\n )\n}\n\n/** Separate setting page: disables only this plugin's own rendering. */\nexport function UpdateSettings({ ui }: { ui: SharedUi }): ReactNS.ReactElement {\n const preferences = useObservable(ui.preferences)\n const snapshot = useObservable(ui.status)\n const [showGuidance, setShowGuidance] = React.useState(false)\n const previews = snapshot.status?.channels.filter(release => release.channel !== 'latest') ?? []\n const channelOptions = snapshot.status === null\n ? [{ channel: preferences.channel }]\n : visibleChannelReleases(snapshot.status)\n return (\n <section className=\"dus-settings\">\n <h2 className=\"dus-settings-heading\">{t('settings.title')}</h2>\n <div className=\"dus-settings-card\">\n <label className=\"dus-settings-toggle\">\n <input\n type=\"checkbox\"\n checked={preferences.sidebarEnabled}\n disabled={!preferences.writable}\n onChange={(event) => { ui.preferences.setSidebarEnabled(event.currentTarget.checked) }}\n />\n <span>{t('settings.sidebar')}</span>\n </label>\n <p className=\"dus-settings-hint\">{t('settings.sidebarHint')}</p>\n {!preferences.writable && <p className=\"dus-settings-hint\">{t('settings.readonly')}</p>}\n </div>\n <div className=\"dus-settings-card\">\n <label className=\"dus-settings-field\">\n <span>{t('settings.channel')}</span>\n <select\n className=\"dus-channel-select\"\n value={preferences.channel}\n disabled={!preferences.writable}\n onChange={(event) => { ui.preferences.setChannel(event.currentTarget.value as ReleaseChannel) }}\n >\n {channelOptions.map(option => <option value={option.channel} key={option.channel}>{channelLabel(option.channel)}</option>)}\n </select>\n </label>\n <p className=\"dus-settings-hint\">{t('settings.channelHint')}</p>\n <p className=\"dus-settings-hint\">{t('panel.current')}: <code>{snapshot.status?.currentVersion ?? '…'}</code></p>\n <p className=\"dus-settings-hint\">{t('preview.follow')}</p>\n {ui.canManage && <button className=\"dus-action\" type=\"button\" aria-expanded={showGuidance} onClick={() => { setShowGuidance(!showGuidance) }}>{t(showGuidance ? 'preview.close' : 'preview.open')}</button>}\n {ui.canManage && showGuidance && <section aria-label={t('preview.open')}>\n <p className=\"dus-warning\">{t('preview.risk')}</p>\n <button className=\"dus-action\" type=\"button\" disabled={snapshot.loading} onClick={() => { void ui.status.refresh(undefined, preferences.cacheTtlMinutes) }}>{t(snapshot.loading ? 'panel.checking' : 'panel.check')}</button>\n {snapshot.error !== null && <p role=\"alert\">{snapshot.error}</p>}\n {previews.length === 0 && <p>{t('preview.unavailable')}</p>}\n {previews.map(release => {\n const status = snapshot.status!\n const command = previewCommand(status, release.version)\n return <div className=\"dus-settings-card\" key={release.channel}>\n <p>{channelLabel(release.channel)} · {t('preview.target')}: <code>{release.version ?? t('panel.notChecked')}</code></p>\n <p>{compatibilityLabel(release.compatibility)}</p>\n {release.version === null ? <p>{t('preview.unavailable')}</p> : release.version === status.currentVersion ? <p>{t('preview.same')}</p> : command !== null ? <><p>{t('panel.command')}</p><code className=\"dus-command\" tabIndex={0}>{command}</code></> : <p>{t('preview.manual')}</p>}\n </div>\n })}\n <p className=\"dus-note\">{t('panel.commandNote')}</p>\n </section>}\n </div>\n </section>\n )\n}\n","/** Minimal structural client faces — runtime services stay owned by DSH. */\n\nimport { isReleaseChannel, type ChannelRelease, type UpdateStatus } from '../shared/types.ts'\n\nexport interface Observable<T> {\n getSnapshot(): T\n subscribe(listener: () => void): () => void\n}\n\nexport interface ConnectionRpc {\n call(channel: string, endpoint: string, payload: unknown, signal?: AbortSignal): Promise<unknown>\n}\n\nexport interface ConnectionClient {\n isLoopback?: boolean\n rpc?: ConnectionRpc\n}\n\nexport interface SettingsScopeSnapshot {\n status?: unknown\n value?: unknown\n writable?: unknown\n}\n\nexport interface SettingsScope {\n getSnapshot(): SettingsScopeSnapshot\n subscribe(listener: () => void): () => void\n set(field: string, value: unknown): Promise<void>\n}\n\nexport interface SettingsScopeBinder {\n bind(spec: { namespace: string }): SettingsScope\n}\n\nexport interface SlotRegistration {\n name: string\n id?: string\n order?: number\n /** Single-slot arbitration: the lowest registered priority renders. */\n priority?: number\n label?: () => string\n locale?: string\n inject?: () => unknown\n}\n\nexport interface Slots {\n inject(name: string, callback: () => unknown): () => void\n register(registration: SlotRegistration, component: (props: Record<string, unknown>) => unknown): () => void\n}\n\nexport interface ClientContext {\n slots: Slots\n get(name: string): unknown\n inject(names: string[], callback: (ctx: unknown) => void): () => void\n effect(setup: () => (() => void) | void, label?: string): () => void\n}\n\nexport function errorMessage(error: unknown): string {\n const text = error instanceof Error ? error.message : String(error)\n return text.replace(/\\s+/g, ' ').trim().slice(0, 220) || 'unknown error'\n}\n\nfunction stringOrNull(value: unknown): string | null {\n return typeof value === 'string' ? value : null\n}\n\n/** Reject malformed RPC output before it reaches a slot component. */\nexport function updateStatusOf(value: unknown): UpdateStatus | undefined {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\n const record = value as Record<string, unknown>\n if (typeof record.currentVersion !== 'string' || typeof record.hasUpdate !== 'boolean'\n || typeof record.cached !== 'boolean' || typeof record.installKind !== 'string'\n || typeof record.upgradeCommand !== 'string' || typeof record.releaseUrl !== 'string'\n || typeof record.changelogUrl !== 'string' || typeof record.packageName !== 'string'\n || !isReleaseChannel(record.channel) || !Array.isArray(record.channels) || record.canApplyInPlace !== false) return undefined\n const validKind = record.installKind === 'npm-global' || record.installKind === 'pnpm-global'\n || record.installKind === 'source-checkout' || record.installKind === 'unknown'\n if (!validKind) return undefined\n const latestVersion = record.latestVersion === null ? null : stringOrNull(record.latestVersion)\n const checkedAt = record.checkedAt === null ? null : stringOrNull(record.checkedAt)\n const warning = record.warning === null ? null : stringOrNull(record.warning)\n const publishedAt = record.publishedAt === null ? null : stringOrNull(record.publishedAt)\n if ((record.latestVersion !== null && latestVersion === null) || (record.checkedAt !== null && checkedAt === null)\n || (record.warning !== null && warning === null) || (record.publishedAt !== null && publishedAt === null)) return undefined\n const channels: ChannelRelease[] = []\n for (const raw of record.channels) {\n if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) return undefined\n const item = raw as Record<string, unknown>\n const version = item.version === null ? null : stringOrNull(item.version)\n const channelPublishedAt = item.publishedAt === null ? null : stringOrNull(item.publishedAt)\n if (!isReleaseChannel(item.channel) || (item.version !== null && version === null)\n || (item.publishedAt !== null && channelPublishedAt === null)\n || (item.compatibility !== 'verified' && item.compatibility !== 'unverified' && item.compatibility !== 'incompatible')) return undefined\n channels.push({ channel: item.channel, version, publishedAt: channelPublishedAt, compatibility: item.compatibility })\n }\n return {\n currentVersion: record.currentVersion,\n latestVersion,\n hasUpdate: record.hasUpdate,\n cached: record.cached,\n checkedAt,\n warning,\n installKind: record.installKind as UpdateStatus['installKind'],\n upgradeCommand: record.upgradeCommand,\n releaseUrl: record.releaseUrl,\n changelogUrl: record.changelogUrl,\n publishedAt,\n packageName: record.packageName,\n channel: record.channel,\n channels,\n canApplyInPlace: false,\n }\n}\n","/** Small observable stores shared by the independent sidebar and overlay slots. */\n\nimport { DEFAULT_CACHE_TTL_MINUTES, isCacheTtlMinutes, isReleaseChannel, PLUGIN_ID, RELEASE_CHANNELS, UPDATE_ENDPOINTS, UPDATE_STATUS_CHANNEL, type ReleaseChannel, type UpdateStatus } from '../shared/types.ts'\nimport type { ConnectionClient, Observable, SettingsScope } from './contract.ts'\nimport { errorMessage, updateStatusOf } from './contract.ts'\n\nexport interface StatusSnapshot {\n status: UpdateStatus | null\n loading: boolean\n error: string | null\n}\n\nconst INITIAL_STATUS: StatusSnapshot = { status: null, loading: true, error: null }\n\nexport class StatusStore implements Observable<StatusSnapshot> {\n private snapshot: StatusSnapshot\n private readonly allowRequests: boolean\n private readonly listeners = new Set<() => void>()\n private inFlight: Promise<boolean> | undefined\n private stopped = false\n\n constructor(private readonly connection: ConnectionClient, staticVersion: string | null = null) {\n this.allowRequests = staticVersion === null\n this.snapshot = staticVersion === null\n ? INITIAL_STATUS\n : { status: {\n currentVersion: staticVersion,\n latestVersion: null,\n hasUpdate: false,\n cached: true,\n checkedAt: null,\n warning: null,\n installKind: 'unknown',\n upgradeCommand: '',\n releaseUrl: '',\n changelogUrl: '',\n publishedAt: null,\n packageName: '@deepseek-ai/dsh',\n channel: 'latest',\n channels: RELEASE_CHANNELS.map(channel => ({ channel, version: null, publishedAt: null, compatibility: 'unverified' })),\n canApplyInPlace: false,\n }, loading: false, error: null }\n }\n\n getSnapshot = (): StatusSnapshot => this.snapshot\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener)\n return () => { this.listeners.delete(listener) }\n }\n\n /** First mount reads the Host's cached status; it never starts a browser timer. */\n async load(cacheTtlMinutes: number = DEFAULT_CACHE_TTL_MINUTES): Promise<void> {\n if (this.allowRequests) await this.request(false, this.snapshot.status?.channel ?? 'latest', cacheTtlMinutes)\n }\n\n /** User gesture only: force the Host to bypass TTL (while retaining single-flight). */\n async refresh(channel: ReleaseChannel = this.snapshot.status?.channel ?? 'latest', cacheTtlMinutes: number = DEFAULT_CACHE_TTL_MINUTES): Promise<void> {\n if (this.allowRequests) await this.request(true, channel, cacheTtlMinutes)\n }\n\n /** Channel selection re-projects the Host cache; it is not a forced refresh. */\n async selectChannel(channel: ReleaseChannel, cacheTtlMinutes: number = DEFAULT_CACHE_TTL_MINUTES): Promise<void> {\n if (!this.allowRequests) return\n // A persisted preference or a newer selection can arrive while another\n // channel is in flight. Keep checking after every joined request until the\n // requested projection is actually the published snapshot.\n for (let attempts = 0; attempts < 3 && !this.stopped && this.snapshot.status?.channel !== channel; attempts += 1) {\n const pending = this.inFlight\n if (pending !== undefined && !await pending) return\n if (this.stopped || this.snapshot.status?.channel === channel) return\n if (!await this.request(false, channel, cacheTtlMinutes)) return\n }\n }\n\n stop(): void {\n this.stopped = true\n this.listeners.clear()\n }\n\n private publish(next: StatusSnapshot): void {\n if (this.stopped) return\n this.snapshot = next\n for (const listener of this.listeners) listener()\n }\n\n private request(force: boolean, channel: ReleaseChannel, cacheTtlMinutes: number): Promise<boolean> {\n if (this.inFlight !== undefined) return this.inFlight\n const rpc = this.connection.rpc\n if (rpc === undefined || typeof rpc.call !== 'function') {\n this.publish({ ...this.snapshot, loading: false, error: 'DSH connection RPC is unavailable' })\n return Promise.resolve(false)\n }\n\n this.publish({ ...this.snapshot, loading: true, error: null })\n const run = (async () => {\n try {\n const endpoint = force ? UPDATE_ENDPOINTS.checkUpdate : UPDATE_ENDPOINTS.getStatus\n const ttl = isCacheTtlMinutes(cacheTtlMinutes) ? cacheTtlMinutes : DEFAULT_CACHE_TTL_MINUTES\n const raw = await rpc.call(UPDATE_STATUS_CHANNEL, endpoint, force\n ? { force: true, channel, cacheTtlMinutes: ttl }\n : { channel, cacheTtlMinutes: ttl })\n if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) throw new Error('invalid update-status RPC response')\n const envelope = raw as { ok?: unknown; value?: unknown; error?: { message?: unknown } }\n if (envelope.ok !== true) throw new Error(typeof envelope.error?.message === 'string' ? envelope.error.message : 'update-status RPC failed')\n const status = updateStatusOf(envelope.value)\n if (status === undefined) throw new Error('invalid update-status payload')\n this.publish({ status, loading: false, error: null })\n return true\n } catch (error) {\n this.publish({ ...this.snapshot, loading: false, error: errorMessage(error) })\n return false\n }\n })()\n this.inFlight = run\n void run.finally(() => {\n if (this.inFlight === run) this.inFlight = undefined\n })\n return run\n }\n}\n\nexport interface PreferencesSnapshot {\n sidebarEnabled: boolean\n channel: ReleaseChannel\n cacheTtlMinutes: number\n writable: boolean\n status: 'loading' | 'ready' | 'unavailable'\n}\n\nconst INITIAL_PREFERENCES: PreferencesSnapshot = {\n sidebarEnabled: true,\n channel: 'latest',\n cacheTtlMinutes: DEFAULT_CACHE_TTL_MINUTES,\n writable: false,\n status: 'loading',\n}\n\nexport class PreferencesStore implements Observable<PreferencesSnapshot> {\n private snapshot: PreferencesSnapshot = INITIAL_PREFERENCES\n private readonly listeners = new Set<() => void>()\n private scope: SettingsScope | undefined\n\n getSnapshot = (): PreferencesSnapshot => this.snapshot\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener)\n return () => { this.listeners.delete(listener) }\n }\n\n attach(scope: SettingsScope): () => void {\n this.scope = scope\n const sync = () => {\n const raw = scope.getSnapshot()\n const value = raw.value !== null && typeof raw.value === 'object' && !Array.isArray(raw.value)\n ? raw.value as Record<string, unknown>\n : {}\n const status = raw.status === 'ready' || raw.status === 'unavailable' ? raw.status : 'loading'\n this.publish({\n sidebarEnabled: value.sidebarEnabled !== false,\n channel: isReleaseChannel(value.channel) ? value.channel : 'latest',\n cacheTtlMinutes: isCacheTtlMinutes(value.cacheTtlMinutes) ? value.cacheTtlMinutes : DEFAULT_CACHE_TTL_MINUTES,\n writable: raw.writable === true,\n status,\n })\n }\n sync()\n return scope.subscribe(sync)\n }\n\n setSidebarEnabled(enabled: boolean): void {\n const previous = this.snapshot\n this.publish({ ...previous, sidebarEnabled: enabled })\n const scope = this.scope\n if (scope === undefined || !previous.writable) return\n void scope.set('sidebarEnabled', enabled).catch(() => {\n // A rejected Host-backed write restores the authoritative scope snapshot.\n try {\n const raw = scope.getSnapshot()\n const value = raw.value !== null && typeof raw.value === 'object' && !Array.isArray(raw.value)\n ? raw.value as Record<string, unknown>\n : {}\n this.publish({\n sidebarEnabled: value.sidebarEnabled !== false,\n channel: isReleaseChannel(value.channel) ? value.channel : 'latest',\n cacheTtlMinutes: isCacheTtlMinutes(value.cacheTtlMinutes) ? value.cacheTtlMinutes : DEFAULT_CACHE_TTL_MINUTES,\n writable: raw.writable === true,\n status: raw.status === 'ready' || raw.status === 'unavailable' ? raw.status : 'loading',\n })\n } catch {\n this.publish(previous)\n }\n })\n }\n\n setChannel(channel: ReleaseChannel): void {\n const previous = this.snapshot\n this.publish({ ...previous, channel })\n const scope = this.scope\n if (scope === undefined || !previous.writable) return\n void scope.set('channel', channel).catch(() => { this.publish(previous) })\n }\n\n setCacheTtlMinutes(cacheTtlMinutes: number): void {\n if (!isCacheTtlMinutes(cacheTtlMinutes)) return\n const previous = this.snapshot\n this.publish({ ...previous, cacheTtlMinutes })\n const scope = this.scope\n if (scope === undefined || !previous.writable) return\n void scope.set('cacheTtlMinutes', cacheTtlMinutes).catch(() => { this.publish(previous) })\n }\n\n private publish(next: PreferencesSnapshot): void {\n const previous = this.snapshot\n if (previous.sidebarEnabled === next.sidebarEnabled && previous.channel === next.channel\n && previous.cacheTtlMinutes === next.cacheTtlMinutes\n && previous.writable === next.writable && previous.status === next.status) return\n this.snapshot = next\n for (const listener of this.listeners) listener()\n }\n}\n\nexport type PanelOrigin = 'brand' | 'rail'\n\nexport interface PanelSnapshot {\n open: boolean\n origin: PanelOrigin\n}\n\n/** Open state also retains its trigger, so the desktop card sits beside it. */\nexport class PanelStore implements Observable<PanelSnapshot> {\n private snapshot: PanelSnapshot = { open: false, origin: 'brand' }\n private readonly listeners = new Set<() => void>()\n\n getSnapshot = (): PanelSnapshot => this.snapshot\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener)\n return () => { this.listeners.delete(listener) }\n }\n\n toggle(origin: PanelOrigin): void {\n const open = !(this.snapshot.open && this.snapshot.origin === origin)\n this.set({ open, origin })\n }\n\n close(): void { this.set({ ...this.snapshot, open: false }) }\n\n private set(next: PanelSnapshot): void {\n if (this.snapshot.open === next.open && this.snapshot.origin === next.origin) return\n this.snapshot = next\n for (const listener of this.listeners) listener()\n }\n}\n\n/** The one namespace name used by Host registration and browser binding. */\nexport const SETTINGS_NAMESPACE = PLUGIN_ID\n","/** Plugin-owned CSS only; no shell DOM selection or official SVG manipulation. */\n\nexport const UPDATE_STATUS_CSS = `\n.dus-brand-name{align-items:center;gap:8px;min-width:0;width:100%;display:flex}\n.dus-brand-deepseek{font-size:15px;font-weight:650;letter-spacing:-.015em;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dus-badge{align-items:center;gap:5px;background:var(--dsw-alias-button-floating-fill);border:1px solid var(--dsw-alias-border-l2);border-radius:999px;color:var(--dsw-alias-label-secondary);cursor:pointer;display:inline-flex;flex:0 0 auto;font-size:11px;font-variant-numeric:tabular-nums;line-height:20px;max-width:132px;outline:none;padding:0 8px;touch-action:manipulation;user-select:none}\n.dus-badge:focus-visible,.dus-footer-button:focus-visible,.dus-action:focus-visible,.dus-close:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}\n.dus-badge:hover{background:var(--dsw-alias-button-floating-hover)}\n.dus-badge[data-update=true]{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}\n.dus-badge[data-error=true]{border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}\n.dus-badge-version{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dus-dot{background:currentColor;border-radius:50%;display:inline-block;flex:0 0 auto;height:6px;width:6px}\n.dus-dot[data-update=true]{animation:dus-pulse 1.5s ease-in-out infinite;background:var(--dsw-alias-state-warn-primary)}\n.dus-dot[data-loading=true]{animation:dus-pulse .9s ease-in-out infinite}\n@keyframes dus-pulse{0%,100%{opacity:.45;transform:scale(.82)}50%{opacity:1;transform:scale(1.15)}}\n@media (prefers-reduced-motion:reduce){.dus-dot[data-update=true],.dus-dot[data-loading=true]{animation:none}}\n.dus-footer-button{align-items:center;background:transparent;border:0;border-radius:10px;color:var(--dsw-alias-label-secondary);cursor:pointer;display:flex;height:44px;justify-content:center;min-height:44px;min-width:44px;padding:0;position:relative;touch-action:manipulation;width:44px}\n.dus-footer-button:hover{background:var(--dsw-alias-button-floating-hover);color:var(--dsw-alias-label-primary)}\n.dus-footer-icon{font-size:18px;line-height:1}\n.dus-footer-dot{border:1.5px solid var(--dsw-specific-sidebar-fill);position:absolute;right:9px;top:9px}\n.dus-overlay-root{background:transparent;border:0;color:inherit;height:100dvh;inset:0;margin:0;max-height:none;max-width:none;padding:0;pointer-events:none;position:fixed;width:100vw}\n.dus-overlay-root::backdrop{background:transparent}\n.dus-backdrop{background:transparent;inset:0;pointer-events:auto;position:absolute}\n.dus-panel{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:14px;box-shadow:var(--dsw-elevation-panel);box-sizing:border-box;color:var(--dsw-alias-label-primary);max-height:min(640px,calc(100dvh - 32px - env(safe-area-inset-top) - env(safe-area-inset-bottom)));overflow:auto;padding:14px;pointer-events:auto;position:absolute;top:12px;width:min(390px,calc(100vw - 24px));z-index:1}\n.dus-panel[data-origin=brand]{left:min(292px,calc(100vw - 402px))}\n.dus-panel[data-origin=rail]{left:min(68px,calc(100vw - 402px))}\n.dus-panel-head{align-items:center;display:flex;gap:8px;justify-content:space-between;margin-bottom:12px}\n.dus-panel-title{font-size:14px;font-weight:650}\n.dus-close{align-items:center;background:transparent;border:0;border-radius:8px;color:inherit;cursor:pointer;display:inline-flex;font-size:20px;height:32px;justify-content:center;line-height:1;min-height:32px;min-width:32px;padding:0;touch-action:manipulation;width:32px}\n.dus-close:hover,.dus-action:hover{background:var(--dsw-alias-button-floating-hover)}\n.dus-cache-setting{border:1px solid var(--dsw-alias-border-l2);border-radius:9px;margin:0 0 12px;padding:9px}\n.dus-cache-field{align-items:center;display:flex;font-size:12px;font-weight:600;gap:10px;justify-content:space-between}\n.dus-cache-input-wrap{align-items:center;display:flex;gap:6px;font-size:11px;font-weight:400}\n.dus-cache-input{background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:7px;color:inherit;font:inherit;min-height:30px;padding:0 7px;text-align:right;width:72px}\n.dus-cache-input:focus{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}\n.dus-cache-input:disabled{cursor:not-allowed;opacity:.55}\n.dus-cache-hint{color:var(--dsw-alias-label-secondary);font-size:11px;line-height:1.4;margin:7px 0 0}\n.dus-state{border-radius:9px;color:var(--dsw-alias-label-primary);font-size:12px;line-height:1.45;margin:0 0 12px;padding:8px 9px}\n.dus-state[data-kind=update],.dus-state[data-kind=warning]{background:var(--dsw-alias-state-warn-tertiary)}\n.dus-state[data-kind=ok]{background:var(--dsw-alias-state-success-tertiary)}\n.dus-state[data-kind=error]{background:var(--dsw-alias-bg-layer-3)}\n.dus-metadata{display:grid;gap:9px;margin:0 0 12px}\n.dus-metadata-row{align-items:baseline;display:grid;gap:8px;grid-template-columns:minmax(0,1fr) auto}\n.dus-meta-label{color:var(--dsw-alias-label-secondary);font-size:12px}\n.dus-meta-value{font-family:var(--dsw-font-family-mono,ui-monospace,SFMono-Regular,Menlo,monospace);font-size:12px;max-width:210px;overflow-wrap:anywhere;text-align:right}\n.dus-meta-sub{color:var(--dsw-alias-label-secondary);font-size:11px;grid-column:1 / -1}\n.dus-warning{border-left:2px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.45;margin:0 0 12px;padding-left:8px}\n.dus-actions{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 12px}\n.dus-action{background:var(--dsw-alias-button-floating-fill);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;color:inherit;cursor:pointer;font-size:12px;line-height:30px;min-height:32px;padding:0 10px;touch-action:manipulation}\n.dus-action:disabled{cursor:wait;opacity:.65}\n.dus-command-label{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600;margin:0 0 6px}\n.dus-command{background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;display:block;font-family:var(--dsw-font-family-mono,ui-monospace,SFMono-Regular,Menlo,monospace);font-size:11px;line-height:1.5;margin:0;overflow-wrap:anywhere;padding:9px;tab-size:2;user-select:text;white-space:pre-wrap}\n.dus-command:focus{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}\n.dus-note{color:var(--dsw-alias-label-secondary);font-size:11px;line-height:1.45;margin:8px 0 0}\n.dus-copy-message{color:var(--dsw-alias-state-business-primary);font-size:11px;margin:7px 0 0}\n.dus-settings{display:grid;gap:14px;max-width:640px;padding:4px 0}\n.dus-settings-heading{font-size:16px;font-weight:650;margin:0}\n.dus-settings-card{border:1px solid var(--dsw-alias-border-l2);border-radius:10px;padding:12px}\n.dus-settings-toggle{align-items:flex-start;cursor:pointer;display:flex;gap:10px;font-size:13px;line-height:1.4}\n.dus-settings-toggle input{accent-color:var(--dsw-alias-state-business-primary);height:18px;margin:0;min-height:18px;min-width:18px;width:18px}\n.dus-settings-field{display:grid;font-size:13px;font-weight:600;gap:8px}\n.dus-channel-select{background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;color:inherit;font:inherit;min-height:40px;padding:0 10px;width:100%}\n.dus-channel-list{border-top:1px solid var(--dsw-alias-border-l2);margin:12px 0 0;padding-top:2px}\n.dus-channel-row{align-items:center;display:grid;font-size:11px;gap:8px;grid-template-columns:minmax(0,1fr) auto;line-height:1.4;padding:6px 0}\n.dus-channel-row[data-selected=true]{color:var(--dsw-alias-state-business-primary)}\n.dus-channel-row code{font-size:11px}\n.dus-channel-compat{color:var(--dsw-alias-label-secondary)}\n.dus-channel-action{background:transparent;border:1px solid var(--dsw-alias-border-l2);border-radius:7px;color:inherit;cursor:pointer;font-size:11px;justify-self:end;min-height:32px;padding:0 9px}\n.dus-channel-action:disabled{cursor:default;opacity:.55}\n.dus-channel-action:not(:disabled):hover{background:var(--dsw-alias-button-floating-hover)}\n.dus-channel-compat[data-compatibility=verified]{color:var(--dsw-alias-state-success-primary)}\n.dus-channel-compat[data-compatibility=incompatible]{color:var(--dsw-alias-state-error-primary)}\n.dus-settings-hint{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.45;margin:8px 0 0}\n@media (max-width:640px),(hover:none) and (pointer:coarse){.dus-panel[data-origin]{border-bottom:0;border-bottom-left-radius:0;border-bottom-right-radius:0;bottom:0;left:0;right:0;max-height:min(78dvh,calc(100dvh - env(safe-area-inset-top)));padding:16px max(16px,env(safe-area-inset-right)) max(16px,env(safe-area-inset-bottom)) max(16px,env(safe-area-inset-left));position:fixed;top:auto;width:100vw}.dus-footer-button{height:48px;min-height:48px;min-width:48px;width:48px}.dus-badge{line-height:24px;min-height:28px}.dus-action{min-height:40px;line-height:38px}.dus-close{height:40px;min-height:40px;min-width:40px;width:40px}}\n`\n","/**\n * DSH Web client half. It replaces only `sidebar.brand.name`, leaves the\n * official fish (`sidebar.brand.mark`) untouched, and adds a collapsed-rail\n * fallback at `sidebar.footer.action`. The detail panel is an additive\n * `shell.overlay`, never a chat-area floating widget.\n */\n\nimport type { ClientContext, ConnectionClient, SettingsScopeBinder } from './contract.ts'\nimport { BrandName, FooterAction, type SharedUi, UpdatePanel, UpdateSettings } from './components.tsx'\nimport { SETTINGS_NAMESPACE, PanelStore, PreferencesStore, StatusStore } from './stores.ts'\nimport { STATIC_COMPATIBLE_VERSION } from '../shared/types.ts'\nimport { t } from './i18n.ts'\nimport { UPDATE_STATUS_CSS } from './styles.ts'\n\nconst PLUGIN_ID = 'dsh-update-status'\nconst CSS_TAG_ID = `${PLUGIN_ID}/styles`\n\nfunction installStyles(): () => void {\n if (typeof document === 'undefined') return () => {}\n const existing = document.querySelector(`style[data-plugin-css=\"${CSS_TAG_ID}\"]`)\n if (existing !== null) return () => {}\n const tag = document.createElement('style')\n tag.dataset.plugin = PLUGIN_ID\n tag.dataset.pluginCss = CSS_TAG_ID\n tag.textContent = UPDATE_STATUS_CSS\n document.head.appendChild(tag)\n return () => {\n const live = document.querySelector(`style[data-plugin-css=\"${CSS_TAG_ID}\"]`)\n if (live?.parentNode !== undefined && live?.parentNode !== null) live.parentNode.removeChild(live)\n }\n}\n\nfunction connectionOf(ctx: ClientContext): ConnectionClient {\n try {\n const candidate = ctx.get('connection')\n return candidate !== null && typeof candidate === 'object' ? candidate as ConnectionClient : {}\n } catch {\n return {}\n }\n}\n\nfunction apply(ctx: ClientContext): void {\n const connection = connectionOf(ctx)\n // The authenticated transport can serve a remote browser too. Restrict the\n // metadata request and command panel to the machine running DSH; remote\n // clients deliberately render only the release this bundle is compatible with.\n const canManage = connection.isLoopback === true\n const status = new StatusStore(connection, canManage ? null : STATIC_COMPATIBLE_VERSION)\n const preferences = new PreferencesStore()\n const panel = new PanelStore()\n const ui: SharedUi = { status, preferences, panel, canManage }\n\n ctx.effect(() => {\n const disposeStyles = installStyles()\n if (canManage) void status.load(preferences.getSnapshot().cacheTtlMinutes)\n return () => {\n status.stop()\n disposeStyles()\n }\n }, 'dsh-update-status: style and first status read')\n\n // This is deliberately separate from the client module's hard injection:\n // a missing settings provider keeps the default visible state and does not\n // prevent the version badge or Host check from working.\n ctx.inject(['settingsScope'], (raw) => {\n const binder = (raw as { settingsScope?: unknown }).settingsScope\n if (binder === null || typeof binder !== 'object' || typeof (binder as SettingsScopeBinder).bind !== 'function') return\n try {\n const scope = (binder as SettingsScopeBinder).bind({ namespace: SETTINGS_NAMESPACE })\n ctx.effect(() => {\n const detach = preferences.attach(scope)\n let selected = status.getSnapshot().status?.channel ?? 'latest'\n const syncPreferences = () => {\n const next = preferences.getSnapshot()\n if (next.channel !== selected) {\n selected = next.channel\n void status.selectChannel(selected, next.cacheTtlMinutes)\n }\n // Changing cache policy deliberately does not issue a network request.\n // Its value is sent on the next ordinary status read or manual check.\n }\n syncPreferences()\n const unsubscribe = preferences.subscribe(syncPreferences)\n return () => { unsubscribe(); detach() }\n }, 'dsh-update-status: sidebar and channel preferences')\n } catch {\n // Default remains enabled when the Host settings namespace is unavailable.\n }\n })\n\n // single slot: DeepSeek + our badge replaces the complete official wordmark\n // (which contains HARNESS), but never touches sidebar.brand.mark.\n ctx.slots.inject('sidebar.brand.name', () => ctx.slots.register(\n // Official brand uses priority 0; the single-slot ledger requires a\n // different, lower priority to shadow it without mutating official code.\n { name: 'sidebar.brand.name', priority: -10 },\n () => BrandName({ ui }),\n ))\n\n // additive fallback; returns null in wide mode to avoid two visible badges.\n ctx.slots.inject('sidebar.footer.action', () => ctx.slots.register(\n { name: 'sidebar.footer.action', id: 'dsh-update-status', order: 40 },\n props => FooterAction({ wide: props.wide, ui }),\n ))\n\n // additive frame overlay for click/tap panel and narrow-view bottom sheet.\n ctx.slots.inject('shell.overlay', () => ctx.slots.register(\n { name: 'shell.overlay', id: 'dsh-update-status', order: 40 },\n () => UpdatePanel({ ui }),\n ))\n\n // Independent settings section provides the required way to hide our entry.\n ctx.slots.inject('settings.section', () => ctx.slots.register(\n { name: 'settings.section', id: 'dsh-update-status', order: 80, label: () => t('settings.title') },\n () => UpdateSettings({ ui }),\n ))\n}\n\nmodule.exports = {\n name: PLUGIN_ID,\n inject: ['slots', 'connection'],\n apply,\n}\n"],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import z from "@deepseek-ai/schemastery";
|
|
2
|
+
import { Context } from "@deepseek-ai/cordis";
|
|
3
|
+
//#region src/shared/types.d.ts
|
|
4
|
+
declare const RELEASE_CHANNELS: readonly ['latest', 'next', 'alpha'];
|
|
5
|
+
type ReleaseChannel = (typeof RELEASE_CHANNELS)[number];
|
|
6
|
+
type ReleaseCompatibility = 'verified' | 'unverified' | 'incompatible';
|
|
7
|
+
type InstallKind = 'npm-global' | 'pnpm-global' | 'source-checkout' | 'unknown';
|
|
8
|
+
interface ChannelRelease {
|
|
9
|
+
channel: ReleaseChannel;
|
|
10
|
+
version: string | null;
|
|
11
|
+
publishedAt: string | null;
|
|
12
|
+
compatibility: ReleaseCompatibility;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A lossless, JSON-serializable snapshot used by both browser surfaces.
|
|
16
|
+
* Nulls are intentional: a failed first check must still render a truthful
|
|
17
|
+
* current-version card instead of an empty or malformed UI.
|
|
18
|
+
*/
|
|
19
|
+
interface UpdateStatus {
|
|
20
|
+
currentVersion: string;
|
|
21
|
+
latestVersion: string | null;
|
|
22
|
+
hasUpdate: boolean;
|
|
23
|
+
cached: boolean;
|
|
24
|
+
checkedAt: string | null;
|
|
25
|
+
warning: string | null;
|
|
26
|
+
installKind: InstallKind;
|
|
27
|
+
upgradeCommand: string;
|
|
28
|
+
releaseUrl: string;
|
|
29
|
+
changelogUrl: string;
|
|
30
|
+
publishedAt: string | null;
|
|
31
|
+
packageName: string;
|
|
32
|
+
/** Selected npm dist-tag used for comparison and command generation. */
|
|
33
|
+
channel: ReleaseChannel;
|
|
34
|
+
/** All supported dist-tags returned by the same cached registry request. */
|
|
35
|
+
channels: ChannelRelease[];
|
|
36
|
+
/** Phase 1 is informational only; the GUI must never apply an update. */
|
|
37
|
+
canApplyInPlace: false;
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/host/installation.d.ts
|
|
41
|
+
interface InstallationInfo {
|
|
42
|
+
currentVersion: string;
|
|
43
|
+
packageName: string;
|
|
44
|
+
channel: string;
|
|
45
|
+
installKind: InstallKind;
|
|
46
|
+
packageRoot?: string;
|
|
47
|
+
upgradeCommand: string;
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/host/update-status.d.ts
|
|
51
|
+
interface RegistryRelease {
|
|
52
|
+
channels: ChannelRelease[];
|
|
53
|
+
}
|
|
54
|
+
type RegistryFetcher = () => Promise<RegistryRelease>;
|
|
55
|
+
interface UpdateStatusServiceOptions {
|
|
56
|
+
installation: InstallationInfo;
|
|
57
|
+
fetchLatest?: RegistryFetcher;
|
|
58
|
+
now?: () => number;
|
|
59
|
+
ttlMs?: number;
|
|
60
|
+
releaseUrl?: string;
|
|
61
|
+
}
|
|
62
|
+
declare class UpdateStatusService {
|
|
63
|
+
private readonly installation;
|
|
64
|
+
private readonly fetchLatest;
|
|
65
|
+
private readonly now;
|
|
66
|
+
private readonly ttlMs;
|
|
67
|
+
private readonly releaseUrl;
|
|
68
|
+
private cache;
|
|
69
|
+
private inFlight;
|
|
70
|
+
constructor(options: UpdateStatusServiceOptions);
|
|
71
|
+
getStatus(channel?: ReleaseChannel, cacheTtlMinutes?: number): Promise<UpdateStatus>;
|
|
72
|
+
/** `force` bypasses TTL but still joins any registry check already in flight. */
|
|
73
|
+
check(force?: boolean, channel?: ReleaseChannel, cacheTtlMinutes?: number): Promise<UpdateStatus>;
|
|
74
|
+
private refreshRelease;
|
|
75
|
+
private statusAfterFailure;
|
|
76
|
+
private statusFromCache;
|
|
77
|
+
private statusWithoutRemoteRelease;
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region src/index.d.ts
|
|
81
|
+
declare const name = "dsh-update-status";
|
|
82
|
+
/** Connection supplies the authenticated transport; settings remains optional. */
|
|
83
|
+
declare const inject: string[];
|
|
84
|
+
interface Config {
|
|
85
|
+
cacheTtlHours?: number;
|
|
86
|
+
timeoutMs?: number;
|
|
87
|
+
autoCheckOnMount?: boolean;
|
|
88
|
+
}
|
|
89
|
+
/** Deployment config only controls metadata-check timing; it never authorizes upgrades. */
|
|
90
|
+
declare const Config: z<Config>;
|
|
91
|
+
declare function apply(ctx: Context, config?: Config): void;
|
|
92
|
+
//#endregion
|
|
93
|
+
export { Config, type InstallKind, type UpdateStatus, UpdateStatusService, apply, inject, name };
|