@jingyi0605/codingns4dsh 0.2.1-rc.5 → 0.2.1-rc.6

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.
Files changed (82) hide show
  1. package/README.en.md +4 -4
  2. package/README.md +5 -5
  3. package/data/build/dist/bootstrap/dsh-peer-host-preboot-shim.d.ts +1 -1
  4. package/data/build/dist/bootstrap/dsh-peer-host-preboot-shim.js +1 -1
  5. package/data/build/dist/client/bundle.js +143 -50
  6. package/data/build/dist/client/bundle.js.map +1 -1
  7. package/data/build/dist/client/cli-slots.js +2 -2
  8. package/data/build/dist/client/cli-slots.js.map +1 -1
  9. package/data/build/dist/client/client.delegate-command.js +3 -2
  10. package/data/build/dist/client/client.delegate-command.js.map +1 -1
  11. package/data/build/dist/client/client.magpie-model-tag.js +24 -8
  12. package/data/build/dist/client/client.magpie-model-tag.js.map +1 -1
  13. package/data/build/dist/client/client.native-workspace-store.js +26 -15
  14. package/data/build/dist/client/client.native-workspace-store.js.map +1 -1
  15. package/data/build/dist/client/client.session-translation.js +25 -0
  16. package/data/build/dist/client/client.session-translation.js.map +1 -1
  17. package/data/build/dist/client/client.transport.js +22 -0
  18. package/data/build/dist/client/client.transport.js.map +1 -1
  19. package/data/build/dist/client/delegate-command.js +2 -1
  20. package/data/build/dist/client/delegate-command.js.map +1 -1
  21. package/data/build/dist/client/desktop-assistant.js +22 -0
  22. package/data/build/dist/client/locale.d.ts.map +1 -1
  23. package/data/build/dist/client/locale.js +4 -0
  24. package/data/build/dist/client/locale.js.map +1 -1
  25. package/data/build/dist/client/locales/panels.d.ts.map +1 -1
  26. package/data/build/dist/client/locales/panels.js +18 -0
  27. package/data/build/dist/client/locales/panels.js.map +1 -1
  28. package/data/build/dist/client/magpie-model-tag.d.ts +4 -2
  29. package/data/build/dist/client/magpie-model-tag.d.ts.map +1 -1
  30. package/data/build/dist/client/magpie-model-tag.js +25 -8
  31. package/data/build/dist/client/magpie-model-tag.js.map +1 -1
  32. package/data/build/dist/client/native-model-translation-menu.d.ts +1 -0
  33. package/data/build/dist/client/native-model-translation-menu.d.ts.map +1 -1
  34. package/data/build/dist/client/native-model-translation-menu.js +2 -2
  35. package/data/build/dist/client/native-model-translation-menu.js.map +1 -1
  36. package/data/build/dist/client/session-translation-chat.d.ts.map +1 -1
  37. package/data/build/dist/client/session-translation-chat.js +6 -2
  38. package/data/build/dist/client/session-translation-chat.js.map +1 -1
  39. package/data/build/dist/client/settings-section.d.ts.map +1 -1
  40. package/data/build/dist/client/settings-section.js +6 -3
  41. package/data/build/dist/client/settings-section.js.map +1 -1
  42. package/data/build/dist/dsh-capabilities/matrix.js +14 -14
  43. package/data/build/dist/dsh-capabilities/matrix.js.map +1 -1
  44. package/data/build/dist/dsh-capabilities/routes.js +10 -10
  45. package/data/build/dist/dsh-capabilities/routes.js.map +1 -1
  46. package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts.map +1 -1
  47. package/data/build/dist/host/cli-adapters/dsh-message-projector.js +5 -2
  48. package/data/build/dist/host/cli-adapters/dsh-message-projector.js.map +1 -1
  49. package/data/build/dist/host/cli-adapters/feature.d.ts.map +1 -1
  50. package/data/build/dist/host/cli-adapters/feature.js +7 -3
  51. package/data/build/dist/host/cli-adapters/feature.js.map +1 -1
  52. package/data/build/dist/host/cli-adapters/magpie-usage.d.ts.map +1 -1
  53. package/data/build/dist/host/cli-adapters/magpie-usage.js +6 -1
  54. package/data/build/dist/host/cli-adapters/magpie-usage.js.map +1 -1
  55. package/data/build/dist/host/dsh-runtime-version.d.ts.map +1 -1
  56. package/data/build/dist/host/dsh-runtime-version.js +4 -1
  57. package/data/build/dist/host/dsh-runtime-version.js.map +1 -1
  58. package/data/build/dist/shared/contracts/cli-adapter.d.ts +2 -0
  59. package/data/build/dist/shared/contracts/cli-adapter.d.ts.map +1 -1
  60. package/data/build/dist/shared/contracts/errors.d.ts +2 -2
  61. package/data/build/dist/shared/contracts/errors.d.ts.map +1 -1
  62. package/data/build/dist/shared/contracts/errors.js +1 -1
  63. package/data/build/dist/shared/contracts/errors.js.map +1 -1
  64. package/data/build/dist/shared/contracts/session-translation.d.ts +4 -0
  65. package/data/build/dist/shared/contracts/session-translation.d.ts.map +1 -1
  66. package/data/build/dist/shared/contracts/session-translation.js +21 -0
  67. package/data/build/dist/shared/contracts/session-translation.js.map +1 -1
  68. package/data/build/dist/shared/contracts/version.d.ts +7 -7
  69. package/data/build/dist/shared/contracts/version.d.ts.map +1 -1
  70. package/data/build/dist/shared/contracts/version.js +11 -17
  71. package/data/build/dist/shared/contracts/version.js.map +1 -1
  72. package/data/build/dist/shared/index.d.ts +1 -1
  73. package/data/build/dist/shared/index.d.ts.map +1 -1
  74. package/data/build/dist/shared/index.js +1 -1
  75. package/data/build/dist/shared/index.js.map +1 -1
  76. package/package.json +3 -3
  77. package/profile/README.md +6 -6
  78. package/profile/package.json +3 -3
  79. package/profile/scripts/check-dsh-install.mjs +14 -1
  80. package/profile/version.json +2 -2
  81. package/scripts/check-dsh-install.mjs +14 -1
  82. package/version.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"client.magpie-model-tag.js","names":["resolveCodingNsTranslator","CODINGNS_RPC_CHANNEL","parseVirtualSessionId","createElement"],"sources":["../../../../src/shared/provider-icon-resources.ts","../../../../src/shared/cli-provider-route.ts","../../../../src/client/provider-icons.ts","../../../../src/shared/debug.ts","../../../../src/client/cli-catalog.ts","../../../../src/client/adapter-catalog-watch.ts","../../../../src/client/model-catalog-cache.ts","../../../../src/client/magpie-model-tag.ts"],"sourcesContent":["/** Client 与 Host 共用固定资源目录;避开 Desktop 将 /assets 固定映射到应用安装目录的路径。 */\nexport const PROVIDER_ICON_PATH = '/api/codingns/provider-icons/'\n\nexport const PROVIDER_ICON_FILES: Readonly<Record<string, string>> = {\n magpie: 'magpie.png',\n dsh: 'deepseek-harness.svg',\n 'command-code': 'command-code.svg',\n 'claude-code': 'claude-code.png',\n kimi: 'kimi.png',\n gemini: 'gemini.png',\n pi: 'pi.svg',\n codex: 'codex.png',\n opencode: 'opencode.png',\n grok: 'grok.png',\n mcode: 'minimax-code.svg',\n zcode: 'zcode.svg',\n r4: 'r4.svg',\n codebuddy: 'codebuddy.svg',\n workbuddy: 'workbuddy.svg',\n 'cursor-cli': 'cursor-cli.svg',\n 'kiro-cli': 'kiro-cli.svg',\n qoder: 'qoder.svg',\n 'qoder-cn': 'qoder-cn.svg',\n antigravity: 'antigravity.svg',\n doubao: 'doubao.png',\n}\n","import type { CodingNsCliAdapterId } from './contracts/cli-adapter.js'\n\nexport const CLI_PROVIDER_PREFIX = 'codingns-cli-'\n\n/** DSH provider routes are global; persisted adapter IDs remain plugin-local. */\nexport function toCliProviderId(adapterId: CodingNsCliAdapterId): string {\n return `${CLI_PROVIDER_PREFIX}${adapterId}`\n}\n\n/** A bare brand name does not establish ownership of a DSH provider. */\nexport function fromCliProviderId(provider: unknown): CodingNsCliAdapterId | undefined {\n if (typeof provider !== 'string' || !provider.startsWith(CLI_PROVIDER_PREFIX)) return undefined\n const adapterId = provider.slice(CLI_PROVIDER_PREFIX.length)\n return adapterId === '' ? undefined : adapterId\n}\n","import { resolveCodingNsTranslator, type CodingNsTranslator } from './locale.js'\nimport { fromCliProviderId } from '../shared/cli-provider-route.js'\nimport { PROVIDER_ICON_FILES } from '../shared/provider-icon-resources.js'\n\nexport interface ProviderVisual {\n readonly adapterId: string | null\n readonly displayName: string\n readonly iconUrl: string | undefined\n readonly color: string\n}\n\ninterface ProviderDefinition {\n readonly adapterId: string\n readonly displayName: string\n readonly displayNameKey?: string\n readonly color: string\n}\n\n/** 未绑定和未知 Agent 使用中性灰,绝不冒充任一已知品牌色。 */\nexport const PROVIDER_NEUTRAL_COLOR = '#71717a'\n\n/**\n * 外部 Agent 标识、显示名称与标签颜色的唯一映射。浏览器入口另行安装内联资产。\n *\n * 标签颜色用于会话行/归档列表的彩色标识:优先贴近本地图标或品牌色,\n * 并保持在浅色与深色主题下都可读的中等明度区间。\n */\nconst PROVIDER_DEFINITIONS: Readonly<Record<string, ProviderDefinition>> = {\n dsh: { adapterId: 'dsh', displayName: 'DeepSeek Harness', color: '#2563eb' },\n 'command-code': { adapterId: 'command-code', displayName: 'Command Code', color: '#8b5cf6' },\n 'claude-code': { adapterId: 'claude-code', displayName: 'Claude Code', color: '#d97757' },\n kimi: { adapterId: 'kimi', displayName: 'Kimi', color: '#0ea5e9' },\n gemini: { adapterId: 'gemini', displayName: 'Gemini CLI', color: '#4285f4' },\n pi: { adapterId: 'pi', displayName: 'Pi', color: '#f59e0b' },\n codex: { adapterId: 'codex', displayName: 'Codex', color: '#10a37f' },\n opencode: { adapterId: 'opencode', displayName: 'OpenCode', color: '#14b8a6' },\n grok: { adapterId: 'grok', displayName: 'Grok', color: '#71717a' },\n mcode: { adapterId: 'mcode', displayName: 'MiniMax Code', color: '#f97316' },\n zcode: { adapterId: 'zcode', displayName: 'ZCode', color: '#38bdf8' },\n codebuddy: { adapterId: 'codebuddy', displayName: 'CodeBuddy', color: '#2563eb' },\n workbuddy: { adapterId: 'workbuddy', displayName: 'WorkBuddy', color: '#0f766e' },\n 'cursor-cli': { adapterId: 'cursor-cli', displayName: 'Cursor CLI', color: '#111827' },\n 'kiro-cli': { adapterId: 'kiro-cli', displayName: 'Kiro CLI', color: '#7c3aed' },\n qoder: { adapterId: 'qoder', displayName: 'Qoder', color: '#ea580c' },\n 'qoder-cn': { adapterId: 'qoder-cn', displayName: 'Qoder CN', color: '#c2410c' },\n antigravity: { adapterId: 'antigravity', displayName: 'Antigravity', color: '#1d4ed8' },\n doubao: { adapterId: 'doubao', displayName: 'Doubao App', displayNameKey: 'provider.doubao', color: '#477fe8' },\n}\n\nconst PROVIDER_ICONS: Record<string, string> = {}\n\nconst PROVIDER_ICON_ALIASES: Readonly<Record<string, string>> = {\n claude: 'claude-code',\n commandcode: 'command-code',\n 'minimax-code': 'mcode',\n minimax: 'mcode',\n cursor: 'cursor-cli',\n agy: 'antigravity',\n codingns4dsh: 'dsh',\n 'workbuddy-ai': 'workbuddy',\n 'grok-(supergrok)': 'grok',\n openai: 'codex',\n 'openai-api': 'codex',\n 'openai-subscription': 'codex',\n 'codex-subscription': 'codex',\n anthropic: 'claude-code',\n 'anthropic-subscription': 'claude-code',\n 'claude-subscription': 'claude-code',\n 'gemini-cli': 'gemini',\n 'google-gemini': 'gemini',\n 'codebuddy-cn': 'codebuddy',\n deepseek: 'dsh',\n 'deepseek-api': 'dsh',\n 'deepseek-harness': 'dsh',\n 'deepseek-subscription': 'dsh',\n supergrok: 'grok',\n}\n\nconst MODEL_PROVIDER_PATTERNS: readonly [RegExp, string][] = [\n [/(?:^|[\\-/])deepseek(?:[-./]|$)/u, 'dsh'],\n [/(?:^|[\\-/])codex(?:[-./]|$)/u, 'codex'],\n [/(?:^|[\\-/])gpt(?:[-./]|$)/u, 'codex'],\n [/(?:^|[\\-/])(?:claude|opus|sonnet|haiku)(?:[-./]|$)/u, 'claude-code'],\n [/(?:^|[\\-/])gemini(?:[-./]|$)/u, 'gemini'],\n [/(?:^|[\\-/])kimi(?:[-./]|$)/u, 'kimi'],\n [/(?:^|[\\-/])grok(?:[-./]|$)/u, 'grok'],\n [/(?:^|[\\-/])(?:minimax|mcode)(?:[-./]|$)/u, 'mcode'],\n [/(?:^|[\\-/])workbuddy(?:[-./]|$)/u, 'workbuddy'],\n [/(?:^|[\\-/])codebuddy(?:[-./]|$)/u, 'codebuddy'],\n [/(?:^|[\\-/])cursor(?:[-./]|$)/u, 'cursor-cli'],\n [/(?:^|[\\-/])qoder(?:[-./]|$)/u, 'qoder'],\n [/(?:^|[\\-/])command(?:-?code)(?:[-./]|$)/u, 'command-code'],\n [/(?:^|[\\-/])zcode(?:[-./]|$)/u, 'zcode'],\n [/(?:^|[\\-/])antigravity(?:[-./]|$)/u, 'antigravity'],\n]\n\nconst KNOWN_PROVIDER_ICON_IDS = new Set([\n ...Object.keys(PROVIDER_DEFINITIONS),\n ...Object.keys(PROVIDER_ICON_FILES),\n ...Object.values(PROVIDER_ICON_ALIASES),\n])\n\n/** 只由浏览器入口调用,使普通 Node 测试不需要加载 png/svg。 */\nexport function installProviderIcons(icons: Readonly<Record<string, string>>): void {\n for (const adapterId of Object.keys(PROVIDER_ICONS)) delete PROVIDER_ICONS[adapterId]\n // 资源也包含 R4 等上游品牌,不要求它同时是可执行的 Agent。\n for (const adapterId of Object.keys(icons)) {\n const iconUrl = icons[adapterId]\n if (iconUrl !== undefined) PROVIDER_ICONS[adapterId] = iconUrl\n }\n}\n\nexport function providerIconUrl(adapterId: string): string | undefined {\n return providerIconUrlForIdentities([adapterId])\n}\n\n/**\n * Resolve one canonical provider asset ID from the identities emitted by a\n * Magpie record. Specific provider identities win over the Magpie gateway;\n * model-family inference is only used when no provider identity is known.\n */\nexport function resolveProviderIconId(identities: readonly (string | null | undefined)[]): string | undefined {\n const candidates = providerIconCandidates(identities)\n return candidates[0]\n}\n\n/** Resolve and load a logo for a record that may expose several identities. */\nexport function providerIconUrlForIdentities(identities: readonly (string | null | undefined)[]): string | undefined {\n for (const iconId of providerIconCandidates(identities)) {\n const iconUrl = PROVIDER_ICONS[iconId]\n if (iconUrl !== undefined) return iconUrl\n }\n return undefined\n}\n\n/**\n * 未绑定和未知值都返回中性占位,绝不冒充任一已知品牌。\n *\n * 第二个参数是 Codingns4DSH 词典翻译函数;未提供时退回内置中文词典,\n * 保证不接 locale 的调用方与单测仍能拿到稳定的展示名。\n */\nexport function providerVisual(adapterId: string | undefined, t?: CodingNsTranslator): ProviderVisual {\n const translate = t ?? resolveCodingNsTranslator()\n if (adapterId === undefined || adapterId.trim() === '') {\n return { adapterId: null, displayName: translate('provider.unbound'), iconUrl: undefined, color: PROVIDER_NEUTRAL_COLOR }\n }\n const normalizedAdapterId = normalizeProviderAdapterId(adapterId)\n const definition = PROVIDER_DEFINITIONS[normalizedAdapterId]\n if (definition === undefined) {\n return { adapterId, displayName: translate('provider.unknown', { adapterId }), iconUrl: undefined, color: PROVIDER_NEUTRAL_COLOR }\n }\n return { ...definition, displayName: definition.displayNameKey ? translate(definition.displayNameKey) : definition.displayName, iconUrl: providerIconUrl(adapterId) }\n}\n\n/** 兼容旧版 CN profile 的会话快照,但不重新暴露第二个 Provider。 */\nfunction normalizeProviderAdapterId(adapterId: string): string {\n const normalized = fromCliProviderId(adapterId) ?? adapterId\n return normalized === 'codebuddy-cn' ? 'codebuddy' : normalized\n}\n\nfunction providerIconCandidates(identities: readonly (string | null | undefined)[]): readonly string[] {\n const specific: string[] = []\n const inferred: string[] = []\n const gateway: string[] = []\n const seen = new Set<string>()\n let hasSpecificProvider = false\n\n const add = (target: string[], iconId: string): void => {\n if (seen.has(iconId)) return\n seen.add(iconId)\n target.push(iconId)\n }\n\n for (const identity of identities) {\n if (identity === undefined || identity === null || identity.trim() === '') continue\n const normalized = normalizeProviderIdentity(identity)\n const cliAdapterId = fromCliProviderId(normalized)\n const values = [\n ...(cliAdapterId === undefined ? [] : [normalizeProviderIdentity(cliAdapterId)]),\n normalized,\n ...normalized.split('/').filter((value) => value !== '').reverse(),\n ]\n for (const value of values) {\n const iconId = canonicalProviderIconId(value)\n if (iconId === undefined) continue\n if (iconId === 'magpie') add(gateway, iconId)\n else {\n hasSpecificProvider = true\n add(specific, iconId)\n }\n }\n for (const value of values) {\n for (const [pattern, iconId] of MODEL_PROVIDER_PATTERNS) {\n if (pattern.test(value)) add(inferred, iconId)\n }\n }\n }\n\n // Do not let a gateway label mask the actual provider or a recognizable model family.\n return hasSpecificProvider ? specific : [...inferred, ...gateway]\n}\n\nfunction canonicalProviderIconId(value: string): string | undefined {\n const normalized = normalizeProviderIdentity(value)\n const aliased = PROVIDER_ICON_ALIASES[normalized] ?? normalized\n if (KNOWN_PROVIDER_ICON_IDS.has(aliased) || PROVIDER_ICONS[aliased] !== undefined) return aliased\n return undefined\n}\n\nfunction normalizeProviderIdentity(value: string): string {\n return value.trim().toLocaleLowerCase().replace(/[\\s_]+/gu, '-')\n}\n\nexport { PROVIDER_DEFINITIONS, PROVIDER_ICONS }\n","/**\n * Codingns4DSH 调试日志开关。\n *\n * 调试输出默认关闭。需要查看启动或 RPC 追踪时,使用\n * `CODINGNS4DSH_DEBUG=1 dsh ...` 启动 DSH;浏览器侧同时支持 `?dshDebug=1`。\n * 只看警告和错误时使用 `CODINGNS4DSH_DEBUG_LEVEL=warn`,也接受\n * `CODINGNS4DSH_DEBUG=warn` 作为简写。\n */\nexport const CODINGNS4DSH_DEBUG_ENV = 'CODINGNS4DSH_DEBUG'\nexport const CODINGNS4DSH_DEBUG_LEVEL_ENV = 'CODINGNS4DSH_DEBUG_LEVEL'\n/** 兼容脚本化启动器的显式警告模式开关。 */\nexport const CODINGNS4DSH_DEBUG_WARN_ENV = 'CODINGNS4DSH_DEBUG_WARN'\n\nconst LEGACY_DEBUG_ENV = 'CODINGNS4DSH_TUNNEL_DEBUG'\n\nexport type CodingNsDebugLevel = 'off' | 'warn' | 'info'\n\n/** 当前运行环境是否明确要求输出调试日志。 */\nexport function resolveCodingNsDebugEnabled(): boolean {\n return resolveCodingNsDebugLevel() !== 'off'\n}\n\n/** 解析调试日志级别;`warn` 会过滤普通追踪信息,只保留警告和错误。 */\nexport function resolveCodingNsDebugLevel(): CodingNsDebugLevel {\n const globals = globalThis as typeof globalThis & {\n __CODINGNS4DSH_DEBUG_ENABLED__?: unknown\n __CODINGNS4DSH_DEBUG_LEVEL__?: unknown\n __CODINGNS4DSH_TUNNEL_DEBUG__?: unknown\n }\n if (globals.__CODINGNS4DSH_DEBUG_LEVEL__ !== undefined) {\n return parseDebugLevel(globals.__CODINGNS4DSH_DEBUG_LEVEL__)\n }\n const globalValue = globals.__CODINGNS4DSH_DEBUG_ENABLED__ ?? globals.__CODINGNS4DSH_TUNNEL_DEBUG__\n if (globalValue !== undefined) return parseDebugValue(globalValue) ? 'info' : 'off'\n\n if (typeof location !== 'undefined') {\n const searchParams = new URL(location.href).searchParams\n const queryValue = searchParams.get('dshDebugLevel') ?? searchParams.get('dshDebug')\n if (queryValue !== null) return parseDebugLevel(queryValue)\n }\n\n if (typeof localStorage !== 'undefined') {\n try {\n const storedLevel = localStorage.getItem('codingns4dsh-debug-level')\n if (storedLevel !== null) return parseDebugLevel(storedLevel)\n const storedWarn = localStorage.getItem('codingns4dsh-debug-warn')\n if (storedWarn !== null && parseDebugValue(storedWarn)) return 'warn'\n const stored = localStorage.getItem('codingns4dsh-debug')\n ?? localStorage.getItem('codingns4dsh-tunnel-debug')\n if (stored !== null) return parseDebugLevel(stored)\n } catch {\n // 隐私模式或受限 iframe 可能禁止读取 localStorage,继续检查进程环境变量。\n }\n }\n\n if (typeof process !== 'undefined') {\n const level = process.env[CODINGNS4DSH_DEBUG_LEVEL_ENV]\n if (level !== undefined) return parseDebugLevel(level)\n if (parseDebugValue(process.env[CODINGNS4DSH_DEBUG_WARN_ENV])) return 'warn'\n return parseDebugLevel(process.env[CODINGNS4DSH_DEBUG_ENV] ?? process.env[LEGACY_DEBUG_ENV])\n }\n return 'off'\n}\n\n/** 输出受统一开关控制的调试信息。 */\nexport function debugInfo(message: unknown, ...args: unknown[]): void {\n if (resolveCodingNsDebugLevel() === 'info') console.info(message, ...args)\n}\n\n/** 输出受统一开关控制的调试警告。 */\nexport function debugWarn(message: unknown, ...args: unknown[]): void {\n if (resolveCodingNsDebugEnabled()) console.warn(message, ...args)\n}\n\nfunction parseDebugValue(value: unknown): boolean {\n if (typeof value === 'boolean') return value\n if (typeof value !== 'string') return false\n return /^(1|true|yes|on)$/iu.test(value.trim())\n}\n\nfunction parseDebugLevel(value: unknown): CodingNsDebugLevel {\n if (typeof value === 'boolean') return value ? 'info' : 'off'\n if (typeof value !== 'string') return 'off'\n const normalized = value.trim().toLowerCase()\n if (/^(warn|warning|error)$/u.test(normalized)) return 'warn'\n if (/^(1|true|yes|on|info|debug)$/u.test(normalized)) return 'info'\n return 'off'\n}\n","import type {\n CodingNsCliAdapterDescriptor,\n CodingNsCliModel,\n CodingNsCliModelCatalog,\n CodingNsCliSessionRecord,\n} from '../shared/contracts/cli-adapter.js'\nimport { CODINGNS_RPC_CHANNEL } from '../shared/contracts/transport.js'\nimport { debugInfo, debugWarn } from '../shared/debug.js'\nimport type { CodingNsRpcClient } from './features/types.js'\nimport type { CodingNsTranslator } from './locale.js'\n\n/** 设置页和选择器使用同一状态文案,检测中或失败都不能显示成未安装。 */\nexport function adapterDetectionLabel(adapter: CodingNsCliAdapterDescriptor): 'cli.detecting' | 'cli.detectionFailed' | 'cli.installed' | 'cli.installedOffline' | 'cli.notInstalled' {\n if (adapter.detectionState === 'pending' || adapter.detectionState === 'running') return 'cli.detecting'\n if (adapter.detectionState === 'error') return 'cli.detectionFailed'\n if (adapter.installed && adapter.runtimeState === 'installed') return 'cli.installedOffline'\n return adapter.installed ? 'cli.installed' : 'cli.notInstalled'\n}\n\n/** Client 侧访问 Host CLI 命名空间的统一入口。 */\nexport async function callCliRpc<T>(rpc: CodingNsRpcClient, action: string, payload: unknown, signal?: AbortSignal): Promise<T> {\n let response\n try {\n debugInfo('codingns4dsh: cli rpc request', { channel: CODINGNS_RPC_CHANNEL, action })\n response = await rpc.call(CODINGNS_RPC_CHANNEL, `cli/${action}`, payload, signal)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n if (!/HTTP (?:404|405)\\b/u.test(message)) throw error\n debugWarn('codingns4dsh: cli rpc fallback', { action, error: message })\n try {\n response = await rpc.call('/api', `codingns/cli/${action}`, payload, signal)\n } catch (fallbackError) {\n console.error('codingns4dsh: cli rpc fallback failed', { action, error: fallbackError })\n throw fallbackError\n }\n }\n if (!response.ok) {\n console.error('codingns4dsh: cli rpc response error', { action, error: response.error })\n throw new Error(response.error.message)\n }\n debugInfo('codingns4dsh: cli rpc response success', { action })\n return response.value as T\n}\n\nexport function adapterCatalogWithDsh(catalog: readonly CodingNsCliAdapterDescriptor[], dshVersion?: string): CodingNsCliAdapterDescriptor[] {\n // 对话框只展示实际可用的适配器;未安装或已停用的适配器由设置页管理。\n const available = catalog.filter((adapter) => adapter.installed && adapter.enabled)\n const version = dshVersion?.trim()\n const existingDsh = available.find((adapter) => adapter.id === 'dsh')\n if (existingDsh !== undefined) {\n if (version === undefined || version === '' || existingDsh.version === version) return available\n return available.map((adapter) => adapter.id === 'dsh' ? { ...adapter, version } : adapter)\n }\n return [{ id: 'dsh', name: 'DeepSeek Harness', installed: true, enabled: true, version: version === undefined || version === '' ? null : version, command: null }, ...available]\n}\n\nexport function firstModel(catalog: CodingNsCliModelCatalog): CodingNsCliModel | undefined {\n for (const group of catalog.groups) {\n const model = group.models[0]\n if (model !== undefined) return model\n }\n return undefined\n}\n\nexport function findModel(catalog: CodingNsCliModelCatalog, modelId: string | undefined): CodingNsCliModel | undefined {\n if (modelId === undefined) return undefined\n for (const group of catalog.groups) {\n const model = group.models.find((item) => item.id === modelId)\n if (model !== undefined) return model\n }\n return undefined\n}\n\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\n/** 旧 Host 缺少重新检测动作时给出版本提示;网络和检测错误仍保留原始原因。 */\nexport function catalogRefreshErrorMessage(error: unknown, t: CodingNsTranslator): string {\n const message = errorMessage(error)\n return /^未知 CLI RPC: cli\\/catalog\\/refresh$/u.test(message)\n ? t('cli.redetectHostUnsupported')\n : message\n}\n\n/** 读取 Host 持久化的外部会话索引;兼容数组和带 items/sessions 的响应包装。 */\nexport async function listCliSessions(\n rpc: CodingNsRpcClient,\n options: { readonly includeArchived?: boolean; readonly adapterId?: string } = {},\n): Promise<readonly CodingNsCliSessionRecord[]> {\n const value = await callCliRpc<unknown>(rpc, 'session/list', options)\n const rows = Array.isArray(value)\n ? value\n : isRecord(value) && Array.isArray(value.items)\n ? value.items\n : isRecord(value) && Array.isArray(value.sessions)\n ? value.sessions\n : []\n return rows.filter(isCliSessionRecord).map(redactCliSessionRecord)\n}\n\n/** 把已存在的 DSH 会话恢复到原生会话页面;插件不接管消息列表。 */\nexport async function restoreCliSession(\n rpc: CodingNsRpcClient,\n record: CodingNsCliSessionRecord,\n): Promise<void> {\n await callCliRpc(rpc, 'session/set', {\n sessionId: record.dshSessionId,\n adapterId: record.adapterId,\n ...(record.modelId ? { modelId: record.modelId } : {}),\n ...(record.effortId ? { effortId: record.effortId } : {}),\n ...(record.serviceTierId ? { serviceTierId: record.serviceTierId } : {}),\n ...(record.providerId ? { providerId: record.providerId } : {}),\n ...(record.providerSessionId ? { providerSessionId: record.providerSessionId } : {}),\n })\n navigateToDshSession(record.dshSessionId)\n}\n\n/** 通过 Host 同步归档 DSH 原生会话和 Codingns4DSH 外部会话索引。 */\nexport async function archiveCliSession(\n rpc: CodingNsRpcClient,\n sessionId: string,\n): Promise<void> {\n await callCliRpc(rpc, 'session/archive', { sessionId })\n}\n\n/**\n * 使用 DSH 当前的会话路由,而不是在插件中复制会话消息组件。\n * 旧版 DSH 使用 `/sessions/:id`,新版 workspace 页面使用同一路径的 workspace 前缀,\n * 因此保留当前 workspace 段并只替换 session id。\n */\nexport function navigateToDshSession(sessionId: string): void {\n if (typeof window === 'undefined' || sessionId.trim() === '') return\n const encoded = encodeURIComponent(sessionId.trim())\n const pathname = window.location.pathname\n const nextPath = /^(\\/workspaces\\/[^/]+\\/sessions\\/)[^/]+(?:\\/.*)?$/u.test(pathname)\n ? pathname.replace(/^(\\/workspaces\\/[^/]+\\/sessions\\/)[^/]+(?:\\/.*)?$/u, `$1${encoded}`)\n : /^\\/sessions\\/[^/]+(?:\\/.*)?$/u.test(pathname)\n ? pathname.replace(/^\\/sessions\\/[^/]+(?:\\/.*)?$/u, `/sessions/${encoded}`)\n : `/sessions/${encoded}`\n if (`${window.location.pathname}${window.location.search}${window.location.hash}` === `${nextPath}${window.location.search}${window.location.hash}`) return\n window.history.pushState({}, '', nextPath)\n window.dispatchEvent(new PopStateEvent('popstate'))\n}\n\nfunction isCliSessionRecord(value: unknown): value is CodingNsCliSessionRecord {\n if (!isRecord(value)) return false\n return typeof value.dshSessionId === 'string'\n && value.dshSessionId.trim() !== ''\n && typeof value.adapterId === 'string'\n && value.adapterId.trim() !== ''\n && (value.status === 'active' || value.status === 'idle' || value.status === 'error' || value.status === 'archived')\n && typeof value.createdAt === 'string'\n && typeof value.updatedAt === 'string'\n}\n\n/** 双重防护:即使旧 Host 错误返回 rawStoreRef,浏览器也不会把它留在状态中。 */\nfunction redactCliSessionRecord(record: CodingNsCliSessionRecord): CodingNsCliSessionRecord {\n const { rawStoreRef: _rawStoreRef, ...safe } = record\n return safe\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n","import type { CodingNsCliAdapterDescriptor } from '../shared/contracts/cli-adapter.js'\nimport type { CodingNsRpcClient } from './features/types.js'\nimport { callCliRpc } from './cli-catalog.js'\n\nconst loads = new WeakMap<CodingNsRpcClient, Map<string, Promise<readonly CodingNsCliAdapterDescriptor[]>>>()\nexport type AdapterCatalogChange =\n | { readonly kind: 'adapter' }\n | { readonly kind: 'models'; readonly adapterId: string }\n\nconst listeners = new WeakMap<CodingNsRpcClient, Set<(change: AdapterCatalogChange) => void>>()\n\n/** 手动检测完成后,让已挂载的选择器和模型目录一起更新。 */\nexport function notifyAdapterCatalogChanged(rpc: CodingNsRpcClient): void {\n publishCatalogChange(rpc, { kind: 'adapter' })\n}\n\n/** Model enrichment must not trigger a fresh adapter-installation scan. */\nexport function notifyModelCatalogChanged(rpc: CodingNsRpcClient, adapterId: string): void {\n publishCatalogChange(rpc, { kind: 'models', adapterId })\n}\n\nfunction publishCatalogChange(rpc: CodingNsRpcClient, change: AdapterCatalogChange): void {\n for (const listener of listeners.get(rpc) ?? []) listener(change)\n}\n\nexport function subscribeAdapterCatalogChanged(rpc: CodingNsRpcClient, listener: (change: AdapterCatalogChange) => void): () => void {\n let entries = listeners.get(rpc)\n if (entries === undefined) { entries = new Set(); listeners.set(rpc, entries) }\n entries.add(listener)\n return () => { entries.delete(listener) }\n}\n\n/** Poll only while installation detection or an explicitly requested release check is pending. */\nexport function watchAdapterCatalog(\n rpc: CodingNsRpcClient,\n sessionId: string | undefined,\n onValue: (value: readonly CodingNsCliAdapterDescriptor[]) => void,\n onError: (error: unknown) => void = () => undefined,\n): () => void {\n let active = true\n let busy = false\n let dirty = false\n let started = Date.now()\n let failures = 0\n let timer: ReturnType<typeof setTimeout> | undefined\n const refresh = async (): Promise<void> => {\n if (!active) return\n if (busy) { dirty = true; return }\n clearTimeout(timer)\n busy = true\n try {\n let requests = loads.get(rpc)\n if (requests === undefined) { requests = new Map(); loads.set(rpc, requests) }\n const key = sessionId ?? ''\n let request = requests.get(key)\n if (request === undefined) {\n request = callCliRpc<readonly CodingNsCliAdapterDescriptor[]>(rpc, 'catalog', sessionId === undefined ? {} : { sessionId }, AbortSignal.timeout(10_000))\n .finally(() => { if (requests.get(key) === request) requests.delete(key) })\n requests.set(key, request)\n }\n const value = await request\n if (!active) return\n failures = 0\n onValue(value)\n if (value.some((entry) => entry.detectionState === 'pending' || entry.detectionState === 'running' || entry.update?.state === 'checking') && Date.now() - started < 120_000) {\n timer = setTimeout(() => { void refresh() }, 1_000)\n }\n } catch (error) {\n if (active) {\n failures += 1\n if (failures === 1) onError(error)\n if (Date.now() - started < 120_000) timer = setTimeout(() => { void refresh() }, Math.min(1_000 * 2 ** failures, 15_000))\n }\n }\n finally {\n busy = false\n if (dirty && active) { dirty = false; void refresh() }\n }\n }\n const remove = subscribeAdapterCatalogChanged(rpc, (change) => {\n if (change.kind !== 'adapter') return\n started = Date.now()\n void refresh()\n })\n void refresh()\n return () => { active = false; clearTimeout(timer); remove() }\n}\n","import type { CodingNsCliModelCatalog } from '../shared/contracts/cli-adapter.js'\nimport type { CodingNsRpcClient } from './features/types.js'\nimport { callCliRpc } from './cli-catalog.js'\nimport { notifyModelCatalogChanged } from './adapter-catalog-watch.js'\nimport { parseVirtualSessionId } from '../shared/contracts/peer-host.js'\n\n/**\n * Client 侧模型目录缓存。\n *\n * Agent 选择器、模型选择器和委派弹层共享同一份 RPC 结果。缓存只属于当前\n * RPC 客户端实例与会话所属 Host,同一 Host 的会话共享目录,跨 Host 不复用。\n */\nconst modelCatalogCaches = new WeakMap<object, Map<string, CodingNsCliModelCatalog>>()\nconst modelCatalogLoads = new WeakMap<object, Map<string, Promise<CodingNsCliModelCatalog>>>()\n/** PeerHost 复用页面 RPC 实例,用稳定的 Host 身份隔离目录、请求与复检节流。 */\nconst modelCatalogHostKeys = new WeakMap<object, Map<string, object>>()\n\nfunction modelCatalogKey(rpc: CodingNsRpcClient, sessionId?: string): object {\n const hostId = sessionId === undefined ? undefined : parseVirtualSessionId(sessionId)?.hostId\n if (hostId === undefined) return rpc as object\n let hosts = modelCatalogHostKeys.get(rpc as object)\n if (hosts === undefined) {\n hosts = new Map()\n modelCatalogHostKeys.set(rpc as object, hosts)\n }\n let key = hosts.get(hostId)\n if (key === undefined) { key = {}; hosts.set(hostId, key) }\n return key\n}\n\n/**\n * Client 缓存有效期。\n *\n * 目录里既有模型清单,也有账号级事实(例如 Codex 的 `officialSubscription`\n * 与 `defaultServiceTier`)。后者会随用户在外部工具里切换供应商或登录状态而\n * 变化,而页面不会因此重新挂载。若 Client 永久持有第一次的结果,依赖这些事实\n * 的控件(Codex 官方订阅的 Fast 档位开关)就会在整场会话里一直缺失。\n *\n * 因此这里给出一个短 TTL:命中即用(不阻塞渲染),过期后重新请求。Host 侧还会\n * 比对 Provider 配置指纹,配置真正变化时立即失效,不依赖这个 TTL。\n */\nexport const MODEL_CATALOG_CACHE_TTL_MS = 60_000\n\ninterface CachedCatalog {\n readonly value: CodingNsCliModelCatalog\n readonly storedAt: number\n readonly ttlMs: number\n}\n\nconst modelCatalogCacheTimes = new WeakMap<object, Map<string, CachedCatalog>>()\n\nfunction cacheEntry(rpc: CodingNsRpcClient, adapterId: string, sessionId?: string): CachedCatalog | undefined {\n return cacheTimesFor(rpc, sessionId).get(adapterId)\n}\n\nfunction cacheTimesFor(rpc: CodingNsRpcClient, sessionId?: string): Map<string, CachedCatalog> {\n const key = modelCatalogKey(rpc, sessionId)\n let times = modelCatalogCacheTimes.get(key)\n if (times === undefined) {\n times = new Map()\n modelCatalogCacheTimes.set(key, times)\n }\n return times\n}\n\nfunction storeCatalog(rpc: CodingNsRpcClient, adapterId: string, value: CodingNsCliModelCatalog, sessionId?: string, ttlMs = MODEL_CATALOG_CACHE_TTL_MS): void {\n getModelCatalogCache(rpc, sessionId).set(adapterId, value)\n cacheTimesFor(rpc, sessionId).set(adapterId, { value, storedAt: Date.now(), ttlMs })\n}\n\n/** 指定会话时只作废其 Host;旧调用不传会话时仍清理整个 RPC 的指定目录。 */\nexport function invalidateModelCatalogCache(rpc: CodingNsRpcClient, adapterId?: string, sessionId?: string): void {\n const keys = sessionId === undefined\n ? [rpc as object, ...(modelCatalogHostKeys.get(rpc as object)?.values() ?? [])]\n : [modelCatalogKey(rpc, sessionId)]\n for (const key of keys) {\n const cache = modelCatalogCaches.get(key)\n const times = modelCatalogCacheTimes.get(key)\n const loads = modelCatalogLoads.get(key)\n if (adapterId === undefined) loads?.clear()\n else loads?.delete(adapterId)\n if (adapterId === undefined) { cache?.clear(); times?.clear() }\n else { cache?.delete(adapterId); times?.delete(adapterId) }\n }\n}\n\n/**\n * 「判定可能过期」时的复检节流。\n *\n * 目录声明了服务档位却未确认官方订阅时,值得再探测一次;但真实第三方接入会\n * 长期停在这个状态,不能每次挂载都发一次请求。这里按适配器记录最近一次复检\n * 时间,只有超过间隔才允许再次作废缓存。\n */\nexport const MODEL_CATALOG_REVALIDATE_INTERVAL_MS = 60_000\n\nconst modelCatalogRevalidations = new WeakMap<object, Map<string, number>>()\n\nexport function shouldRevalidateModelCatalog(\n rpc: CodingNsRpcClient,\n adapterId: string,\n needsRevalidation: boolean,\n sessionId?: string,\n): boolean {\n if (!needsRevalidation) return false\n const key = modelCatalogKey(rpc, sessionId)\n let times = modelCatalogRevalidations.get(key)\n if (times === undefined) {\n times = new Map()\n modelCatalogRevalidations.set(key, times)\n }\n const last = times.get(adapterId)\n const now = Date.now()\n if (last !== undefined && now - last < MODEL_CATALOG_REVALIDATE_INTERVAL_MS) return false\n times.set(adapterId, now)\n return true\n}\n\nexport function getModelCatalogCache(rpc: CodingNsRpcClient, sessionId?: string): Map<string, CodingNsCliModelCatalog> {\n const key = modelCatalogKey(rpc, sessionId)\n let cache = modelCatalogCaches.get(key)\n if (cache === undefined) {\n cache = new Map()\n modelCatalogCaches.set(key, cache)\n }\n return cache\n}\n\nexport function loadModelCatalog(rpc: CodingNsRpcClient, adapterId: string, sessionId?: string): Promise<CodingNsCliModelCatalog> {\n const cached = getModelCatalogCache(rpc, sessionId).get(adapterId)\n const entry = cached === undefined ? undefined : cacheEntry(rpc, adapterId, sessionId)\n // A successful stale catalog stays visible while a fresh base and optional\n // Magpie enrichment load in the background.\n if (cached !== undefined && cached.fallback !== true && entry?.value === cached && isFreshCacheEntry(rpc, adapterId, cached, sessionId)) {\n return Promise.resolve(cached)\n }\n const loads = getModelCatalogLoadCache(rpc, sessionId)\n const running = loads.get(adapterId)\n if (running !== undefined) return cached !== undefined && cached.fallback !== true ? Promise.resolve(cached) : running\n\n const hasStaleCatalog = cached !== undefined && cached.fallback !== true && entry?.value === cached\n if (cached !== undefined && !hasStaleCatalog) invalidateModelCatalogCache(rpc, adapterId, sessionId)\n\n const request = callCliRpc<CodingNsCliModelCatalog>(rpc, 'models', {\n adapterId,\n stage: 'base',\n ...(sessionId === undefined ? {} : { sessionId }),\n }).then((value) => {\n // 手动重新检测已替换请求时,迟到结果不能复活被作废的目录。\n if (loads.get(adapterId) !== request) return loadModelCatalog(rpc, adapterId, sessionId)\n if (value.fallback === true) {\n if (hasStaleCatalog && cached !== undefined) storeCatalog(rpc, adapterId, cached, sessionId, 5_000)\n else invalidateModelCatalogCache(rpc, adapterId, sessionId)\n } else {\n storeCatalog(rpc, adapterId, value, sessionId)\n if (hasStaleCatalog) notifyModelCatalogChanged(rpc, adapterId)\n }\n return value\n })\n loads.set(adapterId, request)\n\n // The base result above is the only part awaited by the caller. Enrichment\n // is a second, shared Host request; its completed snapshot replaces the base\n // cache and wakes mounted selectors without a timer or blocking spinner.\n void request.then(async (base) => {\n if (base.fallback === true || base.magpiePending !== true || loads.get(adapterId) !== request) return\n try {\n const enriched = await callCliRpc<CodingNsCliModelCatalog>(rpc, 'models', {\n adapterId,\n stage: 'enriched',\n ...(sessionId === undefined ? {} : { sessionId }),\n })\n if (loads.get(adapterId) !== request || getModelCatalogCache(rpc, sessionId).get(adapterId) !== base || enriched.fallback === true) return\n storeCatalog(rpc, adapterId, enriched, sessionId)\n notifyModelCatalogChanged(rpc, adapterId)\n } catch {\n if (loads.get(adapterId) !== request || getModelCatalogCache(rpc, sessionId).get(adapterId) !== base) return\n const readyBase = withoutMagpiePending(base)\n storeCatalog(rpc, adapterId, readyBase, sessionId, 5_000)\n notifyModelCatalogChanged(rpc, adapterId)\n }\n }).catch(() => {\n if (loads.get(adapterId) !== request) return\n const current = getModelCatalogCache(rpc, sessionId).get(adapterId)\n if (current === undefined || current.fallback === true || cacheEntry(rpc, adapterId, sessionId)?.value !== current) return\n // Keep showing the last good snapshot and avoid immediately retrying a\n // failing Host after every render.\n storeCatalog(rpc, adapterId, current, sessionId, 5_000)\n }).finally(() => {\n if (loads.get(adapterId) === request) loads.delete(adapterId)\n })\n\n if (hasStaleCatalog) return Promise.resolve(cached)\n return request\n}\n\nfunction withoutMagpiePending(catalog: CodingNsCliModelCatalog): CodingNsCliModelCatalog {\n if (catalog.magpiePending !== true) return catalog\n const { magpiePending: _magpiePending, ...ready } = catalog\n return ready\n}\n\n/** 缓存条目是否仍在有效期内;没有时间戳的旧条目按过期处理并触发一次重新读取。 */\nfunction isFreshCacheEntry(rpc: CodingNsRpcClient, adapterId: string, cached: CodingNsCliModelCatalog, sessionId?: string): boolean {\n const entry = cacheEntry(rpc, adapterId, sessionId)\n if (entry === undefined || entry.value !== cached) return false\n return Date.now() - entry.storedAt < entry.ttlMs\n}\n\nfunction getModelCatalogLoadCache(rpc: CodingNsRpcClient, sessionId?: string): Map<string, Promise<CodingNsCliModelCatalog>> {\n const key = modelCatalogKey(rpc, sessionId)\n let cache = modelCatalogLoads.get(key)\n if (cache === undefined) {\n cache = new Map()\n modelCatalogLoads.set(key, cache)\n }\n return cache\n}\n","import { createElement, type ReactElement } from 'react'\nimport { providerIconUrl } from './provider-icons.js'\nimport { PROVIDER_ICON_PATH } from '../shared/provider-icon-resources.js'\n\nexport const MAGPIE_MODEL_TAG_ATTRIBUTE = 'data-codingns-magpie-model-tag'\n\n/**\n * Magpie 模型来源标签使用的喜鹊图标。\n *\n * 图标必须走本机 Host 的固定资源路由:此前指向 GitHub 上的 `icon-256.png`,\n * 而在离线、Host 无外网出口,或页面策略只允许 `img-src 'self'` 时该外链会被\n * 浏览器拦截,标签容器虽然渲染出来却不显示任何图像。本地路由随插件一起安装,\n * 无网络依赖,也不会被同源策略挡住。\n */\nexport function magpieModelLogoUrl(): string {\n return providerIconUrl('magpie') ?? `${PROVIDER_ICON_PATH}magpie.png`\n}\n\nconst tagStyle = {\n display: 'inline-flex',\n flex: 'none',\n alignItems: 'center',\n justifyContent: 'center',\n width: '18px',\n height: '18px',\n marginInlineStart: 'auto',\n whiteSpace: 'nowrap',\n verticalAlign: 'middle',\n} as const\n\nconst tagLogoStyle = {\n display: 'block',\n width: '16px',\n height: '16px',\n flex: '0 0 16px',\n objectFit: 'contain',\n borderRadius: '4px',\n} as const\n\n/** Compact visual source marker shared by every model-list surface. */\nexport function MagpieModelTag(): ReactElement {\n return createElement('span', {\n [MAGPIE_MODEL_TAG_ATTRIBUTE]: '',\n role: 'note',\n 'aria-label': 'Provided by Magpie',\n title: 'Provided by Magpie',\n style: tagStyle,\n }, createElement('img', { src: magpieModelLogoUrl(), alt: 'Provided by Magpie', style: tagLogoStyle }))\n}\n\n/** Native DSH owns its menu DOM, so its option rows receive the same badge imperatively. */\nexport function createMagpieModelTagNode(document: Document, modelId?: string): HTMLSpanElement {\n const tag = document.createElement('span')\n tag.setAttribute(MAGPIE_MODEL_TAG_ATTRIBUTE, '')\n if (modelId !== undefined) tag.dataset.modelId = modelId\n tag.setAttribute('role', 'note')\n tag.setAttribute('aria-label', 'Provided by Magpie')\n tag.title = 'Provided by Magpie'\n Object.assign(tag.style, tagStyle)\n\n const logo = document.createElement('img')\n logo.setAttribute('src', magpieModelLogoUrl())\n logo.setAttribute('alt', 'Provided by Magpie')\n Object.assign(logo.style, tagLogoStyle)\n tag.append(logo)\n return tag\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.magpie-model-tag.js","names":["resolveCodingNsTranslator","CODINGNS_RPC_CHANNEL","parseVirtualSessionId","createElement"],"sources":["../../../../src/shared/provider-icon-resources.ts","../../../../src/shared/cli-provider-route.ts","../../../../src/client/provider-icons.ts","../../../../src/shared/debug.ts","../../../../src/client/cli-catalog.ts","../../../../src/client/adapter-catalog-watch.ts","../../../../src/client/model-catalog-cache.ts","../../../../src/client/magpie-model-tag.ts"],"sourcesContent":["/** Client 与 Host 共用固定资源目录;避开 Desktop 将 /assets 固定映射到应用安装目录的路径。 */\nexport const PROVIDER_ICON_PATH = '/api/codingns/provider-icons/'\n\nexport const PROVIDER_ICON_FILES: Readonly<Record<string, string>> = {\n magpie: 'magpie.png',\n dsh: 'deepseek-harness.svg',\n 'command-code': 'command-code.svg',\n 'claude-code': 'claude-code.png',\n kimi: 'kimi.png',\n gemini: 'gemini.png',\n pi: 'pi.svg',\n codex: 'codex.png',\n opencode: 'opencode.png',\n grok: 'grok.png',\n mcode: 'minimax-code.svg',\n zcode: 'zcode.svg',\n r4: 'r4.svg',\n codebuddy: 'codebuddy.svg',\n workbuddy: 'workbuddy.svg',\n 'cursor-cli': 'cursor-cli.svg',\n 'kiro-cli': 'kiro-cli.svg',\n qoder: 'qoder.svg',\n 'qoder-cn': 'qoder-cn.svg',\n antigravity: 'antigravity.svg',\n doubao: 'doubao.png',\n}\n","import type { CodingNsCliAdapterId } from './contracts/cli-adapter.js'\n\nexport const CLI_PROVIDER_PREFIX = 'codingns-cli-'\n\n/** DSH provider routes are global; persisted adapter IDs remain plugin-local. */\nexport function toCliProviderId(adapterId: CodingNsCliAdapterId): string {\n return `${CLI_PROVIDER_PREFIX}${adapterId}`\n}\n\n/** A bare brand name does not establish ownership of a DSH provider. */\nexport function fromCliProviderId(provider: unknown): CodingNsCliAdapterId | undefined {\n if (typeof provider !== 'string' || !provider.startsWith(CLI_PROVIDER_PREFIX)) return undefined\n const adapterId = provider.slice(CLI_PROVIDER_PREFIX.length)\n return adapterId === '' ? undefined : adapterId\n}\n","import { resolveCodingNsTranslator, type CodingNsTranslator } from './locale.js'\nimport { fromCliProviderId } from '../shared/cli-provider-route.js'\nimport { PROVIDER_ICON_FILES } from '../shared/provider-icon-resources.js'\n\nexport interface ProviderVisual {\n readonly adapterId: string | null\n readonly displayName: string\n readonly iconUrl: string | undefined\n readonly color: string\n}\n\ninterface ProviderDefinition {\n readonly adapterId: string\n readonly displayName: string\n readonly displayNameKey?: string\n readonly color: string\n}\n\n/** 未绑定和未知 Agent 使用中性灰,绝不冒充任一已知品牌色。 */\nexport const PROVIDER_NEUTRAL_COLOR = '#71717a'\n\n/**\n * 外部 Agent 标识、显示名称与标签颜色的唯一映射。浏览器入口另行安装内联资产。\n *\n * 标签颜色用于会话行/归档列表的彩色标识:优先贴近本地图标或品牌色,\n * 并保持在浅色与深色主题下都可读的中等明度区间。\n */\nconst PROVIDER_DEFINITIONS: Readonly<Record<string, ProviderDefinition>> = {\n dsh: { adapterId: 'dsh', displayName: 'DeepSeek Harness', color: '#2563eb' },\n 'command-code': { adapterId: 'command-code', displayName: 'Command Code', color: '#8b5cf6' },\n 'claude-code': { adapterId: 'claude-code', displayName: 'Claude Code', color: '#d97757' },\n kimi: { adapterId: 'kimi', displayName: 'Kimi', color: '#0ea5e9' },\n gemini: { adapterId: 'gemini', displayName: 'Gemini CLI', color: '#4285f4' },\n pi: { adapterId: 'pi', displayName: 'Pi', color: '#f59e0b' },\n codex: { adapterId: 'codex', displayName: 'Codex', color: '#10a37f' },\n opencode: { adapterId: 'opencode', displayName: 'OpenCode', color: '#14b8a6' },\n grok: { adapterId: 'grok', displayName: 'Grok', color: '#71717a' },\n mcode: { adapterId: 'mcode', displayName: 'MiniMax Code', color: '#f97316' },\n zcode: { adapterId: 'zcode', displayName: 'ZCode', color: '#38bdf8' },\n codebuddy: { adapterId: 'codebuddy', displayName: 'CodeBuddy', color: '#2563eb' },\n workbuddy: { adapterId: 'workbuddy', displayName: 'WorkBuddy', color: '#0f766e' },\n 'cursor-cli': { adapterId: 'cursor-cli', displayName: 'Cursor CLI', color: '#111827' },\n 'kiro-cli': { adapterId: 'kiro-cli', displayName: 'Kiro CLI', color: '#7c3aed' },\n qoder: { adapterId: 'qoder', displayName: 'Qoder', color: '#ea580c' },\n 'qoder-cn': { adapterId: 'qoder-cn', displayName: 'Qoder CN', color: '#c2410c' },\n antigravity: { adapterId: 'antigravity', displayName: 'Antigravity', color: '#1d4ed8' },\n doubao: { adapterId: 'doubao', displayName: 'Doubao App', displayNameKey: 'provider.doubao', color: '#477fe8' },\n}\n\nconst PROVIDER_ICONS: Record<string, string> = {}\n\nconst PROVIDER_ICON_ALIASES: Readonly<Record<string, string>> = {\n claude: 'claude-code',\n commandcode: 'command-code',\n 'minimax-code': 'mcode',\n minimax: 'mcode',\n cursor: 'cursor-cli',\n agy: 'antigravity',\n codingns4dsh: 'dsh',\n 'workbuddy-ai': 'workbuddy',\n 'grok-(supergrok)': 'grok',\n openai: 'codex',\n 'openai-api': 'codex',\n 'openai-subscription': 'codex',\n 'codex-subscription': 'codex',\n anthropic: 'claude-code',\n 'anthropic-subscription': 'claude-code',\n 'claude-subscription': 'claude-code',\n 'gemini-cli': 'gemini',\n 'google-gemini': 'gemini',\n 'codebuddy-cn': 'codebuddy',\n deepseek: 'dsh',\n 'deepseek-api': 'dsh',\n 'deepseek-harness': 'dsh',\n 'deepseek-subscription': 'dsh',\n supergrok: 'grok',\n}\n\nconst MODEL_PROVIDER_PATTERNS: readonly [RegExp, string][] = [\n [/(?:^|[\\-/])deepseek(?:[-./]|$)/u, 'dsh'],\n [/(?:^|[\\-/])codex(?:[-./]|$)/u, 'codex'],\n [/(?:^|[\\-/])gpt(?:[-./]|$)/u, 'codex'],\n [/(?:^|[\\-/])(?:claude|opus|sonnet|haiku)(?:[-./]|$)/u, 'claude-code'],\n [/(?:^|[\\-/])gemini(?:[-./]|$)/u, 'gemini'],\n [/(?:^|[\\-/])kimi(?:[-./]|$)/u, 'kimi'],\n [/(?:^|[\\-/])grok(?:[-./]|$)/u, 'grok'],\n [/(?:^|[\\-/])(?:minimax|mcode)(?:[-./]|$)/u, 'mcode'],\n [/(?:^|[\\-/])workbuddy(?:[-./]|$)/u, 'workbuddy'],\n [/(?:^|[\\-/])codebuddy(?:[-./]|$)/u, 'codebuddy'],\n [/(?:^|[\\-/])cursor(?:[-./]|$)/u, 'cursor-cli'],\n [/(?:^|[\\-/])qoder(?:[-./]|$)/u, 'qoder'],\n [/(?:^|[\\-/])command(?:-?code)(?:[-./]|$)/u, 'command-code'],\n [/(?:^|[\\-/])zcode(?:[-./]|$)/u, 'zcode'],\n [/(?:^|[\\-/])antigravity(?:[-./]|$)/u, 'antigravity'],\n]\n\nconst KNOWN_PROVIDER_ICON_IDS = new Set([\n ...Object.keys(PROVIDER_DEFINITIONS),\n ...Object.keys(PROVIDER_ICON_FILES),\n ...Object.values(PROVIDER_ICON_ALIASES),\n])\n\n/** 只由浏览器入口调用,使普通 Node 测试不需要加载 png/svg。 */\nexport function installProviderIcons(icons: Readonly<Record<string, string>>): void {\n for (const adapterId of Object.keys(PROVIDER_ICONS)) delete PROVIDER_ICONS[adapterId]\n // 资源也包含 R4 等上游品牌,不要求它同时是可执行的 Agent。\n for (const adapterId of Object.keys(icons)) {\n const iconUrl = icons[adapterId]\n if (iconUrl !== undefined) PROVIDER_ICONS[adapterId] = iconUrl\n }\n}\n\nexport function providerIconUrl(adapterId: string): string | undefined {\n return providerIconUrlForIdentities([adapterId])\n}\n\n/**\n * Resolve one canonical provider asset ID from the identities emitted by a\n * Magpie record. Specific provider identities win over the Magpie gateway;\n * model-family inference is only used when no provider identity is known.\n */\nexport function resolveProviderIconId(identities: readonly (string | null | undefined)[]): string | undefined {\n const candidates = providerIconCandidates(identities)\n return candidates[0]\n}\n\n/** Resolve and load a logo for a record that may expose several identities. */\nexport function providerIconUrlForIdentities(identities: readonly (string | null | undefined)[]): string | undefined {\n for (const iconId of providerIconCandidates(identities)) {\n const iconUrl = PROVIDER_ICONS[iconId]\n if (iconUrl !== undefined) return iconUrl\n }\n return undefined\n}\n\n/**\n * 未绑定和未知值都返回中性占位,绝不冒充任一已知品牌。\n *\n * 第二个参数是 Codingns4DSH 词典翻译函数;未提供时退回内置中文词典,\n * 保证不接 locale 的调用方与单测仍能拿到稳定的展示名。\n */\nexport function providerVisual(adapterId: string | undefined, t?: CodingNsTranslator): ProviderVisual {\n const translate = t ?? resolveCodingNsTranslator()\n if (adapterId === undefined || adapterId.trim() === '') {\n return { adapterId: null, displayName: translate('provider.unbound'), iconUrl: undefined, color: PROVIDER_NEUTRAL_COLOR }\n }\n const normalizedAdapterId = normalizeProviderAdapterId(adapterId)\n const definition = PROVIDER_DEFINITIONS[normalizedAdapterId]\n if (definition === undefined) {\n return { adapterId, displayName: translate('provider.unknown', { adapterId }), iconUrl: undefined, color: PROVIDER_NEUTRAL_COLOR }\n }\n return { ...definition, displayName: definition.displayNameKey ? translate(definition.displayNameKey) : definition.displayName, iconUrl: providerIconUrl(adapterId) }\n}\n\n/** 兼容旧版 CN profile 的会话快照,但不重新暴露第二个 Provider。 */\nfunction normalizeProviderAdapterId(adapterId: string): string {\n const normalized = fromCliProviderId(adapterId) ?? adapterId\n return normalized === 'codebuddy-cn' ? 'codebuddy' : normalized\n}\n\nfunction providerIconCandidates(identities: readonly (string | null | undefined)[]): readonly string[] {\n const specific: string[] = []\n const inferred: string[] = []\n const gateway: string[] = []\n const seen = new Set<string>()\n let hasSpecificProvider = false\n\n const add = (target: string[], iconId: string): void => {\n if (seen.has(iconId)) return\n seen.add(iconId)\n target.push(iconId)\n }\n\n for (const identity of identities) {\n if (identity === undefined || identity === null || identity.trim() === '') continue\n const normalized = normalizeProviderIdentity(identity)\n const cliAdapterId = fromCliProviderId(normalized)\n const values = [\n ...(cliAdapterId === undefined ? [] : [normalizeProviderIdentity(cliAdapterId)]),\n normalized,\n ...normalized.split('/').filter((value) => value !== '').reverse(),\n ]\n for (const value of values) {\n const iconId = canonicalProviderIconId(value)\n if (iconId === undefined) continue\n if (iconId === 'magpie') add(gateway, iconId)\n else {\n hasSpecificProvider = true\n add(specific, iconId)\n }\n }\n for (const value of values) {\n for (const [pattern, iconId] of MODEL_PROVIDER_PATTERNS) {\n if (pattern.test(value)) add(inferred, iconId)\n }\n }\n }\n\n // Do not let a gateway label mask the actual provider or a recognizable model family.\n return hasSpecificProvider ? specific : [...inferred, ...gateway]\n}\n\nfunction canonicalProviderIconId(value: string): string | undefined {\n const normalized = normalizeProviderIdentity(value)\n const aliased = PROVIDER_ICON_ALIASES[normalized] ?? normalized\n if (KNOWN_PROVIDER_ICON_IDS.has(aliased) || PROVIDER_ICONS[aliased] !== undefined) return aliased\n return undefined\n}\n\nfunction normalizeProviderIdentity(value: string): string {\n return value.trim().toLocaleLowerCase().replace(/[\\s_]+/gu, '-')\n}\n\nexport { PROVIDER_DEFINITIONS, PROVIDER_ICONS }\n","/**\n * Codingns4DSH 调试日志开关。\n *\n * 调试输出默认关闭。需要查看启动或 RPC 追踪时,使用\n * `CODINGNS4DSH_DEBUG=1 dsh ...` 启动 DSH;浏览器侧同时支持 `?dshDebug=1`。\n * 只看警告和错误时使用 `CODINGNS4DSH_DEBUG_LEVEL=warn`,也接受\n * `CODINGNS4DSH_DEBUG=warn` 作为简写。\n */\nexport const CODINGNS4DSH_DEBUG_ENV = 'CODINGNS4DSH_DEBUG'\nexport const CODINGNS4DSH_DEBUG_LEVEL_ENV = 'CODINGNS4DSH_DEBUG_LEVEL'\n/** 兼容脚本化启动器的显式警告模式开关。 */\nexport const CODINGNS4DSH_DEBUG_WARN_ENV = 'CODINGNS4DSH_DEBUG_WARN'\n\nconst LEGACY_DEBUG_ENV = 'CODINGNS4DSH_TUNNEL_DEBUG'\n\nexport type CodingNsDebugLevel = 'off' | 'warn' | 'info'\n\n/** 当前运行环境是否明确要求输出调试日志。 */\nexport function resolveCodingNsDebugEnabled(): boolean {\n return resolveCodingNsDebugLevel() !== 'off'\n}\n\n/** 解析调试日志级别;`warn` 会过滤普通追踪信息,只保留警告和错误。 */\nexport function resolveCodingNsDebugLevel(): CodingNsDebugLevel {\n const globals = globalThis as typeof globalThis & {\n __CODINGNS4DSH_DEBUG_ENABLED__?: unknown\n __CODINGNS4DSH_DEBUG_LEVEL__?: unknown\n __CODINGNS4DSH_TUNNEL_DEBUG__?: unknown\n }\n if (globals.__CODINGNS4DSH_DEBUG_LEVEL__ !== undefined) {\n return parseDebugLevel(globals.__CODINGNS4DSH_DEBUG_LEVEL__)\n }\n const globalValue = globals.__CODINGNS4DSH_DEBUG_ENABLED__ ?? globals.__CODINGNS4DSH_TUNNEL_DEBUG__\n if (globalValue !== undefined) return parseDebugValue(globalValue) ? 'info' : 'off'\n\n if (typeof location !== 'undefined') {\n const searchParams = new URL(location.href).searchParams\n const queryValue = searchParams.get('dshDebugLevel') ?? searchParams.get('dshDebug')\n if (queryValue !== null) return parseDebugLevel(queryValue)\n }\n\n if (typeof localStorage !== 'undefined') {\n try {\n const storedLevel = localStorage.getItem('codingns4dsh-debug-level')\n if (storedLevel !== null) return parseDebugLevel(storedLevel)\n const storedWarn = localStorage.getItem('codingns4dsh-debug-warn')\n if (storedWarn !== null && parseDebugValue(storedWarn)) return 'warn'\n const stored = localStorage.getItem('codingns4dsh-debug')\n ?? localStorage.getItem('codingns4dsh-tunnel-debug')\n if (stored !== null) return parseDebugLevel(stored)\n } catch {\n // 隐私模式或受限 iframe 可能禁止读取 localStorage,继续检查进程环境变量。\n }\n }\n\n if (typeof process !== 'undefined') {\n const level = process.env[CODINGNS4DSH_DEBUG_LEVEL_ENV]\n if (level !== undefined) return parseDebugLevel(level)\n if (parseDebugValue(process.env[CODINGNS4DSH_DEBUG_WARN_ENV])) return 'warn'\n return parseDebugLevel(process.env[CODINGNS4DSH_DEBUG_ENV] ?? process.env[LEGACY_DEBUG_ENV])\n }\n return 'off'\n}\n\n/** 输出受统一开关控制的调试信息。 */\nexport function debugInfo(message: unknown, ...args: unknown[]): void {\n if (resolveCodingNsDebugLevel() === 'info') console.info(message, ...args)\n}\n\n/** 输出受统一开关控制的调试警告。 */\nexport function debugWarn(message: unknown, ...args: unknown[]): void {\n if (resolveCodingNsDebugEnabled()) console.warn(message, ...args)\n}\n\nfunction parseDebugValue(value: unknown): boolean {\n if (typeof value === 'boolean') return value\n if (typeof value !== 'string') return false\n return /^(1|true|yes|on)$/iu.test(value.trim())\n}\n\nfunction parseDebugLevel(value: unknown): CodingNsDebugLevel {\n if (typeof value === 'boolean') return value ? 'info' : 'off'\n if (typeof value !== 'string') return 'off'\n const normalized = value.trim().toLowerCase()\n if (/^(warn|warning|error)$/u.test(normalized)) return 'warn'\n if (/^(1|true|yes|on|info|debug)$/u.test(normalized)) return 'info'\n return 'off'\n}\n","import type {\n CodingNsCliAdapterDescriptor,\n CodingNsCliModel,\n CodingNsCliModelCatalog,\n CodingNsCliSessionRecord,\n} from '../shared/contracts/cli-adapter.js'\nimport { CODINGNS_RPC_CHANNEL } from '../shared/contracts/transport.js'\nimport { debugInfo, debugWarn } from '../shared/debug.js'\nimport type { CodingNsRpcClient } from './features/types.js'\nimport type { CodingNsTranslator } from './locale.js'\n\n/** 设置页和选择器使用同一状态文案,检测中或失败都不能显示成未安装。 */\nexport function adapterDetectionLabel(adapter: CodingNsCliAdapterDescriptor): 'cli.detecting' | 'cli.detectionFailed' | 'cli.installed' | 'cli.installedOffline' | 'cli.notInstalled' {\n if (adapter.detectionState === 'pending' || adapter.detectionState === 'running') return 'cli.detecting'\n if (adapter.detectionState === 'error') return 'cli.detectionFailed'\n if (adapter.installed && adapter.runtimeState === 'installed') return 'cli.installedOffline'\n return adapter.installed ? 'cli.installed' : 'cli.notInstalled'\n}\n\n/** Client 侧访问 Host CLI 命名空间的统一入口。 */\nexport async function callCliRpc<T>(rpc: CodingNsRpcClient, action: string, payload: unknown, signal?: AbortSignal): Promise<T> {\n let response\n try {\n debugInfo('codingns4dsh: cli rpc request', { channel: CODINGNS_RPC_CHANNEL, action })\n response = await rpc.call(CODINGNS_RPC_CHANNEL, `cli/${action}`, payload, signal)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n if (!/HTTP (?:404|405)\\b/u.test(message)) throw error\n debugWarn('codingns4dsh: cli rpc fallback', { action, error: message })\n try {\n response = await rpc.call('/api', `codingns/cli/${action}`, payload, signal)\n } catch (fallbackError) {\n console.error('codingns4dsh: cli rpc fallback failed', { action, error: fallbackError })\n throw fallbackError\n }\n }\n if (!response.ok) {\n console.error('codingns4dsh: cli rpc response error', { action, error: response.error })\n throw new Error(response.error.message)\n }\n debugInfo('codingns4dsh: cli rpc response success', { action })\n return response.value as T\n}\n\nexport function adapterCatalogWithDsh(catalog: readonly CodingNsCliAdapterDescriptor[], dshVersion?: string): CodingNsCliAdapterDescriptor[] {\n // 对话框只展示实际可用的适配器;未安装或已停用的适配器由设置页管理。\n const available = catalog.filter((adapter) => adapter.installed && adapter.enabled)\n const version = dshVersion?.trim()\n const existingDsh = available.find((adapter) => adapter.id === 'dsh')\n if (existingDsh !== undefined) {\n if (version === undefined || version === '' || existingDsh.version === version) return available\n return available.map((adapter) => adapter.id === 'dsh' ? { ...adapter, version } : adapter)\n }\n return [{ id: 'dsh', name: 'DeepSeek Harness', installed: true, enabled: true, version: version === undefined || version === '' ? null : version, command: null }, ...available]\n}\n\nexport function firstModel(catalog: CodingNsCliModelCatalog): CodingNsCliModel | undefined {\n for (const group of catalog.groups) {\n const model = group.models[0]\n if (model !== undefined) return model\n }\n return undefined\n}\n\nexport function findModel(catalog: CodingNsCliModelCatalog, modelId: string | undefined): CodingNsCliModel | undefined {\n if (modelId === undefined) return undefined\n for (const group of catalog.groups) {\n const model = group.models.find((item) => item.id === modelId)\n if (model !== undefined) return model\n }\n return undefined\n}\n\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\n/** 旧 Host 缺少重新检测动作时给出版本提示;网络和检测错误仍保留原始原因。 */\nexport function catalogRefreshErrorMessage(error: unknown, t: CodingNsTranslator): string {\n const message = errorMessage(error)\n return /^未知 CLI RPC: cli\\/catalog\\/refresh$/u.test(message)\n ? t('cli.redetectHostUnsupported')\n : message\n}\n\n/** 读取 Host 持久化的外部会话索引;兼容数组和带 items/sessions 的响应包装。 */\nexport async function listCliSessions(\n rpc: CodingNsRpcClient,\n options: { readonly includeArchived?: boolean; readonly adapterId?: string } = {},\n): Promise<readonly CodingNsCliSessionRecord[]> {\n const value = await callCliRpc<unknown>(rpc, 'session/list', options)\n const rows = Array.isArray(value)\n ? value\n : isRecord(value) && Array.isArray(value.items)\n ? value.items\n : isRecord(value) && Array.isArray(value.sessions)\n ? value.sessions\n : []\n return rows.filter(isCliSessionRecord).map(redactCliSessionRecord)\n}\n\n/** 把已存在的 DSH 会话恢复到原生会话页面;插件不接管消息列表。 */\nexport async function restoreCliSession(\n rpc: CodingNsRpcClient,\n record: CodingNsCliSessionRecord,\n): Promise<void> {\n await callCliRpc(rpc, 'session/set', {\n sessionId: record.dshSessionId,\n adapterId: record.adapterId,\n ...(record.modelId ? { modelId: record.modelId } : {}),\n ...(record.effortId ? { effortId: record.effortId } : {}),\n ...(record.serviceTierId ? { serviceTierId: record.serviceTierId } : {}),\n ...(record.providerId ? { providerId: record.providerId } : {}),\n ...(record.providerSessionId ? { providerSessionId: record.providerSessionId } : {}),\n })\n navigateToDshSession(record.dshSessionId)\n}\n\n/** 通过 Host 同步归档 DSH 原生会话和 Codingns4DSH 外部会话索引。 */\nexport async function archiveCliSession(\n rpc: CodingNsRpcClient,\n sessionId: string,\n): Promise<void> {\n await callCliRpc(rpc, 'session/archive', { sessionId })\n}\n\n/**\n * 使用 DSH 当前的会话路由,而不是在插件中复制会话消息组件。\n * 旧版 DSH 使用 `/sessions/:id`,新版 workspace 页面使用同一路径的 workspace 前缀,\n * 因此保留当前 workspace 段并只替换 session id。\n */\nexport function navigateToDshSession(sessionId: string): void {\n if (typeof window === 'undefined' || sessionId.trim() === '') return\n const encoded = encodeURIComponent(sessionId.trim())\n const pathname = window.location.pathname\n const nextPath = /^(\\/workspaces\\/[^/]+\\/sessions\\/)[^/]+(?:\\/.*)?$/u.test(pathname)\n ? pathname.replace(/^(\\/workspaces\\/[^/]+\\/sessions\\/)[^/]+(?:\\/.*)?$/u, `$1${encoded}`)\n : /^\\/sessions\\/[^/]+(?:\\/.*)?$/u.test(pathname)\n ? pathname.replace(/^\\/sessions\\/[^/]+(?:\\/.*)?$/u, `/sessions/${encoded}`)\n : `/sessions/${encoded}`\n if (`${window.location.pathname}${window.location.search}${window.location.hash}` === `${nextPath}${window.location.search}${window.location.hash}`) return\n window.history.pushState({}, '', nextPath)\n window.dispatchEvent(new PopStateEvent('popstate'))\n}\n\nfunction isCliSessionRecord(value: unknown): value is CodingNsCliSessionRecord {\n if (!isRecord(value)) return false\n return typeof value.dshSessionId === 'string'\n && value.dshSessionId.trim() !== ''\n && typeof value.adapterId === 'string'\n && value.adapterId.trim() !== ''\n && (value.status === 'active' || value.status === 'idle' || value.status === 'error' || value.status === 'archived')\n && typeof value.createdAt === 'string'\n && typeof value.updatedAt === 'string'\n}\n\n/** 双重防护:即使旧 Host 错误返回 rawStoreRef,浏览器也不会把它留在状态中。 */\nfunction redactCliSessionRecord(record: CodingNsCliSessionRecord): CodingNsCliSessionRecord {\n const { rawStoreRef: _rawStoreRef, ...safe } = record\n return safe\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n","import type { CodingNsCliAdapterDescriptor } from '../shared/contracts/cli-adapter.js'\nimport type { CodingNsRpcClient } from './features/types.js'\nimport { callCliRpc } from './cli-catalog.js'\n\nconst loads = new WeakMap<CodingNsRpcClient, Map<string, Promise<readonly CodingNsCliAdapterDescriptor[]>>>()\nexport type AdapterCatalogChange =\n | { readonly kind: 'adapter' }\n | { readonly kind: 'models'; readonly adapterId: string }\n\nconst listeners = new WeakMap<CodingNsRpcClient, Set<(change: AdapterCatalogChange) => void>>()\n\n/** 手动检测完成后,让已挂载的选择器和模型目录一起更新。 */\nexport function notifyAdapterCatalogChanged(rpc: CodingNsRpcClient): void {\n publishCatalogChange(rpc, { kind: 'adapter' })\n}\n\n/** Model enrichment must not trigger a fresh adapter-installation scan. */\nexport function notifyModelCatalogChanged(rpc: CodingNsRpcClient, adapterId: string): void {\n publishCatalogChange(rpc, { kind: 'models', adapterId })\n}\n\nfunction publishCatalogChange(rpc: CodingNsRpcClient, change: AdapterCatalogChange): void {\n for (const listener of listeners.get(rpc) ?? []) listener(change)\n}\n\nexport function subscribeAdapterCatalogChanged(rpc: CodingNsRpcClient, listener: (change: AdapterCatalogChange) => void): () => void {\n let entries = listeners.get(rpc)\n if (entries === undefined) { entries = new Set(); listeners.set(rpc, entries) }\n entries.add(listener)\n return () => { entries.delete(listener) }\n}\n\n/** Poll only while installation detection or an explicitly requested release check is pending. */\nexport function watchAdapterCatalog(\n rpc: CodingNsRpcClient,\n sessionId: string | undefined,\n onValue: (value: readonly CodingNsCliAdapterDescriptor[]) => void,\n onError: (error: unknown) => void = () => undefined,\n): () => void {\n let active = true\n let busy = false\n let dirty = false\n let started = Date.now()\n let failures = 0\n let timer: ReturnType<typeof setTimeout> | undefined\n const refresh = async (): Promise<void> => {\n if (!active) return\n if (busy) { dirty = true; return }\n clearTimeout(timer)\n busy = true\n try {\n let requests = loads.get(rpc)\n if (requests === undefined) { requests = new Map(); loads.set(rpc, requests) }\n const key = sessionId ?? ''\n let request = requests.get(key)\n if (request === undefined) {\n request = callCliRpc<readonly CodingNsCliAdapterDescriptor[]>(rpc, 'catalog', sessionId === undefined ? {} : { sessionId }, AbortSignal.timeout(10_000))\n .finally(() => { if (requests.get(key) === request) requests.delete(key) })\n requests.set(key, request)\n }\n const value = await request\n if (!active) return\n failures = 0\n onValue(value)\n if (value.some((entry) => entry.detectionState === 'pending' || entry.detectionState === 'running' || entry.update?.state === 'checking') && Date.now() - started < 120_000) {\n timer = setTimeout(() => { void refresh() }, 1_000)\n }\n } catch (error) {\n if (active) {\n failures += 1\n if (failures === 1) onError(error)\n if (Date.now() - started < 120_000) timer = setTimeout(() => { void refresh() }, Math.min(1_000 * 2 ** failures, 15_000))\n }\n }\n finally {\n busy = false\n if (dirty && active) { dirty = false; void refresh() }\n }\n }\n const remove = subscribeAdapterCatalogChanged(rpc, (change) => {\n if (change.kind !== 'adapter') return\n started = Date.now()\n void refresh()\n })\n void refresh()\n return () => { active = false; clearTimeout(timer); remove() }\n}\n","import type { CodingNsCliModelCatalog } from '../shared/contracts/cli-adapter.js'\nimport type { CodingNsRpcClient } from './features/types.js'\nimport { callCliRpc } from './cli-catalog.js'\nimport { notifyModelCatalogChanged } from './adapter-catalog-watch.js'\nimport { parseVirtualSessionId } from '../shared/contracts/peer-host.js'\n\n/**\n * Client 侧模型目录缓存。\n *\n * Agent 选择器、模型选择器和委派弹层共享同一份 RPC 结果。缓存只属于当前\n * RPC 客户端实例与会话所属 Host,同一 Host 的会话共享目录,跨 Host 不复用。\n */\nconst modelCatalogCaches = new WeakMap<object, Map<string, CodingNsCliModelCatalog>>()\nconst modelCatalogLoads = new WeakMap<object, Map<string, Promise<CodingNsCliModelCatalog>>>()\n/** PeerHost 复用页面 RPC 实例,用稳定的 Host 身份隔离目录、请求与复检节流。 */\nconst modelCatalogHostKeys = new WeakMap<object, Map<string, object>>()\n\nfunction modelCatalogKey(rpc: CodingNsRpcClient, sessionId?: string): object {\n const hostId = sessionId === undefined ? undefined : parseVirtualSessionId(sessionId)?.hostId\n if (hostId === undefined) return rpc as object\n let hosts = modelCatalogHostKeys.get(rpc as object)\n if (hosts === undefined) {\n hosts = new Map()\n modelCatalogHostKeys.set(rpc as object, hosts)\n }\n let key = hosts.get(hostId)\n if (key === undefined) { key = {}; hosts.set(hostId, key) }\n return key\n}\n\n/**\n * Client 缓存有效期。\n *\n * 目录里既有模型清单,也有账号级事实(例如 Codex 的 `officialSubscription`\n * 与 `defaultServiceTier`)。后者会随用户在外部工具里切换供应商或登录状态而\n * 变化,而页面不会因此重新挂载。若 Client 永久持有第一次的结果,依赖这些事实\n * 的控件(Codex 官方订阅的 Fast 档位开关)就会在整场会话里一直缺失。\n *\n * 因此这里给出一个短 TTL:命中即用(不阻塞渲染),过期后重新请求。Host 侧还会\n * 比对 Provider 配置指纹,配置真正变化时立即失效,不依赖这个 TTL。\n */\nexport const MODEL_CATALOG_CACHE_TTL_MS = 60_000\n\ninterface CachedCatalog {\n readonly value: CodingNsCliModelCatalog\n readonly storedAt: number\n readonly ttlMs: number\n}\n\nconst modelCatalogCacheTimes = new WeakMap<object, Map<string, CachedCatalog>>()\n\nfunction cacheEntry(rpc: CodingNsRpcClient, adapterId: string, sessionId?: string): CachedCatalog | undefined {\n return cacheTimesFor(rpc, sessionId).get(adapterId)\n}\n\nfunction cacheTimesFor(rpc: CodingNsRpcClient, sessionId?: string): Map<string, CachedCatalog> {\n const key = modelCatalogKey(rpc, sessionId)\n let times = modelCatalogCacheTimes.get(key)\n if (times === undefined) {\n times = new Map()\n modelCatalogCacheTimes.set(key, times)\n }\n return times\n}\n\nfunction storeCatalog(rpc: CodingNsRpcClient, adapterId: string, value: CodingNsCliModelCatalog, sessionId?: string, ttlMs = MODEL_CATALOG_CACHE_TTL_MS): void {\n getModelCatalogCache(rpc, sessionId).set(adapterId, value)\n cacheTimesFor(rpc, sessionId).set(adapterId, { value, storedAt: Date.now(), ttlMs })\n}\n\n/** 指定会话时只作废其 Host;旧调用不传会话时仍清理整个 RPC 的指定目录。 */\nexport function invalidateModelCatalogCache(rpc: CodingNsRpcClient, adapterId?: string, sessionId?: string): void {\n const keys = sessionId === undefined\n ? [rpc as object, ...(modelCatalogHostKeys.get(rpc as object)?.values() ?? [])]\n : [modelCatalogKey(rpc, sessionId)]\n for (const key of keys) {\n const cache = modelCatalogCaches.get(key)\n const times = modelCatalogCacheTimes.get(key)\n const loads = modelCatalogLoads.get(key)\n if (adapterId === undefined) loads?.clear()\n else loads?.delete(adapterId)\n if (adapterId === undefined) { cache?.clear(); times?.clear() }\n else { cache?.delete(adapterId); times?.delete(adapterId) }\n }\n}\n\n/**\n * 「判定可能过期」时的复检节流。\n *\n * 目录声明了服务档位却未确认官方订阅时,值得再探测一次;但真实第三方接入会\n * 长期停在这个状态,不能每次挂载都发一次请求。这里按适配器记录最近一次复检\n * 时间,只有超过间隔才允许再次作废缓存。\n */\nexport const MODEL_CATALOG_REVALIDATE_INTERVAL_MS = 60_000\n\nconst modelCatalogRevalidations = new WeakMap<object, Map<string, number>>()\n\nexport function shouldRevalidateModelCatalog(\n rpc: CodingNsRpcClient,\n adapterId: string,\n needsRevalidation: boolean,\n sessionId?: string,\n): boolean {\n if (!needsRevalidation) return false\n const key = modelCatalogKey(rpc, sessionId)\n let times = modelCatalogRevalidations.get(key)\n if (times === undefined) {\n times = new Map()\n modelCatalogRevalidations.set(key, times)\n }\n const last = times.get(adapterId)\n const now = Date.now()\n if (last !== undefined && now - last < MODEL_CATALOG_REVALIDATE_INTERVAL_MS) return false\n times.set(adapterId, now)\n return true\n}\n\nexport function getModelCatalogCache(rpc: CodingNsRpcClient, sessionId?: string): Map<string, CodingNsCliModelCatalog> {\n const key = modelCatalogKey(rpc, sessionId)\n let cache = modelCatalogCaches.get(key)\n if (cache === undefined) {\n cache = new Map()\n modelCatalogCaches.set(key, cache)\n }\n return cache\n}\n\nexport function loadModelCatalog(rpc: CodingNsRpcClient, adapterId: string, sessionId?: string): Promise<CodingNsCliModelCatalog> {\n const cached = getModelCatalogCache(rpc, sessionId).get(adapterId)\n const entry = cached === undefined ? undefined : cacheEntry(rpc, adapterId, sessionId)\n // A successful stale catalog stays visible while a fresh base and optional\n // Magpie enrichment load in the background.\n if (cached !== undefined && cached.fallback !== true && entry?.value === cached && isFreshCacheEntry(rpc, adapterId, cached, sessionId)) {\n return Promise.resolve(cached)\n }\n const loads = getModelCatalogLoadCache(rpc, sessionId)\n const running = loads.get(adapterId)\n if (running !== undefined) return cached !== undefined && cached.fallback !== true ? Promise.resolve(cached) : running\n\n const hasStaleCatalog = cached !== undefined && cached.fallback !== true && entry?.value === cached\n if (cached !== undefined && !hasStaleCatalog) invalidateModelCatalogCache(rpc, adapterId, sessionId)\n\n const request = callCliRpc<CodingNsCliModelCatalog>(rpc, 'models', {\n adapterId,\n stage: 'base',\n ...(sessionId === undefined ? {} : { sessionId }),\n }).then((value) => {\n // 手动重新检测已替换请求时,迟到结果不能复活被作废的目录。\n if (loads.get(adapterId) !== request) return loadModelCatalog(rpc, adapterId, sessionId)\n if (value.fallback === true) {\n if (hasStaleCatalog && cached !== undefined) storeCatalog(rpc, adapterId, cached, sessionId, 5_000)\n else invalidateModelCatalogCache(rpc, adapterId, sessionId)\n } else {\n storeCatalog(rpc, adapterId, value, sessionId)\n if (hasStaleCatalog) notifyModelCatalogChanged(rpc, adapterId)\n }\n return value\n })\n loads.set(adapterId, request)\n\n // The base result above is the only part awaited by the caller. Enrichment\n // is a second, shared Host request; its completed snapshot replaces the base\n // cache and wakes mounted selectors without a timer or blocking spinner.\n void request.then(async (base) => {\n if (base.fallback === true || base.magpiePending !== true || loads.get(adapterId) !== request) return\n try {\n const enriched = await callCliRpc<CodingNsCliModelCatalog>(rpc, 'models', {\n adapterId,\n stage: 'enriched',\n ...(sessionId === undefined ? {} : { sessionId }),\n })\n if (loads.get(adapterId) !== request || getModelCatalogCache(rpc, sessionId).get(adapterId) !== base || enriched.fallback === true) return\n storeCatalog(rpc, adapterId, enriched, sessionId)\n notifyModelCatalogChanged(rpc, adapterId)\n } catch {\n if (loads.get(adapterId) !== request || getModelCatalogCache(rpc, sessionId).get(adapterId) !== base) return\n const readyBase = withoutMagpiePending(base)\n storeCatalog(rpc, adapterId, readyBase, sessionId, 5_000)\n notifyModelCatalogChanged(rpc, adapterId)\n }\n }).catch(() => {\n if (loads.get(adapterId) !== request) return\n const current = getModelCatalogCache(rpc, sessionId).get(adapterId)\n if (current === undefined || current.fallback === true || cacheEntry(rpc, adapterId, sessionId)?.value !== current) return\n // Keep showing the last good snapshot and avoid immediately retrying a\n // failing Host after every render.\n storeCatalog(rpc, adapterId, current, sessionId, 5_000)\n }).finally(() => {\n if (loads.get(adapterId) === request) loads.delete(adapterId)\n })\n\n if (hasStaleCatalog) return Promise.resolve(cached)\n return request\n}\n\nfunction withoutMagpiePending(catalog: CodingNsCliModelCatalog): CodingNsCliModelCatalog {\n if (catalog.magpiePending !== true) return catalog\n const { magpiePending: _magpiePending, ...ready } = catalog\n return ready\n}\n\n/** 缓存条目是否仍在有效期内;没有时间戳的旧条目按过期处理并触发一次重新读取。 */\nfunction isFreshCacheEntry(rpc: CodingNsRpcClient, adapterId: string, cached: CodingNsCliModelCatalog, sessionId?: string): boolean {\n const entry = cacheEntry(rpc, adapterId, sessionId)\n if (entry === undefined || entry.value !== cached) return false\n return Date.now() - entry.storedAt < entry.ttlMs\n}\n\nfunction getModelCatalogLoadCache(rpc: CodingNsRpcClient, sessionId?: string): Map<string, Promise<CodingNsCliModelCatalog>> {\n const key = modelCatalogKey(rpc, sessionId)\n let cache = modelCatalogLoads.get(key)\n if (cache === undefined) {\n cache = new Map()\n modelCatalogLoads.set(key, cache)\n }\n return cache\n}\n","import { createElement, type ReactElement } from 'react'\nimport { providerIconUrl } from './provider-icons.js'\nimport { PROVIDER_ICON_PATH } from '../shared/provider-icon-resources.js'\n\nexport const MAGPIE_MODEL_TAG_ATTRIBUTE = 'data-codingns-magpie-model-tag'\n\n/**\n * Magpie 模型来源标签使用的喜鹊图标。\n *\n * 图标必须走本机 Host 的固定资源路由:此前指向 GitHub 上的 `icon-256.png`,\n * 而在离线、Host 无外网出口,或页面策略只允许 `img-src 'self'` 时该外链会被\n * 浏览器拦截,标签容器虽然渲染出来却不显示任何图像。本地路由随插件一起安装,\n * 无网络依赖,也不会被同源策略挡住。\n */\nexport function magpieModelLogoUrl(): string {\n return providerIconUrl('magpie') ?? `${PROVIDER_ICON_PATH}magpie.png`\n}\n\nconst tagStyle = {\n display: 'inline-flex',\n flex: 'none',\n alignItems: 'center',\n justifyContent: 'center',\n minWidth: '18px',\n maxWidth: '45%',\n gap: '4px',\n height: '18px',\n marginInlineStart: 'auto',\n whiteSpace: 'nowrap',\n verticalAlign: 'middle',\n} as const\n\nconst tagLogoStyle = {\n display: 'block',\n width: '16px',\n height: '16px',\n flex: '0 0 16px',\n objectFit: 'contain',\n borderRadius: '4px',\n} as const\n\nconst providerStyle = {\n minWidth: 0,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n fontSize: '12px',\n color: 'var(--dsw-alias-label-secondary)',\n} as const\n\n/** Compact visual source marker shared by every model-list surface. */\nexport function MagpieModelTag(props: { readonly providerId?: string | undefined }): ReactElement {\n return createElement('span', {\n [MAGPIE_MODEL_TAG_ATTRIBUTE]: '',\n role: 'note',\n 'aria-label': props.providerId ?? 'Provided by Magpie',\n title: props.providerId ?? 'Provided by Magpie',\n style: tagStyle,\n }, props.providerId === undefined ? null : createElement('span', { style: providerStyle }, props.providerId),\n createElement('img', { src: magpieModelLogoUrl(), alt: 'Provided by Magpie', style: tagLogoStyle }))\n}\n\n/** Native DSH owns its menu DOM, so its option rows receive the same badge imperatively. */\nexport function createMagpieModelTagNode(document: Document, modelId?: string, providerId?: string): HTMLSpanElement {\n const tag = document.createElement('span')\n tag.setAttribute(MAGPIE_MODEL_TAG_ATTRIBUTE, '')\n if (modelId !== undefined) tag.dataset.modelId = modelId\n if (providerId !== undefined) tag.dataset.providerId = providerId\n tag.setAttribute('role', 'note')\n tag.setAttribute('aria-label', providerId ?? 'Provided by Magpie')\n tag.title = providerId ?? 'Provided by Magpie'\n Object.assign(tag.style, tagStyle)\n\n if (providerId !== undefined) {\n const provider = document.createElement('span')\n provider.textContent = providerId\n Object.assign(provider.style, providerStyle)\n tag.append(provider)\n }\n const logo = document.createElement('img')\n logo.setAttribute('src', magpieModelLogoUrl())\n logo.setAttribute('alt', 'Provided by Magpie')\n Object.assign(logo.style, tagLogoStyle)\n tag.append(logo)\n return tag\n}\n"],"mappings":"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"}
