dsh-multi-router 0.5.6 → 0.5.8
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 +13 -0
- package/README.md +10 -4
- package/cordis.patch.yml +2 -2
- package/lib/{chunk-XKDXPB5T.js → chunk-ILRW3ELD.js} +28 -11
- package/lib/chunk-ILRW3ELD.js.map +7 -0
- package/lib/{chunk-CT6ZYIAF.js → chunk-P43AWJ4Q.js} +9 -5
- package/lib/chunk-P43AWJ4Q.js.map +7 -0
- package/lib/client.js +93 -37
- package/lib/client.js.map +3 -3
- package/lib/host-v0.5.8.js +514 -0
- package/lib/host.js +154 -24
- package/lib/index.js +154 -24
- package/lib/index.js.map +4 -4
- package/lib/manager.js +1 -1
- package/lib/shim.js +1 -1
- package/package.json +1 -1
- package/lib/chunk-CT6ZYIAF.js.map +0 -7
- package/lib/chunk-XKDXPB5T.js.map +0 -7
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/manager.mjs", "../package.json", "../upstream/qoder/src/status-paths.ts", "../upstream/qoder/src/variants.ts", "../upstream/qoder/src/auth.ts", "../src/migration.mjs", "../src/plugin-updates.mjs", "../upstream/workbuddy/src/update.ts", "../src/workbuddy-login.mjs"],
|
|
4
|
+
"sourcesContent": ["import { createHash, randomBytes, timingSafeEqual } from 'node:crypto';\nimport { version as pluginVersion } from '../package.json';\nimport { readFile, mkdir, mkdtemp, rm } from 'node:fs/promises';\nimport { watch } from 'node:fs';\nimport { dirname, join, relative, resolve } from 'node:path';\nimport { withFileLock } from '@deepseek-ai/dsh-atomic-write';\nimport { PROVIDERS, PROVIDER_NAMES, ROUTE_PRESETS, validateConfig, writePrivateJson, isFreeModel, beijingDay } from './config.mjs';\nimport { modelWithCurrentPromotion } from '../upstream/workbuddy/src/upstream.ts';\nimport { importAccount, readPortableCredential, discoverLocalAccounts, localAccountKey } from './accounts.mjs';\nimport { hostIsLoopback } from '../upstream/workbuddy/src/loopback.ts';\nimport { Telemetry } from './telemetry.mjs';\nimport { jsonCredential } from './clients.mjs';\nimport { QODER_VARIANTS } from '../upstream/qoder/src/variants.ts';\nimport { qoderOwnAuthPath } from '../upstream/qoder/src/auth.ts';\nimport { matchModel } from './router.mjs';\nimport { routeReasoning, reasoningModes } from './reasoning.mjs';\nimport { exportConfiguration, decodeConfiguration, migrationSummary, prepareMigration } from './migration.mjs';\nimport { PluginUpdates } from './plugin-updates.mjs';\nimport { Checkins, supportsCheckin } from './checkins.mjs';\nimport { WorkBuddyLogin } from './workbuddy-login.mjs';\n\nexport const MANAGEMENT_PATH = '/.well-known/dsh-multi-router';\nconst revisionOf = raw => createHash('sha256').update(JSON.stringify(raw)).digest('hex');\nexport class ManagementError extends Error {\n constructor(status, message) { super(message); this.status = status; }\n}\nconst bad = message => { throw new ManagementError(400, message); };\nconst finite = (value, fallback) => Number.isSafeInteger(value) && value > 0 ? value : fallback;\nexport function modelInfo(row) {\n const billing = row.billing ? { free: row.billing.free === true, rateUnknown: row.billing.rateUnknown === true,\n ...(typeof row.billing.credits === 'string' ? { credits: row.billing.credits } : {}) } : undefined;\n const reasoning = row.reasoning?.supported ? { supports: true, supportedEfforts: row.reasoning.supported,\n defaultEffort: row.reasoning.defaultEffort, canDisableThinking: row.reasoning.supported.includes('off') } : row.reasoning;\n return { id: row.id, name: row.name || row.id, contextWindow: finite(row.contextWindow, 200000),\n maxTokens: Math.min(finite(row.maxTokens, 32000), finite(row.contextWindow, 200000)),\n supportsImages: row.supportsImages === true || row.multimodal === true || row.input?.includes('image') === true,\n ...(reasoning ? { reasoning } : {}), ...(billing ? { billing } : {}),\n ...(typeof row.creditMultiplier === 'number' && Number.isFinite(row.creditMultiplier) && row.creditMultiplier >= 0 ? { creditMultiplier: row.creditMultiplier } : {}),\n ...(Array.isArray(row.promotions) ? { promotions: row.promotions.map(p => ({ start: p.start, end: p.end, factor: p.factor, priority: p.priority, label: typeof p.label === 'string' ? p.label : '' })) } : {}) };\n}\n\nexport class Manager {\n constructor(file, router, onChange = () => {}, pluginAccess = {}) {\n this.file = file; this.router = router; this.onChange = onChange;\n this.catalogFile = join(dirname(file), 'catalogs.json');\n this.catalogs = new Map(); this.catalogErrors = new Map(); this.refreshes = new Map();\n this.closed = false; this.monitorFlights = new Map(); this.loginInfo = new Map();\n this.telemetry = new Telemetry(join(dirname(file), 'usage.json'));\n this.plugins = new PluginUpdates({ ...pluginAccess, stateFile: join(dirname(file), 'plugin-updates.json'), onInstalled: name => {\n if (name !== 'dsh-multi-router' || !this.runtime?.canReload()) return false;\n this.runtime.schedule(); return true;\n } });\n this.checkins = new Checkins(join(dirname(file), 'checkins.json'), this);\n this.workbuddyLogin = new WorkBuddyLogin(join(dirname(file), 'workbuddy-login.json'), { fetchImpl: pluginAccess.fetchImpl });\n this.setupFile = join(dirname(file), 'initial-setup.json');\n router.telemetry = this.telemetry; router.monitor = a => this.monitorAccount(a);\n router.prepareFree = () => this.checkFreeModels(true);\n router.freeModels = account => this.freeModels(account);\n\n }\n async load() {\n this.raw = JSON.parse(await readFile(this.file, 'utf8'));\n try { this.setup = JSON.parse(await readFile(this.setupFile, 'utf8')); } catch { this.setup = undefined; }\n this.config = validateConfig(this.raw, this.file);\n await this.checkins.load();\n await this.plugins.load();\n try {\n const saved = JSON.parse(await readFile(this.catalogFile, 'utf8'));\n for (const account of this.config.accounts) {\n const item = saved[account.id];\n if (item?.credentialFile === account.credentialFile && Array.isArray(item.models)) {\n this.catalogs.set(account.id, { ...item, models: item.models.filter(m => typeof m.id === 'string' && m.id.length > 0).map(modelInfo) });\n }\n }\n } catch { /* No saved directory yet; never invent a provider's model roster. */ }\n this.telemetry.configure(this.config.usageRetentionDays);\n await this.telemetry.load();\n await Promise.all(this.config.accounts.map(a => this.readLogin(a)));\n this.publish();\n }\n async readLogin(account) {\n try {\n const raw = await jsonCredential(account.credentialFile), c = raw.credential;\n this.loginInfo.set(account.id, account.provider.startsWith('qoder')\n ? { state: raw.pat ? 'configured' : 'missing', kind: 'PAT', refreshable: false }\n : { state: !c?.accessToken ? 'missing' : c?.expiresAtMs > Date.now() ? 'valid' : c?.refreshToken ? 'refresh-needed' : 'expired', name: c?.nickname || c?.accountName || c?.uid || c?.userId,\n identity: c?.uid || c?.userId, expiresAt: c?.expiresAtMs, refreshExpiresAt: c?.refreshExpiresAtMs, refreshable: !!c?.refreshToken, kind: '\u5BA2\u6237\u7AEF\u767B\u5F55\u6001', edition: c?.edition });\n } catch { this.loginInfo.set(account.id, { state: 'missing' }); }\n }\n async syncLocalAccounts(provider, force = false) {\n if (this.localScan) return this.localScan;\n this.localScan = (async () => {\n const discovered = await discoverLocalAccounts(provider);\n this.localDiscovery = [...(this.localDiscovery ?? []).filter(s => !discovered.status.some(n => n.provider === s.provider)),\n ...discovered.status.map(s => ({ ...s, checkedAt: Date.now() }))];\n if (this.closed || !discovered.accounts.length) return;\n await withFileLock(this.file, async () => {\n if (this.closed) return;\n let raw = JSON.parse(await readFile(this.file, 'utf8'));\n let changed = false;\n const saved = new Map();\n for (const item of discovered.accounts) {\n const key = localAccountKey(item.provider, item.document);\n if (!force && raw.ignoredLocalAccounts?.includes(key)) continue;\n const config = validateConfig(raw, this.file);\n let existing, current;\n for (const a of config.accounts.filter(a => a.provider === item.provider)) {\n try { const value = await jsonCredential(a.credentialFile);\n if (localAccountKey(a.provider, value) === key) { existing = a; current = value; break; }\n } catch { /* Keep unreadable saved accounts; do not replace a different identity. */ }\n }\n const id = existing?.id ?? `local_${createHash('sha256').update(key).digest('hex').slice(0, 20)}`;\n const recordSaved = () => { if (!saved.has(item.provider)) saved.set(item.provider, new Set()); saved.get(item.provider).add(id); };\n let sameDevice = true;\n if (existing && item.identityDocument) {\n try { const identity = await jsonCredential(existing.identityFile);\n sameDevice = identity.machineId === item.identityDocument.machineId && identity.deviceId === item.identityDocument.deviceId;\n } catch { sameDevice = false; }\n }\n if (existing && sameDevice && current.credential.expiresAtMs >= item.document.credential.expiresAtMs) { recordSaved(); continue; }\n const base = join(dirname(this.file), 'accounts'); await mkdir(base, { recursive: true, mode: 0o700 });\n const staging = await mkdtemp(join(base, `${id}-`));\n try {\n const credentialFile = join(staging, 'credential.json'), identityFile = join(staging, 'identity.json');\n await importAccount({ ...item, credentialFile, identityFile });\n const paths = { credentialFile: relative(dirname(this.file), credentialFile),\n ...(item.provider.startsWith('trae') ? { identityFile: relative(dirname(this.file), identityFile) } : {}) };\n const next = structuredClone(raw);\n if (existing) Object.assign(next.accounts.find(a => a.id === id), paths);\n else next.accounts.push({ id, provider: item.provider,\n name: item.document.credential.nickname || item.document.credential.accountName || item.document.credential.uid || item.document.credential.userId, ...paths });\n next.ignoredLocalAccounts = (raw.ignoredLocalAccounts ?? []).filter(k => k !== key);\n validateConfig(next, this.file);\n await writePrivateJson(this.file, next); raw = next; changed = true;\n recordSaved();\n this.router.clients.delete(id); this.catalogs.delete(id); this.catalogErrors.delete(id);\n } catch (e) { await rm(staging, { recursive: true, force: true });\n this.localDiscovery = this.localDiscovery.map(s => s.provider === item.provider ? { ...s, state: 'unreadable', code: 'import_failed' } : s); }\n }\n if (changed) { this.raw = raw; this.config = validateConfig(raw, this.file);\n await Promise.all(this.config.accounts.map(a => this.readLogin(a))); this.publish(); }\n this.localDiscovery = this.localDiscovery.map(s => discovered.status.some(d => d.provider === s.provider) ? { ...s, savedCount: saved.get(s.provider)?.size ?? 0 } : s);\n }, { waitMs: 30000 });\n })().finally(() => { this.localScan = undefined; });\n return this.localScan;\n }\n async finishInitialSetup() {\n if (this.setup?.completedAt) return;\n await withFileLock(this.setupFile, async () => {\n try { this.setup = JSON.parse(await readFile(this.setupFile, 'utf8')); } catch { /* First installation. */ }\n if (this.setup?.completedAt) return;\n this.setup = { completedAt: Date.now(), dismissed: false };\n await writePrivateJson(this.setupFile, this.setup);\n });\n }\n async monitorAccount(account) {\n if (this.monitorFlights.has(account.id)) return this.monitorFlights.get(account.id);\n const promise = (async () => {\n try {\n const client = await this.router.client(account);\n if (!client.accountInfo) return;\n const snapshot = await client.accountInfo(AbortSignal.timeout(30000));\n if (this.closed || !this.config.accounts.some(a => a.id === account.id && a.credentialFile === account.credentialFile)) return;\n this.loginInfo.set(account.id, snapshot.login);\n await this.telemetry.observe(account.id, snapshot);\n } catch (e) {\n if (this.closed) return;\n const old = this.telemetry.row('accounts', account.id).balance;\n await this.telemetry.observe(account.id, { ...old, error: { code: 'usage_fetch_failed', status: Number(e.status ?? e.failure?.status) || 502 }, attemptedAt: Date.now() });\n await this.readLogin(account);\n }\n })().finally(() => this.monitorFlights.delete(account.id));\n this.monitorFlights.set(account.id, promise); return promise;\n }\n async monitorAll(provider) { await Promise.all(this.config.accounts.filter(a => !provider || a.provider === provider).map(a => this.monitorAccount(a))); }\n freeAccounts() {\n const targets = Object.values(this.config.routes).filter(r => r.freeOnly).flatMap(r => r.targets);\n return this.config.accounts.filter(a => a.enabled !== false && targets.some(t => t.provider === a.provider && (!t.account || t.account === a.id)));\n }\n freeModels(account) {\n const saved = this.catalogs.get(account.id);\n if (this.catalogErrors.has(account.id) || !saved || beijingDay(saved.fetchedAt) !== beijingDay(Date.now())) return [];\n return saved.models.map(m => modelWithCurrentPromotion(m)).filter(m => isFreeModel(m));\n }\n async checkFreeModels(force = false) {\n await Promise.all(this.freeAccounts().filter(a => {\n const saved = this.catalogs.get(a.id);\n if (force) return true;\n if (Date.now() - (this.catalogErrors.get(a.id)?.at ?? 0) < 300000) return false;\n return !saved || beijingDay(saved.fetchedAt) !== beijingDay(Date.now()) || saved.pricingVersion !== 1;\n }).map(a => this.refreshAccount(a, 'pricing')));\n }\n freeStatus(row) {\n const accounts = this.config.accounts.filter(a => a.enabled !== false && row.targets.some(t => t.provider === a.provider && (!t.account || t.account === a.id)));\n return { checking: accounts.some(a => this.refreshes.has(a.id)),\n accounts: accounts.map(a => ({ id: a.id, provider: a.provider, name: a.name ?? a.id, checkedAt: this.catalogs.get(a.id)?.fetchedAt,\n error: this.catalogErrors.get(a.id), models: this.freeModels(a).map(m => ({ id: m.id, name: m.name })) })) };\n }\n freeRoutes(parentId, row) {\n const groups = new Map();\n for (const account of this.config.accounts.filter(a => a.enabled !== false)) {\n for (const model of this.freeModels(account)) {\n if (!row.targets.some(t => t.provider === account.provider && (!t.account || t.account === account.id)\n && (!t.model || t.model === model.id) && (!t.models || t.models.includes(model.id)))) continue;\n // Exact provider/model identity: equal display names never merge different versions.\n const id = `free_${createHash('sha256').update(JSON.stringify([parentId, account.provider, model.id])).digest('hex').slice(0, 24)}`;\n if (!groups.has(id)) groups.set(id, { id, models: [], targets: [], accountNames: [], modelName: model.name, provider: account.provider, modelId: model.id });\n const group = groups.get(id);\n group.models.push({ model, provider: account.provider });\n group.targets.push({ provider: account.provider, account: account.id, model: model.id });\n group.accountNames.push(account.name ?? account.id);\n }\n }\n return [...groups.values()].map(({ models, ...group }) => {\n const preference = row.freeModels?.[group.id] ?? {}, reasoning = routeReasoning(models);\n const selected = preference.reasoningEffort;\n return { ...group, parentId, dynamicFree: true, freeOnly: true, strategy: 'failover', preferExpiringCredits: false,\n name: `Free \u00B7 ${group.modelName} \u00B7 ${PROVIDER_NAMES[group.provider]}`, reasoning,\n ...(selected && reasoning?.supportedEfforts.includes(selected) ? { reasoningEffort: selected } : {}),\n configuredEffort: selected ?? null, effortUnavailable: !!selected && !reasoning?.supportedEfforts.includes(selected),\n visible: row.visible !== false && preference.visible !== false, selected: preference.visible !== false,\n supportsImages: models.every(({ model }) => model.supportsImages),\n contextWindow: Math.min(row.contextWindow, ...models.map(({ model }) => model.contextWindow)),\n maxTokens: Math.min(row.maxTokens, ...models.map(({ model }) => model.maxTokens), ...models.map(({ model }) => model.contextWindow)) };\n });\n }\n adapterModels() {\n const rows = this.routeModels();\n return [...rows.filter(r => r.freeOnly).flatMap(r => this.freeRoutes(r.id, r)),\n ...rows.filter(r => !r.freeOnly), ...rows.filter(r => r.freeOnly).map(r => ({ ...r, visible: false }))];\n }\n publish() {\n this.telemetry.configure(this.config.usageRetentionDays);\n this.revision = revisionOf(this.raw);\n const routes = { ...this.config.routes };\n for (const model of this.adapterModels().filter(m => m.dynamicFree)) routes[model.id] = model;\n for (const provider of PROVIDERS) for (const model of this.providerModels(provider)) {\n routes[`${provider}::${model.id}`] = { ...model, targets: [{ provider, model: model.id }] };\n }\n this.router.updateConfig({ ...this.config, routes });\n this.onChange();\n }\n providerModels(provider) {\n const rows = new Map();\n for (const account of this.config.accounts.filter(a => a.provider === provider && a.enabled !== false)) {\n for (const model of this.catalogs.get(account.id)?.models ?? []) {\n const old = rows.get(model.id);\n // Advertise budgets every candidate account can honour.\n rows.set(model.id, old ? { ...old, contextWindow: Math.min(old.contextWindow, model.contextWindow),\n maxTokens: Math.min(old.maxTokens, model.maxTokens), supportsImages: old.supportsImages && model.supportsImages,\n reasoning: routeReasoning([{ model: old, provider }, { model, provider }]) } : { ...model,\n ...(reasoningModes(model, provider).length ? { reasoning: routeReasoning([{ model, provider }]) } : {}) });\n }\n }\n return [...rows.values()].map(model => ({ ...model,\n name: this.config.models[provider]?.[model.id]?.name ?? model.name }));\n }\n hiddenModels(provider) {\n return this.providerModels(provider).filter(m => !this.modelVisible(provider, m.id)).map(m => m.id);\n }\n modelVisible(provider, id) { return this.config.models[provider]?.[id]?.visible ?? this.config.modelVisibility[provider] ?? false; }\n routeModels() {\n return Object.entries(this.config.routes).sort(([, a], [, b]) => Number(!!b.freeOnly) - Number(!!a.freeOnly)).map(([id, row]) => {\n const effectiveTargets = row.freeOnly ? this.freeRoutes(id, row).flatMap(r => r.targets) : row.targets;\n const sources = effectiveTargets.flatMap(target => this.config.accounts.filter(a => a.enabled !== false && a.provider === target.provider\n && (!target.account || target.account === a.id)).flatMap(a => {\n const catalog = this.catalogs.get(a.id)?.models ?? [];\n const models = target.models ? target.models.map(model => catalog.find(m => m.id === model)).filter(Boolean)\n : [matchModel(id, target, catalog)].filter(Boolean);\n return models.map(model => ({ model, provider: a.provider }));\n }));\n const models = sources.map(s => s.model), reasoning = routeReasoning(sources);\n return { ...row, supportsImages: models.length > 0 && models.every(m => m.supportsImages), reasoning,\n ...(row.freeOnly && models.length ? { contextWindow: Math.min(row.contextWindow, ...models.map(m => m.contextWindow)), maxTokens: Math.min(row.maxTokens, ...models.map(m => m.maxTokens), ...models.map(m => m.contextWindow)) } : {}),\n id, name: row.name ?? id, expiringStatus: { ...this.telemetry.data.expiringRounds[id] },\n ...(row.freeOnly ? { freeStatus: { ...this.freeStatus(row), modelRoutes: this.freeRoutes(id, row) } } : {}) };\n });\n }\n async ensureCatalog(provider, force = false) {\n await Promise.all(this.config.accounts.filter(a => a.provider === provider && a.enabled !== false).map(a => this.refreshAccount(a, force)));\n }\n async refreshAccount(account, force) {\n const saved = this.catalogs.get(account.id);\n if (!force && saved && Date.now() - saved.fetchedAt < this.config.catalogTtlMs) return;\n if (!force && Date.now() - (this.catalogErrors.get(account.id)?.at ?? 0) < 10000) return;\n if (this.refreshes.has(account.id)) return this.refreshes.get(account.id);\n const promise = (async () => {\n try {\n if (force === true) this.router.clients.delete(account.id);\n const client = await this.router.client(account);\n const models = (await client.models(AbortSignal.timeout(60000), !!force)).map(modelInfo);\n // A late response may not resurrect an account removed while discovery was running.\n if (this.closed || !this.config.accounts.some(a => a.id === account.id && a.credentialFile === account.credentialFile)) return;\n this.catalogs.set(account.id, { credentialFile: account.credentialFile, fetchedAt: Date.now(), pricingVersion: 1, models });\n this.catalogErrors.delete(account.id);\n await withFileLock(this.catalogFile, () => writePrivateJson(this.catalogFile, Object.fromEntries(this.catalogs)));\n } catch (error) {\n if (this.closed || !this.config.accounts.some(a => a.id === account.id)) return;\n this.catalogErrors.set(account.id, { status: Number(error.status ?? error.failure?.status) || 502, code: 'catalog_fetch_failed', at: Date.now() });\n }\n if (!this.closed) this.publish();\n })().finally(() => this.refreshes.delete(account.id));\n this.refreshes.set(account.id, promise);\n return promise;\n }\n state() {\n const status = this.router.status();\n return { pluginVersion, startup: this.startup, runtime: this.runtime?.state(), revision: this.revision, localDiscovery: this.localDiscovery ?? [], setup: this.setup,\n pluginUpdates: this.plugins.state(),\n checkins: this.checkins.state(),\n telemetry: this.telemetry.state(),\n accounts: this.config.accounts.map(a => ({ id: a.id, provider: a.provider, name: a.name ?? a.id,\n enabled: a.enabled !== false, status: status.find(s => s.id === a.id),\n login: this.loginInfo.get(a.id), usage: this.telemetry.row('accounts', a.id),\n modelCount: this.catalogs.get(a.id)?.models.length ?? 0,\n fetchedAt: this.catalogs.get(a.id)?.fetchedAt, error: this.catalogErrors.get(a.id) })),\n providers: PROVIDERS.map(id => ({ id, name: PROVIDER_NAMES[id], models: this.providerModels(id).map(m => ({ ...m,\n visible: this.modelVisible(id, m.id) })) })),\n presets: Object.entries(ROUTE_PRESETS).map(([id, route]) => ({ id, ...structuredClone(route), added: Object.hasOwn(this.config.routes, id),\n availableProviders: [...new Set(route.targets.filter(t => route.freeOnly\n ? this.config.accounts.some(a => a.enabled !== false && a.provider === t.provider && this.freeModels(a).length)\n : matchModel(id, t, this.providerModels(t.provider))).map(t => t.provider))] })),\n routes: this.routeModels(), options: { cooldownMs: this.config.cooldownMs, requestTimeoutMs: this.config.requestTimeoutMs,\n retryServerErrors: this.config.retryServerErrors, usageRetentionDays: this.config.usageRetentionDays } };\n }\n async action(input) {\n if (!input || typeof input !== 'object' || Array.isArray(input)) bad('\u8BF7\u6C42\u683C\u5F0F\u65E0\u6548');\n if (input.action === 'plugin.reload') { if (!this.runtime) bad('\u5F53\u524D\u540E\u53F0\u4E0D\u652F\u6301\u91CD\u65B0\u52A0\u8F7D'); this.runtime.retryAt = 0; this.runtime.schedule(0); return this.state(); }\n if (input.action === 'workbuddy.sms') {\n try { const workbuddyLogin = await this.workbuddyLogin.send(input.phone); return { ...this.state(), workbuddyLogin }; } catch (e) { bad(e.message); }\n }\n if (input.action === 'workbuddy.login') {\n if (input.revision !== revisionOf(JSON.parse(await readFile(this.file, 'utf8')))) throw new ManagementError(409, '\u914D\u7F6E\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u65B0\u63D0\u4EA4\u767B\u5F55');\n let login; try { login = await this.workbuddyLogin.complete(input.challenge, input.code, input.verify ?? true); } catch (e) { bad(e.message); }\n let existing;\n for (const a of this.config.accounts.filter(a => a.provider === 'workbuddy')) {\n try { if ((await jsonCredential(a.credentialFile)).credential.uid === login.document.credential.uid) { existing = a; break; } } catch { /* Preserve unreadable accounts. */ }\n }\n if (input.id && input.id !== existing?.id) bad('\u767B\u5F55\u8EAB\u4EFD\u4E0E\u6B63\u5728\u7F16\u8F91\u7684\u8D26\u53F7\u4E0D\u540C\uFF0C\u8BF7\u4ECE\u6DFB\u52A0\u8D26\u53F7\u5165\u53E3\u4FDD\u5B58');\n const state = await this.action({ action: existing ? 'account.credentials' : 'account.add', revision: input.revision,\n id: existing?.id ?? `workbuddy_${randomBytes(8).toString('hex')}`, provider: 'workbuddy', name: input.name, document: login.document });\n this.workbuddyLogin.finish();\n return { ...state, loginResult: { warning: login.warning, saved: true } };\n }\n if (input.action === 'checkins.verify') {\n const account = this.config.accounts.find(a => a.id === input.id && a.provider === 'workbuddy');\n if (!account) bad('\u8BF7\u9009\u62E9 WorkBuddy \u4E2D\u56FD\u7248\u8D26\u53F7');\n if (this.checkins.flight || this.checkins.failed) bad('\u8BF7\u7B49\u5F85\u7B7E\u5230\u5B8C\u6210\uFF0C\u6216\u5148\u4FEE\u590D\u7B7E\u5230\u8BB0\u5F55');\n try { await this.workbuddyLogin.reserve('verifyAt', 30000); } catch (e) { bad(e.message); }\n try {\n const client = await this.router.client(account);\n await client.checkin.validate(AbortSignal.timeout(30000));\n await this.checkins.credentialsUpdated(account.id);\n await this.readLogin(account);\n } catch { bad('\u767B\u5F55\u9A8C\u8BC1\u672A\u901A\u8FC7\uFF1A\u8BF7\u5728\u8D26\u53F7\u4E0E\u767B\u5F55\u4E2D\u66F4\u65B0\u51ED\u8BC1\uFF1B\u4E0D\u4F1A\u81EA\u52A8\u91CD\u8BD5\u6216\u9886\u53D6'); }\n return this.state();\n }\n if (input.action === 'checkins.run') {\n try { this.checkins.start(input.ids); } catch (e) { bad(e.message); }\n return this.state();\n }\n if (input.action === 'checkins.resume') {\n try { await this.checkins.resume(input.provider); } catch (e) { bad(e.message); }\n return this.state();\n }\n if (typeof input.action === 'string' && input.action.startsWith('plugins.')) {\n try { await this.plugins.action(input); } catch (e) { bad(e.message); }\n return this.state();\n }\n if (input.action === 'setup.dismiss') {\n await withFileLock(this.setupFile, async () => {\n this.setup = { ...this.setup, completedAt: this.setup?.completedAt ?? Date.now(), dismissed: true };\n await writePrivateJson(this.setupFile, this.setup);\n });\n return this.state();\n }\n if (input.action === 'account.export') {\n if (input.revision !== revisionOf(JSON.parse(await readFile(this.file, 'utf8')))) throw new ManagementError(409, '\u914D\u7F6E\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u5237\u65B0\u540E\u63D0\u53D6\u51ED\u8BC1');\n const account = this.config.accounts.find(a => a.id === input.id);\n if (!account) bad('\u8D26\u53F7\u4E0D\u5B58\u5728');\n let credential;\n try { credential = await readPortableCredential(account); } catch { bad('\u8D26\u53F7\u51ED\u8BC1\u4E0D\u53EF\u8BFB\uFF0C\u8BF7\u8865\u5145\u6216\u66F4\u65B0\u540E\u518D\u63D0\u53D6'); }\n if (!credential) bad('\u8D26\u53F7\u5C1A\u672A\u4FDD\u5B58\u51ED\u8BC1\uFF0C\u8BF7\u5148\u8865\u5145\u767B\u5F55\u4FE1\u606F');\n return { ...this.state(), exported: { filename: `dsh-account-${account.provider}-${account.id}.json`,\n document: { ...credential.document, ...(credential.identity ? { identity: credential.identity } : {}),\n format: 'dsh-multi-router-account', provider: account.provider, name: account.name || account.id } } };\n }\n if (input.action === 'config.export') {\n if (input.revision !== revisionOf(JSON.parse(await readFile(this.file, 'utf8')))) throw new ManagementError(409, '\u914D\u7F6E\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u5237\u65B0\u540E\u5BFC\u51FA');\n try { return { ...this.state(), exported: { filename: `dsh-multi-router-${input.includeCredentials ? 'encrypted' : 'settings'}-${new Date().toISOString().slice(0, 10)}.json`, document: await exportConfiguration(this, input) } }; }\n catch (e) { bad(e.message); }\n }\n if (input.action === 'config.preview') {\n try { const portable = await decodeConfiguration(input); return { ...this.state(), importPreview: migrationSummary(this, portable, input.mode) }; }\n catch (e) { bad(e.message); }\n }\n if (input.action === 'monitor.refresh' || input.action === 'account.refresh') {\n if (input.provider && !PROVIDERS.includes(input.provider)) bad('\u672A\u77E5\u4F9B\u5E94\u5546');\n if (input.action === 'account.refresh') { const account = this.config.accounts.find(a => a.id === input.id); if (!account) bad('\u8D26\u53F7\u4E0D\u5B58\u5728'); this.router.clients.delete(account.id); await this.monitorAccount(account); }\n else { await this.syncLocalAccounts(input.provider); await this.monitorAll(input.provider); }\n return this.state();\n }\n if (input.action === 'accounts.discover') {\n if (input.provider && !PROVIDERS.includes(input.provider)) bad('\u672A\u77E5\u4F9B\u5E94\u5546');\n await this.syncLocalAccounts(input.provider, true);\n await Promise.all([this.monitorAll(input.provider), ...this.config.accounts.filter(a => !input.provider || a.provider === input.provider).map(a => this.refreshAccount(a, true))]);\n return this.state();\n }\n if (input.action === 'account.capture') {\n if (!PROVIDERS.includes(input.provider)) bad('\u672A\u77E5\u4F9B\u5E94\u5546');\n input = { ...input, action: 'account.add', id: `${input.provider.replace('-', '_')}_${randomBytes(4).toString('hex')}`, capture: true };\n }\n if (input.action === 'refresh') {\n if (input.provider && !PROVIDERS.includes(input.provider)) bad('\u672A\u77E5\u4F9B\u5E94\u5546');\n await Promise.all((input.provider ? [input.provider] : PROVIDERS).map(p => this.ensureCatalog(p, true)));\n return this.state();\n }\n if (input.action === 'free.refresh') { await this.checkFreeModels(true); return this.state(); }\n return withFileLock(this.file, async () => {\n let raw = JSON.parse(await readFile(this.file, 'utf8'));\n if (input.revision !== revisionOf(raw)) throw new ManagementError(409, '\u914D\u7F6E\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u5237\u65B0\u540E\u518D\u4FDD\u5B58');\n raw.routes ??= structuredClone(this.config.routes);\n let staging;\n try {\n const account = raw.accounts.find(a => a.id === input.id);\n if (input.action === 'config.import') {\n try {\n const prepared = await prepareMigration(this, raw, await decodeConfiguration(input), input.mode);\n staging = prepared.staging;\n await writePrivateJson(`${this.file}.before-import-${Date.now()}-${randomBytes(3).toString('hex')}.bak`, raw);\n raw = prepared.raw;\n } catch (e) { bad(e.message); }\n } else if (input.action === 'account.add' || input.action === 'account.credentials') {\n const replacing = input.action === 'account.credentials';\n if (replacing) { if (!account) bad('\u8D26\u53F7\u4E0D\u5B58\u5728'); input = { ...input, provider: account.provider }; }\n if (!/^[a-zA-Z0-9_-]{1,64}$/.test(input.id ?? '') || !PROVIDERS.includes(input.provider)) bad('\u8D26\u53F7 ID \u6216\u4F9B\u5E94\u5546\u65E0\u6548');\n if (account && !replacing) bad('\u8D26\u53F7 ID \u5DF2\u5B58\u5728\uFF0C\u8BF7\u4F7F\u7528\u4E0D\u540C ID');\n const base = join(dirname(this.file), 'accounts'); await mkdir(base, { recursive: true, mode: 0o700 });\n staging = await mkdtemp(join(base, `${input.id}-`));\n const credentialFile = join(staging, 'credential.json'), identityFile = join(staging, 'identity.json');\n const added = { id: input.id, name: input.name || account?.name || input.id, provider: input.provider,\n credentialFile: relative(dirname(this.file), credentialFile),\n ...(input.provider.startsWith('trae') ? { identityFile: relative(dirname(this.file), identityFile) } : {}) };\n if (replacing) raw.accounts[raw.accounts.indexOf(account)] = { ...account, ...added, enabled: true };\n else raw.accounts.push(added);\n validateConfig(raw, this.file);\n if (input.document !== undefined) {\n try { await importAccount({ provider: input.provider, credentialFile, identityFile, document: input.document, identityDocument: input.identityDocument }); }\n catch { bad('\u51ED\u8BC1\u683C\u5F0F\u65E0\u6548\uFF1A\u8BF7\u68C0\u67E5\u5FC5\u586B\u5B57\u6BB5\u3001\u533A\u57DF\u548C Trae \u8BBE\u5907\u8EAB\u4EFD'); }\n } else if (input.provider.startsWith('qoder') && input.pat) {\n if (typeof input.pat !== 'string' || input.pat.length > 8192 || /\\s/.test(input.pat.trim())) bad('PAT \u683C\u5F0F\u65E0\u6548');\n await writePrivateJson(credentialFile, { version: 2, pat: input.pat.trim(),\n region: input.provider === 'qoder' ? 'china' : 'global', savedAt: new Date().toISOString() });\n } else {\n const source = input.source;\n if (!source && (input.provider.startsWith('workbuddy') || input.provider.startsWith('trae'))) {\n const discovered = await discoverLocalAccounts(input.provider);\n const item = discovered.accounts.find(a => !input.edition || input.edition === 'auto' || a.document.credential.edition === input.edition);\n if (!item) bad(discovered.status.some(s => s.state === 'unreadable')\n ? '\u627E\u5230\u672C\u673A\u767B\u5F55\u6587\u4EF6\uFF0C\u4F46\u51ED\u8BC1\u6216\u8BBE\u5907\u8EAB\u4EFD\u65E0\u6CD5\u8BFB\u53D6\u3002\u8BF7\u5728\u5B98\u65B9\u5BA2\u6237\u7AEF\u91CD\u65B0\u767B\u5F55\u540E\u91CD\u8BD5\uFF0C\u6216\u624B\u52A8\u5BFC\u5165\u51ED\u8BC1\u3002'\n : '\u672A\u627E\u5230\u6240\u9009\u533A\u57DF\u7684\u672C\u673A\u767B\u5F55\u3002\u8BF7\u5148\u5728\u5B98\u65B9\u5BA2\u6237\u7AEF\u767B\u5F55\uFF0C\u518D\u70B9\u51FB\u91CD\u65B0\u68C0\u6D4B\u3002');\n try { await importAccount({ ...item, credentialFile, identityFile }); }\n catch { bad('\u672C\u673A\u51ED\u8BC1\u5BFC\u5165\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u5BA2\u6237\u7AEF\u767B\u5F55\u72B6\u6001\u4E0E\u8BBE\u5907\u8EAB\u4EFD'); }\n } else {\n const file = source || (input.provider.startsWith('qoder') ? qoderOwnAuthPath(QODER_VARIANTS.find(v => v.id === input.provider)) : undefined);\n if (typeof file !== 'string' || !file.trim()) bad('\u672A\u627E\u5230\u767B\u5F55\u6587\u4EF6\uFF0C\u8BF7\u586B\u5199\u6765\u6E90\u8DEF\u5F84\u6216 Qoder PAT');\n try { await importAccount({ provider: input.provider, source: resolve(file), credentialFile, identityFile,\n edition: input.edition, identitySource: input.identity ? resolve(input.identity) : undefined }); }\n catch { bad('\u8D26\u53F7\u5BFC\u5165\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u767B\u5F55\u6587\u4EF6\u3001\u533A\u57DF\u3001Trae edition \u548C\u8BBE\u5907\u8EAB\u4EFD'); }\n }\n }\n const imported = await jsonCredential(credentialFile);\n const fingerprint = value => input.provider.startsWith('qoder') ? value.pat : value.credential?.uid || value.credential?.userId;\n for (const existing of input.capture || input.document !== undefined ? this.config.accounts.filter(a => a.provider === input.provider && a.id !== input.id) : []) {\n let value; try { value = await jsonCredential(existing.credentialFile); } catch { continue; }\n if (fingerprint(value) && fingerprint(value) === fingerprint(imported)) bad(`\u6B64\u767B\u5F55\u8D26\u53F7\u5DF2\u5728\u8D26\u53F7\u6C60\u4E2D\uFF1A${existing.name || existing.id}\uFF0C\u8BF7\u5207\u6362\u5BA2\u6237\u7AEF\u8D26\u53F7\u540E\u518D\u83B7\u53D6`);\n }\n if (!input.name && !replacing) added.name = imported.credential?.nickname || imported.credential?.accountName || input.id;\n } else if (input.action === 'account.update') {\n if (!account) bad('\u8D26\u53F7\u4E0D\u5B58\u5728');\n if (input.autoCheckin !== undefined) {\n if (typeof input.autoCheckin !== 'boolean' || !supportsCheckin(account.provider)) bad('\u6B64\u5E73\u53F0\u6682\u4E0D\u652F\u6301\u81EA\u52A8\u7B7E\u5230');\n account.autoCheckin = input.autoCheckin;\n }\n if (input.name !== undefined) account.name = input.name;\n if (input.enabled !== undefined) account.enabled = input.enabled;\n } else if (input.action === 'accounts.enabled') {\n if ((input.provider !== undefined && !PROVIDERS.includes(input.provider)) || typeof input.enabled !== 'boolean') bad('\u4F9B\u5E94\u5546\u6216\u8DEF\u7531\u53C2\u4E0E\u5F00\u5173\u65E0\u6548');\n for (const a of raw.accounts.filter(a => !input.provider || a.provider === input.provider)) a.enabled = input.enabled;\n } else if (input.action === 'account.move') {\n if (!account || ![-1, 1].includes(input.direction)) bad('\u8D26\u53F7\u6216\u987A\u5E8F\u65E0\u6548');\n const group = raw.accounts.filter(a => a.provider === account.provider), position = group.indexOf(account) + input.direction;\n if (position >= 0 && position < group.length) {\n const index = raw.accounts.indexOf(account), next = raw.accounts.indexOf(group[position]);\n [raw.accounts[index], raw.accounts[next]] = [raw.accounts[next], raw.accounts[index]];\n }\n } else if (input.action === 'account.remove') {\n if (!account) bad('\u8D26\u53F7\u4E0D\u5B58\u5728');\n if (Object.values(raw.routes).some(r => r.targets.some(t => t.account === input.id))) bad('\u8BF7\u5148\u79FB\u9664\u8DEF\u7531\u4E2D\u7ED1\u5B9A\u6B64\u8D26\u53F7\u7684\u76EE\u6807');\n if (account.provider.startsWith('workbuddy') || account.provider.startsWith('trae')) {\n try { raw.ignoredLocalAccounts = [...new Set([...(raw.ignoredLocalAccounts ?? []), localAccountKey(account.provider, await jsonCredential(this.config.accounts.find(a => a.id === account.id).credentialFile))])]; } catch {}\n }\n raw.accounts = raw.accounts.filter(a => a.id !== input.id);\n } else if (input.action === 'models.visibility') {\n if ((input.provider !== undefined && !PROVIDERS.includes(input.provider)) || typeof input.visible !== 'boolean') bad('\u4F9B\u5E94\u5546\u6216\u5C55\u793A\u5F00\u5173\u65E0\u6548');\n raw.modelVisibility = { ...raw.modelVisibility }; raw.models = { ...raw.models };\n for (const provider of input.provider ? [input.provider] : PROVIDERS) {\n raw.modelVisibility[provider] = input.visible;\n raw.models[provider] = Object.fromEntries(Object.entries(raw.models[provider] ?? {}).map(([id, pref]) => [id, { ...pref, visible: input.visible }]));\n }\n } else if (input.action === 'model.update') {\n if (!PROVIDERS.includes(input.provider) || typeof input.id !== 'string' || !input.id || input.id.length > 256) bad('\u6A21\u578B\u65E0\u6548');\n raw.models = { ...raw.models, [input.provider]: { ...raw.models?.[input.provider],\n [input.id]: { ...raw.models?.[input.provider]?.[input.id],\n ...(input.name !== undefined ? { name: input.name } : {}), ...(input.visible !== undefined ? { visible: input.visible } : {}) } } };\n } else if (input.action === 'free.model.update') {\n const parent = raw.routes[input.parentId];\n if (!parent?.freeOnly || !this.freeRoutes(input.parentId, this.config.routes[input.parentId]).some(m => m.id === input.id)) bad('\u514D\u8D39\u6A21\u578B\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u5237\u65B0\u9875\u9762');\n const model = this.freeRoutes(input.parentId, this.config.routes[input.parentId]).find(m => m.id === input.id);\n if (input.reasoningEffort !== undefined && input.reasoningEffort !== null && !model.reasoning?.supportedEfforts.includes(input.reasoningEffort)) bad('\u6B64\u514D\u8D39\u6A21\u578B\u4E0D\u652F\u6301\u6240\u9009\u63A8\u7406\u7B49\u7EA7');\n parent.freeModels = { ...parent.freeModels, [input.id]: { ...parent.freeModels?.[input.id],\n ...(input.visible !== undefined ? { visible: input.visible } : {}),\n ...(input.reasoningEffort !== undefined ? { reasoningEffort: input.reasoningEffort } : {}) } };\n } else if (input.action === 'route.save') {\n if (input.id === undefined || input.id === '') {\n input.id = input.previousId || `route_${randomBytes(8).toString('hex')}`;\n }\n if (!/^[a-zA-Z0-9_.-]{1,128}$/.test(input.id ?? '')) bad('\u8DEF\u7531 ID \u4EC5\u652F\u6301\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u70B9\u3001\u4E0B\u5212\u7EBF\u548C\u77ED\u6A2A\u7EBF');\n if (input.previousId && !Object.hasOwn(raw.routes, input.previousId)) bad('\u539F\u8DEF\u7531\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5237\u65B0\u9875\u9762');\n if (input.previousId !== input.id && Object.hasOwn(raw.routes, input.id)) bad('\u8DEF\u7531 ID \u5DF2\u5B58\u5728');\n raw.routes = { ...raw.routes, [input.id]: input.route };\n if (input.previousId && input.previousId !== input.id) delete raw.routes[input.previousId];\n } else if (input.action === 'route.force-expiring') {\n if (!Object.hasOwn(raw.routes, input.id)) bad('\u8DEF\u7531\u4E0D\u5B58\u5728');\n raw.routes[input.id].preferExpiringCredits = true;\n await this.telemetry.restartExpiring(input.id);\n const route = this.router.config.routes[input.id], strategy = route.strategy ?? 'failover';\n if (['tokens', 'credits'].includes(strategy)) await this.telemetry.advance(input.id, this.router.candidates(input.id), JSON.stringify({ strategy, targets: route.targets }));\n } else if (input.action === 'route.remove') {\n if (!Object.hasOwn(raw.routes, input.id)) bad('\u8DEF\u7531\u4E0D\u5B58\u5728');\n delete raw.routes[input.id];\n } else if (input.action === 'preset.add') {\n const id = input.id ?? 'deepseek-v4.1-flash';\n if (!Object.hasOwn(ROUTE_PRESETS, id)) bad('\u672A\u77E5\u9884\u914D\u7F6E\u8DEF\u7531');\n if (Object.hasOwn(raw.routes, id)) bad('\u9884\u914D\u7F6E\u8DEF\u7531\u5DF2\u5B58\u5728\uFF0C\u4E0D\u8986\u76D6\u5DF2\u6709\u8BBE\u7F6E');\n raw.routes[id] = structuredClone(ROUTE_PRESETS[id]);\n } else if (input.action === 'preset.add-all') {\n for (const [id, route] of Object.entries(ROUTE_PRESETS)) if (!Object.hasOwn(raw.routes, id)) raw.routes[id] = structuredClone(route);\n } else if (input.action === 'checkins.settings') {\n if (this.checkins.flight) bad('\u8BF7\u7B49\u5F85\u5F53\u524D\u7B7E\u5230\u5B8C\u6210\u540E\u4FEE\u6539\u8BA1\u5212');\n if (!input.schedule) bad('\u8BF7\u586B\u5199\u7B7E\u5230\u8BA1\u5212');\n raw.checkinSchedule = input.schedule;\n } else if (input.action === 'options.save') {\n for (const key of ['cooldownMs', 'requestTimeoutMs', 'retryServerErrors', 'usageRetentionDays']) if (input[key] !== undefined) raw[key] = input[key];\n } else bad('\u672A\u77E5\u64CD\u4F5C');\n let config;\n try { config = validateConfig(raw, this.file); } catch (error) { bad(error.message); }\n await writePrivateJson(this.file, raw);\n staging = undefined; // The new account's files now belong to the committed configuration.\n this.raw = raw; this.config = config;\n for (const id of this.catalogs.keys()) if (!config.accounts.some(a => a.id === id && a.credentialFile === this.catalogs.get(id).credentialFile)) { this.catalogs.delete(id); this.catalogErrors.delete(id); }\n await Promise.all(config.accounts.map(a => this.readLogin(a)));\n this.publish();\n await this.telemetry.persist();\n } finally { if (staging) await rm(staging, { recursive: true, force: true }); }\n return this.state();\n }, { waitMs: 30000 }).then(async state => {\n if (input.action === 'config.import') {\n void Promise.all([this.monitorAll(), ...PROVIDERS.map(p => this.ensureCatalog(p, true))]).catch(() => {});\n }\n if (input.action === 'preset.add' || input.action === 'preset.add-all') { await this.checkFreeModels(); return this.state(); }\n if (input.action === 'account.add' || input.action === 'account.credentials') {\n const account = this.config.accounts.find(a => a.id === input.id);\n if (input.action === 'account.credentials' && !this.checkins.failed) await this.checkins.credentialsUpdated(input.id);\n if (account) { await Promise.all([this.refreshAccount(account, true), this.monitorAccount(account)]); return this.state(); }\n }\n return state;\n });\n }\n watch(onError) {\n let timer;\n const watcher = watch(dirname(this.file), (_, filename) => {\n if (filename && String(filename) !== this.file.split(/[\\\\/]/).pop()) return;\n clearTimeout(timer);\n timer = setTimeout(() => { void withFileLock(this.file, async () => {\n const raw = JSON.parse(await readFile(this.file, 'utf8'));\n if (this.closed || revisionOf(raw) === this.revision) return;\n const config = validateConfig(raw, this.file); this.raw = raw; this.config = config; this.publish(); await this.telemetry.persist();\n }).catch(() => onError?.()); }, 150);\n });\n return () => { this.closed = true; clearTimeout(timer); watcher.close(); };\n }\n}\n\nexport function managementHandler(manager) {\n const key = randomBytes(32).toString('base64url');\n const json = (res, status, value) => {\n res.writeHead(status, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store', 'X-Content-Type-Options': 'nosniff' });\n res.end(JSON.stringify(value));\n };\n return async (req, res) => {\n manager.requests = (manager.requests ?? 0) + 1;\n try {\n const remote = req.socket?.remoteAddress;\n if (!hostIsLoopback(req.headers.host) || (remote && !['127.0.0.1', '::1', '::ffff:127.0.0.1'].includes(remote))) throw new ManagementError(403, '\u4EC5\u5141\u8BB8\u672C\u673A\u8BF7\u6C42');\n if (req.headers.origin && req.headers.origin !== `http://${req.headers.host}` && req.headers.origin !== `https://${req.headers.host}`) throw new ManagementError(403, '\u6765\u6E90\u65E0\u6548');\n if (req.headers['sec-fetch-site'] === 'cross-site') throw new ManagementError(403, '\u6765\u6E90\u65E0\u6548');\n if (req.method === 'GET') { json(res, 200, { ...manager.state(), key }); return; }\n if (req.method !== 'POST') throw new ManagementError(405, '\u65B9\u6CD5\u65E0\u6548');\n const actual = Buffer.from(req.headers['x-multi-router-key'] ?? ''), expected = Buffer.from(key);\n if (actual.length !== expected.length || !timingSafeEqual(actual, expected)) throw new ManagementError(401, '\u8BF7\u5237\u65B0\u914D\u7F6E\u9875\u9762');\n if (!/^application\\/json(?:\\s*;|$)/i.test(req.headers['content-type'] ?? '')) throw new ManagementError(415, '\u9700\u8981 JSON');\n let size = 0, chunks = [];\n for await (const chunk of req) { size += chunk.length; if (size > 1024 * 1024) throw new ManagementError(413, '\u8BF7\u6C42\u8FC7\u5927'); chunks.push(chunk); }\n let input;\n try { input = JSON.parse(Buffer.concat(chunks).toString('utf8')); } catch { throw new ManagementError(400, 'JSON \u65E0\u6548'); }\n json(res, 200, { ...await manager.action(input), key });\n } catch (error) {\n json(res, error instanceof ManagementError ? error.status : 500,\n { error: error instanceof ManagementError ? error.message : '\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u914D\u7F6E\u548C\u6765\u6E90\u6587\u4EF6' });\n } finally { manager.requests--; }\n };\n}\n", "{\n \"name\": \"dsh-multi-router\",\n \"version\": \"0.5.8\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/AndroidSix/dsh-multi-router.git\"\n },\n \"description\": \"Multi-account WorkBuddy, Trae and Qoder routing for DeepSeek Harness\",\n \"type\": \"module\",\n \"main\": \"lib/index.js\",\n \"bin\": {\n \"dsh-multi-router\": \"lib/cli.js\"\n },\n \"exports\": {\n \".\": \"./lib/index.js\",\n \"./host\": \"./lib/host.js\",\n \"./client\": \"./lib/client.js\",\n \"./cordis.patch.yml\": \"./cordis.patch.yml\",\n \"./package.json\": \"./package.json\"\n },\n \"engines\": {\n \"node\": \"^22.19.0 || >=24.0.0\"\n },\n \"files\": [\n \"lib\",\n \"cordis.patch.yml\",\n \"README.md\",\n \"LICENSE\",\n \"THIRD_PARTY_NOTICES.md\",\n \"upstream-lock.json\",\n \"router.example.json\",\n \"CHANGELOG.md\"\n ],\n \"dsh\": {\n \"bundle\": {\n \"patch\": \"./cordis.patch.yml\"\n },\n \"client\": {\n \"inject\": [\n \"@deepseek-ai/dsh-client-ui-renderer\"\n ],\n \"platform\": \"web\"\n }\n },\n \"scripts\": {\n \"build\": \"node scripts/build.mjs\",\n \"test\": \"node --test tests/*.test.mjs\",\n \"check\": \"npm run build && npm test\",\n \"pack:release\": \"npm run build && npm pack --ignore-scripts\",\n \"fetch-upstream\": \"node scripts/fetch-upstream.mjs\"\n },\n \"dependencies\": {\n \"@earendil-works/pi-ai\": \"0.87.1\",\n \"yaml\": \"2.9.1\"\n },\n \"peerDependencies\": {\n \"@deepseek-ai/cordis\": \"^4.0.4\",\n \"@deepseek-ai/dsh-atomic-write\": \"0.2.0-rc.2\",\n \"@deepseek-ai/dsh-attachment\": \"0.2.0-rc.2\",\n \"@deepseek-ai/dsh-home-paths\": \"0.2.0-rc.2\",\n \"@deepseek-ai/dsh-llm\": \"0.2.0-rc.2\",\n \"@deepseek-ai/dsh-llm-pi-ai\": \"0.2.0-rc.2\",\n \"@deepseek-ai/schemastery\": \"^3.18.4\",\n \"react\": \"^18.2.0\"\n },\n \"devDependencies\": {\n \"@deepseek-ai/cordis\": \"^4.0.4\",\n \"@deepseek-ai/dsh-atomic-write\": \"0.2.0-rc.2\",\n \"@deepseek-ai/dsh-attachment\": \"0.2.0-rc.2\",\n \"@deepseek-ai/dsh-home-paths\": \"0.2.0-rc.2\",\n \"@deepseek-ai/dsh-llm\": \"0.2.0-rc.2\",\n \"@deepseek-ai/dsh-llm-pi-ai\": \"0.2.0-rc.2\",\n \"@deepseek-ai/schemastery\": \"^3.18.4\",\n \"esbuild\": \"^0.25.0\",\n \"react\": \"^18.2.0\",\n \"react-dom\": \"^18.2.0\"\n },\n \"license\": \"MIT\",\n \"keywords\": [\n \"dsh-plugin\",\n \"deepseek-harness\",\n \"multi-account\",\n \"model-router\",\n \"plugin-updater\"\n ]\n}\n", "/** Node-free constants and types shared by the Host and browser halves. */\n\nimport type { QoderRegion } from './qoder/region.ts'\n\n/** The two Qoder product variants this plugin serves, by provider id. */\nexport type QoderVariantId = 'qoder' | 'qoder-global'\n\n/** Plugin-owned status endpoint consumed by its browser half. */\nexport const QODER_STATUS_PATH = '/plugins/dsh-qoder-connect/status'\n\n/**\n * Plugin-owned settings endpoint consumed by its browser half.\n *\n * GET answers the whole entry configuration as three layers (value/base/user)\n * plus the write key; POST applies one patch. This is the plugin's own settings\n * surface, replacing writes through the host's settings service \u2014 see\n * {@link ./settings-store.ts} for why.\n */\nexport const QODER_SETTINGS_FACE_PATH = '/plugins/dsh-qoder-connect/settings'\n\n/**\n * Plugin-owned probe control endpoint.\n *\n * Separate from the status route because it accepts writes: the status route's\n * loopback Host/Origin guard protects against a DNS-rebinding *page*, which is\n * not the same as authorizing a state-changing action. This route therefore\n * also requires the in-process key the browser half receives with the status\n * document.\n */\nexport const QODER_PROBE_PATH = '/plugins/dsh-qoder-connect/probe'\n\n/**\n * Plugin-owned PAT endpoint, one per variant.\n *\n * A POST here saves (validates and persists) a Personal Access Token, or\n * clears the stored one. Unlike the read-only status GET it is a write \u2014\n * it persists a credential \u2014 so it also requires the in-process key the\n * browser half receives with the status document.\n */\nexport const QODER_AUTH_PATH = '/plugins/dsh-qoder-connect/auth'\n\n/**\n * The international (Qoder Global) variant's own triple of routes.\n *\n * Kept as separate constants rather than a computed suffix so both halves\n * reference literal strings: the browser bundle and the host bundle are built\n * independently, and a shared expression is one build-config drift away from\n * the desk asking a route the host never mounted.\n */\nexport const QODER_GLOBAL_STATUS_PATH = '/plugins/dsh-qoder-connect/global/status'\nexport const QODER_GLOBAL_PROBE_PATH = '/plugins/dsh-qoder-connect/global/probe'\nexport const QODER_GLOBAL_AUTH_PATH = '/plugins/dsh-qoder-connect/global/auth'\n\n/**\n * One action the PAT route accepts.\n *\n * `save-pat` validates the pasted token against the variant's region and, only\n * on success, persists it; `clear` removes the stored credential. There is no\n * device flow and no credential import: the token is the whole auth surface.\n */\nexport type QoderAuthAction = 'save-pat' | 'clear'\n\n/** Request body accepted by the PAT route. */\nexport interface QoderAuthRequest {\n action: QoderAuthAction\n /** The token to validate and store; required for `save-pat`. */\n pat?: string\n}\n\n/** Where the credential in effect came from. */\nexport type QoderCredentialSource = 'card' | 'env' | 'cli'\n\n/**\n * Redacted summary of one variant's PAT.\n *\n * Never the token itself: the browser half displays where the credential came\n * from, when it was saved, and the last four characters \u2014 enough to tell two\n * tokens apart, not enough to misuse one.\n */\nexport interface QoderPatSummary {\n source: QoderCredentialSource\n /** When the stored token was saved, epoch milliseconds; absent for env fallback. */\n savedAtMs?: number\n /** Last four characters of the token. */\n patTail?: string\n}\n\n/** One model's recorded probe observation, as the card displays it. */\nexport interface QoderWebProbeModel {\n id: string\n name: string\n /** `validating` results carry efforts; the other states never do. */\n validation: 'validating' | 'non-validating' | 'unknown'\n efforts: readonly string[]\n probedAt: number\n}\n\n/** Probe section of the status document. */\nexport interface QoderWebProbeSection {\n /** Whether the user has authorized probing. */\n consent: boolean\n /** Whether a sweep is in flight right now. */\n running: boolean\n /** Models the user could probe by hand (undeclared yet reasoning-capable). */\n candidates: readonly string[]\n /** Recorded observations. */\n results: readonly QoderWebProbeModel[]\n}\n\n/** Action requested from the probe control route. */\nexport interface QoderProbeAction {\n /**\n * `probe` spends credit on one model; `clear` drops recorded observations;\n * `refresh` re-reads the credential and re-fetches the model catalog;\n * `set-maximum-context-window` persists the card's maximum-window\n * preference (one per variant section).\n *\n * All are writes, which is why they share this route's in-process key\n * and loopback guards rather than the read-only status GET.\n */\n action: 'probe' | 'clear' | 'refresh' | 'set-maximum-context-window' | 'clear-checkin-logs' | 'checkin' | 'set-models-enabled'\n /** Target model id; required for `probe`. */\n model?: string\n /** Requested value for `set-maximum-context-window` or `set-models-enabled`. */\n enabled?: boolean\n /** Target model ids for `set-models-enabled` (supports single, batch, or all). */\n models?: readonly string[]\n}\n\n/**\n * Where the models a card is currently showing came from.\n *\n * The plan requires the card to distinguish a live catalog from the built-in\n * fallback, and to say when the last attempt failed \u2014 otherwise a stale list is\n * indistinguishable from an offline one, and a user cannot tell whether the\n * models they see still match the upstream.\n */\nexport interface QoderWebCatalog {\n /**\n * Where the models on screen came from, in degradation order:\n * `live` (fetched now) \u2192 `saved` (this account's last successful fetch,\n * restored after a restart or a failed fetch) \u2192 `fallback` (the roster\n * compiled into the plugin). The card distinguishes them because \"stale\" and\n * \"offline with a saved list\" are different situations for the user.\n */\n source: 'live' | 'saved' | 'fallback'\n /** When the live catalog last succeeded, epoch ms. */\n fetchedAt?: number\n /** Why the most recent fetch failed, when it did, redacted for display. */\n error?: string\n}\n\n/** One quota package and its remaining credit. */\nexport interface QoderWebCreditAccount {\n packageName: string\n remain: number\n size: number\n unlimited?: true\n /**\n * When the package's credit expires, carried through in whatever form the\n * upstream reported it (an ISO string or a numeric epoch-millisecond value\n * normalized to an ISO string). Absent when the upstream reported no\n * expiry \u2014 rendered as \"no expiry\", never guessed into a date.\n */\n packageEndTime?: string\n}\n\n/** Aggregated credit answer rendered by the plugin card. */\nexport interface QoderWebCredits {\n /**\n * Usage percentage across the account (0..100), taken from the Qoder quota\n * answer's `userQuota.percentage`. The card renders its headline from this.\n */\n total: number\n /** Summed per-package totals \u2014 the denominator of the dashboard's bar. */\n totalSize?: number\n accounts: readonly QoderWebCreditAccount[]\n /** The account's quota is uncapped; renderers test this flag first. */\n unlimited?: true\n /** When the current quota cycle ends, verbatim from the upstream. */\n cycleResetTime?: string\n}\n\n/**\n * One catalog model as the status document snapshots it.\n *\n * A plain-Qoder mirror of `src/qoder/catalog.ts`'s `QoderCatalogModel` (the\n * WorkBuddy-era billing/promotion/free fields are gone): the browser half\n * renders reasoning, price factor, and context capacity from these fields and\n * nothing else. Field names follow the Qoder catalog vocabulary so the two\n * halves cannot drift on spelling.\n */\nexport interface QoderCatalogModelSnapshot {\n id: string\n name: string\n /** Effective input budget in tokens. */\n contextWindow?: number\n /** The upstream's preferred window before a larger one is selected. */\n defaultContextWindow?: number\n /** Selectable window sizes the upstream declares, ascending. */\n supportedContextWindows?: readonly number[]\n /** Whether the model reasons at all. */\n isReasoning?: boolean\n /** Effort ids the model advertises (wire spellings). */\n reasoningEfforts?: readonly string[]\n /** The model's default effort id, when the upstream names one. */\n defaultReasoningEffort?: string\n /** Price multiplier vs the baseline (1 = base rate); absent means unknown. */\n priceFactor?: number\n /** Whether the model accepts image input. */\n supportsImages?: boolean\n /** Upstream provenance marker (`system` / `user`), when reported. */\n source?: string\n}\n\n/** The JSON document the plugin card renders. */\nexport type QoderWebStatus =\n | {\n status: 'signed-in'\n /** Which upstream region the stored token belongs to. */\n region?: QoderRegion\n /** Redacted summary of the PAT in effect. */\n pat?: QoderPatSummary\n credits?: QoderWebCredits\n creditsError?: string\n /** The models the plugin serves, as catalog snapshots. */\n models?: readonly QoderCatalogModelSnapshot[]\n /** Where those models came from, and whether the last fetch failed. */\n catalog?: QoderWebCatalog\n /** Reasoning-effort probe state, consent, and recorded observations. */\n probe?: QoderWebProbeSection\n /** Card preference selecting larger declared context windows. */\n useMaximumContextWindow?: boolean\n /** Disabled model IDs (blacklist) for this variant. */\n disabledModels?: readonly string[]\n /**\n * The last automatic job-token refresh the self-heal performed, epoch ms.\n * Absent when no refresh has happened in this process. The card renders\n * this as a visible \"token auto-refreshed\" notice, so an otherwise\n * invisible recovery is observable.\n */\n jobTokenRefreshedAt?: number\n /**\n * In-process key authorizing probe control writes. Handed to the card with\n * the status document (the card is same-origin and already had to pass the\n * loopback guard); it is never persisted and rotates per process.\n */\n probeKey?: string\n /**\n * Daily check-in status record for this variant.\n */\n checkIn?: {\n lastDate: string\n lastAt: number\n status: 'claimed' | 'already-claimed' | 'before-window' | 'no-campaign' | 'error'\n amount?: number | undefined\n message?: string | undefined\n /**\n * When the scheduler's timer is next due, epoch ms.\n *\n * A day already claimed goes deliberately quiet, so without this the\n * card cannot tell \"scheduled and waiting\" from \"no timer at all\" \u2014\n * which is exactly the doubt a missing timer created.\n */\n nextRunAt?: number | undefined\n logs?: readonly {\n id: string\n date: string\n timestamp: number\n status: 'claimed' | 'already-claimed' | 'before-window' | 'no-campaign' | 'error'\n amount?: number | undefined\n campaignKey?: string | undefined\n message?: string | undefined\n }[] | undefined\n }\n /**\n * In-process key authorizing PAT writes, including clearing. Travels with\n * the document for the same reason `probeKey` does.\n */\n authKey?: string\n }\n | {\n /**\n * No usable token, and the card may save one.\n *\n * Its own arm rather than an optional field on the signed-in document,\n * because the PAT key below is exactly what a signed-out card needs and a\n * signed-in one does not: the two states ask for different actions, and a\n * single arm would let a card offer clear and save at once.\n */\n status: 'signed-out'\n /**\n * Why no credential is usable, when that is diagnosable rather than simply\n * \"nobody signed in\" \u2014 a stale WorkBuddy-era credential file being the\n * case that matters. The card renders it in place of the generic hint.\n */\n reason?: string\n /**\n * In-process key authorizing PAT writes; see the signed-in arm's\n * `probeKey` for why it travels with the document.\n */\n authKey?: string\n }\n | { status: 'error'; message: string }\n", "/**\n * The two Qoder products this one plugin serves.\n *\n * Both are the same upstream in different regions, and they differ by route\n * (endpoints per `src/qoder/transport/endpoints.ts`), file identity, and display\n * identity. Everything that varies between them is collected here as one\n * descriptor, so no module has to carry its own `if (international)` branch and\n * a third variant would be a data change rather than a refactor.\n *\n * Each variant holds its own Personal Access Token: a token minted on\n * qoder.com does not work against the China deployment and vice versa, and the\n * two files, routes, and catalogs never cross.\n *\n * This module is host-side (it names files and routes). The browser half takes\n * the same ids and routes from the Node-free `status-paths.ts`, which stays the\n * single source shared by both halves.\n *\n * @module dsh-qoder-connect/variants\n */\n\nimport {\n QODER_AUTH_PATH,\n QODER_GLOBAL_AUTH_PATH,\n QODER_GLOBAL_PROBE_PATH,\n QODER_GLOBAL_STATUS_PATH,\n QODER_PROBE_PATH,\n QODER_STATUS_PATH,\n} from './status-paths.ts'\nimport type { QoderVariantId } from './status-paths.ts'\nimport type { QoderRegion } from './qoder/region.ts'\n\nexport type { QoderVariantId }\n\n/** One Qoder product variant. */\nexport interface QoderVariant {\n /** Provider id registered with DSH, e.g. `qoder-global`. */\n id: QoderVariantId\n /** Model-group heading and card title stem, e.g. `Qoder Global`. */\n displayName: string\n /** Product name as users know it, for diagnostics and error copy. */\n appName: string\n /** Which upstream region this variant's transport talks to. */\n region: QoderRegion\n /** Basename of the plugin-owned credential file under the data dir. */\n ownFilename: string\n /** Basename of the plugin-owned probe-record file under the data dir. */\n probeFilename: string\n /**\n * Basename of the plugin-owned saved-catalog file under the data dir.\n *\n * One per variant, like the probe records: the two deployments disagree about\n * rates, windows, and even which models exist for a shared id, so a catalog\n * saved from one must never be served as the other's.\n */\n catalogFilename: string\n /** Same-origin status route consumed by this variant's card. */\n statusPath: string\n /** Same-origin probe-control route consumed by this variant's card. */\n probePath: string\n /** Same-origin PAT route consumed by this variant's card. */\n authPath: string\n}\n\n/** China Qoder first: the no-suffix arm keeps the plugin's primary routes. */\nexport const QODER_VARIANTS: readonly QoderVariant[] = [\n {\n id: 'qoder',\n displayName: 'Qoder',\n appName: 'Qoder',\n region: 'china',\n ownFilename: '.qoder-auth.json',\n probeFilename: '.qoder-probe.json',\n catalogFilename: '.qoder-catalog.json',\n statusPath: QODER_STATUS_PATH,\n probePath: QODER_PROBE_PATH,\n authPath: QODER_AUTH_PATH,\n },\n {\n id: 'qoder-global',\n displayName: 'Qoder Global',\n appName: 'Qoder Global',\n region: 'global',\n ownFilename: '.qoder-global-auth.json',\n probeFilename: '.qoder-global-probe.json',\n catalogFilename: '.qoder-global-catalog.json',\n statusPath: QODER_GLOBAL_STATUS_PATH,\n probePath: QODER_GLOBAL_PROBE_PATH,\n authPath: QODER_GLOBAL_AUTH_PATH,\n },\n]\n\n/** The China variant; the plugin's default and compatibility anchor. */\nexport const CHINA_VARIANT: QoderVariant = QODER_VARIANTS[0]!\n\n/** The international variant. */\nexport const GLOBAL_VARIANT: QoderVariant = QODER_VARIANTS[1]!\n\n/** Look up a variant by provider id. */\nexport function variantFor(id: string): QoderVariant | undefined {\n return QODER_VARIANTS.find(variant => variant.id === id)\n}\n", "/**\n * Qoder credential storage \u2014 one Personal Access Token per variant.\n *\n * Every credential the plugin holds is a PAT the human pasted into the\n * variant's card (or exported into the environment, or saved by the CLI).\n * There is no device flow, no token refresh, and no expiry: a PAT is valid\n * until the user revokes it, so this store only reads, writes, and deletes a\n * small JSON document.\n *\n * One file per variant inside the plugin's data directory\n * (`<.dsh-qoder-connect>/`). The on-disk schema is\n * `{version: 2, pat, region, savedAt}` \u2014 deliberately narrower than the\n * WorkBuddy-era document it replaces: anything this file does not name is\n * not a fact the plugin knows.\n *\n * @module dsh-qoder-connect/auth\n */\n\nimport { createHash } from 'node:crypto'\nimport { mkdir, readFile, rm } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { writeFileAtomic } from '@deepseek-ai/dsh-atomic-write'\nimport { qoderPluginDataDir, QODER_DATA_DIR_ENV, QODER_DATA_DIR_NAME } from './paths.ts'\nimport type { QoderRegion } from './qoder/region.ts'\nimport type { QoderCredentialSource, QoderPatSummary } from './status-paths.ts'\nimport type { QoderVariant } from './variants.ts'\n\n// Re-exported for compatibility: existing callers import these from here.\nexport { qoderPluginDataDir, QODER_DATA_DIR_ENV, QODER_DATA_DIR_NAME }\n\n/** The on-disk document version this writer produces. */\nconst AUTH_SCHEMA_VERSION = 2\n\n/** Environment fallback for the global arm when no file exists. */\nexport const QODER_PAT_ENV_GLOBAL = 'QODER_PERSONAL_ACCESS_TOKEN'\n\n/** Environment fallback for the China arm when no file exists. */\nexport const QODER_PAT_ENV_CN = 'QODER_CN_PERSONAL_ACCESS_TOKEN'\n\n/** Basename of the China variant's credential file inside the data directory. */\nexport const QODER_AUTH_FILENAME = '.qoder-auth.json'\n\n/** Minimal logger surface the plugin context already provides. */\nexport interface AuthLogger {\n warn?(...args: unknown[]): void\n}\n\n/** Runtime credential, timestamps in epoch milliseconds. */\nexport interface QoderCredential {\n pat: string\n region: QoderRegion\n /** When the stored token was saved; absent for environment-sourced tokens. */\n savedAtMs?: number\n source: QoderCredentialSource\n}\n\n/** Read-only sign-in summary for status, the PAT route, and doctor output. */\nexport interface QoderAuthStatus {\n state: 'configured' | 'missing'\n /** Redacted summary of the token in effect, when there is one. */\n pat?: QoderPatSummary\n /** Which upstream region the token is used against. */\n region?: QoderRegion\n /** Why no credential is usable, when diagnosable (a stale legacy file). */\n reason?: string\n /** Absolute path of the credential file this store owns. */\n filePath: string\n}\n\n/** Constructor options. */\nexport interface QoderStoreOptions {\n variant: QoderVariant\n /** Explicit plugin-owned credential path, defaulting under the data dir. */\n ownPath?: string\n /** Logger for the legacy-file warning; optional so tests stay quiet. */\n logger?: AuthLogger\n}\n\n/** Last four characters of a token, for display. */\nexport function patTail(pat: string): string | undefined {\n const trimmed = pat.trim()\n return trimmed.length >= 4 ? trimmed.slice(-4) : undefined\n}\n\n/**\n * Stable identity key for a credential, used by probe records and saved\n * catalogs.\n *\n * A PAT is a bearer secret, so the key is its one-way hash rather than any\n * suffix of it: surfaces that show the key (cards, JSON diagnostics) leak\n * nothing usable, while two reads of the same token still correlate locally.\n */\nexport function qoderCredentialIdentity(credential: Pick<QoderCredential, 'pat'>): string {\n return `pat:${createHash('sha256').update(credential.pat).digest('hex').slice(0, 16)}`\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction isRegion(value: unknown): value is QoderRegion {\n return value === 'global' || value === 'china'\n}\n\nexport class QoderCredentialStore {\n private readonly variant: QoderVariant\n private readonly ownPath: string\n private readonly logger: AuthLogger | undefined\n /** The legacy-file warning is emitted once per process, not per read. */\n private legacyWarned = false\n\n constructor(options: QoderStoreOptions) {\n this.variant = options.variant\n this.ownPath = options.ownPath ?? join(qoderPluginDataDir(), options.variant.ownFilename)\n this.logger = options.logger\n }\n\n /** Absolute path of this variant's credential file, for display and tests. */\n ownAuthPath(): string {\n return this.ownPath\n }\n\n /**\n * The credential currently in effect, or `undefined` when there is none.\n *\n * Resolution order: the plugin-owned file, then the arm's environment\n * variable (only when no file exists \u2014 a saved token always wins over a\n * stray env), then nothing. There is no refresh and no expiry check: a PAT\n * lives until revoked.\n */\n async current(): Promise<QoderCredential | undefined> {\n const stored = await this.readOwn()\n if (stored !== undefined) return stored\n return this.fromEnvironment()\n }\n\n /**\n * The credential, or a thrown `MISSING_CREDENTIAL` error.\n *\n * Callers that serve requests (the shim, the catalog sweep) use this so the\n * absence of a token surfaces as the same classified failure the transport\n * itself raises when a saved token turns out empty.\n */\n async resolve(): Promise<QoderCredential> {\n const credential = await this.current()\n if (credential === undefined || credential.pat.trim() === '') {\n throw new Error('qoder: MISSING_CREDENTIAL \u2014 no Personal Access Token is configured. Add one in the Qoder settings card.')\n }\n return credential\n }\n\n /** The token in effect as a bare string, rejecting when there is none. */\n async patPromise(): Promise<string> {\n return (await this.resolve()).pat\n }\n\n /**\n * Persist a token for this variant. The caller is responsible for having\n * validated it against the region first (`validateApiKey` upstream).\n */\n async save(pat: string, source: QoderCredentialSource = 'card'): Promise<QoderCredential> {\n const trimmed = pat.trim()\n if (trimmed === '') throw new Error('qoder: cannot save an empty Personal Access Token')\n const credential: QoderCredential = {\n pat: trimmed,\n region: this.variant.region,\n savedAtMs: Date.now(),\n source,\n }\n await this.writeOwn(credential)\n return credential\n }\n\n /** Remove the stored credential. A missing file is not an error. */\n async clear(): Promise<void> {\n try {\n await rm(this.ownPath, { force: true })\n } catch {\n // Best effort: a file that cannot be removed will fail validation later\n // and surface through `status()` the same way.\n }\n }\n\n /** Alias kept for call-site readability (`logout` is just clearing). */\n async logout(): Promise<void> {\n await this.clear()\n }\n\n /** Redacted summary for the card, the PAT route, and doctor output. */\n async status(): Promise<QoderAuthStatus> {\n const base: { filePath: string; region?: QoderRegion } = {\n filePath: this.ownPath,\n region: this.variant.region,\n }\n const credential = await this.current()\n if (credential === undefined) {\n return {\n state: 'missing',\n ...base,\n ...this.pendingLegacyReason === undefined ? {} : { reason: this.pendingLegacyReason },\n }\n }\n const tail = patTail(credential.pat)\n return {\n state: 'configured',\n ...base,\n pat: {\n source: credential.source,\n ...credential.savedAtMs === undefined ? {} : { savedAtMs: credential.savedAtMs },\n ...tail === undefined ? {} : { patTail: tail },\n },\n }\n }\n\n /** Set when a read found a stale WorkBuddy-era file; consumed once. */\n private pendingLegacyReason: string | undefined\n\n private async fromEnvironment(): Promise<QoderCredential | undefined> {\n const name = this.variant.region === 'china' ? QODER_PAT_ENV_CN : QODER_PAT_ENV_GLOBAL\n const value = process.env[name]?.trim()\n if (value === undefined || value === '') return undefined\n return { pat: value, region: this.variant.region, source: 'env' }\n }\n\n private async readOwn(): Promise<QoderCredential | undefined> {\n let text: string\n try {\n text = await readFile(this.ownPath, 'utf8')\n } catch (error: unknown) {\n // An absent file means \"not signed in\". Any other read failure is treated\n // the same way rather than thrown: the only recovery either way is to\n // save the token again, and a status read must never break the card.\n this.pendingLegacyReason = undefined\n return undefined\n }\n let parsed: unknown\n try {\n parsed = JSON.parse(text)\n } catch {\n this.pendingLegacyReason = undefined\n return undefined\n }\n if (!isRecord(parsed)) {\n this.pendingLegacyReason = undefined\n return undefined\n }\n // A WorkBuddy-era document (it carries `accessToken` and no `pat`) is not a\n // credential this plugin can use in any form. Treat it as invalid \u2014 never a\n // fake migration \u2014 and say so, so the card points at the right fix.\n if (typeof parsed['accessToken'] === 'string' && parsed['pat'] === undefined) {\n this.pendingLegacyReason = 'stale WorkBuddy credential file; save a Qoder Personal Access Token instead'\n if (!this.legacyWarned) {\n this.legacyWarned = true\n this.logger?.warn?.(\n `qoder: ${this.variant.displayName}: ${this.ownPath} holds a WorkBuddy-era credential;`\n + ' it is ignored. Save a Qoder Personal Access Token to replace it.',\n )\n }\n return undefined\n }\n this.pendingLegacyReason = undefined\n const pat = typeof parsed['pat'] === 'string' ? parsed['pat'].trim() : ''\n if (pat === '') return undefined\n const region = isRegion(parsed['region']) ? parsed['region'] : this.variant.region\n const savedAt = typeof parsed['savedAt'] === 'number' && Number.isFinite(parsed['savedAt'])\n ? parsed['savedAt']\n : undefined\n return {\n pat,\n region,\n ...savedAt === undefined ? {} : { savedAtMs: savedAt },\n // A file this store wrote came from the card or the CLI; `source` is not\n // persisted because \"card vs cli\" only records who typed the command, and\n // a file left by any other tool is indistinguishable from the card's.\n source: 'card',\n }\n }\n\n private async writeOwn(credential: QoderCredential): Promise<void> {\n const document = {\n version: AUTH_SCHEMA_VERSION,\n pat: credential.pat,\n region: credential.region,\n savedAt: credential.savedAtMs ?? Date.now(),\n }\n const directory = dirname(this.ownPath)\n try {\n await mkdir(directory, { recursive: true, mode: 0o700 })\n } catch {\n // An existing or uncreatable directory surfaces on the write below.\n }\n await writeFileAtomic(this.ownPath, `${JSON.stringify(document, null, 2)}\\n`, {\n mode: 0o600,\n dirMode: 0o700,\n })\n this.pendingLegacyReason = undefined\n }\n}\n\n/**\n * The plugin-owned credential path for one variant's default filename.\n * Kept as a free function for the CLI, which builds no store per display line.\n */\nexport function qoderOwnAuthPath(variant: QoderVariant): string {\n return join(qoderPluginDataDir(), variant.ownFilename)\n}\n", "import { randomBytes, scrypt, createCipheriv, createDecipheriv } from 'node:crypto';\nimport { promisify } from 'node:util';\nimport { mkdir, mkdtemp, rm } from 'node:fs/promises';\nimport { dirname, join, relative } from 'node:path';\nimport { validateConfig, writePrivateJson } from './config.mjs';\nimport { importAccount, readPortableCredential } from './accounts.mjs';\n\nconst derive = promisify(scrypt);\nconst FORMAT = 'dsh-multi-router';\nconst MAX_BYTES = 512 * 1024;\nconst pick = (value, keys) => Object.fromEntries(keys.filter(k => Object.hasOwn(value ?? {}, k)).map(k => [k, value[k]]));\nconst options = ['cooldownMs', 'requestTimeoutMs', 'catalogTtlMs', 'retryServerErrors', 'modelVisibility', 'usageRetentionDays', 'checkinSchedule'];\nfunction settings(config) {\n return { ...pick(config, options), models: Object.fromEntries(Object.entries(config.models ?? {}).map(([p, rows]) => [p, Object.fromEntries(Object.entries(rows).map(([id, pref]) => [id, pick(pref, ['name', 'visible'])]))])),\n accounts: config.accounts.map(a => pick(a, ['id', 'provider', 'name', 'enabled', 'autoCheckin'])),\n routes: Object.fromEntries(Object.entries(config.routes).map(([id, r]) => [id, {\n ...pick(r, ['name', 'visible', 'strategy', 'contextWindow', 'maxTokens', 'preferExpiringCredits', 'expiringWithinDays', 'freeOnly', 'freeModels']),\n targets: r.targets.map(t => pick(t, ['provider', 'account', 'model', 'models', 'weight', 'tokenBudget', 'creditBudget'])),\n }])) };\n}\nconst problem = message => { throw Error(message); };\nfunction password(value, exporting = false) {\n if (typeof value !== 'string' || value.length > 1024 || value.length < (exporting ? 10 : 1)) problem(exporting ? '\u8FC1\u79FB\u5BC6\u7801\u81F3\u5C11 10 \u4E2A\u5B57\u7B26' : '\u8BF7\u8F93\u5165\u8FC1\u79FB\u5BC6\u7801');\n}\nexport async function exportConfiguration(manager, input) {\n const payload = { format: FORMAT, version: 1, encrypted: false, createdAt: new Date().toISOString(), config: settings(manager.config) };\n if (!input.includeCredentials) return payload;\n password(input.password, true);\n payload.credentials = {};\n for (const account of manager.config.accounts) {\n try {\n const credential = await readPortableCredential(account);\n if (credential) Object.defineProperty(payload.credentials, account.id, { value: credential, enumerable: true });\n } catch { problem(`\u8D26\u53F7 ${account.id} \u7684\u51ED\u8BC1\u4E0D\u53EF\u8BFB\uFF0C\u8BF7\u4FEE\u590D\u540E\u5BFC\u51FA\u6216\u9009\u62E9\u4EC5\u914D\u7F6E`); }\n }\n const salt = randomBytes(16), iv = randomBytes(12), key = await derive(input.password, salt, 32);\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n const bytes = Buffer.from(JSON.stringify(payload));\n if (bytes.length > MAX_BYTES) problem('\u914D\u7F6E\u8FC7\u5927\uFF0C\u65E0\u6CD5\u5BFC\u51FA');\n const data = Buffer.concat([cipher.update(bytes), cipher.final()]);\n return { format: FORMAT, version: 1, encrypted: true, cipher: 'aes-256-gcm', kdf: 'scrypt',\n salt: salt.toString('base64'), iv: iv.toString('base64'), tag: cipher.getAuthTag().toString('base64'), data: data.toString('base64') };\n}\nexport async function decodeConfiguration(input) {\n let payload;\n try {\n if (typeof input.document !== 'string' || Buffer.byteLength(input.document) > 900 * 1024) problem('\u8FC1\u79FB\u6587\u4EF6\u8FC7\u5927');\n payload = JSON.parse(input.document);\n } catch { problem('\u8BF7\u9009\u62E9\u6709\u6548\u7684\u63D2\u4EF6\u8FC1\u79FB JSON \u6587\u4EF6\uFF08\u5C0F\u4E8E 900 KB\uFF09'); }\n if (payload?.format !== FORMAT || payload.version !== 1) problem('\u4E0D\u662F\u53D7\u652F\u6301\u7684\u63D2\u4EF6\u8FC1\u79FB\u6587\u4EF6');\n const encrypted = payload.encrypted === true;\n if (encrypted) {\n password(input.password);\n try {\n if (payload.cipher !== 'aes-256-gcm' || payload.kdf !== 'scrypt') throw Error();\n const salt = Buffer.from(payload.salt, 'base64'), iv = Buffer.from(payload.iv, 'base64'), tag = Buffer.from(payload.tag, 'base64'), data = Buffer.from(payload.data, 'base64');\n if (salt.length !== 16 || iv.length !== 12 || tag.length !== 16 || data.length > MAX_BYTES) throw Error();\n const decipher = createDecipheriv('aes-256-gcm', await derive(input.password, salt, 32), iv);\n decipher.setAuthTag(tag);\n payload = JSON.parse(Buffer.concat([decipher.update(data), decipher.final()]).toString('utf8'));\n } catch { problem('\u5BC6\u7801\u9519\u8BEF\u6216\u8FC1\u79FB\u6587\u4EF6\u5DF2\u635F\u574F'); }\n }\n if (payload?.format !== FORMAT || payload.version !== 1 || !Array.isArray(payload.config?.accounts) || payload.config.accounts.length > 200 || !payload.config.routes || typeof payload.config.routes !== 'object' || Object.keys(payload.config.routes).length > 500) problem('\u8FC1\u79FB\u914D\u7F6E\u683C\u5F0F\u65E0\u6548');\n if (payload.credentials && !encrypted) problem('\u542B\u51ED\u8BC1\u7684\u8FC1\u79FB\u6587\u4EF6\u5FC5\u987B\u52A0\u5BC6');\n if (payload.credentials && (typeof payload.credentials !== 'object' || Array.isArray(payload.credentials))) problem('\u8FC1\u79FB\u51ED\u8BC1\u683C\u5F0F\u65E0\u6548');\n // Imported paths are never read: every credential receives a new local private file.\n const config = settings(payload.config);\n validateConfig({ ...config, accounts: config.accounts.map(a => ({ ...a, credentialFile: 'placeholder.json' })) });\n if (payload.credentials && Object.keys(payload.credentials).some(id => !config.accounts.some(a => a.id === id))) problem('\u8FC1\u79FB\u51ED\u8BC1\u5B58\u5728\u672A\u77E5\u8D26\u53F7');\n return { config, credentials: payload.credentials ?? {}, encrypted };\n}\nexport function migrationSummary(manager, portable, mode) {\n if (!['merge', 'replace'].includes(mode)) problem('\u8BF7\u9009\u62E9\u5408\u5E76\u6216\u66FF\u6362');\n for (const a of portable.config.accounts) {\n const old = manager.config.accounts.find(b => b.id === a.id);\n if (mode === 'merge' && old && old.provider !== a.provider) problem(`\u8D26\u53F7 ${a.id} \u7684\u4F9B\u5E94\u5546\u51B2\u7A81\uFF0C\u8BF7\u6539\u7528\u66FF\u6362\u6216\u4FEE\u6539\u5BFC\u5165\u6587\u4EF6`);\n }\n const existing = id => mode === 'merge' && manager.config.accounts.some(a => a.id === id);\n return { mode, accounts: portable.config.accounts.length, newAccounts: portable.config.accounts.filter(a => !existing(a.id)).length,\n credentials: Object.keys(portable.credentials).length,\n needsLogin: portable.config.accounts.filter(a => !Object.hasOwn(portable.credentials, a.id) && !existing(a.id)).length,\n routes: Object.keys(portable.config.routes).length,\n overwrittenRoutes: Object.keys(portable.config.routes).filter(id => Object.hasOwn(manager.config.routes, id)).length };\n}\nexport async function prepareMigration(manager, raw, portable, mode) {\n migrationSummary(manager, portable, mode);\n const base = join(dirname(manager.file), 'accounts'); await mkdir(base, { recursive: true, mode: 0o700 });\n const staging = await mkdtemp(join(base, 'migration-'));\n try {\n const imported = [];\n for (const a of portable.config.accounts) {\n const old = mode === 'merge' && raw.accounts.find(b => b.id === a.id), secret = Object.hasOwn(portable.credentials, a.id) ? portable.credentials[a.id] : undefined;\n if (!secret && old) { imported.push({ ...old, ...a }); continue; }\n const credentialFile = join(staging, a.id, 'credential.json'), identityFile = join(staging, a.id, 'identity.json');\n if (secret) await importAccount({ provider: a.provider, credentialFile, identityFile, document: secret.document, identityDocument: secret.identity });\n else { await writePrivateJson(credentialFile, {}); if (a.provider.startsWith('trae')) await writePrivateJson(identityFile, {}); }\n imported.push({ ...a, ...(!secret ? { enabled: false } : {}), credentialFile: relative(dirname(manager.file), credentialFile),\n ...(a.provider.startsWith('trae') ? { identityFile: relative(dirname(manager.file), identityFile) } : {}) });\n }\n const next = mode === 'replace' ? { ...portable.config, accounts: imported } : { ...raw, ...pick(portable.config, options),\n accounts: [...raw.accounts.map(a => imported.find(b => b.id === a.id) ?? a), ...imported.filter(a => !raw.accounts.some(b => b.id === a.id))],\n routes: { ...raw.routes, ...portable.config.routes },\n models: Object.fromEntries([...new Set([...Object.keys(raw.models ?? {}), ...Object.keys(portable.config.models)])].map(p => [p, { ...raw.models?.[p], ...portable.config.models[p] }])) };\n validateConfig(next, manager.file);\n return { raw: next, staging };\n } catch (error) { await rm(staging, { recursive: true, force: true }); throw error; }\n}\n", "import { readFile, stat, rm } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport { createRequire } from 'node:module';\nimport { pathToFileURL } from 'node:url';\nimport { parse as parseYaml } from 'yaml';\nimport { withFileLock, writeFileAtomic } from '@deepseek-ai/dsh-atomic-write';\nimport { writePrivateJson } from './config.mjs';\nimport { parseWorkBuddyVersion, compareWorkBuddyVersions } from '../upstream/workbuddy/src/update.ts';\n\nconst packageName = /^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$/i;\nconst safeRef = /^[a-zA-Z0-9._/-]{1,200}$/;\nexport function parsePluginSource(name, spec) {\n if (!packageName.test(name) || typeof spec !== 'string' || spec.length > 600 || spec.startsWith('-') || spec.trim() !== spec || /[\\x00-\\x1f]/.test(spec)) return { kind: 'unsupported' };\n const git = /^(?:github:|git\\+https:\\/\\/github\\.com\\/|https:\\/\\/github\\.com\\/|git\\+ssh:\\/\\/git@github\\.com\\/|git@github\\.com:)?([\\w.-]+)\\/([\\w.-]+?)(?:\\.git)?(?:#(.+))?$/.exec(spec);\n if (git && !spec.startsWith('@') && !spec.startsWith('file:') && !spec.startsWith('link:')) {\n const [, owner, repo, ref] = git;\n if (owner === '.' || owner === '..' || repo === '.' || repo === '..' || (ref && (!safeRef.test(ref) || ref.includes('..')))) return { kind: 'unsupported' };\n return { kind: 'github', owner, repo, ref, source: `github:${owner}/${repo}${ref ? '#' + ref : ''}` };\n }\n if (/^(?:file:|link:|workspace:|https?:|git|\\/|\\.)/.test(spec)) return { kind: 'unsupported' };\n const alias = /^npm:((?:@[^/]+\\/)?[^@]+)(?:@(.+))?$/.exec(spec);\n const actual = alias?.[1] ?? name, range = alias?.[2] ?? spec;\n if (!packageName.test(actual) || !/^[a-zA-Z0-9.*^~<>=|+ -]{1,160}$/.test(range)) return { kind: 'unsupported' };\n // Explicit dist-tags retain their channel; exact versions and ranges update to latest.\n const channel = /^[a-zA-Z][\\w.-]*$/.test(range);\n return { kind: 'npm', package: actual, alias: !!alias, channel, tag: channel ? range : 'latest', source: spec };\n}\nexport function githubCommit(value) {\n if (typeof value !== 'string') return undefined;\n return /(?:\\/tar\\.gz\\/|\\/tarball\\/|#)([a-f0-9]{40})(?:\\b|\\()/i.exec(value)?.[1]?.toLowerCase();\n}\nasync function jsonFile(file) { try { return JSON.parse(await readFile(file, 'utf8')); } catch { return undefined; } }\nasync function locks(dir) {\n let pnpm;\n try { pnpm = parseYaml(await readFile(join(dir, 'pnpm-lock.yaml'), 'utf8'), { maxAliasCount: 20 }); } catch { /* npm profiles use package-lock instead. */ }\n const npm = await jsonFile(join(dir, 'package-lock.json'));\n const times = await Promise.all(['pnpm-lock.yaml', 'package-lock.json'].map(name => stat(join(dir, name)).then(s => s.mtimeMs).catch(() => 0)));\n return { pnpm, npm, preferNpm: times[1] > times[0] };\n}\nasync function publicJson(url, fetchImpl, signal) {\n const res = await fetchImpl(url, { signal: AbortSignal.any([signal, AbortSignal.timeout(12000)]),\n // Request only the SHA: the default JSON includes file patches and can be megabytes.\n headers: { Accept: 'application/vnd.github.sha', 'User-Agent': 'dsh-multi-router-plugin-updates' }, redirect: 'error' });\n if (!res.ok) throw Error(res.status === 403 || res.status === 429 ? '\u8FDC\u7AEF\u9650\u6D41\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5' : res.status === 404 ? '\u4ED3\u5E93 / \u7248\u672C\u4E0D\u5B58\u5728\uFF0C\u6216\u9700\u8981\u79C1\u6709\u4ED3\u5E93\u6388\u6743' : `\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25\uFF08HTTP ${res.status}\uFF09`);\n let size = 0, chunks = [];\n for await (const chunk of res.body) { size += chunk.byteLength; if (size > 256 * 1024) throw Error('\u66F4\u65B0\u5143\u6570\u636E\u8FC7\u5927'); chunks.push(Buffer.from(chunk)); }\n const text = Buffer.concat(chunks).toString('utf8').trim();\n return /^[a-f0-9]{40}$/i.test(text) ? { sha: text } : JSON.parse(text);\n}\nconst short = sha => sha?.slice(0, 8);\nasync function registryVersion(service, profile, spec, signal) {\n const require = createRequire(profile.installAnchor);\n const { viewProfilePackage } = await import(pathToFileURL(require.resolve('@deepseek-ai/dsh-plugin-manager/operations')).href);\n const { registryPlan } = await import(pathToFileURL(require.resolve('@deepseek-ai/dsh-plugin-manager/registry')).href);\n for (const registry of registryPlan(undefined, await service.registries())) {\n const answer = await viewProfilePackage(profile.dir, spec, { ...profile.packageManager, registry, timeoutMs: 12000, signal });\n if (signal.aborted) throw Error('\u68C0\u67E5\u5DF2\u53D6\u6D88');\n if (answer.exitCode !== 0) continue;\n const parsed = JSON.parse(answer.stdout), metadata = Array.isArray(parsed) ? parsed.at(-1) : parsed;\n if (metadata?.version) return metadata;\n }\n throw Error('npm \u67E5\u8BE2\u5931\u8D25\uFF1B\u8BF7\u68C0\u67E5 DSH \u7F51\u7EDC\u3001registry \u8BBE\u7F6E\u6216\u5305\u7684\u8BBF\u95EE\u6743\u9650');\n}\nasync function refreshGitPlugin(service, profile, row, options, signal) {\n const require = createRequire(profile.installAnchor);\n const { runProfilePnpm } = await import(pathToFileURL(require.resolve('@deepseek-ai/dsh-plugin-manager/operations')).href);\n const { registryPlan, attributeFailure } = await import(pathToFileURL(require.resolve('@deepseek-ai/dsh-plugin-manager/registry')).href);\n const { classifyInstallFailure } = await import(pathToFileURL(require.resolve('@deepseek-ai/dsh-plugin-manager')).href);\n const plan = registryPlan(options.registry, await service.registries());\n return withFileLock(join(profile.dir, 'package.json'), async () => {\n const files = await Promise.all(['package.json', 'pnpm-lock.yaml'].map(async name => {\n const path = join(profile.dir, name);\n try { return { path, content: await readFile(path, 'utf8') }; } catch (e) { if (e.code !== 'ENOENT') throw e; return { path }; }\n }));\n const restore = () => Promise.all(files.map(f => f.content === undefined ? rm(f.path, { force: true }) : writeFileAtomic(f.path, f.content, { mode: 0o600 })));\n if (JSON.parse(files[0].content).dependencies?.[row.name] !== row.spec) throw Error('\u5B89\u88C5\u6765\u6E90\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5');\n let result;\n try {\n for (const registry of plan) {\n signal.throwIfAborted();\n // pnpm add reuses an unchanged Git lock; update explicitly refreshes its tracked ref.\n const run = await runProfilePnpm({ ...profile, profile: profile.name }, ['update', row.name, ...(registry ? [`--registry=${registry}`] : [])], {\n execution: 'service', ...profile.packageManager, signal, outputBytes: 16384, idleTimeoutMs: 600000,\n lookupTimeoutMs: 20000, activateNewBundles: false,\n });\n if (run.exitCode === 0 && !run.timedOut && !signal.aborted) return { packageResult: run, application: 'restart-required' };\n const kind = classifyInstallFailure({ log: run.output, timedOut: run.timedOut });\n result = { packageResult: { ...run, kind }, application: signal.aborted ? 'cancelled' : 'failed',\n ...(run.incompatible?.length ? { error: { code: 'incompatible-version' } } : {}) };\n await restore();\n if (signal.aborted || attributeFailure(kind, run.output, { kind: 'git', host: 'github.com' }) !== 'registry') break;\n }\n return result;\n } catch (e) { await restore(); throw e; }\n }, { waitMs: 120000 });\n}\nexport class PluginUpdates {\n constructor({ service = () => undefined, profile = () => undefined, fetchImpl = (...args) => fetch(...args), lookup = registryVersion, refreshGit = refreshGitPlugin, onInstalled, stateFile, now = Date.now } = {}) {\n this.stateFile = stateFile; this.now = now; this.dismissed = {}; this.lastAttempt = 0; this.saveQueue = Promise.resolve();\n this.service = service; this.profile = profile; this.fetchImpl = fetchImpl;\n this.rows = []; this.abort = new AbortController();\n this.lookup = lookup;\n this.refreshGit = refreshGit;\n this.onInstalled = onInstalled;\n }\n async load() {\n const saved = this.stateFile && await jsonFile(this.stateFile);\n if (saved?.version === 1) { this.lastAttempt = Number.isFinite(saved.lastAttempt) ? saved.lastAttempt : 0; this.checkedAt = saved.checkedAt; this.dismissed = saved.dismissed && typeof saved.dismissed === 'object' && !Array.isArray(saved.dismissed) ? saved.dismissed : {}; this.rows = Array.isArray(saved.rows) ? saved.rows.filter(r => ['github', 'npm'].includes(r.source?.kind)) : []; }\n }\n persist() {\n if (!this.stateFile) return Promise.resolve();\n const saved = structuredClone({ version: 1, lastAttempt: this.lastAttempt, checkedAt: this.checkedAt, dismissed: this.dismissed, rows: this.rows.filter(r => ['github', 'npm'].includes(r.source.kind)) });\n this.saveQueue = this.saveQueue.catch(() => {}).then(() => writePrivateJson(this.stateFile, saved)); return this.saveQueue;\n }\n reminderKey(row) { return JSON.stringify([row.name, row.source, row.version, row.latestVersion ?? row.latestCommit]); }\n reminders() { return this.rows.filter(r => r.status === 'available' && (!Object.hasOwn(this.dismissed, r.name) || this.dismissed[r.name] !== this.reminderKey(r))).map(r => ({ key: this.reminderKey(r), name: r.name, version: r.version, latestVersion: r.latestVersion, latestCommit: r.latestCommit })); }\n async dismiss(keys) {\n if (!Array.isArray(keys) || keys.length > 200 || keys.some(k => typeof k !== 'string')) throw Error('\u65E0\u6548\u7684\u63D0\u9192\u5217\u8868');\n for (const row of this.reminders()) if (keys.includes(row.key)) Object.defineProperty(this.dismissed, row.name, { value: row.key, enumerable: true, configurable: true, writable: true });\n await this.persist();\n }\n async tick() {\n if (this.flight || !this.state().available) return;\n // Revalidate cached notices against the local installed inventory, including\n // removals and updates made through DSH or another plugin manager.\n await this.list();\n if (this.abort.signal.aborted) return;\n if (this.flight || this.now() >= this.lastAttempt && this.now() - this.lastAttempt < 86400000) return;\n // Reserve before I/O: minute ticks and restarts cannot hammer failed sources.\n this.lastAttempt = this.now(); await this.persist();\n if (!this.flight && !this.abort.signal.aborted) this.check();\n }\n state() { return { available: !!this.service()?.listBundles && !!this.profile()?.dir,\n checkedAt: this.checkedAt, reminders: this.reminders(), autoCheckHours: 24, rows: this.rows.map(({ spec, ...row }) => ({ ...row, source: row.source.kind === 'unsupported' ? { kind: 'unsupported' } : row.source })), job: this.job, error: this.error }; }\n async list() {\n const service = this.service(), profile = this.profile();\n if (!service?.listBundles || !profile?.dir) { this.rows = []; return; }\n const [manifest, bundles, lock] = await Promise.all([jsonFile(join(profile.dir, 'package.json')), service.listBundles(), locks(profile.dir)]);\n if (!manifest) throw Error('\u5F53\u524D DSH \u914D\u7F6E\u7684\u63D2\u4EF6\u6E05\u5355\u65E0\u6CD5\u8BFB\u53D6');\n this.rows = bundles.filter(b => (b.installed || b.version) && manifest.dependencies?.[b.name]\n && b.removable !== false).map(b => {\n const spec = manifest.dependencies?.[b.name];\n const source = parsePluginSource(b.name, spec);\n const npm = lock.npm?.packages?.[`node_modules/${b.name}`]?.resolved;\n const pnpm = lock.pnpm?.importers?.['.']?.dependencies?.[b.name]?.version;\n const installed = lock.preferNpm ? npm ?? pnpm : pnpm ?? npm;\n const previous = this.rows.find(r => r.name === b.name && r.spec === spec && r.version === b.version && r.commit === githubCommit(installed));\n return { ...previous, name: b.name, version: b.version, enabled: b.enabled, spec, source,\n commit: githubCommit(installed), status: previous?.status ?? (source.kind === 'unsupported' ? 'unsupported' : 'unchecked'),\n ...(source.kind === 'unsupported' ? { message: '\u672C\u5730\u6587\u4EF6 / \u94FE\u63A5\u6765\u6E90\uFF0C\u8BF7\u901A\u8FC7\u539F\u5B89\u88C5\u65B9\u5F0F\u66F4\u65B0' } : {}) };\n });\n }\n async checkRow(row) {\n try {\n if (row.source.kind === 'npm') {\n const spec = `${row.source.package}@${row.source.tag}`;\n const found = await this.lookup(this.service(), this.profile(), spec, this.abort.signal);\n if (!found.version || found.problem && found.problem !== 'already-installed') throw Error(found.problem === 'not-found' ? 'npm \u4E2D\u672A\u627E\u5230\u8BE5\u5305\u6216\u9891\u9053' : 'npm \u67E5\u8BE2\u5931\u8D25\uFF1B\u8BF7\u68C0\u67E5 DSH \u7684\u7F51\u7EDC\u4E0E registry \u8BBE\u7F6E');\n if (!parseWorkBuddyVersion(found.version) || row.version && !parseWorkBuddyVersion(row.version)) throw Error('\u65E0\u6CD5\u6BD4\u8F83\u7248\u672C\u53F7');\n row.latestVersion = found.version;\n row.target = `${row.name}@${row.source.alias ? `npm:${row.source.package}@` : ''}${row.source.channel ? row.source.tag : found.version}`;\n row.status = !row.version || compareWorkBuddyVersions(found.version, row.version) > 0 ? 'available' : 'current';\n row.message = !row.version ? '\u5B89\u88C5\u6587\u4EF6\u4E0D\u53EF\u8BFB\uFF0C\u53EF\u91CD\u65B0\u5B89\u88C5\u8BE5\u6765\u6E90\u4FEE\u590D' : row.status === 'current' ? '\u5F53\u524D\u7248\u672C\u5DF2\u662F\u8BE5\u9891\u9053\u6700\u65B0\uFF0C\u6216\u9AD8\u4E8E\u8BE5\u9891\u9053' : undefined;\n } else if (row.source.kind === 'github') {\n const { owner, repo, ref } = row.source;\n const url = `https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/commits/${encodeURIComponent(ref ?? 'HEAD')}`;\n const found = await publicJson(url, this.fetchImpl, this.abort.signal);\n if (!/^[a-f0-9]{40}$/i.test(found.sha)) throw Error('GitHub \u8FD4\u56DE\u65E0\u6548\u63D0\u4EA4\u4FE1\u606F');\n row.latestCommit = found.sha.toLowerCase();\n row.target = `${row.name}@${row.spec}`;\n row.status = row.commit === row.latestCommit ? 'current' : 'available';\n row.message = row.commit ? (row.status === 'available' ? `\u63D0\u4EA4 ${short(row.commit)} \u2192 ${short(row.latestCommit)}` : '\u8BE5\u5206\u652F / \u6807\u7B7E\u7684\u63D0\u4EA4\u5DF2\u540C\u6B65') : '\u65E0\u6CD5\u8BFB\u53D6\u672C\u5730 Git \u63D0\u4EA4\uFF0C\u53EF\u91CD\u65B0\u5B89\u88C5\u5DF2\u68C0\u67E5\u7684\u6765\u6E90';\n if (ref && /^[a-f0-9]{7,40}$/i.test(ref)) { row.status = 'pinned'; row.message = '\u5B89\u88C5\u6765\u6E90\u56FA\u5B9A\u5728 Git \u63D0\u4EA4\uFF1B\u4FDD\u7559\u6B64\u63D0\u4EA4\uFF0C\u4E0D\u81EA\u52A8\u5207\u6362\u5206\u652F'; }\n }\n row.checkedAt = Date.now();\n row.checkedEnabled = row.enabled;\n } catch (error) { row.status = 'failed'; row.message = error.message; delete row.target; }\n }\n start(kind, task) {\n if (this.flight) throw Error('\u5DF2\u6709\u63D2\u4EF6\u64CD\u4F5C\u6B63\u5728\u6267\u884C\uFF0C\u8BF7\u7B49\u5F85\u5B8C\u6210');\n this.job = { id: randomUUID(), kind, state: 'running', startedAt: Date.now(), results: [], total: 0 };\n this.error = undefined;\n this.flight = Promise.resolve().then(() => task(this.job)).then(() => { this.job.state = this.job.cancelRequested ? 'cancelled' : 'done'; }, e => { this.job.state = this.job.cancelRequested ? 'cancelled' : 'failed'; this.job.message = e.message; })\n .finally(async () => { this.job.finishedAt = Date.now(); try { await this.persist(); } catch { this.error = '\u66F4\u65B0\u68C0\u67E5\u8BB0\u5F55\u672A\u80FD\u4FDD\u5B58\uFF0C\u8BF7\u68C0\u67E5\u672C\u5730\u76EE\u5F55\u6743\u9650'; } this.flight = undefined; });\n }\n check() {\n this.start('check', async job => {\n this.lastAttempt = this.now(); await this.persist();\n await this.list();\n const rows = this.rows.filter(r => ['npm', 'github'].includes(r.source.kind)); job.total = rows.length;\n // Small pool keeps registry requests bounded without making one failed plugin stop the list.\n let next = 0;\n await Promise.all(Array.from({ length: Math.min(3, rows.length) }, async () => {\n while (next < rows.length && !job.cancelRequested) { const row = rows[next++]; await this.checkRow(row); job.results.push({ name: row.name, status: row.status, message: row.message }); }\n }));\n this.checkedAt = Date.now();\n });\n }\n async installRow(row, registry) {\n const original = await jsonFile(join(this.profile().dir, 'package.json'));\n if (original?.dependencies?.[row.name] !== row.spec) throw Error('\u5B89\u88C5\u6765\u6E90\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5');\n const current = (await this.service().listBundles()).find(b => b.name === row.name);\n if (!current || current.enabled !== row.checkedEnabled || current.version !== row.version) throw Error('\u63D2\u4EF6\u7248\u672C\u6216\u542F\u7528\u72B6\u6001\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5');\n const options = { enabled: row.enabled, requestId: this.job.id, ...(registry ? { registry } : {}) };\n let result;\n if (row.source.kind === 'github') {\n this.gitAbort = new AbortController();\n try { result = await this.refreshGit(this.service(), this.profile(), row, options, AbortSignal.any([this.abort.signal, this.gitAbort.signal])); }\n finally { this.gitAbort = undefined; }\n } else result = await this.service().installBundle(row.target, options);\n if (result.packageResult && result.packageResult.exitCode !== 0 || ['failed', 'cancelled'].includes(result.application) || result.error) {\n return { name: row.name, status: 'failed', application: result.application,\n message: result.pendingBuilds?.length ? '\u4F9D\u8D56\u6784\u5EFA\u811A\u672C\u9700\u8981\u6388\u6743\uFF0C\u8BF7\u5230 DSH \u63D2\u4EF6\u5B89\u88C5\u9875\u5141\u8BB8\u8FD9\u4E9B\u811A\u672C\u540E\u91CD\u8BD5' : result.error?.code === 'incompatible-version' ? '\u63D2\u4EF6\u4E0E\u5F53\u524D DSH \u4E0D\u517C\u5BB9\uFF0C\u8BF7\u5148\u5347\u7EA7 DSH \u6216\u9009\u62E9\u517C\u5BB9\u7248\u672C' : `\u5B89\u88C5\u672A\u5B8C\u6210\uFF08${result.error?.code ?? result.packageResult?.kind ?? 'unknown'}\uFF09\uFF1B\u8BF7\u5230 DSH \u63D2\u4EF6\u9875\u67E5\u770B\u5B89\u88C5\u65E5\u5FD7`,\n pendingBuilds: result.pendingBuilds ?? [], logPath: result.packageResult?.logPath };\n }\n const installed = (await this.service().listBundles()).find(b => b.name === row.name);\n if (row.source.kind === 'npm' && installed?.version !== row.latestVersion) return { name: row.name, status: 'failed',\n message: `\u5B9E\u9645\u5B89\u88C5\u7248\u672C ${installed?.version ?? '\u672A\u77E5'} \u4E0E\u68C0\u67E5\u7248\u672C ${row.latestVersion} \u4E0D\u540C\uFF1B\u8BF7\u7A0D\u540E\u91CD\u65B0\u68C0\u67E5\uFF0C\u53EF\u80FD\u662F\u955C\u50CF\u5C1A\u672A\u540C\u6B65\u6216\u53D1\u884C\u65F6\u95F4\u9650\u5236` };\n if (row.source.kind === 'github') {\n const lock = await locks(this.profile().dir);\n const pnpm = lock.pnpm?.importers?.['.']?.dependencies?.[row.name]?.version, npm = lock.npm?.packages?.[`node_modules/${row.name}`]?.resolved;\n if (githubCommit(lock.preferNpm ? npm ?? pnpm : pnpm ?? npm) !== row.latestCommit) return { name: row.name, status: 'failed', restartRequired: true,\n message: '\u5B9E\u9645 Git \u63D0\u4EA4\u4E0E\u68C0\u67E5\u7ED3\u679C\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u540E\u91CD\u8BD5\uFF1B\u4E0D\u628A\u4ECD\u505C\u7559\u5728\u65E7\u9501\u6587\u4EF6\u7684\u5B89\u88C5\u62A5\u544A\u4E3A\u6210\u529F' };\n }\n const reloadPending = result.application === 'restart-required' && this.onInstalled?.(row.name) === true;\n return { name: row.name, status: 'installed', application: reloadPending ? 'reload-pending' : result.application, message: reloadPending ? '\u5DF2\u5B89\u88C5\uFF0C\u7B49\u5F85\u5F53\u524D\u64CD\u4F5C\u7ED3\u675F\u540E\u81EA\u52A8\u52A0\u8F7D\uFF1B\u8FD0\u884C\u7248\u672C\u89C1\u9762\u677F\u9876\u90E8' : result.application === 'restart-required' ? '\u5DF2\u5B89\u88C5\uFF0C\u5B8C\u5168\u9000\u51FA\u5E76\u91CD\u65B0\u6253\u5F00 DSH \u540E\u751F\u6548' : '\u5B89\u88C5\u5B8C\u6210', restartRequired: !reloadPending && result.application === 'restart-required' };\n }\n update(names, registry) {\n if (!Array.isArray(names) || !names.length || names.length > 200 || names.some(n => typeof n !== 'string') || new Set(names).size !== names.length) throw Error('\u8BF7\u9009\u62E9\u8981\u66F4\u65B0\u7684\u63D2\u4EF6');\n const selected = names.map(name => this.rows.find(r => r.name === name));\n if (selected.some(r => !r || !['available', 'failed'].includes(r.status) || !r.target || Date.now() - r.checkedAt > 600000)) throw Error('\u8BF7\u5148\u68C0\u67E5\u66F4\u65B0\uFF0C\u518D\u9009\u62E9\u53EF\u66F4\u65B0\u7684\u63D2\u4EF6\uFF08\u68C0\u67E5\u7ED3\u679C\u6709\u6548\u671F 10 \u5206\u949F\uFF09');\n // Updating this manager last avoids losing the batch if the host gains module reload support.\n selected.sort((a, b) => Number(a.name === 'dsh-multi-router') - Number(b.name === 'dsh-multi-router'));\n this.start('update', async job => {\n job.total = selected.length;\n for (const row of selected) {\n if (job.cancelRequested) break;\n job.current = row.name;\n let result;\n try { result = await this.installRow(row, registry); } catch (e) { result = { name: row.name, status: 'failed', message: e.message }; }\n job.results.push(result);\n row.status = result.status; row.message = result.message;\n }\n delete job.current; await this.list();\n });\n }\n install(spec, registry) {\n if (typeof spec !== 'string' || spec.length > 600 || spec.startsWith('-') || /[\\s\\x00-\\x1f]/.test(spec)) throw Error('\u8BF7\u8F93\u5165\u4E00\u4E2A npm \u5305\u540D\u6216 GitHub \u5B89\u88C5\u5730\u5740');\n const named = /^((?:@[^/]+\\/)?[^@]+)(?:@(.+))?$/.exec(spec);\n const github = parsePluginSource('placeholder', spec);\n const npm = named && parsePluginSource(named[1], named[2] || 'latest');\n if (github.kind !== 'github' && npm?.kind !== 'npm') throw Error('\u4EC5\u652F\u6301 npm \u5305\u540D / \u7248\u672C\u6216 github:\u7528\u6237/\u4ED3\u5E93');\n this.start('install', async job => {\n job.total = 1; job.current = spec;\n const result = await this.service().installBundle(spec, { requestId: job.id, ...(registry ? { registry } : {}) });\n const reloadPending = !result.error && result.packageResult?.exitCode === 0 && result.application === 'restart-required' && this.onInstalled?.(result.bundle) === true;\n job.results.push({ name: result.bundle ?? spec, status: result.error || ['failed', 'cancelled'].includes(result.application) || result.packageResult && result.packageResult.exitCode !== 0 ? 'failed' : 'installed',\n message: result.error ? `\u5B89\u88C5\u672A\u5B8C\u6210\uFF08${result.error.code}\uFF09\uFF0C\u8BF7\u67E5\u770B DSH \u63D2\u4EF6\u5B89\u88C5\u65E5\u5FD7` : reloadPending ? '\u5DF2\u5B89\u88C5\uFF0C\u7B49\u5F85\u5F53\u524D\u64CD\u4F5C\u7ED3\u675F\u540E\u81EA\u52A8\u52A0\u8F7D' : result.application === 'restart-required' ? '\u5DF2\u5B89\u88C5\uFF0C\u8BF7\u5B8C\u5168\u9000\u51FA\u5E76\u91CD\u542F DSH' : '\u5B89\u88C5\u5B8C\u6210',\n application: reloadPending ? 'reload-pending' : result.application, pendingBuilds: result.pendingBuilds ?? [], restartRequired: !reloadPending && result.application === 'restart-required' });\n delete job.current; await this.list();\n });\n }\n async action(input) {\n if (!this.state().available) throw Error('\u5F53\u524D DSH \u672A\u63D0\u4F9B\u63D2\u4EF6\u7BA1\u7406\u63A5\u53E3\uFF0C\u8BF7\u5347\u7EA7 DSH \u540E\u91CD\u8BD5');\n if (input.registry && !['https://registry.npmjs.org/', 'https://registry.npmmirror.com/'].includes(input.registry)) throw Error('\u65E0\u6548\u7684 npm \u6765\u6E90');\n if (input.action === 'plugins.list') { if (!this.flight) await this.list(); }\n else if (input.action === 'plugins.dismiss') await this.dismiss(input.keys);\n else if (input.action === 'plugins.check') this.check();\n else if (input.action === 'plugins.update') this.update(input.names, input.registry);\n else if (input.action === 'plugins.install') this.install(input.spec, input.registry);\n else if (input.action === 'plugins.cancel') { if (this.job?.state === 'running') { this.job.cancelRequested = true; if (this.gitAbort) this.gitAbort.abort(); else if (this.job.kind !== 'check') await this.service().cancelInstall?.(this.job.id); } }\n else throw Error('\u672A\u77E5\u63D2\u4EF6\u64CD\u4F5C');\n }\n}\n", "/**\n * Public update metadata and bounded version checking for WorkBuddy Connect.\n *\n * Two upstreams, strictly layered so the judgement never depends on the\n * enrichment: npm's dist-tags decide whether a newer release exists, and only\n * then is GitHub's release list consulted \u2014 one request that feeds both the\n * \"versions behind\" count and the per-release notes. Every upstream answer is\n * treated as untrusted input: bodies are size-capped while streaming, releases\n * are re-validated on the browser side by {@link parseWorkBuddyUpdateResult}\n * before anything renders.\n *\n * This module is host/browser shared and dependency-free by design (the client\n * bundle's runtime imports stay React + local modules only).\n *\n * @module dsh-workbuddy-connect/update\n */\n\nexport const WORKBUDDY_REPOSITORY_URL = 'https://github.com/corrinehu/dsh-workbuddy-connect'\nexport const WORKBUDDY_UPDATE_PACKAGE_NAME = 'dsh-workbuddy-connect'\nexport const WORKBUDDY_UPDATE_NPM_METADATA_URL = `https://registry.npmjs.org/-/package/${WORKBUDDY_UPDATE_PACKAGE_NAME}/dist-tags`\nexport const WORKBUDDY_UPDATE_RELEASES_API_URL = `${WORKBUDDY_REPOSITORY_URL.replace('https://github.com', 'https://api.github.com/repos')}/releases?per_page=100`\nexport const WORKBUDDY_RELEASE_PAGE_BASE = `${WORKBUDDY_REPOSITORY_URL}/releases/tag/`\nexport const WORKBUDDY_UPDATE_TIMEOUT_MS = 8_000\nexport const WORKBUDDY_UPDATE_MAX_METADATA_BYTES = 64 * 1024\nexport const WORKBUDDY_UPDATE_MAX_RELEASES_BYTES = 1024 * 1024\n/** GitHub caps one page at 100 releases; ours is far below that today. */\nconst RELEASES_LIST_MAX = 100\nconst RELEASE_NAME_MAX_CHARS = 200\nconst RELEASE_NOTES_MAX_CHARS = 16_000\n\n/** One release between the current and latest version, newest first. */\nexport interface WorkBuddyUpdateRelease {\n version: string\n /** Release title as written on GitHub, e.g. the bilingual summary line. */\n name?: string\n /** Cleaned release notes body, truncated. */\n notes?: string\n /** ISO publication time, validated loosely. */\n publishedAt?: string\n}\n\nexport type WorkBuddyUpdateResult =\n | {\n status: 'up-to-date'\n currentVersion: string\n latestVersion: string\n }\n | {\n status: 'update-available'\n currentVersion: string\n latestVersion: string\n releaseUrl: string\n /**\n * Releases between (current, latest], newest first. Empty \u2014 with\n * `versionsBehind` absent \u2014 when GitHub could not be reached: the\n * judgement (npm) stands, only the enrichment degrades.\n */\n releases: readonly WorkBuddyUpdateRelease[]\n /** Present iff the release list was fetched; equals `releases.length`. */\n versionsBehind?: number\n }\n | {\n status: 'unavailable'\n currentVersion: string\n reason: 'invalid-current-version' | 'registry-unavailable' | 'invalid-registry-response'\n }\n\nexport type WorkBuddyUpdateFetch = (input: string, init?: RequestInit) => Promise<Response>\n\ninterface ParsedVersion {\n major: number\n minor: number\n patch: number\n prerelease: Array<number | string>\n}\n\n/** Parse one exact SemVer version, accepting the conventional leading `v`. */\nexport function parseWorkBuddyVersion(raw: string): ParsedVersion | undefined {\n if (typeof raw !== 'string') return undefined\n const normalized = raw.startsWith('v') ? raw.slice(1) : raw\n const match = /^(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-]+)*)?$/u.exec(normalized)\n if (match === null) return undefined\n const rawPrerelease = match[4] === undefined ? [] : match[4].split('.')\n if (rawPrerelease.some(identifier => /^\\d+$/u.test(identifier) && !/^(0|[1-9]\\d*)$/u.test(identifier))) return undefined\n const prerelease = rawPrerelease.map(identifier => /^(0|[1-9]\\d*)$/u.test(identifier) ? Number(identifier) : identifier)\n if (prerelease.some(identifier => typeof identifier === 'number' && !Number.isSafeInteger(identifier))) return undefined\n const parsed = {\n major: Number(match[1]),\n minor: Number(match[2]),\n patch: Number(match[3]),\n prerelease,\n }\n return [parsed.major, parsed.minor, parsed.patch].every(Number.isSafeInteger) ? parsed : undefined\n}\n\n/**\n * One canonical spelling per SemVer value: leading `v` and build metadata\n * fold away, so `v0.6.4`, `0.6.4`, and `0.6.4+build` dedupe as one release.\n * Returns `undefined` for unparseable input; callers drop those first.\n */\nexport function canonicalWorkBuddyVersion(version: string): string | undefined {\n const parsed = parseWorkBuddyVersion(version)\n if (parsed === undefined) return undefined\n return `${String(parsed.major)}.${String(parsed.minor)}.${String(parsed.patch)}`\n + (parsed.prerelease.length === 0 ? '' : `-${parsed.prerelease.join('.')}`)\n}\n\nfunction compareIdentifiers(left: number | string, right: number | string): number {\n if (typeof left === 'number' && typeof right === 'number') return left < right ? -1 : left > right ? 1 : 0\n if (typeof left === 'number') return -1\n if (typeof right === 'number') return 1\n return left < right ? -1 : left > right ? 1 : 0\n}\n\n/** Compare two versions using SemVer precedence (build metadata ignored). */\nexport function compareWorkBuddyVersions(left: string, right: string): number {\n const a = parseWorkBuddyVersion(left)\n const b = parseWorkBuddyVersion(right)\n if (a === undefined || b === undefined) throw new TypeError('invalid WorkBuddy Connect version')\n for (const [aPart, bPart] of [[a.major, b.major], [a.minor, b.minor], [a.patch, b.patch]] as const) {\n if (aPart !== bPart) return aPart < bPart ? -1 : 1\n }\n if (a.prerelease.length === 0 && b.prerelease.length !== 0) return 1\n if (a.prerelease.length !== 0 && b.prerelease.length === 0) return -1\n for (let index = 0; index < Math.max(a.prerelease.length, b.prerelease.length); index += 1) {\n const aPart = a.prerelease[index]\n const bPart = b.prerelease[index]\n if (aPart === undefined) return -1\n if (bPart === undefined) return 1\n const comparison = compareIdentifiers(aPart, bPart)\n if (comparison !== 0) return comparison\n }\n return 0\n}\n\nfunction boundedText(value: string, maxBytes: number): string {\n const bytes = new TextEncoder().encode(value)\n if (bytes.byteLength > maxBytes) throw new RangeError('update response is too large')\n return value\n}\n\nasync function readBoundedText(response: Response, maxBytes: number): Promise<string> {\n if (response.body === null) return boundedText(await response.text(), maxBytes)\n const reader = response.body.getReader()\n const decoder = new TextDecoder()\n const chunks: string[] = []\n let total = 0\n try {\n while (true) {\n const next = await reader.read()\n if (next.done) break\n total += next.value.byteLength\n if (total > maxBytes) {\n await reader.cancel()\n throw new RangeError('update response is too large')\n }\n chunks.push(decoder.decode(next.value, { stream: true }))\n }\n chunks.push(decoder.decode())\n return chunks.join('')\n } finally {\n reader.releaseLock()\n }\n}\n\nasync function fetchBounded(\n fetchImpl: WorkBuddyUpdateFetch,\n url: string,\n maxBytes: number,\n timeoutMs: number,\n headers: Record<string, string>,\n): Promise<{ response: Response, text: string }> {\n const controller = new AbortController()\n const timer = setTimeout(() => { controller.abort(new Error('update request timed out')) }, timeoutMs)\n try {\n const response = await fetchImpl(url, { headers, signal: controller.signal })\n const text = await readBoundedText(response, maxBytes)\n return { response, text }\n } finally {\n clearTimeout(timer)\n }\n}\n\n/** Strip control characters, normalize newlines, and cap the length. */\nfunction cleanReleaseText(value: unknown, maxLength: number): string | undefined {\n if (typeof value !== 'string' || value.length === 0) return undefined\n const clean = value\n .replace(/[\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]/gu, '')\n .replace(/\\r\\n?/gu, '\\n')\n .trim()\n .slice(0, maxLength)\n return clean.length === 0 ? undefined : clean\n}\n\nfunction cleanPublishedAt(value: unknown): string | undefined {\n return typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2}T/iu.test(value) ? value.slice(0, 64) : undefined\n}\n\n/**\n * The `latest` dist-tag only. Pre-release channels are not this plugin's\n * release line, so recommending one would be wrong even when newer.\n */\nfunction latestDistTag(value: unknown): string | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined\n const tags = (value as Record<string, unknown>)['dist-tags'] ?? value\n if (typeof tags !== 'object' || tags === null || Array.isArray(tags)) return undefined\n const candidate = (tags as Record<string, unknown>)['latest']\n return typeof candidate === 'string' && parseWorkBuddyVersion(candidate) !== undefined ? candidate : undefined\n}\n\nexport function releasePageUrl(version: string): string {\n return `${WORKBUDDY_RELEASE_PAGE_BASE}v${version}`\n}\n\n/**\n * Parse GitHub's release-list page into the in-range releases, newest first.\n * Unknown entry shapes are skipped, never fatal: the count and the notes both\n * degrade per-entry rather than dropping the whole judgement.\n */\nfunction releasesInRange(currentVersion: string, latestVersion: string, value: unknown): WorkBuddyUpdateRelease[] | undefined {\n if (!Array.isArray(value) || value.length > RELEASES_LIST_MAX) return undefined\n const releases: WorkBuddyUpdateRelease[] = []\n const seen = new Set<string>()\n for (const raw of value) {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) continue\n const entry = raw as Record<string, unknown>\n const tag = entry['tag_name']\n if (typeof tag !== 'string') continue\n const version = parseWorkBuddyVersion(tag)\n if (version === undefined) continue\n if (compareWorkBuddyVersions(tag, currentVersion) <= 0 || compareWorkBuddyVersions(tag, latestVersion) > 0) continue\n // Dedupe by SemVer value, not spelling: `v0.6.4` and `0.6.4` are one\n // release, and neither the count nor the rows may list it twice.\n const canonical = canonicalWorkBuddyVersion(tag)\n if (canonical === undefined || seen.has(canonical)) continue\n seen.add(canonical)\n const name = cleanReleaseText(entry['name'], RELEASE_NAME_MAX_CHARS)\n const notes = cleanReleaseText(entry['body'], RELEASE_NOTES_MAX_CHARS)\n const publishedAt = cleanPublishedAt(entry['published_at'])\n releases.push({ version: tag, ...name === undefined ? {} : { name }, ...notes === undefined ? {} : { notes }, ...publishedAt === undefined ? {} : { publishedAt } })\n }\n releases.sort((left, right) => compareWorkBuddyVersions(right.version, left.version))\n return releases\n}\n\n/** Enrich an available update from GitHub's release list; degrade on failure. */\nasync function releaseList(\n currentVersion: string,\n latestVersion: string,\n fetchImpl: WorkBuddyUpdateFetch,\n timeoutMs: number,\n): Promise<WorkBuddyUpdateRelease[] | undefined> {\n try {\n const { response, text } = await fetchBounded(\n fetchImpl,\n WORKBUDDY_UPDATE_RELEASES_API_URL,\n WORKBUDDY_UPDATE_MAX_RELEASES_BYTES,\n timeoutMs,\n { accept: 'application/vnd.github+json' },\n )\n if (!response.ok) return undefined\n return releasesInRange(currentVersion, latestVersion, JSON.parse(text) as unknown)\n } catch {\n return undefined\n }\n}\n\n/** Check npm's public dist-tags and enrich an available update with release notes. */\nexport async function checkWorkBuddyUpdate(options: {\n currentVersion: string\n fetchImpl?: WorkBuddyUpdateFetch\n timeoutMs?: number\n}): Promise<WorkBuddyUpdateResult> {\n const { currentVersion } = options\n if (parseWorkBuddyVersion(currentVersion) === undefined) {\n return { status: 'unavailable', currentVersion, reason: 'invalid-current-version' }\n }\n const fetchImpl = options.fetchImpl ?? fetch\n const timeoutMs = options.timeoutMs ?? WORKBUDDY_UPDATE_TIMEOUT_MS\n let metadata: unknown\n try {\n const { response, text } = await fetchBounded(\n fetchImpl,\n WORKBUDDY_UPDATE_NPM_METADATA_URL,\n WORKBUDDY_UPDATE_MAX_METADATA_BYTES,\n timeoutMs,\n { accept: 'application/json' },\n )\n if (!response.ok) return { status: 'unavailable', currentVersion, reason: 'registry-unavailable' }\n metadata = JSON.parse(text) as unknown\n } catch (error: unknown) {\n return {\n status: 'unavailable',\n currentVersion,\n reason: error instanceof SyntaxError || error instanceof RangeError ? 'invalid-registry-response' : 'registry-unavailable',\n }\n }\n const latestVersion = latestDistTag(metadata)\n if (latestVersion === undefined) return { status: 'unavailable', currentVersion, reason: 'invalid-registry-response' }\n if (compareWorkBuddyVersions(latestVersion, currentVersion) <= 0) {\n return { status: 'up-to-date', currentVersion, latestVersion: currentVersion }\n }\n const releases = await releaseList(currentVersion, latestVersion, fetchImpl, timeoutMs)\n return {\n status: 'update-available',\n currentVersion,\n latestVersion,\n releaseUrl: releasePageUrl(latestVersion),\n releases: releases ?? [],\n ...releases === undefined ? {} : { versionsBehind: releases.length },\n }\n}\n\n/**\n * Validate a route response before the browser renders it. Same distrust as\n * the host side: the versions must parse, `update-available` must still hold\n * under a fresh comparison, the release URL must equal the one derived from\n * the version, and every listed release must fall in (current, latest] \u2014 a\n * host that invents content fails closed here.\n */\nexport function parseWorkBuddyUpdateResult(value: unknown): WorkBuddyUpdateResult | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined\n const record = value as Record<string, unknown>\n const currentVersion = record['currentVersion']\n if (typeof currentVersion !== 'string' || parseWorkBuddyVersion(currentVersion) === undefined) return undefined\n if (record['status'] === 'unavailable') {\n const reason = record['reason']\n return reason === 'invalid-current-version' || reason === 'registry-unavailable' || reason === 'invalid-registry-response'\n ? { status: 'unavailable', currentVersion, reason }\n : undefined\n }\n const latestVersion = record['latestVersion']\n if (typeof latestVersion !== 'string' || parseWorkBuddyVersion(latestVersion) === undefined) return undefined\n if (record['status'] === 'up-to-date') {\n return { status: 'up-to-date', currentVersion, latestVersion }\n }\n if (record['status'] !== 'update-available' || compareWorkBuddyVersions(latestVersion, currentVersion) <= 0) return undefined\n const expectedUrl = releasePageUrl(latestVersion)\n if (record['releaseUrl'] !== expectedUrl) return undefined\n if (!Array.isArray(record['releases']) || record['releases'].length > RELEASES_LIST_MAX) return undefined\n const seen = new Set<string>()\n const releases: WorkBuddyUpdateRelease[] = []\n for (const raw of record['releases']) {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) return undefined\n const entry = raw as Record<string, unknown>\n const version = entry['version']\n if (typeof version !== 'string' || parseWorkBuddyVersion(version) === undefined) return undefined\n // The range is re-derived, not trusted: an out-of-range or duplicate\n // entry means the document is not what this checker produced. Duplicates\n // count by SemVer value \u2014 two spellings of one version are as rejectable\n // as the same string twice.\n if (compareWorkBuddyVersions(version, currentVersion) <= 0 || compareWorkBuddyVersions(version, latestVersion) > 0) return undefined\n const canonical = canonicalWorkBuddyVersion(version)\n if (canonical === undefined || seen.has(canonical)) return undefined\n seen.add(canonical)\n const name = cleanReleaseText(entry['name'], RELEASE_NAME_MAX_CHARS)\n const notes = cleanReleaseText(entry['notes'], RELEASE_NOTES_MAX_CHARS)\n const publishedAt = cleanPublishedAt(entry['publishedAt'])\n releases.push({ version, ...name === undefined ? {} : { name }, ...notes === undefined ? {} : { notes }, ...publishedAt === undefined ? {} : { publishedAt } })\n }\n const rawVersionsBehind = record['versionsBehind']\n if (rawVersionsBehind !== undefined\n && (typeof rawVersionsBehind !== 'number' || !Number.isSafeInteger(rawVersionsBehind) || rawVersionsBehind !== releases.length)) return undefined\n return {\n status: 'update-available',\n currentVersion,\n latestVersion,\n releaseUrl: expectedUrl,\n releases,\n ...rawVersionsBehind === undefined ? {} : { versionsBehind: rawVersionsBehind },\n }\n}\n", "// SMS endpoint flow adapted from L0NE-6/WorkBuddy-Daily (MIT); see THIRD_PARTY_NOTICES.md.\nimport { randomBytes } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { withFileLock } from '@deepseek-ai/dsh-atomic-write';\nimport { writePrivateJson } from './config.mjs';\nimport { workbuddyToken, refreshWorkBuddyCheckinCredential } from './clients.mjs';\nimport { readLimitedText } from '../upstream/qoder/src/qoder/transport/request.ts';\n\nexport class WorkBuddyLogin {\n constructor(file, { fetchImpl = (...args) => fetch(...args), now = Date.now } = {}) {\n this.file = file; this.fetchImpl = fetchImpl; this.now = now; this.abort = new AbortController();\n this.abort.signal.addEventListener('abort', () => this.finish(), { once: true });\n }\n async reserve(field, ms) {\n await withFileLock(this.file, async () => {\n let state = {}; try { state = JSON.parse(await readFile(this.file, 'utf8')); } catch (e) { if (e.code !== 'ENOENT') throw Error('\u767B\u5F55\u51B7\u5374\u8BB0\u5F55\u4E0D\u53EF\u8BFB\uFF0C\u8BF7\u68C0\u67E5\u672C\u673A\u6587\u4EF6'); }\n if (state.pausedUntil > this.now() || state[field] > this.now()) throw Error('\u8BF7\u6C42\u51B7\u5374\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\uFF1B\u5E73\u53F0\u9650\u5236\u8BF7\u5728\u5B98\u65B9\u5BA2\u6237\u7AEF\u5904\u7406');\n state[field] = this.now() + ms; await writePrivateJson(this.file, state);\n });\n }\n async pause() {\n this.pending = undefined;\n await withFileLock(this.file, async () => {\n const state = JSON.parse(await readFile(this.file, 'utf8')); state.pausedUntil = this.now() + 15 * 60000;\n await writePrivateJson(this.file, state);\n });\n }\n async post(path, body) {\n let response;\n try { response = await this.fetchImpl(`https://www.workbuddy.cn/v2/plugin/login/${path}`, {\n method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', Origin: 'https://www.workbuddy.cn', Referer: 'https://www.workbuddy.cn/' },\n body: JSON.stringify(body), signal: AbortSignal.any([this.abort.signal, AbortSignal.timeout(30000)]), redirect: 'error',\n }); } catch { throw Error('\u767B\u5F55\u8BF7\u6C42\u672A\u5B8C\u6210\uFF0C\u8BF7\u7A0D\u540E\u624B\u52A8\u91CD\u8BD5\uFF1B\u4E0D\u4F1A\u81EA\u52A8\u91CD\u53D1\u77ED\u4FE1'); }\n if ([403, 429].includes(response.status)) { await this.pause(); throw Error('\u5E73\u53F0\u9650\u5236\u6216\u9700\u8981\u9A8C\u8BC1\uFF0C\u5DF2\u6682\u505C\u767B\u5F55\u8BF7\u6C42\uFF0C\u8BF7\u4F7F\u7528\u5B98\u65B9\u5BA2\u6237\u7AEF'); }\n if (!response.ok) throw Error('\u5B98\u65B9\u767B\u5F55\u670D\u52A1\u6682\u4E0D\u53EF\u7528\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5');\n let result; try { result = JSON.parse(await readLimitedText(response, 256 * 1024, 'Login')); } catch { throw Error('\u767B\u5F55\u54CD\u5E94\u65E0\u6CD5\u8BC6\u522B\uFF0C\u8BF7\u4F7F\u7528\u5B98\u65B9\u5BA2\u6237\u7AEF'); }\n if (result?.code !== 0) {\n if ([403, 429].includes(result?.code) || /\u9891\u7E41|\u56FE\u5F62\u9A8C\u8BC1\u7801|\u6ED1\u5757|\u5B89\u5168\u9A8C\u8BC1|captcha|risk|too many|frequent|\u9A8C\u8BC1\u5931\u8D25\u6B21\u6570/i.test(result?.msg || '')) {\n await this.pause(); throw Error('\u5E73\u53F0\u9650\u5236\u6216\u9700\u8981\u9A8C\u8BC1\uFF0C\u5DF2\u6682\u505C\u767B\u5F55\u8BF7\u6C42\uFF0C\u8BF7\u4F7F\u7528\u5B98\u65B9\u5BA2\u6237\u7AEF');\n }\n throw Error(path === 'token' ? '\u767B\u5F55\u672A\u6210\u529F\uFF0C\u8BF7\u68C0\u67E5\u9A8C\u8BC1\u7801\u662F\u5426\u6B63\u786E\u3001\u8FC7\u671F\uFF1B\u4EC5\u652F\u6301\u5DF2\u6709\u8D26\u53F7' : '\u77ED\u4FE1\u672A\u53D1\u9001\u6210\u529F\uFF0C\u8BF7\u786E\u8BA4\u5DF2\u6709\u8D26\u53F7\u53CA\u624B\u673A\u53F7\uFF0C\u6216\u4F7F\u7528\u5B98\u65B9\u5BA2\u6237\u7AEF');\n }\n return result.data ?? {};\n }\n async send(phone) {\n if (typeof phone !== 'string' || !/^1[3-9]\\d{9}$/.test(phone)) throw Error('\u8BF7\u8F93\u5165 11 \u4F4D\u4E2D\u56FD\u5927\u9646\u624B\u673A\u53F7');\n if (this.flight) throw Error('\u767B\u5F55\u8BF7\u6C42\u6B63\u5728\u5904\u7406\u4E2D');\n this.flight = (async () => {\n await this.reserve('smsAt', 60000); this.pending = undefined;\n const data = await this.post('send-sms', { phone });\n const expires = Math.min(300, Math.max(1, Number(data.expires_in) || 300)) * 1000;\n this.pending = { phone, challenge: randomBytes(24).toString('hex'), expiresAt: this.now() + expires, attempts: 0 };\n clearTimeout(this.expiryTimer); this.expiryTimer = setTimeout(() => this.finish(), expires); this.expiryTimer.unref();\n return { challenge: this.pending.challenge, expiresAt: this.pending.expiresAt, resendAt: this.now() + 60000 };\n })();\n try { return await this.flight; } finally { this.flight = undefined; }\n }\n async complete(challenge, code, verify = true) {\n if (typeof challenge !== 'string' || !this.pending || challenge !== this.pending.challenge || this.pending.expiresAt <= this.now()) throw Error('\u672C\u6B21\u767B\u5F55\u5DF2\u8FC7\u671F\u6216\u63D2\u4EF6\u5DF2\u91CD\u542F\uFF0C\u8BF7\u91CD\u65B0\u83B7\u53D6\u9A8C\u8BC1\u7801');\n if (this.flight) throw Error('\u767B\u5F55\u8BF7\u6C42\u6B63\u5728\u5904\u7406\u4E2D');\n if (this.pending.document) return this.pending;\n if (typeof code !== 'string' || !/^\\d{4,8}$/.test(code) || typeof verify !== 'boolean') throw Error('\u8BF7\u8F93\u5165\u6536\u5230\u7684\u77ED\u4FE1\u9A8C\u8BC1\u7801');\n if (this.pending.attempts >= 5) throw Error('\u672C\u6B21\u9A8C\u8BC1\u7801\u5C1D\u8BD5\u6B21\u6570\u5DF2\u8FBE\u4E0A\u9650\uFF0C\u8BF7\u7A0D\u540E\u91CD\u65B0\u83B7\u53D6');\n this.flight = (async () => {\n await this.reserve('loginAt', 5000); const pending = this.pending; pending.attempts++;\n const data = await this.post('token', { login_method: 'phone', phone: pending.phone, sms_code: code });\n const accessToken = data.accessToken || data.access_token, refreshToken = data.refreshToken || data.refresh_token;\n let token; try { token = workbuddyToken(accessToken); } catch { throw Error('\u767B\u5F55\u8FD4\u56DE\u7684\u4EE4\u724C\u4E0D\u5C5E\u4E8E WorkBuddy \u4E2D\u56FD\u7248\uFF0C\u8BF7\u4F7F\u7528\u5B98\u65B9\u5BA2\u6237\u7AEF'); }\n if (typeof refreshToken !== 'string' || !refreshToken || !Number.isFinite(token.exp) || token.exp * 1000 <= this.now()) throw Error('\u767B\u5F55\u54CD\u5E94\u7F3A\u5C11\u6709\u6548\u51ED\u8BC1\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55');\n let credential = { accessToken, refreshToken, uid: token.sub, expiresAtMs: token.exp * 1000, domain: 'www.workbuddy.cn', source: 'dsh' };\n if (verify) {\n try {\n const rotated = await refreshWorkBuddyCheckinCredential(credential, { fetchImpl: this.fetchImpl, signal: AbortSignal.any([this.abort.signal, AbortSignal.timeout(30000)]) });\n credential = { ...credential, accessToken: rotated.accessToken, refreshToken: rotated.refreshToken || credential.refreshToken,\n expiresAtMs: Date.now() + rotated.expiresInSec * 1000 };\n } catch { pending.warning = '\u767B\u5F55\u51ED\u8BC1\u5DF2\u4FDD\u5B58\uFF0C\u4F46\u5237\u65B0\u4EE4\u724C\u9A8C\u8BC1\u672A\u901A\u8FC7\uFF1B\u8BF7\u7A0D\u540E\u5728\u8D26\u53F7\u8BE6\u60C5\u68C0\u67E5\u767B\u5F55\u6709\u6548\u671F\u3002'; }\n }\n // Keep only the short-lived server-side result so a save conflict can retry without consuming the SMS again.\n delete pending.phone;\n pending.document = { version: 1, credential }; return pending;\n })();\n try { return await this.flight; } finally { this.flight = undefined; }\n }\n finish() { clearTimeout(this.expiryTimer); this.pending = undefined; }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["randomBytes", "readFile", "mkdir", "mkdtemp", "rm", "dirname", "join", "relative", "withFileLock", "dirname", "join", "join", "dirname", "rm", "join", "writeFileAtomic", "join", "require", "options", "rm", "writeFileAtomic", "randomBytes", "readFile", "withFileLock", "withFileLock", "readFile", "randomBytes", "join", "dirname", "readFile", "withFileLock", "a", "mkdir", "mkdtemp", "relative", "rm", "models", "randomBytes"]
|
|
7
|
+
}
|
|
@@ -15,6 +15,7 @@ import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
|
15
15
|
import { Readable } from "node:stream";
|
|
16
16
|
import { pipeline } from "node:stream/promises";
|
|
17
17
|
function createShim(router, { modelPrefix = "" } = {}) {
|
|
18
|
+
let active = 0;
|
|
18
19
|
const secret = randomBytes(32).toString("base64url");
|
|
19
20
|
const server = createServer((req, res) => {
|
|
20
21
|
void handle(req, res);
|
|
@@ -29,6 +30,7 @@ function createShim(router, { modelPrefix = "" } = {}) {
|
|
|
29
30
|
res.end(JSON.stringify(value));
|
|
30
31
|
};
|
|
31
32
|
async function handle(req, res) {
|
|
33
|
+
active++;
|
|
32
34
|
const controller = new AbortController();
|
|
33
35
|
req.on("aborted", () => controller.abort());
|
|
34
36
|
res.on("close", () => {
|
|
@@ -93,19 +95,21 @@ function createShim(router, { modelPrefix = "" } = {}) {
|
|
|
93
95
|
hint: error instanceof RouteError ? error.hint : void 0,
|
|
94
96
|
attempts: error instanceof RouteError ? error.attempts : []
|
|
95
97
|
} });
|
|
98
|
+
} finally {
|
|
99
|
+
active--;
|
|
96
100
|
}
|
|
97
101
|
}
|
|
98
102
|
return {
|
|
99
103
|
ready,
|
|
104
|
+
active: () => active,
|
|
100
105
|
token: () => secret,
|
|
101
106
|
baseUrl: () => `http://127.0.0.1:${server.address().port}`,
|
|
107
|
+
// Stop accepting new work, let an already streaming response finish. A
|
|
108
|
+
// reload can race a call that began immediately after the idle check.
|
|
102
109
|
close: async () => {
|
|
103
110
|
await ready.catch(() => {
|
|
104
111
|
});
|
|
105
|
-
await new Promise((resolve) =>
|
|
106
|
-
server.close(resolve);
|
|
107
|
-
server.closeAllConnections();
|
|
108
|
-
});
|
|
112
|
+
await new Promise((resolve) => server.close(resolve));
|
|
109
113
|
}
|
|
110
114
|
};
|
|
111
115
|
}
|
|
@@ -113,4 +117,4 @@ function createShim(router, { modelPrefix = "" } = {}) {
|
|
|
113
117
|
export {
|
|
114
118
|
createShim
|
|
115
119
|
};
|
|
116
|
-
//# sourceMappingURL=chunk-
|
|
120
|
+
//# sourceMappingURL=chunk-P43AWJ4Q.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/shim.mjs"],
|
|
4
|
+
"sourcesContent": ["import { createServer } from 'node:http';\nimport { randomBytes, timingSafeEqual } from 'node:crypto';\nimport { Readable } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\nimport { hostIsLoopback, originIsLoopback } from '../upstream/workbuddy/src/loopback.ts';\nimport { RouteError } from './router.mjs';\nimport { REASONING_EFFORTS } from './reasoning.mjs';\n\nexport function createShim(router, { modelPrefix = '' } = {}) {\n let active = 0;\n const secret = randomBytes(32).toString('base64url');\n const server = createServer((req, res) => { void handle(req, res); });\n const ready = new Promise((resolve, reject) => {\n server.once('listening', resolve); server.once('error', reject);\n });\n server.listen(0, '127.0.0.1');\n const json = (res, status, value) => {\n res.writeHead(status, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(value));\n };\n async function handle(req, res) {\n active++;\n const controller = new AbortController();\n req.on('aborted', () => controller.abort());\n res.on('close', () => { if (!res.writableEnded) controller.abort(); });\n const signal = AbortSignal.any([controller.signal, AbortSignal.timeout(router.config.requestTimeoutMs)]);\n try {\n if (!hostIsLoopback(req.headers.host) || !originIsLoopback(req.headers.origin)) throw new RouteError(403, 'loopback_required');\n const bearer = Buffer.from((req.headers.authorization ?? '').replace(/^Bearer\\s+/i, ''));\n const expected = Buffer.from(secret);\n if (bearer.length !== expected.length || !timingSafeEqual(bearer, expected)) throw new RouteError(401, 'unauthorized');\n if (req.method === 'GET' && req.url === '/router/status') { json(res, 200, router.status()); return; }\n if (req.method === 'GET' && req.url === '/v1/models') {\n json(res, 200, { object: 'list', data: Object.keys(router.config.routes).filter(id => modelPrefix ? id.startsWith(modelPrefix) : !id.includes('::'))\n .map(id => ({ id: modelPrefix ? id.slice(modelPrefix.length) : id, object: 'model', created: 0, owned_by: 'multi-router' })) }); return;\n }\n if (req.method !== 'POST' || req.url !== '/v1/chat/completions') throw new RouteError(404, 'not_found');\n if (!/^application\\/json(?:\\s*;|$)/i.test(req.headers['content-type'] ?? '')) throw new RouteError(415, 'json_required');\n let size = 0; const chunks = [];\n for await (const chunk of req) {\n size += chunk.length;\n if (size > 32 * 1024 * 1024) throw new RouteError(413, 'request_too_large');\n chunks.push(chunk); signal.throwIfAborted();\n }\n let input;\n try { input = JSON.parse(Buffer.concat(chunks).toString('utf8')); }\n catch { throw new RouteError(400, 'invalid_json'); }\n if (!input || typeof input !== 'object' || Array.isArray(input)) throw new RouteError(400, 'invalid_request');\n const effort = req.headers['x-multi-router-reasoning'];\n if (effort !== undefined) {\n if (effort !== 'default' && !REASONING_EFFORTS.includes(effort)) throw new RouteError(400, 'invalid_reasoning_effort');\n input.reasoning_effort = effort === 'default' ? null : effort;\n }\n const selected = await router.chat({ ...input, model: modelPrefix + input.model }, signal, { callId: typeof req.headers['x-multi-router-call'] === 'string' ? req.headers['x-multi-router-call'] : undefined, session: typeof req.headers['x-multi-router-session'] === 'string' ? req.headers['x-multi-router-session'] : undefined });\n signal.throwIfAborted();\n res.writeHead(200, { 'Content-Type': 'text/event-stream; charset=utf-8', 'Cache-Control': 'no-cache',\n 'X-Accel-Buffering': 'no', 'X-Router-Account': selected.account, 'X-Router-Provider': selected.provider });\n await pipeline(Readable.fromWeb(selected.response.body), res, { signal });\n } catch (error) {\n if (res.destroyed) return;\n if (res.headersSent) { res.destroy(); return; }\n const status = error instanceof RouteError ? error.status : signal.aborted ? 504 : 500;\n json(res, status, { error: { type: error instanceof RouteError ? error.code : signal.aborted ? 'request_timeout' : 'internal_error',\n message: error instanceof RouteError ? error.message : 'Router request failed',\n hint: error instanceof RouteError ? error.hint : undefined,\n attempts: error instanceof RouteError ? error.attempts : [] } });\n } finally { active--; }\n }\n return { ready, active: () => active, token: () => secret, baseUrl: () => `http://127.0.0.1:${server.address().port}`,\n // Stop accepting new work, let an already streaming response finish. A\n // reload can race a call that began immediately after the idle check.\n close: async () => { await ready.catch(() => {}); await new Promise(resolve => server.close(resolve)); } };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|