@@ -9,13 +9,13 @@ window.__ModuleLoader__.load({
9
9
  //#region src/shared/contracts/version.ts
10
10
  /** DSH verification target, synchronized with the root version.json. */
11
11
  const DSH_VERSION = "0.2.1-rc.3";
12
+ /** DSH 测试版本别名,供新代码表达语义,保留 DSH_VERSION 兼容旧调用方。 */
13
+ const DSH_TESTED_VERSION = DSH_VERSION;
12
14
  /**
13
- * Supported hosts retain the 0.2.0-rc.2 floor and include 0.2.1-rc.2.
14
- * Capability adapters preserve earlier subagent, peer and message contracts.
15
- * Keep an explicit upper bound: a later prerelease requires verification before
16
- * either installation checks or runtime capability selection may accept it.
15
+ * Only the minimum version blocks installation and activation.
16
+ * Hosts newer than DSH_TESTED_VERSION receive an advisory warning.
17
17
  */
18
- const DSH_COMPATIBILITY = ">=0.2.0-rc.2 <=0.2.1-rc.3";
18
+ const DSH_COMPATIBILITY = ">=0.2.0-rc.2";
19
19
  /**
20
20
  * 兼容范围下界,即插件仍然接受的最低 DSH 版本。
21
21
  *
@@ -24,7 +24,7 @@ window.__ModuleLoader__.load({
24
24
  * “不支持的 DSH 版本”,把仅仅缺少启动页注入的页面误判为宿主不兼容。
25
25
  */
26
26
  function minimumSupportedDshVersion() {
27
- return /^>=([^ ]+)/u.exec(">=0.2.0-rc.2 <=0.2.1-rc.3")?.[1] ?? "0.2.1-rc.3";
27
+ return /^>=([^ ]+)/u.exec(">=0.2.0-rc.2")?.[1] ?? "0.2.1-rc.3";
28
28
  }
29
29
  /** Host 注入到浏览器页面的真实 DSH 版本全局字段。 */
30
30
  const CODINGNS_DSH_VERSION_GLOBAL = "__CODINGNS_DSH_VERSION__";
@@ -33,17 +33,16 @@ window.__ModuleLoader__.load({
33
33
  return /^0\.1\.5(?:-|$)/u.test(version);
34
34
  }
35
35
  /** Codingns4DSH 插件自身的 npm 版本。 */
36
- const CODINGNS_VERSION = "0.2.1-rc.5";
37
- /** 判断宿主版本是否落在当前插件声明的 DSH 兼容范围内;范围省略上界时不校验上限。 */
36
+ const CODINGNS_VERSION = "0.2.1-rc.6";
37
+ /** Accept any valid host version at or above the supported minimum. */
38
38
  function isDshVersionCompatible(version) {
39
- const match = /^>=([^ ]+)(?: <=([^ ]+))?$/u.exec(DSH_COMPATIBILITY);
39
+ return isDshVersionAtLeast(version, minimumSupportedDshVersion());
40
+ }
41
+ /** Newer hosts stay enabled; this predicate controls advisory notices only. */
42
+ function isDshVersionNewerThanTested(version) {
40
43
  const actual = parseVersion(version);
41
- const minimum = parseVersion(match?.[1] ?? "");
42
- if (match === null || !actual || !minimum) return version === DSH_VERSION;
43
- if (match[2] === void 0) return compareVersions(actual, minimum) >= 0;
44
- const maximum = parseVersion(match[2]);
45
- if (maximum === void 0) return version === DSH_VERSION;
46
- return compareVersions(actual, minimum) >= 0 && compareVersions(actual, maximum) <= 0;
44
+ const tested = parseVersion(DSH_TESTED_VERSION);
45
+ return actual !== void 0 && tested !== void 0 && compareVersions(actual, tested) > 0;
47
46
  }
48
47
  /** 判断 DSH 版本是否达到某个功能模块要求的最低版本。 */
49
48
  function isDshVersionAtLeast(version, minimum) {
@@ -681,6 +680,12 @@ window.__ModuleLoader__.load({
681
680
  return DSH_COMPATIBILITY;
682
681
  }
683
682
  });
683
+ Object.defineProperty(exports, "DSH_TESTED_VERSION", {
684
+ enumerable: true,
685
+ get: function() {
686
+ return DSH_TESTED_VERSION;
687
+ }
688
+ });
684
689
  Object.defineProperty(exports, "DSH_VERSION", {
685
690
  enumerable: true,
686
691
  get: function() {
@@ -747,6 +752,12 @@ window.__ModuleLoader__.load({
747
752
  return isDshVersionCompatible;
748
753
  }
749
754
  });
755
+ Object.defineProperty(exports, "isDshVersionNewerThanTested", {
756
+ enumerable: true,
757
+ get: function() {
758
+ return isDshVersionNewerThanTested;
759
+ }
760
+ });
750
761
  Object.defineProperty(exports, "isFeatureDshVersionCompatible", {
751
762
  enumerable: true,
752
763
  get: function() {