dsh-multi-router 0.6.10 → 0.6.12
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 +12 -0
- package/README.md +13 -3
- package/cordis.patch.yml +2 -2
- package/lib/api-service.js +2 -2
- package/lib/{chunk-R2Z4WGR6.js → chunk-4L2CBGXN.js} +31 -27
- package/lib/chunk-4L2CBGXN.js.map +7 -0
- package/lib/{chunk-LXDLKLM6.js → chunk-NZF36O5I.js} +2 -2
- package/lib/{chunk-47YTECKF.js → chunk-TM5XDMGY.js} +2 -2
- package/lib/{chunk-P7CNCBSY.js → chunk-V37VG7MN.js} +62 -20
- package/lib/chunk-V37VG7MN.js.map +7 -0
- package/lib/{chunk-LH6RKOZD.js → chunk-WDIT4E2W.js} +2 -2
- package/lib/cli.js +2 -2
- package/lib/client.js +14 -2
- package/lib/client.js.map +2 -2
- package/lib/clients.js +2 -2
- package/lib/{host-v0.6.10.js → host-v0.6.12.js} +5 -5
- package/lib/host.js +5 -5
- package/lib/index.js +5 -5
- package/lib/manager.js +4 -4
- package/lib/router.js +1 -1
- package/lib/shim.js +2 -2
- package/package.json +1 -1
- package/lib/chunk-P7CNCBSY.js.map +0 -7
- package/lib/chunk-R2Z4WGR6.js.map +0 -7
- /package/lib/{chunk-LXDLKLM6.js.map → chunk-NZF36O5I.js.map} +0 -0
- /package/lib/{chunk-47YTECKF.js.map → chunk-TM5XDMGY.js.map} +0 -0
- /package/lib/{chunk-LH6RKOZD.js.map → chunk-WDIT4E2W.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。版本号从 `0.1` 起以功能迭代为主,接口在 `1.0` 前可能变化。
|
|
4
4
|
|
|
5
|
+
## 0.6.12
|
|
6
|
+
|
|
7
|
+
- 插件更新确认框增加「允许本次指定版本立即安装」选项,默认勾选、可关闭;确认后仅保存所示 npm 包与确切版本的等待期例外,无需手动修改配置。每次更新仍需确认所示版本,其他依赖、兼容性和脚本策略保持不变。
|
|
8
|
+
- 校验确认版本与检查快照一致,保留原 YAML 注释及策略,合并同包的版本例外;配置无效或不可写时停止安装,避免误关全局保护。
|
|
9
|
+
- 兼容新版 DSH 将 `installBundle` 限为新安装的行为:收到 `already-installed` 后使用官方更新执行器,继续验证实际安装版本。
|
|
10
|
+
|
|
11
|
+
## 0.6.11
|
|
12
|
+
|
|
13
|
+
- 修复 0.6.10 引入的回归:「积分使用均衡」在临期账号之间不再生效。0.6.10 按**精确到期日**分组,到期日不同的临期账号各自成为独立分组,降权只在组内进行,于是最早到期的账号用完额度后仍会一直霸占请求,直到积分包耗尽或到期——恰好废掉了「每用满阈值就换账号」这个功能本身。
|
|
14
|
+
- 分组改为按**是否持有临期积分**:临期账号整体排在非临期账号之前(临期优先不被折扣与均衡破坏),临期账号之间仍正常按额度轮换。折扣排序则仍按精确到期日分组,因为倍率与到期时间无关,不能把到期更晚但更便宜的积分包排到前面。
|
|
15
|
+
- 新增回归测试覆盖临期组内的额度轮换,并已验证按精确到期日分组时该测试立即失败。
|
|
16
|
+
|
|
5
17
|
## 0.6.10
|
|
6
18
|
|
|
7
19
|
- 修复「按积分折扣排序」与「积分使用均衡」会打乱临期积分优先级的问题:两者此前都是对全部候选做整体重排,因此一个更便宜、或本轮还没用完额度的非临期账号,可能插到仍有临期积分的账号前面。
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
一个插件内置 WorkBuddy、Trae、Qoder 的认证、模型发现和聊天传输,提供三家的多账号池及集中路由。运行不依赖原来三个 DSH 插件;三家代码随安装包一起打包。基于 MIT 上游,固定版本见 `upstream-lock.json`,许可见 `THIRD_PARTY_NOTICES.md`。
|
|
8
8
|
|
|
9
|
-
版本:0.6.
|
|
9
|
+
版本:0.6.12。适配 DSH Desktop / Web 0.2.1-rc.2(同时兼容 0.2.0-rc.2),Node.js ^22.19.0 或 >=24。
|
|
10
10
|
|
|
11
11
|
## 在 DSH 里管理
|
|
12
12
|
|
|
@@ -115,7 +115,14 @@ Qoder 的 `dfmodel` 在真实目录里显示为 DeepSeek-Flash,未声明具体
|
|
|
115
115
|
|
|
116
116
|
`discountOrder: true` 开启「按积分折扣排序」(默认开启)。每次请求按各渠道当前公布的**积分倍率**从小到大排列候选账号,倍率越低越便宜、越先用。倍率来自模型目录并随目录刷新,限时促销到期后自动恢复,因此不需要定时任务。三家的数据形态不同(Trae 为数值 `creditMultiplier`,WorkBuddy 与 Qoder 为 `x0.11` 字符串),统一解析后把生效中的 `promotions[].factor` 作为折上折计入,`factor` 为 0 表示直接替换成本价。
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
优先级沿用既有约定,并按**是否持有临期积分**分成互不跨越的两组:持有临期积分的账号整体排在其余账号之前,无论倍率高低或本轮是否已用完额度,因此折扣与额度都不会破坏临期优先。
|
|
119
|
+
|
|
120
|
+
两组内部规则不同:
|
|
121
|
+
|
|
122
|
+
- **临期组**:先按到期时间排列(越早到期越优先),折扣不参与(倍率与到期时间无关,不能让到期更晚但更便宜的积分包排到前面);「积分使用均衡」的额度降权在组内生效,所以最早到期的账号用完阈值后会让位给同为临期的其他账号,而不是被非临期账号插队。
|
|
123
|
+
- **其余账号**:按配置顺序排列,折扣排序与额度降权同样在组内生效;未公布倍率的账号排在最后,不会被当成免费。
|
|
124
|
+
|
|
125
|
+
冷却只作用于临期优先本身,普通路由照常运行。`creditRates` 是每次发布时从目录派生的运行时数据而非配置,面板回传或手工编辑会在归一化阶段被丢弃。Free 自动免费模型路由不参与,也不展示该开关。
|
|
119
126
|
|
|
120
127
|
额度只决定下一次请求选哪个账号,不中断正在生成的回答;并发请求、最后一次请求可能使阈值超过,积分结算延迟也可能造成超额。这是轮换阈值,不是上游消费硬上限。
|
|
121
128
|
|
|
@@ -163,11 +170,14 @@ Qoder 的 `dfmodel` 在真实目录里显示为 DeepSeek-Flash,未声明具体
|
|
|
163
170
|
|
|
164
171
|
- **npm 来源**:比较 SemVer,保留 `latest` / `next` 等频道;固定版本和版本范围在用户确认更新后升级到最新正式版本。查询沿用 DSH 的 registry、网络、认证与镜像回退设置。
|
|
165
172
|
- **GitHub 来源**:比较原分支 / 标签的 Git 提交,版本号未变化也能发现更新;安装时使用官方 `pnpm update` 路径刷新原分支,并核验实际锁文件提交,避免 `pnpm add` 复用旧锁文件。支持 `github:用户/仓库`、GitHub HTTPS / SSH 地址及锁文件中的提交;固定 Git 提交不自动解除。GitHub 查询需要能够访问仓库公开元数据,私有仓库或限流会显示原因,不会猜测最新提交。
|
|
173
|
+
- **立即安装新版**:在「查看并更新」的确认框默认勾选「允许本次指定版本立即安装(不等待 24 小时)」,仅为框中列出的 npm 包与确切版本保存等待期例外;点击确认后才生效,可取消勾选继续遵守等待期。其他版本、间接依赖、兼容检查及脚本授权保持原策略;若新依赖也在等待期内,仍会提示等待,不自动扩大例外。GitHub 来源仍沿用原分支更新。
|
|
166
174
|
- 可按名称、来源和可更新状态筛选;支持单个更新、勾选批量更新、取消以及失败后重试。更新前显示目标,并保留每个插件原有启用 / 停用状态。
|
|
167
175
|
- 可直接输入 npm 包名 / 指定版本,或 `github:用户/仓库` 安装新插件。实际安装由 DSH 官方插件管理服务执行兼容检查、镜像重试、配置锁及失败回滚;依赖构建脚本仍在 DSH 原安装页授权,不自动绕过。
|
|
168
176
|
- 结果显示实际安装是否成功及是否需要重启。npm 镜像尚未同步、网络超时、版本不兼容会明确提示。GitHub 下载不会由 npm 镜像代替。
|
|
169
177
|
- 本地文件 / 开发链接标记为原方式更新。不同 DSH 配置之间相互独立,只操作当前配置。
|
|
170
178
|
|
|
179
|
+

|
|
180
|
+
|
|
171
181
|
## 侧栏用量概览
|
|
172
182
|
|
|
173
183
|
左侧底部默认显示今日与累计 Token,点击打开本插件详情。可在面板版本号旁取消「侧栏用量」,设置会持久保存。今日按北京时间统计;每分钟仅读取本机统计缓存,隐藏窗口暂停,不增加平台用量请求。未返回 usage 的调用不估算 Token,悬停可查看说明。
|
|
@@ -240,7 +250,7 @@ dsh plugin --profile desktop add dsh-multi-router
|
|
|
240
250
|
dsh plugin --profile desktop add dsh-multi-router@0.5.9 --registry=https://registry.npmjs.org/
|
|
241
251
|
```
|
|
242
252
|
|
|
243
|
-
先确认安装成功,再核对插件页的安装版本及面板顶部的运行版本。DSH 内置 pnpm 的新包等待策略可能选择至少 24 小时前的版本;指定刚发布的版本也可能触发 `ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION
|
|
253
|
+
先确认安装成功,再核对插件页的安装版本及面板顶部的运行版本。DSH 内置 pnpm 的新包等待策略可能选择至少 24 小时前的版本;指定刚发布的版本也可能触发 `ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION`。此时换镜像、卸载重装或重启不会解除策略。可等待到期,或在本插件「插件更新 → 查看并更新」勾选「允许本次指定版本立即安装」并确认,自动保存所示确切版本的例外;插件不会关闭全局等待策略,未授权版本及间接依赖仍受保护。首次安装本插件时尚无此面板,仍需等待到期或手动配置确切版本例外。输入包名却得到旧版,可能涉及安装器缓存、镜像、旧锁文件或安装失败回滚,不能只凭 `operation-error` 判断。插件内更新器会验证实际版本、展示安装声明与检查频道;失败时可查看脱敏诊断。文件占用、网络失败与插件加载错误分别处理,不把失败安装归因于面板缓存。v0.5.6 旧后台首次迁移后可关闭再启用本插件一次;无需先卸载或删除账号配置。
|
|
244
254
|
|
|
245
255
|
### 方式二:GitHub 链接安装
|
|
246
256
|
|
package/cordis.patch.yml
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
- insert:
|
|
2
|
-
- id: llm-multi-router-v2-0.6.
|
|
3
|
-
name: ./lib/host-v0.6.
|
|
2
|
+
- id: llm-multi-router-v2-0.6.12
|
|
3
|
+
name: ./lib/host-v0.6.12.js
|
package/lib/api-service.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ApiService
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TM5XDMGY.js";
|
|
4
4
|
import "./chunk-4V52V5GO.js";
|
|
5
5
|
import "./chunk-DNQPZMPF.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-4L2CBGXN.js";
|
|
7
7
|
import "./chunk-GEBZMIMA.js";
|
|
8
8
|
export {
|
|
9
9
|
ApiService
|
|
@@ -338,22 +338,22 @@ var Router = class {
|
|
|
338
338
|
/**
|
|
339
339
|
* Sort candidates inside each expiring-credit group, never across the boundary.
|
|
340
340
|
*
|
|
341
|
-
* `
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
* its own group rather than counting as the cheapest.
|
|
341
|
+
* `group` classifies a candidate — expiring versus not — and only the order inside a
|
|
342
|
+
* group changes. That keeps every account holding expiring credits ahead of the ones
|
|
343
|
+
* that do not, whatever their price, while the accounts within the expiring group are
|
|
344
|
+
* still ordered among themselves. `key` returning undefined means "no opinion" and
|
|
345
|
+
* sorts last inside its own group rather than counting as the cheapest.
|
|
346
346
|
*/
|
|
347
|
-
sortWithinGroups(candidates,
|
|
347
|
+
sortWithinGroups(candidates, group, key) {
|
|
348
348
|
const groups = /* @__PURE__ */ new Map();
|
|
349
349
|
for (const candidate of candidates) {
|
|
350
|
-
const
|
|
351
|
-
if (!groups.has(
|
|
352
|
-
groups.get(
|
|
350
|
+
const name = group(candidate);
|
|
351
|
+
if (!groups.has(name)) groups.set(name, []);
|
|
352
|
+
groups.get(name).push(candidate);
|
|
353
353
|
}
|
|
354
354
|
const result = [];
|
|
355
|
-
for (const
|
|
356
|
-
const decorated =
|
|
355
|
+
for (const members of groups.values()) {
|
|
356
|
+
const decorated = members.map((candidate, index) => ({ candidate, index, key: key(candidate) }));
|
|
357
357
|
decorated.sort((a, b) => {
|
|
358
358
|
if (a.key === b.key) return a.index - b.index;
|
|
359
359
|
if (a.key === void 0) return 1;
|
|
@@ -366,15 +366,18 @@ var Router = class {
|
|
|
366
366
|
}
|
|
367
367
|
/**
|
|
368
368
|
* Move accounts whose observed credit spend exceeded this route's threshold behind
|
|
369
|
-
* the ones that still have headroom,
|
|
369
|
+
* the ones that still have headroom, inside each expiring-credit group.
|
|
370
370
|
*
|
|
371
371
|
* This is a preference, not a filter: the caller keeps every candidate, so a route
|
|
372
372
|
* whose accounts are all over budget still serves requests instead of failing. The
|
|
373
373
|
* baseline is per route and per account, so switching accounts resets a newcomer's
|
|
374
374
|
* counter to zero while the previous account stays demoted for the rest of the round.
|
|
375
375
|
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
376
|
+
* `group` splits candidates into expiring and non-expiring. Scoping the demotion to
|
|
377
|
+
* that split keeps an account holding expiring credits ahead of one that does not,
|
|
378
|
+
* while the expiring accounts still take turns among themselves — grouping by the exact
|
|
379
|
+
* expiry date instead would leave each of them alone in its own group, and the allowance
|
|
380
|
+
* would never move a request off an account that still has credits left.
|
|
378
381
|
*
|
|
379
382
|
* Once every candidate in a group has spent its allowance the round is over and those
|
|
380
383
|
* baselines restart from the current total. Without that reset the counters only ever
|
|
@@ -383,7 +386,7 @@ var Router = class {
|
|
|
383
386
|
* Spend is inferred from platform balance drops, so one request may overshoot and an
|
|
384
387
|
* account without a usable balance reading is never demoted on a guess.
|
|
385
388
|
*/
|
|
386
|
-
demoteOverBudget(alias, route, candidates,
|
|
389
|
+
demoteOverBudget(alias, route, candidates, group = () => false) {
|
|
387
390
|
if (!candidates.length) return candidates;
|
|
388
391
|
const threshold = route.creditBalanceThreshold ?? 1e3;
|
|
389
392
|
const bases = this.budgets.get(alias) ?? /* @__PURE__ */ new Map();
|
|
@@ -392,14 +395,14 @@ var Router = class {
|
|
|
392
395
|
for (const id of bases.keys()) if (!live.has(id)) bases.delete(id);
|
|
393
396
|
const groups = /* @__PURE__ */ new Map();
|
|
394
397
|
for (const candidate of candidates) {
|
|
395
|
-
const
|
|
396
|
-
if (!groups.has(
|
|
397
|
-
groups.get(
|
|
398
|
+
const name = group(candidate);
|
|
399
|
+
if (!groups.has(name)) groups.set(name, []);
|
|
400
|
+
groups.get(name).push(candidate);
|
|
398
401
|
}
|
|
399
402
|
const result = [];
|
|
400
|
-
for (const
|
|
403
|
+
for (const group2 of groups.values()) {
|
|
401
404
|
const fresh = [], spent = [];
|
|
402
|
-
for (const candidate of
|
|
405
|
+
for (const candidate of group2) {
|
|
403
406
|
const id = candidate.account.id, row = this.telemetry.row("accounts", id);
|
|
404
407
|
const observed = row.creditsObserved ?? 0;
|
|
405
408
|
if (!bases.has(id)) bases.set(id, observed);
|
|
@@ -415,9 +418,9 @@ var Router = class {
|
|
|
415
418
|
result.push(...fresh);
|
|
416
419
|
continue;
|
|
417
420
|
}
|
|
418
|
-
if (spent.length ===
|
|
419
|
-
for (const candidate of
|
|
420
|
-
result.push(...
|
|
421
|
+
if (spent.length === group2.length) {
|
|
422
|
+
for (const candidate of group2) bases.set(candidate.account.id, this.telemetry.row("accounts", candidate.account.id).creditsObserved ?? 0);
|
|
423
|
+
result.push(...group2);
|
|
421
424
|
continue;
|
|
422
425
|
}
|
|
423
426
|
result.push(...fresh, ...spent);
|
|
@@ -562,16 +565,17 @@ var Router = class {
|
|
|
562
565
|
}
|
|
563
566
|
preferActive ??= await this.syncExpiring(alias, route, expiryCandidates, below);
|
|
564
567
|
const expiry = (c) => preferActive && !this.telemetry.expiring(alias).completed.includes(c.account.id) ? this.expiringAt(c.account, route) : Infinity;
|
|
568
|
+
const expiringGroup = (c) => Number.isFinite(expiry(c));
|
|
565
569
|
if (preferActive) {
|
|
566
570
|
const ordered = candidates.map((candidate, index) => ({ candidate, index }));
|
|
567
|
-
ordered.sort((a, b) => expiry(a.candidate) - expiry(b.candidate) || a.index - b.index);
|
|
571
|
+
ordered.sort((a, b) => Number(expiringGroup(b.candidate)) - Number(expiringGroup(a.candidate)) || expiry(a.candidate) - expiry(b.candidate) || a.index - b.index);
|
|
568
572
|
candidates = ordered.map((entry) => entry.candidate);
|
|
569
573
|
}
|
|
570
|
-
if (route.discountOrder && !route.freeOnly) candidates = this.sortWithinGroups(candidates, expiry, (candidate) => {
|
|
574
|
+
if (route.discountOrder && !route.freeOnly) candidates = this.sortWithinGroups(candidates, (candidate) => expiry(candidate), (candidate) => {
|
|
571
575
|
const rate = route.creditRates?.[candidate.account.id];
|
|
572
576
|
return rate === void 0 ? void 0 : rate;
|
|
573
577
|
});
|
|
574
|
-
if (route.balanceCredits && !route.freeOnly && this.telemetry) candidates = this.demoteOverBudget(alias, route, candidates,
|
|
578
|
+
if (route.balanceCredits && !route.freeOnly && this.telemetry) candidates = this.demoteOverBudget(alias, route, candidates, expiringGroup);
|
|
575
579
|
if (strategy === "weighted") {
|
|
576
580
|
let eligible = candidates.filter(available);
|
|
577
581
|
const nearest = Math.min(Infinity, ...eligible.map(expiry));
|
|
@@ -667,4 +671,4 @@ export {
|
|
|
667
671
|
matchModel,
|
|
668
672
|
Router
|
|
669
673
|
};
|
|
670
|
-
//# sourceMappingURL=chunk-
|
|
674
|
+
//# sourceMappingURL=chunk-4L2CBGXN.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/telemetry.mjs", "../src/model-context.mjs", "../src/router.mjs"],
|
|
4
|
+
"sourcesContent": ["import { createHash, randomUUID } from 'node:crypto';\nimport { assistantStreamFirstTokenTime } from '@deepseek-ai/dsh-llm';\nimport { readFile } from 'node:fs/promises';\nimport { writePrivateJson } from './config.mjs';\nconst empty = () => ({ requests: 0, failures: 0, input: 0, output: 0, tokens: 0, unmetered: 0 });\nconst day = at => new Date(at).toLocaleDateString('en-CA', { timeZone: 'Asia/Shanghai' });\nconst safe = n => typeof n === 'number' && Number.isFinite(n) && n >= 0 ? n : 0;\nconst measured = n => typeof n === 'number' && Number.isFinite(n) && n >= 0 ? n : null;\nexport class Telemetry {\n constructor(file, now = Date.now) { this.file = file; this.now = now; this.retentionDays = 30; this.data = { accounts: {}, routes: {}, days: {}, rounds: {}, expiringRounds: {}, events: [] }; this.queue = Promise.resolve(); }\n async load() {\n try { const saved = JSON.parse(await readFile(this.file, 'utf8')); if (saved.version !== 1) throw Error('Unsupported telemetry'); this.data = { ...saved, expiringRounds: saved.expiringRounds ?? {} }; }\n catch (e) { if (e.code !== 'ENOENT') throw e; }\n if (this.prune()) await this.persist();\n }\n configure(retentionDays) { this.retentionDays = retentionDays; }\n prune() {\n const cutoff = this.now() - this.retentionDays * 86400000, before = this.data.events.length;\n this.data.events = this.data.events.filter(e => Number.isFinite(e.at) && e.at >= cutoff);\n return before !== this.data.events.length;\n }\n row(group, key) { if (!Object.hasOwn(this.data[group], key)) Object.defineProperty(this.data[group], key, { value: empty(), enumerable: true, writable: true }); return this.data[group][key]; }\n count(alias, account) { return this.row('routes', JSON.stringify([alias, account])); }\n expiring(alias) {\n if (!Object.hasOwn(this.data.expiringRounds, alias)) Object.defineProperty(this.data.expiringRounds, alias, { value: { accounts: [], completed: [], cooldownUntil: 0, number: 1 }, enumerable: true, writable: true });\n return this.data.expiringRounds[alias];\n }\n restartExpiring(alias) { const row = this.expiring(alias); row.accounts = []; row.completed = []; row.cooldownUntil = 0; row.number++; return this.persist(); }\n round(alias, signature) {\n if (!Object.hasOwn(this.data.rounds, alias) || this.data.rounds[alias].signature !== signature) Object.defineProperty(this.data.rounds, alias, { value: { signature, number: 1, bases: {} }, enumerable: true, writable: true });\n return this.data.rounds[alias];\n }\n advance(alias, candidates, signature) {\n const round = this.round(alias, signature); round.number++;\n for (const c of candidates) Object.defineProperty(round.bases, c.account.id, { value: { tokens: this.count(alias, c.account.id).tokens, credits: this.row('accounts', c.account.id).creditsObserved ?? 0 }, enumerable: true, writable: true, configurable: true });\n return this.persist();\n }\n observe(account, snapshot) {\n const row = this.row('accounts', account);\n if (Number.isFinite(snapshot.remaining) && snapshot.unit === 'credits') {\n const sameCycle = row.balance?.cycle === snapshot.cycle;\n const change = sameCycle && Number.isFinite(row.balance?.remaining) ? Math.max(0, row.balance.remaining - snapshot.remaining) : 0;\n row.creditsObserved = (row.creditsObserved ?? 0) + change;\n }\n row.balance = snapshot;\n return this.persist();\n }\n record(event) {\n const at = this.now();\n const rows = [this.row('accounts', event.account), this.count(event.alias, event.account), this.row('days', day(at))];\n for (const row of rows) {\n row.requests++; if (!event.ok) row.failures++;\n if (event.usage) { const input = safe(event.usage.prompt_tokens), output = safe(event.usage.completion_tokens); row.input += input; row.output += output; row.tokens += safe(event.usage.total_tokens) || input + output; }\n else if (event.status === 200 || event.accepted) row.unmetered++;\n }\n const input = measured(event.usage?.prompt_tokens), output = measured(event.usage?.completion_tokens);\n this.data.events.unshift({ at, account: event.account, provider: event.provider, alias: event.alias, model: event.model ?? null, status: event.status,\n outcome: event.ok ? 'completed' : event.cancelled ? 'cancelled' : 'failed', input, output,\n tokens: measured(event.usage?.total_tokens) ?? (input !== null && output !== null ? input + output : null),\n cachedInput: measured(event.usage?.prompt_tokens_details?.cached_tokens), reasoningOutput: measured(event.usage?.completion_tokens_details?.reasoning_tokens),\n callId: event.callId ?? null, session: event.session ?? null, source: event.source === 'api' ? 'api' : 'dsh',\n timing: event.timing ? Object.fromEntries(['modelMs', 'ttftMs', 'decodeMs', 'decodeTokens'].map(k => [k, measured(event.timing[k])])) : null, timingSource: event.timing ? 'upstream' : null });\n const dates = Object.keys(this.data.days).sort(); for (const key of dates.slice(0, -31)) delete this.data.days[key];\n return this.persist();\n }\n persist() { this.prune(); const saved = structuredClone({ ...this.data, version: 1 }); this.queue = this.queue.catch(() => {}).then(() => writePrivateJson(this.file, saved)); return this.queue; }\n state() { this.prune(); return { ...structuredClone(this.data), retentionDays: this.retentionDays, today: day(this.now()), updatedAt: this.now() }; }\n}\n\n// Pass bytes through unchanged; parse only usage and terminal/error markers, never persist content.\nexport function meterResponse(response, complete, signal, { now = () => performance.now(), startedAt = now() } = {}) {\n if (!response.body) return response;\n const reader = response.body.getReader(), decoder = new TextDecoder();\n let pending = '', usage, ended = false, failed = false, finished = false, firstToken = null, terminalAt = null;\n async function finish(cancelled = false) { if (finished) return; finished = true; const end = terminalAt ?? now(); await complete({ usage, ok: ended && !failed && !cancelled, cancelled, timing: { modelMs: Math.max(0, end - startedAt), ttftMs: firstToken === null ? null : Math.max(0, firstToken - startedAt), decodeMs: firstToken === null ? null : Math.max(0, end - firstToken), decodeTokens: firstToken === null ? null : measured(usage?.completion_tokens) } }); }\n function inspect(bytes) {\n pending += decoder.decode(bytes, { stream: true });\n let split;\n while ((split = /\\r?\\n\\r?\\n/.exec(pending))) {\n const frame = pending.slice(0, split.index); pending = pending.slice(split.index + split[0].length);\n const data = frame.split(/\\r?\\n/).filter(l => l.startsWith('data:')).map(l => l.slice(5).trimStart()).join('\\n');\n if (data === '[DONE]') { ended = true; terminalAt ??= now(); continue; }\n try { const value = JSON.parse(data); if (value.usage && ['prompt_tokens', 'completion_tokens', 'total_tokens'].some(k => Number.isFinite(value.usage[k]) && value.usage[k] >= 0)) usage = value.usage; if (value.error) failed = true; if (firstToken === null && value.choices?.some(c => { const d = c.delta; return [d?.content, d?.reasoning_content, d?.reasoning].some(v => typeof v === 'string' && v.trim()) || d?.tool_calls?.some(t => t.function?.name || t.function?.arguments); })) firstToken = now(); if (value.choices?.some(c => c.finish_reason)) { ended = true; terminalAt ??= now(); } } catch { /* Unknown frame is forwarded. */ }\n }\n if (pending.length > 1024 * 1024) { pending = ''; failed = true; }\n }\n const body = new ReadableStream({\n async pull(controller) {\n try { signal?.throwIfAborted(); const chunk = await reader.read(); if (chunk.done) { await finish(); controller.close(); } else { inspect(chunk.value); controller.enqueue(chunk.value); } }\n catch (e) { await finish(signal?.aborted); controller.error(e); await reader.cancel().catch(() => {}); }\n },\n async cancel(reason) { await reader.cancel(reason).catch(() => {}); await finish(!ended); },\n });\n return new Response(body, { status: response.status, headers: response.headers });\n}\n\n// Link local transport attempts to DSH steps without retaining titles, prompts,\n// tool names/arguments/results, or the original session identity.\nexport class SessionMetrics {\n constructor(telemetry) { this.telemetry = telemetry; this.steps = new Map(); }\n key(id) { return createHash('sha256').update(String(id)).digest('hex').slice(0, 24); }\n beginCall(sessionId, purpose) {\n const callId = randomUUID(), session = sessionId == null ? null : this.key(sessionId);\n const step = session && this.steps.get(session);\n if (step && !purpose) step.callId = callId;\n return { callId, session };\n }\n event(session, event) {\n const key = this.key(session.id), d = event.data;\n if (event.type === 'step/start') { this.steps.set(key, { turn: d.turn, step: d.step, start: event.time, first: null, calls: new Map(), toolMs: 0, toolCount: 0, toolsCompleted: 0 }); return; }\n const step = this.steps.get(key);\n if (!step) return;\n if (d.turn !== undefined && (d.turn !== step.turn || d.step !== undefined && d.step !== step.step)) return;\n if (event.type === 'assistant/attempt') { step.first ??= assistantStreamFirstTokenTime(d.stream) ?? null; return; }\n const row = this.telemetry.data.events.find(e => e.callId === step.callId && e.session === key);\n if (event.type === 'assistant/message') {\n if (!row || d.interrupted) return;\n const first = step.first ?? assistantStreamFirstTokenTime(d.stream) ?? null;\n const output = measured(d.usage?.outputTokens);\n row.timing = { modelMs: Math.max(0, event.time - step.start), ttftMs: first === null ? null : Math.max(0, first - step.start),\n decodeMs: first === null || output === null ? null : Math.max(0, event.time - first), decodeTokens: first === null ? null : output };\n row.timingSource = 'dsh-step';\n } else if (event.type === 'tool/call' && row?.timingSource === 'dsh-step') {\n if (!step.calls.has(d.callId)) { step.calls.set(d.callId, event.time); step.toolCount++; }\n } else if (event.type === 'tool/result' && step.calls.has(d.message?.source?.callId)) {\n const id = d.message.source.callId;\n step.toolMs += Math.max(0, event.time - step.calls.get(id)); step.toolsCompleted++; step.calls.delete(id);\n } else if (event.type === 'step/end' || event.type === 'turn/end') {\n this.steps.delete(key);\n } else return;\n if (row?.timingSource !== 'dsh-step') return;\n Object.assign(row.timing, { toolMs: step.toolMs, toolCount: step.toolCount, toolsCompleted: step.toolsCompleted });\n return this.telemetry.persist();\n }\n dispose(session) { this.steps.delete(this.key(session.id)); }\n}\n", "const positive = n => Number.isSafeInteger(n) && n > 0;\n\n// Preserve native/default tiers separately from the local DSH budget.\nexport function contextInfo(model) {\n const defaultContextWindow = positive(model.defaultContextWindow) ? model.defaultContextWindow\n : positive(model.contextWindow) ? model.contextWindow : 200000;\n const supportedContextWindows = [...new Set([defaultContextWindow, model.contextWindow, model.maxContextWindow,\n ...(Array.isArray(model.supportedContextWindows) ? model.supportedContextWindows : [])].filter(positive))].sort((a, b) => a - b);\n const maxContextWindow = supportedContextWindows.at(-1);\n return { defaultContextWindow, supportedContextWindows, maxContextWindow, contextWindow: maxContextWindow };\n}\n\nexport function resolveContext(models, selected, fallback = 200000) {\n const infos = models.map(contextInfo);\n const maxContextWindow = infos.length ? Math.max(...infos.map(m => m.maxContextWindow)) : fallback;\n const contextWindow = positive(selected) ? Math.min(selected, maxContextWindow) : maxContextWindow;\n return { maxContextWindow, contextWindow, contextKnown: infos.length > 0, configuredContextWindow: positive(selected) ? selected : null,\n supportedContextWindows: [...new Set([contextWindow, ...infos.flatMap(m => m.supportedContextWindows)])].sort((a, b) => a - b) };\n}\n\n// Select the smallest real wire tier that can honour a local budget. Never mutate\n// the shared discovered catalog: concurrent routes may request different tiers.\nexport function qoderContextModel(model, budget) {\n if (!model?.contextOptions) return model;\n const entries = Object.entries(model.contextOptions).filter(([, v]) => positive(v.tokenCount)).sort((a, b) => a[1].tokenCount - b[1].tokenCount);\n if (!entries.length) return model;\n const selected = budget == null ? entries.at(-1) : entries.find(([, v]) => v.tokenCount >= budget);\n if (!selected) throw Object.assign(Error('context_window_unavailable'), { status: 400, code: 'context_window_unavailable' });\n return { ...model, contextWindow: selected[1].tokenCount,\n contextOptions: Object.fromEntries(Object.entries(model.contextOptions).map(([key, value]) => [key, { ...value, isDefault: key === selected[0] }])) };\n}\n", "import { meterResponse } from './telemetry.mjs';\nimport { isFreeModel } from './config.mjs';\nimport { reasoningModes } from './reasoning.mjs';\nimport { contextInfo } from './model-context.mjs';\nexport class RouteError extends Error {\n constructor(status, code, attempts = [], hint) {\n super(`${code}${attempts.length ? ': ' + attempts.map(a => `${a.account} HTTP ${a.status}`).join(', ') : ''}${hint ? `\uFF08${hint}\uFF09` : ''}`);\n this.status = status; this.code = code; this.attempts = attempts; this.hint = hint;\n }\n}\nconst normalize = value => value.toLowerCase().replace(/[^a-z0-9]/g, '').replace(/official$/, '');\nexport function abortable(promise, signal) {\n if (!signal) return promise;\n // Attach handlers even if already aborted, so a late rejection is consumed.\n return new Promise((resolve, reject) => {\n const abort = () => reject(signal.reason ?? new DOMException('Aborted', 'AbortError'));\n signal.addEventListener('abort', abort, { once: true });\n if (signal.aborted) abort();\n Promise.resolve(promise).then(resolve, reject).finally(() => signal.removeEventListener('abort', abort));\n });\n}\nexport function matchModel(alias, target, catalog, effort, provider = target.provider) {\n const allowed = m => m && (effort === undefined || reasoningModes(m, provider).includes(effort));\n if (target.model) return catalog.find(m => m.id === target.model && allowed(m));\n if (target.models) return target.models.map(id => catalog.find(m => m.id === id)).find(allowed);\n if (alias === 'ds4.1f') return catalog.find(m => allowed(m) && [m.id, m.name ?? ''].some(x => normalize(x) === 'deepseekv41flash'));\n}\n\nexport class Router {\n constructor(config, createClient, onAttempt = () => {}, now = Date.now) {\n this.config = config; this.createClient = createClient; this.onAttempt = onAttempt; this.now = now;\n this.telemetry = null; this.scores = new Map(); this.monitor = null; this.clients = new Map(); this.cooldowns = new Map(); this.active = new Map(); this.budgets = new Map();\n }\n /**\n * Sort candidates inside each expiring-credit group, never across the boundary.\n *\n * `group` classifies a candidate \u2014 expiring versus not \u2014 and only the order inside a\n * group changes. That keeps every account holding expiring credits ahead of the ones\n * that do not, whatever their price, while the accounts within the expiring group are\n * still ordered among themselves. `key` returning undefined means \"no opinion\" and\n * sorts last inside its own group rather than counting as the cheapest.\n */\n sortWithinGroups(candidates, group, key) {\n const groups = new Map();\n for (const candidate of candidates) {\n const name = group(candidate);\n if (!groups.has(name)) groups.set(name, []);\n groups.get(name).push(candidate);\n }\n const result = [];\n for (const members of groups.values()) {\n const decorated = members.map((candidate, index) => ({ candidate, index, key: key(candidate) }));\n decorated.sort((a, b) => {\n if (a.key === b.key) return a.index - b.index;\n if (a.key === undefined) return 1;\n if (b.key === undefined) return -1;\n return a.key - b.key;\n });\n result.push(...decorated.map(entry => entry.candidate));\n }\n return result;\n }\n /**\n * Move accounts whose observed credit spend exceeded this route's threshold behind\n * the ones that still have headroom, inside each expiring-credit group.\n *\n * This is a preference, not a filter: the caller keeps every candidate, so a route\n * whose accounts are all over budget still serves requests instead of failing. The\n * baseline is per route and per account, so switching accounts resets a newcomer's\n * counter to zero while the previous account stays demoted for the rest of the round.\n *\n * `group` splits candidates into expiring and non-expiring. Scoping the demotion to\n * that split keeps an account holding expiring credits ahead of one that does not,\n * while the expiring accounts still take turns among themselves \u2014 grouping by the exact\n * expiry date instead would leave each of them alone in its own group, and the allowance\n * would never move a request off an account that still has credits left.\n *\n * Once every candidate in a group has spent its allowance the round is over and those\n * baselines restart from the current total. Without that reset the counters only ever\n * grow, every account stays demoted forever and the ordering stops changing after one pass.\n *\n * Spend is inferred from platform balance drops, so one request may overshoot and an\n * account without a usable balance reading is never demoted on a guess.\n */\n demoteOverBudget(alias, route, candidates, group = () => false) {\n if (!candidates.length) return candidates;\n const threshold = route.creditBalanceThreshold ?? 1000;\n const bases = this.budgets.get(alias) ?? new Map();\n this.budgets.set(alias, bases);\n const live = new Set(candidates.map(c => c.account.id));\n for (const id of bases.keys()) if (!live.has(id)) bases.delete(id);\n const groups = new Map();\n for (const candidate of candidates) {\n const name = group(candidate);\n if (!groups.has(name)) groups.set(name, []);\n groups.get(name).push(candidate);\n }\n const result = [];\n for (const group of groups.values()) {\n const fresh = [], spent = [];\n for (const candidate of group) {\n const id = candidate.account.id, row = this.telemetry.row('accounts', id);\n const observed = row.creditsObserved ?? 0;\n if (!bases.has(id)) bases.set(id, observed);\n const used = observed - bases.get(id);\n // A balance rewrite (prepaid top-up, new settlement cycle) must not keep an account\n // demoted on a negative counter.\n if (!Number.isFinite(used) || used < 0) { bases.set(id, observed); fresh.push(candidate); continue; }\n (used >= threshold ? spent : fresh).push(candidate);\n }\n if (!spent.length) { result.push(...fresh); continue; }\n if (spent.length === group.length) {\n // Every account in this group has used its allowance: bank the totals and start a\n // new round for the group.\n for (const candidate of group) bases.set(candidate.account.id, this.telemetry.row('accounts', candidate.account.id).creditsObserved ?? 0);\n result.push(...group);\n continue;\n }\n result.push(...fresh, ...spent);\n }\n return result;\n }\n updateConfig(config) {\n for (const old of this.config.accounts) {\n const next = config.accounts.find(a => a.id === old.id);\n if (!next || next.provider !== old.provider || next.credentialFile !== old.credentialFile || next.identityFile !== old.identityFile) this.clients.delete(old.id);\n }\n this.config = config;\n for (const alias of this.active.keys()) if (!Object.hasOwn(config.routes, alias)) this.active.delete(alias);\n for (const alias of this.budgets.keys()) if (!Object.hasOwn(config.routes, alias)) this.budgets.delete(alias);\n }\n async client(account) {\n if (!this.clients.has(account.id)) this.clients.set(account.id, Promise.resolve().then(() => this.createClient(account)));\n try { return await this.clients.get(account.id); }\n catch (error) { this.clients.delete(account.id); throw error; }\n }\n status() {\n return this.config.accounts.map(a => ({ id: a.id, provider: a.provider, enabled: a.enabled !== false,\n cooldowns: [...this.cooldowns].filter(([key, time]) => key.startsWith(`${a.id}:`) && time > this.now())\n .map(([key, time]) => ({ route: key.slice(a.id.length + 1), remainingMs: time - this.now() })),\n activeFor: [...this.active].filter(([, key]) => key.split(':')[0] === a.id).map(([alias]) => alias) }));\n }\n candidates(alias) {\n const route = this.config.routes[alias];\n if (!Object.hasOwn(this.config.routes, alias)) throw new RouteError(404, 'unknown_model', [], '\u63D2\u4EF6\u8DEF\u7531\u8868\u4E2D\u6CA1\u6709\u8BE5\u8C03\u7528\u540D\u79F0\uFF0C\u8BF7\u5728\u914D\u7F6E\u9875\u65B0\u5EFA\u6216\u6062\u590D\u5BF9\u5E94\u8DEF\u7531');\n const candidates = route.targets.flatMap((target, index) => this.config.accounts\n .filter(a => a.enabled !== false && a.provider === target.provider && (!target.account || a.id === target.account))\n .flatMap(account => route.freeOnly ? (this.freeModels?.(account) ?? []).filter(m => (!target.model || m.id === target.model) && (!target.models || target.models.includes(m.id)))\n .map(model => ({ account, target: { ...target, model: model.id, models: undefined }, key: `${account.id}:${index}:${model.id}` }))\n : [{ account, target, key: `${account.id}:${index}` }]));\n const active = candidates.findIndex(c => c.key === this.active.get(alias));\n return active < 0 ? candidates : [...candidates.slice(active), ...candidates.slice(0, active)];\n }\n expiringAt(account, route) {\n const balance = this.telemetry?.row('accounts', account.id).balance;\n if (!balance || balance.error || balance.unit !== 'credits' || this.now() - balance.fetchedAt > 120000) return Infinity;\n const horizon = this.now() + (route.expiringWithinDays ?? 7) * 86400000;\n return Math.min(Infinity, ...(balance.packages ?? []).filter(p => p.remaining > 0 && !p.unlimited && p.expiresAt > this.now() && p.expiresAt <= horizon).map(p => p.expiresAt));\n }\n async syncExpiring(alias, route, candidates, below = () => true) {\n if (!route.preferExpiringCredits || !this.telemetry) return false;\n const round = this.telemetry.expiring(alias);\n if (round.cooldownUntil > this.now()) return false;\n const before = JSON.stringify(round);\n if (round.cooldownUntil) { round.accounts = []; round.completed = []; round.cooldownUntil = 0; round.number++; }\n for (const id of round.accounts) {\n const matches = candidates.filter(c => c.account.id === id), balance = this.telemetry.row('accounts', id).balance;\n const fresh = balance && !balance.error && balance.unit === 'credits' && this.now() - balance.fetchedAt <= 120000;\n if (!matches.length || matches.every(c => !below(c)) || (fresh && !Number.isFinite(this.expiringAt({ id }, route)))) {\n if (!round.completed.includes(id)) round.completed.push(id);\n }\n }\n for (const c of candidates) if (below(c) && Number.isFinite(this.expiringAt(c.account, route)) && !round.accounts.includes(c.account.id)) round.accounts.push(c.account.id);\n // Cooling applies only to expiring-credit priority; ordinary routing keeps running.\n if (round.accounts.length && round.accounts.every(id => round.completed.includes(id))) round.cooldownUntil = this.now() + 3 * 86400000;\n if (JSON.stringify(round) !== before) await this.telemetry.persist();\n return round.cooldownUntil <= this.now();\n }\n remainingCooldown(candidate, alias, route) {\n const id = candidate.account.id;\n const keys = [`${id}:*`, `${id}:${alias}`];\n if (route.freeOnly) keys.push(`${id}:${alias}:${candidate.target.model}`);\n return Math.max(0, ...keys.map(key => (this.cooldowns.get(key) ?? 0) - this.now()));\n }\n exhaustHint({ alias, route, strategy, candidates, expiryCandidates, attempts }) {\n const kinds = new Set(attempts.map(a => a.kind));\n const modelOnly = attempts.length > 0 && [...kinds].every(k => ['model_unavailable', 'reasoning_effort_unavailable', 'model_no_longer_free', 'context_window_unavailable'].includes(k));\n const cooling = candidates.map(c => this.remainingCooldown(c, alias, route)).filter(ms => ms > 0);\n const soonest = cooling.length ? Math.min(...cooling) : undefined;\n const countdown = soonest === undefined ? undefined : `\u7EA6 ${Math.max(1, Math.ceil(soonest / 1000))} \u79D2\u540E\u53EF\u91CD\u8BD5`;\n if (!expiryCandidates.length) return route.freeOnly\n ? '\u8BE5\u8DEF\u7531\u5F53\u524D\u6CA1\u6709\u53EF\u7528\u7684\u514D\u8D39\u6A21\u578B\uFF1A\u53EF\u80FD\u5DF2\u6062\u590D\u6536\u8D39\u3001\u9650\u514D\u5230\u671F\u6216\u76EE\u5F55\u83B7\u53D6\u5931\u8D25'\n : '\u8BE5\u8DEF\u7531\u6CA1\u6709\u53EF\u7528\u7684\u8D26\u53F7\u76EE\u6807\uFF1A\u8D26\u53F7\u53EF\u80FD\u5DF2\u5168\u90E8\u7981\u7528\uFF0C\u6216\u4E0E\u76EE\u6807\u6E20\u9053\u4E0D\u5339\u914D';\n if (kinds.has('context_window_unavailable') && modelOnly) return '\u5019\u9009\u6E20\u9053\u4E0D\u652F\u6301\u5F53\u524D\u4E0A\u4E0B\u6587\u9884\u7B97\uFF0C\u8BF7\u5237\u65B0\u76EE\u5F55\u6216\u5728\u6A21\u578B\uFF0F\u8DEF\u7531\u8BBE\u7F6E\u4E2D\u8C03\u4F4E\u9884\u7B97\uFF1B\u4E0D\u4F1A\u622A\u65AD\u4F1A\u8BDD\u6216\u964D\u7EA7\u5230\u5C0F\u5BB9\u91CF\u6E20\u9053';\n if (modelOnly) return `\u5DF2\u5C1D\u8BD5\u7684\u8D26\u53F7\u76EE\u5F55\u4E2D\u90FD\u6CA1\u6709\u8BE5\u6A21\u578B\u3001\u6240\u9009\u63A8\u7406\u6863\u4F4D\u6216\u514D\u8D39\u8D44\u683C\u4E0D\u6EE1\u8DB3${countdown ? `\uFF1B\u5176\u4F59\u8D26\u53F7\u51B7\u5374\u4E2D\uFF0C${countdown}` : ''}`;\n if (soonest !== undefined && cooling.length >= candidates.length) {\n return attempts.length ? `\u6240\u6709\u5019\u9009\u8D26\u53F7\u672C\u6B21\u8C03\u7528\u5747\u5931\u8D25\u5E76\u5DF2\u8FDB\u5165\u51B7\u5374\uFF0C${countdown}` : `\u5168\u90E8\u8D26\u53F7\u90FD\u5728\u5931\u8D25\u51B7\u5374\u4E2D\uFF0C${countdown}`;\n }\n if (soonest !== undefined) return `\u90E8\u5206\u8D26\u53F7\u4ECD\u5728\u5931\u8D25\u51B7\u5374\u4E2D\uFF0C${countdown}`;\n if (!attempts.length && ['tokens', 'credits'].includes(strategy)) return `\u6240\u6709\u8D26\u53F7\u7684\u672C\u8F6E${strategy === 'tokens' ? ' Token' : '\u79EF\u5206'}\u989D\u5EA6\u5DF2\u7528\u5B8C\uFF0C\u6216\u56E0\u7F3A\u5C11\u7528\u91CF\u8BA1\u91CF\u800C\u6682\u505C\u53C2\u4E0E\u8F6E\u6362`;\n return undefined;\n }\n async chat(input, signal, metadata = {}) {\n const alias = input.model;\n if (!Array.isArray(input.messages) || !input.messages.length || input.stream !== true) throw new RouteError(400, 'messages_and_stream_true_required');\n const initialRoute = this.config.routes[alias];\n if (initialRoute?.freeOnly) {\n await abortable(this.prepareFree?.(), signal);\n if (!this.config.routes[alias]) throw new RouteError(503, 'free_model_pool_unavailable', [], '\u672C\u8DEF\u7531\u4ECA\u5929\u6CA1\u6709\u53EF\u7528\u7684\u514D\u8D39\u6A21\u578B');\n }\n const effort = Object.hasOwn(input, 'reasoning_effort') ? input.reasoning_effort : this.config.routes[alias]?.reasoningEffort;\n input = { ...input }; delete input.reasoning_effort;\n if (effort !== undefined && effort !== null) input.reasoning_effort = effort;\n let candidates = this.candidates(alias);\n const expiryCandidates = [...candidates];\n const route = this.config.routes[alias], strategy = route.strategy ?? 'failover';\n const available = c => (this.cooldowns.get(`${c.account.id}:*`) ?? 0) <= this.now() && (this.cooldowns.get(`${c.account.id}:${alias}`) ?? 0) <= this.now()\n && (!route.freeOnly || (this.cooldowns.get(`${c.account.id}:${alias}:${c.target.model}`) ?? 0) <= this.now());\n if (route.preferExpiringCredits && this.monitor) {\n await Promise.all([...new Map(candidates.filter(available).map(c => [c.account.id, c.account])).values()].map(a => {\n const snapshot = this.telemetry?.row('accounts', a.id).balance;\n return !snapshot || snapshot.error || this.now() - snapshot.fetchedAt > 60000 ? this.monitor(a) : undefined;\n }));\n signal?.throwIfAborted();\n }\n if (strategy === 'credits') {\n await Promise.all([...new Map(candidates.filter(available).map(c => [c.account.id, c.account])).values()].map(a => this.monitor?.(a)));\n signal?.throwIfAborted();\n candidates = candidates.filter(c => { const balance = this.telemetry?.row('accounts', c.account.id).balance; return balance?.unit === 'credits' && Number.isFinite(balance.remaining) && this.now() - balance.fetchedAt < 120000 && !balance.error; });\n if (!candidates.length) throw new RouteError(503, 'credit_usage_unavailable', [], '\u65E0\u6CD5\u83B7\u53D6\u4EFB\u4F55\u5019\u9009\u8D26\u53F7\u7684\u79EF\u5206\u4F59\u989D\u6570\u636E');\n }\n const signature = JSON.stringify({ strategy, targets: route.targets });\n let below = () => true, preferActive;\n if (this.telemetry && ['tokens', 'credits'].includes(strategy)) {\n const round = this.telemetry.round(alias, signature);\n const counters = c => ({ tokens: this.telemetry.count(alias, c.account.id).tokens, credits: this.telemetry.row('accounts', c.account.id).creditsObserved ?? 0 });\n for (const c of candidates) if (!Object.hasOwn(round.bases, c.account.id)) Object.defineProperty(round.bases, c.account.id, { value: counters(c), enumerable: true, writable: true, configurable: true });\n below = c => !round.bases[c.account.id] || counters(c)[strategy] - round.bases[c.account.id][strategy] < (strategy === 'tokens' ? c.target.tokenBudget : c.target.creditBudget);\n preferActive = await this.syncExpiring(alias, route, expiryCandidates, below);\n // Start another round only when every configured, metered candidate has used its budget.\n if (candidates.length && candidates.every(c => !below(c))) {\n await this.telemetry.advance(alias, candidates, signature);\n this.active.delete(alias);\n const allowed = new Set(candidates.map(c => c.key));\n candidates = this.candidates(alias).filter(c => allowed.has(c.key));\n }\n candidates = candidates.filter(below);\n if (strategy === 'tokens' && candidates.some(c => this.telemetry.count(alias, c.account.id).unmetered > 0)) {\n // A missing upstream usage marker cannot silently count as zero forever.\n candidates = candidates.filter(c => this.telemetry.count(alias, c.account.id).unmetered === 0);\n }\n }\n preferActive ??= await this.syncExpiring(alias, route, expiryCandidates, below);\n const expiry = c => preferActive && !this.telemetry.expiring(alias).completed.includes(c.account.id) ? this.expiringAt(c.account, route) : Infinity;\n // One group for accounts holding expiring credits and one for the rest. Every rule\n // below reorders only inside a group, so an expiring account stays ahead of a\n // non-expiring one whatever its price or remaining allowance.\n const expiringGroup = c => Number.isFinite(expiry(c));\n // Soonest expiry first, and that order is the starting point every later rule refines.\n // Comparing dates directly and breaking ties by the original index keeps two\n // non-expiring accounts equal, which subtracting two Infinity values would not.\n if (preferActive) {\n const ordered = candidates.map((candidate, index) => ({ candidate, index }));\n ordered.sort((a, b) => Number(expiringGroup(b.candidate)) - Number(expiringGroup(a.candidate))\n || expiry(a.candidate) - expiry(b.candidate) || a.index - b.index);\n candidates = ordered.map(entry => entry.candidate);\n }\n // Cheapest known rate first, inside the expiring group only. The rate is unrelated to\n // expiry, so it must not reorder accounts by how soon their credits run out: that\n // ordering is the point of the priority rule, and a cheaper pack expiring later is not\n // a reason to spend it first.\n if (route.discountOrder && !route.freeOnly) candidates = this.sortWithinGroups(candidates, candidate => expiry(candidate), candidate => {\n const rate = route.creditRates?.[candidate.account.id];\n return rate === undefined ? undefined : rate;\n });\n if (route.balanceCredits && !route.freeOnly && this.telemetry) candidates = this.demoteOverBudget(alias, route, candidates, expiringGroup);\n if (strategy === 'weighted') {\n let eligible = candidates.filter(available);\n const nearest = Math.min(Infinity, ...eligible.map(expiry));\n if (Number.isFinite(nearest)) eligible = eligible.filter(c => expiry(c) === nearest);\n if (eligible.length) {\n let scores = this.scores.get(alias);\n if (scores?.signature !== signature) { scores = { signature, values: new Map() }; this.scores.set(alias, scores); }\n let total = 0, winner;\n for (const c of eligible) { const weight = c.target.weight ?? 1; total += weight; scores.values.set(c.key, (scores.values.get(c.key) ?? 0) + weight); if (!winner || scores.values.get(c.key) > scores.values.get(winner.key)) winner = c; }\n scores.values.set(winner.key, scores.values.get(winner.key) - total);\n candidates = [winner, ...candidates.filter(c => c !== winner)];\n }\n }\n const attempts = [];\n // Each account/model target is attempted once, even when configuration repeats it.\n const tried = new Set();\n for (const candidate of candidates) {\n signal?.throwIfAborted();\n const { account, target, key } = candidate;\n if (!available(candidate)) continue;\n let result, actualModel, startedAt;\n try {\n const client = await abortable(this.client(account), signal);\n const catalog = await abortable(client.models(signal), signal);\n const suitable = route.enforceContext ? catalog.filter(m => contextInfo(m).maxContextWindow >= route.contextWindow) : catalog;\n const model = matchModel(alias, target, suitable, effort ?? undefined);\n if (!model) { attempts.push({ account: account.id, provider: account.provider, status: 404,\n kind: matchModel(alias, target, catalog, effort ?? undefined) ? 'context_window_unavailable'\n : matchModel(alias, target, catalog) ? 'reasoning_effort_unavailable' : 'model_unavailable' }); continue; }\n if (route.freeOnly && !isFreeModel(model, this.now())) { attempts.push({ account: account.id, provider: account.provider, status: 404, kind: 'model_no_longer_free' }); continue; }\n actualModel = model.id;\n const dedupe = `${account.id}:${model.id}`;\n if (tried.has(dedupe)) continue;\n tried.add(dedupe);\n startedAt = performance.now();\n result = await abortable(client.chat({ ...input, model: model.id }, signal, { contextWindow: route.contextWindow }), signal);\n signal?.throwIfAborted();\n if (result.ok) {\n this.active.set(alias, key);\n this.onAttempt({ account: account.id, provider: account.provider, alias, model: model.id, status: 200 });\n const response = this.telemetry ? meterResponse(result.response, async summary => {\n await this.telemetry.record({ ...summary, ...metadata, account: account.id, provider: account.provider, alias, model: model.id, accepted: true, status: summary.ok ? 200 : summary.cancelled ? 499 : 502 });\n await this.syncExpiring(alias, route, expiryCandidates, below);\n if (strategy === 'credits' || route.preferExpiringCredits) void this.monitor?.(account).then(() => this.syncExpiring(alias, route, expiryCandidates, below)).catch(() => {});\n }, signal, { startedAt }) : result.response;\n return { response, account: account.id, provider: account.provider };\n }\n } catch (error) {\n signal?.throwIfAborted();\n const reported = error.status ?? error.failure?.status ?? /\\bhttp\\s+(\\d{3})\\b/i.exec(error.message ?? '')?.[1];\n result = { ok: false, status: Number(reported) || 502, kind: error.code ?? error.failure?.code ?? 'transport' };\n }\n const status = result.status >= 400 && result.status <= 599 ? result.status : 502;\n const attempt = { account: account.id, provider: account.provider, status, kind: result.kind };\n attempts.push(attempt);\n await this.telemetry?.record({ ...attempt, ...metadata, alias, model: actualModel, ok: false, timing: startedAt === undefined ? null : { modelMs: Math.max(0, performance.now() - startedAt) } });\n // Upstream messages can contain credentials or request text: log metadata only.\n this.onAttempt({ ...attempt, alias });\n const retryable = status < 500 || this.config.retryServerErrors;\n if (!retryable) throw new RouteError(status, 'upstream_failed', attempts, '\u4E0A\u6E38\u8FD4\u56DE 5xx \u4E14\u672A\u5F00\u542F\u300C5xx \u548C\u7F51\u7EDC\u9519\u8BEF\u4E5F\u5207\u6362\u8D26\u53F7\u300D\uFF0C\u672C\u6B21\u8BF7\u6C42\u5DF2\u505C\u6B62');\n const scope = [401, 402, 429].includes(status) ? '*' : route.freeOnly && actualModel ? `${alias}:${actualModel}` : alias;\n this.cooldowns.set(`${account.id}:${scope}`, this.now() + this.config.cooldownMs);\n }\n const hint = this.exhaustHint({ alias, route, strategy, candidates, expiryCandidates, attempts });\n throw new RouteError(503, route.freeOnly ? 'free_model_pool_unavailable' : 'account_pool_exhausted', attempts, hint);\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;AAAA,SAAS,YAAY,kBAAkB;AACvC,SAAS,qCAAqC;AAC9C,SAAS,gBAAgB;AAEzB,IAAM,QAAQ,OAAO,EAAE,UAAU,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,EAAE;AAC9F,IAAM,MAAM,QAAM,IAAI,KAAK,EAAE,EAAE,mBAAmB,SAAS,EAAE,UAAU,gBAAgB,CAAC;AACxF,IAAM,OAAO,OAAK,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,KAAK,KAAK,IAAI,IAAI;AAC9E,IAAM,WAAW,OAAK,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,KAAK,KAAK,IAAI,IAAI;AAC3E,IAAM,YAAN,MAAgB;AAAA,EACrB,YAAY,MAAM,MAAM,KAAK,KAAK;AAAE,SAAK,OAAO;AAAM,SAAK,MAAM;AAAK,SAAK,gBAAgB;AAAI,SAAK,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,GAAG,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,gBAAgB,CAAC,GAAG,QAAQ,CAAC,EAAE;AAAG,SAAK,QAAQ,QAAQ,QAAQ;AAAA,EAAG;AAAA,EAC/N,MAAM,OAAO;AACX,QAAI;AAAE,YAAM,QAAQ,KAAK,MAAM,MAAM,SAAS,KAAK,MAAM,MAAM,CAAC;AAAG,UAAI,MAAM,YAAY,EAAG,OAAM,MAAM,uBAAuB;AAAG,WAAK,OAAO,EAAE,GAAG,OAAO,gBAAgB,MAAM,kBAAkB,CAAC,EAAE;AAAA,IAAG,SACjM,GAAG;AAAE,UAAI,EAAE,SAAS,SAAU,OAAM;AAAA,IAAG;AAC9C,QAAI,KAAK,MAAM,EAAG,OAAM,KAAK,QAAQ;AAAA,EACvC;AAAA,EACA,UAAU,eAAe;AAAE,SAAK,gBAAgB;AAAA,EAAe;AAAA,EAC/D,QAAQ;AACN,UAAM,SAAS,KAAK,IAAI,IAAI,KAAK,gBAAgB,OAAU,SAAS,KAAK,KAAK,OAAO;AACrF,SAAK,KAAK,SAAS,KAAK,KAAK,OAAO,OAAO,OAAK,OAAO,SAAS,EAAE,EAAE,KAAK,EAAE,MAAM,MAAM;AACvF,WAAO,WAAW,KAAK,KAAK,OAAO;AAAA,EACrC;AAAA,EACA,IAAI,OAAO,KAAK;AAAE,QAAI,CAAC,OAAO,OAAO,KAAK,KAAK,KAAK,GAAG,GAAG,EAAG,QAAO,eAAe,KAAK,KAAK,KAAK,GAAG,KAAK,EAAE,OAAO,MAAM,GAAG,YAAY,MAAM,UAAU,KAAK,CAAC;AAAG,WAAO,KAAK,KAAK,KAAK,EAAE,GAAG;AAAA,EAAG;AAAA,EAC/L,MAAM,OAAO,SAAS;AAAE,WAAO,KAAK,IAAI,UAAU,KAAK,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAAA,EAAG;AAAA,EACrF,SAAS,OAAO;AACd,QAAI,CAAC,OAAO,OAAO,KAAK,KAAK,gBAAgB,KAAK,EAAG,QAAO,eAAe,KAAK,KAAK,gBAAgB,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,GAAG,WAAW,CAAC,GAAG,eAAe,GAAG,QAAQ,EAAE,GAAG,YAAY,MAAM,UAAU,KAAK,CAAC;AACrN,WAAO,KAAK,KAAK,eAAe,KAAK;AAAA,EACvC;AAAA,EACA,gBAAgB,OAAO;AAAE,UAAM,MAAM,KAAK,SAAS,KAAK;AAAG,QAAI,WAAW,CAAC;AAAG,QAAI,YAAY,CAAC;AAAG,QAAI,gBAAgB;AAAG,QAAI;AAAU,WAAO,KAAK,QAAQ;AAAA,EAAG;AAAA,EAC9J,MAAM,OAAO,WAAW;AACtB,QAAI,CAAC,OAAO,OAAO,KAAK,KAAK,QAAQ,KAAK,KAAK,KAAK,KAAK,OAAO,KAAK,EAAE,cAAc,UAAW,QAAO,eAAe,KAAK,KAAK,QAAQ,OAAO,EAAE,OAAO,EAAE,WAAW,QAAQ,GAAG,OAAO,CAAC,EAAE,GAAG,YAAY,MAAM,UAAU,KAAK,CAAC;AAC/N,WAAO,KAAK,KAAK,OAAO,KAAK;AAAA,EAC/B;AAAA,EACA,QAAQ,OAAO,YAAY,WAAW;AACpC,UAAM,QAAQ,KAAK,MAAM,OAAO,SAAS;AAAG,UAAM;AAClD,eAAW,KAAK,WAAY,QAAO,eAAe,MAAM,OAAO,EAAE,QAAQ,IAAI,EAAE,OAAO,EAAE,QAAQ,KAAK,MAAM,OAAO,EAAE,QAAQ,EAAE,EAAE,QAAQ,SAAS,KAAK,IAAI,YAAY,EAAE,QAAQ,EAAE,EAAE,mBAAmB,EAAE,GAAG,YAAY,MAAM,UAAU,MAAM,cAAc,KAAK,CAAC;AAClQ,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EACA,QAAQ,SAAS,UAAU;AACzB,UAAM,MAAM,KAAK,IAAI,YAAY,OAAO;AACxC,QAAI,OAAO,SAAS,SAAS,SAAS,KAAK,SAAS,SAAS,WAAW;AACtE,YAAM,YAAY,IAAI,SAAS,UAAU,SAAS;AAClD,YAAM,SAAS,aAAa,OAAO,SAAS,IAAI,SAAS,SAAS,IAAI,KAAK,IAAI,GAAG,IAAI,QAAQ,YAAY,SAAS,SAAS,IAAI;AAChI,UAAI,mBAAmB,IAAI,mBAAmB,KAAK;AAAA,IACrD;AACA,QAAI,UAAU;AACd,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EACA,OAAO,OAAO;AACZ,UAAM,KAAK,KAAK,IAAI;AACpB,UAAM,OAAO,CAAC,KAAK,IAAI,YAAY,MAAM,OAAO,GAAG,KAAK,MAAM,MAAM,OAAO,MAAM,OAAO,GAAG,KAAK,IAAI,QAAQ,IAAI,EAAE,CAAC,CAAC;AACpH,eAAW,OAAO,MAAM;AACtB,UAAI;AAAY,UAAI,CAAC,MAAM,GAAI,KAAI;AACnC,UAAI,MAAM,OAAO;AAAE,cAAMA,SAAQ,KAAK,MAAM,MAAM,aAAa,GAAGC,UAAS,KAAK,MAAM,MAAM,iBAAiB;AAAG,YAAI,SAASD;AAAO,YAAI,UAAUC;AAAQ,YAAI,UAAU,KAAK,MAAM,MAAM,YAAY,KAAKD,SAAQC;AAAA,MAAQ,WACjN,MAAM,WAAW,OAAO,MAAM,SAAU,KAAI;AAAA,IACvD;AACA,UAAM,QAAQ,SAAS,MAAM,OAAO,aAAa,GAAG,SAAS,SAAS,MAAM,OAAO,iBAAiB;AACpG,SAAK,KAAK,OAAO,QAAQ;AAAA,MAAE;AAAA,MAAI,SAAS,MAAM;AAAA,MAAS,UAAU,MAAM;AAAA,MAAU,OAAO,MAAM;AAAA,MAAO,OAAO,MAAM,SAAS;AAAA,MAAM,QAAQ,MAAM;AAAA,MAC7I,SAAS,MAAM,KAAK,cAAc,MAAM,YAAY,cAAc;AAAA,MAAU;AAAA,MAAO;AAAA,MACnF,QAAQ,SAAS,MAAM,OAAO,YAAY,MAAM,UAAU,QAAQ,WAAW,OAAO,QAAQ,SAAS;AAAA,MACrG,aAAa,SAAS,MAAM,OAAO,uBAAuB,aAAa;AAAA,MAAG,iBAAiB,SAAS,MAAM,OAAO,2BAA2B,gBAAgB;AAAA,MAC5J,QAAQ,MAAM,UAAU;AAAA,MAAM,SAAS,MAAM,WAAW;AAAA,MAAM,QAAQ,MAAM,WAAW,QAAQ,QAAQ;AAAA,MACvG,QAAQ,MAAM,SAAS,OAAO,YAAY,CAAC,WAAW,UAAU,YAAY,cAAc,EAAE,IAAI,OAAK,CAAC,GAAG,SAAS,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;AAAA,MAAM,cAAc,MAAM,SAAS,aAAa;AAAA,IAAK,CAAC;AAChM,UAAM,QAAQ,OAAO,KAAK,KAAK,KAAK,IAAI,EAAE,KAAK;AAAG,eAAW,OAAO,MAAM,MAAM,GAAG,GAAG,EAAG,QAAO,KAAK,KAAK,KAAK,GAAG;AAClH,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EACA,UAAU;AAAE,SAAK,MAAM;AAAG,UAAM,QAAQ,gBAAgB,EAAE,GAAG,KAAK,MAAM,SAAS,EAAE,CAAC;AAAG,SAAK,QAAQ,KAAK,MAAM,MAAM,MAAM;AAAA,IAAC,CAAC,EAAE,KAAK,MAAM,iBAAiB,KAAK,MAAM,KAAK,CAAC;AAAG,WAAO,KAAK;AAAA,EAAO;AAAA,EAClM,QAAQ;AAAE,SAAK,MAAM;AAAG,WAAO,EAAE,GAAG,gBAAgB,KAAK,IAAI,GAAG,eAAe,KAAK,eAAe,OAAO,IAAI,KAAK,IAAI,CAAC,GAAG,WAAW,KAAK,IAAI,EAAE;AAAA,EAAG;AACtJ;AAGO,SAAS,cAAc,UAAU,UAAU,QAAQ,EAAE,MAAM,MAAM,YAAY,IAAI,GAAG,YAAY,IAAI,EAAE,IAAI,CAAC,GAAG;AACnH,MAAI,CAAC,SAAS,KAAM,QAAO;AAC3B,QAAM,SAAS,SAAS,KAAK,UAAU,GAAG,UAAU,IAAI,YAAY;AACpE,MAAI,UAAU,IAAI,OAAO,QAAQ,OAAO,SAAS,OAAO,WAAW,OAAO,aAAa,MAAM,aAAa;AAC1G,iBAAe,OAAO,YAAY,OAAO;AAAE,QAAI,SAAU;AAAQ,eAAW;AAAM,UAAM,MAAM,cAAc,IAAI;AAAG,UAAM,SAAS,EAAE,OAAO,IAAI,SAAS,CAAC,UAAU,CAAC,WAAW,WAAW,QAAQ,EAAE,SAAS,KAAK,IAAI,GAAG,MAAM,SAAS,GAAG,QAAQ,eAAe,OAAO,OAAO,KAAK,IAAI,GAAG,aAAa,SAAS,GAAG,UAAU,eAAe,OAAO,OAAO,KAAK,IAAI,GAAG,MAAM,UAAU,GAAG,cAAc,eAAe,OAAO,OAAO,SAAS,OAAO,iBAAiB,EAAE,EAAE,CAAC;AAAA,EAAG;AAC/c,WAAS,QAAQ,OAAO;AACtB,eAAW,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AACjD,QAAI;AACJ,WAAQ,QAAQ,aAAa,KAAK,OAAO,GAAI;AAC3C,YAAM,QAAQ,QAAQ,MAAM,GAAG,MAAM,KAAK;AAAG,gBAAU,QAAQ,MAAM,MAAM,QAAQ,MAAM,CAAC,EAAE,MAAM;AAClG,YAAM,OAAO,MAAM,MAAM,OAAO,EAAE,OAAO,OAAK,EAAE,WAAW,OAAO,CAAC,EAAE,IAAI,OAAK,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC,EAAE,KAAK,IAAI;AAC/G,UAAI,SAAS,UAAU;AAAE,gBAAQ;AAAM,uBAAe,IAAI;AAAG;AAAA,MAAU;AACvE,UAAI;AAAE,cAAM,QAAQ,KAAK,MAAM,IAAI;AAAG,YAAI,MAAM,SAAS,CAAC,iBAAiB,qBAAqB,cAAc,EAAE,KAAK,OAAK,OAAO,SAAS,MAAM,MAAM,CAAC,CAAC,KAAK,MAAM,MAAM,CAAC,KAAK,CAAC,EAAG,SAAQ,MAAM;AAAO,YAAI,MAAM,MAAO,UAAS;AAAM,YAAI,eAAe,QAAQ,MAAM,SAAS,KAAK,OAAK;AAAE,gBAAM,IAAI,EAAE;AAAO,iBAAO,CAAC,GAAG,SAAS,GAAG,mBAAmB,GAAG,SAAS,EAAE,KAAK,OAAK,OAAO,MAAM,YAAY,EAAE,KAAK,CAAC,KAAK,GAAG,YAAY,KAAK,OAAK,EAAE,UAAU,QAAQ,EAAE,UAAU,SAAS;AAAA,QAAG,CAAC,EAAG,cAAa,IAAI;AAAG,YAAI,MAAM,SAAS,KAAK,OAAK,EAAE,aAAa,GAAG;AAAE,kBAAQ;AAAM,yBAAe,IAAI;AAAA,QAAG;AAAA,MAAE,QAAQ;AAAA,MAAoC;AAAA,IAC3nB;AACA,QAAI,QAAQ,SAAS,OAAO,MAAM;AAAE,gBAAU;AAAI,eAAS;AAAA,IAAM;AAAA,EACnE;AACA,QAAM,OAAO,IAAI,eAAe;AAAA,IAC9B,MAAM,KAAK,YAAY;AACrB,UAAI;AAAE,gBAAQ,eAAe;AAAG,cAAM,QAAQ,MAAM,OAAO,KAAK;AAAG,YAAI,MAAM,MAAM;AAAE,gBAAM,OAAO;AAAG,qBAAW,MAAM;AAAA,QAAG,OAAO;AAAE,kBAAQ,MAAM,KAAK;AAAG,qBAAW,QAAQ,MAAM,KAAK;AAAA,QAAG;AAAA,MAAE,SACpL,GAAG;AAAE,cAAM,OAAO,QAAQ,OAAO;AAAG,mBAAW,MAAM,CAAC;AAAG,cAAM,OAAO,OAAO,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MAAG;AAAA,IACzG;AAAA,IACA,MAAM,OAAO,QAAQ;AAAE,YAAM,OAAO,OAAO,MAAM,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAG,YAAM,OAAO,CAAC,KAAK;AAAA,IAAG;AAAA,EAC5F,CAAC;AACD,SAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,SAAS,QAAQ,SAAS,SAAS,QAAQ,CAAC;AAClF;AAIO,IAAM,iBAAN,MAAqB;AAAA,EAC1B,YAAY,WAAW;AAAE,SAAK,YAAY;AAAW,SAAK,QAAQ,oBAAI,IAAI;AAAA,EAAG;AAAA,EAC7E,IAAI,IAAI;AAAE,WAAO,WAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,CAAC,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AAAA,EAAG;AAAA,EACrF,UAAU,WAAW,SAAS;AAC5B,UAAM,SAAS,WAAW,GAAG,UAAU,aAAa,OAAO,OAAO,KAAK,IAAI,SAAS;AACpF,UAAM,OAAO,WAAW,KAAK,MAAM,IAAI,OAAO;AAC9C,QAAI,QAAQ,CAAC,QAAS,MAAK,SAAS;AACpC,WAAO,EAAE,QAAQ,QAAQ;AAAA,EAC3B;AAAA,EACA,MAAM,SAAS,OAAO;AACpB,UAAM,MAAM,KAAK,IAAI,QAAQ,EAAE,GAAG,IAAI,MAAM;AAC5C,QAAI,MAAM,SAAS,cAAc;AAAE,WAAK,MAAM,IAAI,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,MAAM,OAAO,MAAM,MAAM,OAAO,MAAM,OAAO,oBAAI,IAAI,GAAG,QAAQ,GAAG,WAAW,GAAG,gBAAgB,EAAE,CAAC;AAAG;AAAA,IAAQ;AAC9L,UAAM,OAAO,KAAK,MAAM,IAAI,GAAG;AAC/B,QAAI,CAAC,KAAM;AACX,QAAI,EAAE,SAAS,WAAc,EAAE,SAAS,KAAK,QAAQ,EAAE,SAAS,UAAa,EAAE,SAAS,KAAK,MAAO;AACpG,QAAI,MAAM,SAAS,qBAAqB;AAAE,WAAK,UAAU,8BAA8B,EAAE,MAAM,KAAK;AAAM;AAAA,IAAQ;AAClH,UAAM,MAAM,KAAK,UAAU,KAAK,OAAO,KAAK,OAAK,EAAE,WAAW,KAAK,UAAU,EAAE,YAAY,GAAG;AAC9F,QAAI,MAAM,SAAS,qBAAqB;AACtC,UAAI,CAAC,OAAO,EAAE,YAAa;AAC3B,YAAM,QAAQ,KAAK,SAAS,8BAA8B,EAAE,MAAM,KAAK;AACvE,YAAM,SAAS,SAAS,EAAE,OAAO,YAAY;AAC7C,UAAI,SAAS;AAAA,QAAE,SAAS,KAAK,IAAI,GAAG,MAAM,OAAO,KAAK,KAAK;AAAA,QAAG,QAAQ,UAAU,OAAO,OAAO,KAAK,IAAI,GAAG,QAAQ,KAAK,KAAK;AAAA,QAC1H,UAAU,UAAU,QAAQ,WAAW,OAAO,OAAO,KAAK,IAAI,GAAG,MAAM,OAAO,KAAK;AAAA,QAAG,cAAc,UAAU,OAAO,OAAO;AAAA,MAAO;AACrI,UAAI,eAAe;AAAA,IACrB,WAAW,MAAM,SAAS,eAAe,KAAK,iBAAiB,YAAY;AACzE,UAAI,CAAC,KAAK,MAAM,IAAI,EAAE,MAAM,GAAG;AAAE,aAAK,MAAM,IAAI,EAAE,QAAQ,MAAM,IAAI;AAAG,aAAK;AAAA,MAAa;AAAA,IAC3F,WAAW,MAAM,SAAS,iBAAiB,KAAK,MAAM,IAAI,EAAE,SAAS,QAAQ,MAAM,GAAG;AACpF,YAAM,KAAK,EAAE,QAAQ,OAAO;AAC5B,WAAK,UAAU,KAAK,IAAI,GAAG,MAAM,OAAO,KAAK,MAAM,IAAI,EAAE,CAAC;AAAG,WAAK;AAAkB,WAAK,MAAM,OAAO,EAAE;AAAA,IAC1G,WAAW,MAAM,SAAS,cAAc,MAAM,SAAS,YAAY;AACjE,WAAK,MAAM,OAAO,GAAG;AAAA,IACvB,MAAO;AACP,QAAI,KAAK,iBAAiB,WAAY;AACtC,WAAO,OAAO,IAAI,QAAQ,EAAE,QAAQ,KAAK,QAAQ,WAAW,KAAK,WAAW,gBAAgB,KAAK,eAAe,CAAC;AACjH,WAAO,KAAK,UAAU,QAAQ;AAAA,EAChC;AAAA,EACA,QAAQ,SAAS;AAAE,SAAK,MAAM,OAAO,KAAK,IAAI,QAAQ,EAAE,CAAC;AAAA,EAAG;AAC9D;;;ACvIA,IAAM,WAAW,OAAK,OAAO,cAAc,CAAC,KAAK,IAAI;AAG9C,SAAS,YAAY,OAAO;AACjC,QAAM,uBAAuB,SAAS,MAAM,oBAAoB,IAAI,MAAM,uBACtE,SAAS,MAAM,aAAa,IAAI,MAAM,gBAAgB;AAC1D,QAAM,0BAA0B,CAAC,GAAG,IAAI,IAAI;AAAA,IAAC;AAAA,IAAsB,MAAM;AAAA,IAAe,MAAM;AAAA,IAC5F,GAAI,MAAM,QAAQ,MAAM,uBAAuB,IAAI,MAAM,0BAA0B,CAAC;AAAA,EAAE,EAAE,OAAO,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AACjI,QAAM,mBAAmB,wBAAwB,GAAG,EAAE;AACtD,SAAO,EAAE,sBAAsB,yBAAyB,kBAAkB,eAAe,iBAAiB;AAC5G;AAEO,SAAS,eAAe,QAAQ,UAAU,WAAW,KAAQ;AAClE,QAAM,QAAQ,OAAO,IAAI,WAAW;AACpC,QAAM,mBAAmB,MAAM,SAAS,KAAK,IAAI,GAAG,MAAM,IAAI,OAAK,EAAE,gBAAgB,CAAC,IAAI;AAC1F,QAAM,gBAAgB,SAAS,QAAQ,IAAI,KAAK,IAAI,UAAU,gBAAgB,IAAI;AAClF,SAAO;AAAA,IAAE;AAAA,IAAkB;AAAA,IAAe,cAAc,MAAM,SAAS;AAAA,IAAG,yBAAyB,SAAS,QAAQ,IAAI,WAAW;AAAA,IACjI,yBAAyB,CAAC,GAAG,oBAAI,IAAI,CAAC,eAAe,GAAG,MAAM,QAAQ,OAAK,EAAE,uBAAuB,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAAA,EAAE;AACnI;AAIO,SAAS,kBAAkB,OAAO,QAAQ;AAC/C,MAAI,CAAC,OAAO,eAAgB,QAAO;AACnC,QAAM,UAAU,OAAO,QAAQ,MAAM,cAAc,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,SAAS,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,UAAU;AAC/I,MAAI,CAAC,QAAQ,OAAQ,QAAO;AAC5B,QAAM,WAAW,UAAU,OAAO,QAAQ,GAAG,EAAE,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,MAAM;AACjG,MAAI,CAAC,SAAU,OAAM,OAAO,OAAO,MAAM,4BAA4B,GAAG,EAAE,QAAQ,KAAK,MAAM,6BAA6B,CAAC;AAC3H,SAAO;AAAA,IAAE,GAAG;AAAA,IAAO,eAAe,SAAS,CAAC,EAAE;AAAA,IAC5C,gBAAgB,OAAO,YAAY,OAAO,QAAQ,MAAM,cAAc,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,EAAE,GAAG,OAAO,WAAW,QAAQ,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;AAAA,EAAE;AACxJ;;;AC1BO,IAAM,aAAN,cAAyB,MAAM;AAAA,EACpC,YAAY,QAAQ,MAAM,WAAW,CAAC,GAAG,MAAM;AAC7C,UAAM,GAAG,IAAI,GAAG,SAAS,SAAS,OAAO,SAAS,IAAI,OAAK,GAAG,EAAE,OAAO,SAAS,EAAE,MAAM,EAAE,EAAE,KAAK,IAAI,IAAI,EAAE,GAAG,OAAO,SAAI,IAAI,WAAM,EAAE,EAAE;AACvI,SAAK,SAAS;AAAQ,SAAK,OAAO;AAAM,SAAK,WAAW;AAAU,SAAK,OAAO;AAAA,EAChF;AACF;AACA,IAAM,YAAY,WAAS,MAAM,YAAY,EAAE,QAAQ,cAAc,EAAE,EAAE,QAAQ,aAAa,EAAE;AACzF,SAAS,UAAU,SAAS,QAAQ;AACzC,MAAI,CAAC,OAAQ,QAAO;AAEpB,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,QAAQ,MAAM,OAAO,OAAO,UAAU,IAAI,aAAa,WAAW,YAAY,CAAC;AACrF,WAAO,iBAAiB,SAAS,OAAO,EAAE,MAAM,KAAK,CAAC;AACtD,QAAI,OAAO,QAAS,OAAM;AAC1B,YAAQ,QAAQ,OAAO,EAAE,KAAK,SAAS,MAAM,EAAE,QAAQ,MAAM,OAAO,oBAAoB,SAAS,KAAK,CAAC;AAAA,EACzG,CAAC;AACH;AACO,SAAS,WAAW,OAAO,QAAQ,SAAS,QAAQ,WAAW,OAAO,UAAU;AACrF,QAAM,UAAU,OAAK,MAAM,WAAW,UAAa,eAAe,GAAG,QAAQ,EAAE,SAAS,MAAM;AAC9F,MAAI,OAAO,MAAO,QAAO,QAAQ,KAAK,OAAK,EAAE,OAAO,OAAO,SAAS,QAAQ,CAAC,CAAC;AAC9E,MAAI,OAAO,OAAQ,QAAO,OAAO,OAAO,IAAI,QAAM,QAAQ,KAAK,OAAK,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,OAAO;AAC9F,MAAI,UAAU,SAAU,QAAO,QAAQ,KAAK,OAAK,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,KAAK,OAAK,UAAU,CAAC,MAAM,kBAAkB,CAAC;AACpI;AAEO,IAAM,SAAN,MAAa;AAAA,EAClB,YAAY,QAAQ,cAAc,YAAY,MAAM;AAAA,EAAC,GAAG,MAAM,KAAK,KAAK;AACtE,SAAK,SAAS;AAAQ,SAAK,eAAe;AAAc,SAAK,YAAY;AAAW,SAAK,MAAM;AAC/F,SAAK,YAAY;AAAM,SAAK,SAAS,oBAAI,IAAI;AAAG,SAAK,UAAU;AAAM,SAAK,UAAU,oBAAI,IAAI;AAAG,SAAK,YAAY,oBAAI,IAAI;AAAG,SAAK,SAAS,oBAAI,IAAI;AAAG,SAAK,UAAU,oBAAI,IAAI;AAAA,EAC7K;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,iBAAiB,YAAY,OAAO,KAAK;AACvC,UAAM,SAAS,oBAAI,IAAI;AACvB,eAAW,aAAa,YAAY;AAClC,YAAM,OAAO,MAAM,SAAS;AAC5B,UAAI,CAAC,OAAO,IAAI,IAAI,EAAG,QAAO,IAAI,MAAM,CAAC,CAAC;AAC1C,aAAO,IAAI,IAAI,EAAE,KAAK,SAAS;AAAA,IACjC;AACA,UAAM,SAAS,CAAC;AAChB,eAAW,WAAW,OAAO,OAAO,GAAG;AACrC,YAAM,YAAY,QAAQ,IAAI,CAAC,WAAW,WAAW,EAAE,WAAW,OAAO,KAAK,IAAI,SAAS,EAAE,EAAE;AAC/F,gBAAU,KAAK,CAAC,GAAG,MAAM;AACvB,YAAI,EAAE,QAAQ,EAAE,IAAK,QAAO,EAAE,QAAQ,EAAE;AACxC,YAAI,EAAE,QAAQ,OAAW,QAAO;AAChC,YAAI,EAAE,QAAQ,OAAW,QAAO;AAChC,eAAO,EAAE,MAAM,EAAE;AAAA,MACnB,CAAC;AACD,aAAO,KAAK,GAAG,UAAU,IAAI,WAAS,MAAM,SAAS,CAAC;AAAA,IACxD;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBA,iBAAiB,OAAO,OAAO,YAAY,QAAQ,MAAM,OAAO;AAC9D,QAAI,CAAC,WAAW,OAAQ,QAAO;AAC/B,UAAM,YAAY,MAAM,0BAA0B;AAClD,UAAM,QAAQ,KAAK,QAAQ,IAAI,KAAK,KAAK,oBAAI,IAAI;AACjD,SAAK,QAAQ,IAAI,OAAO,KAAK;AAC7B,UAAM,OAAO,IAAI,IAAI,WAAW,IAAI,OAAK,EAAE,QAAQ,EAAE,CAAC;AACtD,eAAW,MAAM,MAAM,KAAK,EAAG,KAAI,CAAC,KAAK,IAAI,EAAE,EAAG,OAAM,OAAO,EAAE;AACjE,UAAM,SAAS,oBAAI,IAAI;AACvB,eAAW,aAAa,YAAY;AAClC,YAAM,OAAO,MAAM,SAAS;AAC5B,UAAI,CAAC,OAAO,IAAI,IAAI,EAAG,QAAO,IAAI,MAAM,CAAC,CAAC;AAC1C,aAAO,IAAI,IAAI,EAAE,KAAK,SAAS;AAAA,IACjC;AACA,UAAM,SAAS,CAAC;AAChB,eAAWC,UAAS,OAAO,OAAO,GAAG;AACnC,YAAM,QAAQ,CAAC,GAAG,QAAQ,CAAC;AAC3B,iBAAW,aAAaA,QAAO;AAC7B,cAAM,KAAK,UAAU,QAAQ,IAAI,MAAM,KAAK,UAAU,IAAI,YAAY,EAAE;AACxE,cAAM,WAAW,IAAI,mBAAmB;AACxC,YAAI,CAAC,MAAM,IAAI,EAAE,EAAG,OAAM,IAAI,IAAI,QAAQ;AAC1C,cAAM,OAAO,WAAW,MAAM,IAAI,EAAE;AAGpC,YAAI,CAAC,OAAO,SAAS,IAAI,KAAK,OAAO,GAAG;AAAE,gBAAM,IAAI,IAAI,QAAQ;AAAG,gBAAM,KAAK,SAAS;AAAG;AAAA,QAAU;AACpG,SAAC,QAAQ,YAAY,QAAQ,OAAO,KAAK,SAAS;AAAA,MACpD;AACA,UAAI,CAAC,MAAM,QAAQ;AAAE,eAAO,KAAK,GAAG,KAAK;AAAG;AAAA,MAAU;AACtD,UAAI,MAAM,WAAWA,OAAM,QAAQ;AAGjC,mBAAW,aAAaA,OAAO,OAAM,IAAI,UAAU,QAAQ,IAAI,KAAK,UAAU,IAAI,YAAY,UAAU,QAAQ,EAAE,EAAE,mBAAmB,CAAC;AACxI,eAAO,KAAK,GAAGA,MAAK;AACpB;AAAA,MACF;AACA,aAAO,KAAK,GAAG,OAAO,GAAG,KAAK;AAAA,IAChC;AACA,WAAO;AAAA,EACT;AAAA,EACA,aAAa,QAAQ;AACnB,eAAW,OAAO,KAAK,OAAO,UAAU;AACtC,YAAM,OAAO,OAAO,SAAS,KAAK,OAAK,EAAE,OAAO,IAAI,EAAE;AACtD,UAAI,CAAC,QAAQ,KAAK,aAAa,IAAI,YAAY,KAAK,mBAAmB,IAAI,kBAAkB,KAAK,iBAAiB,IAAI,aAAc,MAAK,QAAQ,OAAO,IAAI,EAAE;AAAA,IACjK;AACA,SAAK,SAAS;AACd,eAAW,SAAS,KAAK,OAAO,KAAK,EAAG,KAAI,CAAC,OAAO,OAAO,OAAO,QAAQ,KAAK,EAAG,MAAK,OAAO,OAAO,KAAK;AAC1G,eAAW,SAAS,KAAK,QAAQ,KAAK,EAAG,KAAI,CAAC,OAAO,OAAO,OAAO,QAAQ,KAAK,EAAG,MAAK,QAAQ,OAAO,KAAK;AAAA,EAC9G;AAAA,EACA,MAAM,OAAO,SAAS;AACpB,QAAI,CAAC,KAAK,QAAQ,IAAI,QAAQ,EAAE,EAAG,MAAK,QAAQ,IAAI,QAAQ,IAAI,QAAQ,QAAQ,EAAE,KAAK,MAAM,KAAK,aAAa,OAAO,CAAC,CAAC;AACxH,QAAI;AAAE,aAAO,MAAM,KAAK,QAAQ,IAAI,QAAQ,EAAE;AAAA,IAAG,SAC1C,OAAO;AAAE,WAAK,QAAQ,OAAO,QAAQ,EAAE;AAAG,YAAM;AAAA,IAAO;AAAA,EAChE;AAAA,EACA,SAAS;AACP,WAAO,KAAK,OAAO,SAAS,IAAI,QAAM;AAAA,MAAE,IAAI,EAAE;AAAA,MAAI,UAAU,EAAE;AAAA,MAAU,SAAS,EAAE,YAAY;AAAA,MAC7F,WAAW,CAAC,GAAG,KAAK,SAAS,EAAE,OAAO,CAAC,CAAC,KAAK,IAAI,MAAM,IAAI,WAAW,GAAG,EAAE,EAAE,GAAG,KAAK,OAAO,KAAK,IAAI,CAAC,EACnG,IAAI,CAAC,CAAC,KAAK,IAAI,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,aAAa,OAAO,KAAK,IAAI,EAAE,EAAE;AAAA,MAC/F,WAAW,CAAC,GAAG,KAAK,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,GAAG,MAAM,IAAI,MAAM,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,KAAK,MAAM,KAAK;AAAA,IAAE,EAAE;AAAA,EAC1G;AAAA,EACA,WAAW,OAAO;AAChB,UAAM,QAAQ,KAAK,OAAO,OAAO,KAAK;AACtC,QAAI,CAAC,OAAO,OAAO,KAAK,OAAO,QAAQ,KAAK,EAAG,OAAM,IAAI,WAAW,KAAK,iBAAiB,CAAC,GAAG,0KAA8B;AAC5H,UAAM,aAAa,MAAM,QAAQ,QAAQ,CAAC,QAAQ,UAAU,KAAK,OAAO,SACrE,OAAO,OAAK,EAAE,YAAY,SAAS,EAAE,aAAa,OAAO,aAAa,CAAC,OAAO,WAAW,EAAE,OAAO,OAAO,QAAQ,EACjH,QAAQ,aAAW,MAAM,YAAY,KAAK,aAAa,OAAO,KAAK,CAAC,GAAG,OAAO,QAAM,CAAC,OAAO,SAAS,EAAE,OAAO,OAAO,WAAW,CAAC,OAAO,UAAU,OAAO,OAAO,SAAS,EAAE,EAAE,EAAE,EAC7K,IAAI,YAAU,EAAE,SAAS,QAAQ,EAAE,GAAG,QAAQ,OAAO,MAAM,IAAI,QAAQ,OAAU,GAAG,KAAK,GAAG,QAAQ,EAAE,IAAI,KAAK,IAAI,MAAM,EAAE,GAAG,EAAE,IAC/H,CAAC,EAAE,SAAS,QAAQ,KAAK,GAAG,QAAQ,EAAE,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;AAC3D,UAAM,SAAS,WAAW,UAAU,OAAK,EAAE,QAAQ,KAAK,OAAO,IAAI,KAAK,CAAC;AACzE,WAAO,SAAS,IAAI,aAAa,CAAC,GAAG,WAAW,MAAM,MAAM,GAAG,GAAG,WAAW,MAAM,GAAG,MAAM,CAAC;AAAA,EAC/F;AAAA,EACA,WAAW,SAAS,OAAO;AACzB,UAAM,UAAU,KAAK,WAAW,IAAI,YAAY,QAAQ,EAAE,EAAE;AAC5D,QAAI,CAAC,WAAW,QAAQ,SAAS,QAAQ,SAAS,aAAa,KAAK,IAAI,IAAI,QAAQ,YAAY,KAAQ,QAAO;AAC/G,UAAM,UAAU,KAAK,IAAI,KAAK,MAAM,sBAAsB,KAAK;AAC/D,WAAO,KAAK,IAAI,UAAU,IAAI,QAAQ,YAAY,CAAC,GAAG,OAAO,OAAK,EAAE,YAAY,KAAK,CAAC,EAAE,aAAa,EAAE,YAAY,KAAK,IAAI,KAAK,EAAE,aAAa,OAAO,EAAE,IAAI,OAAK,EAAE,SAAS,CAAC;AAAA,EAChL;AAAA,EACA,MAAM,aAAa,OAAO,OAAO,YAAY,QAAQ,MAAM,MAAM;AAC/D,QAAI,CAAC,MAAM,yBAAyB,CAAC,KAAK,UAAW,QAAO;AAC5D,UAAM,QAAQ,KAAK,UAAU,SAAS,KAAK;AAC3C,QAAI,MAAM,gBAAgB,KAAK,IAAI,EAAG,QAAO;AAC7C,UAAM,SAAS,KAAK,UAAU,KAAK;AACnC,QAAI,MAAM,eAAe;AAAE,YAAM,WAAW,CAAC;AAAG,YAAM,YAAY,CAAC;AAAG,YAAM,gBAAgB;AAAG,YAAM;AAAA,IAAU;AAC/G,eAAW,MAAM,MAAM,UAAU;AAC/B,YAAM,UAAU,WAAW,OAAO,OAAK,EAAE,QAAQ,OAAO,EAAE,GAAG,UAAU,KAAK,UAAU,IAAI,YAAY,EAAE,EAAE;AAC1G,YAAM,QAAQ,WAAW,CAAC,QAAQ,SAAS,QAAQ,SAAS,aAAa,KAAK,IAAI,IAAI,QAAQ,aAAa;AAC3G,UAAI,CAAC,QAAQ,UAAU,QAAQ,MAAM,OAAK,CAAC,MAAM,CAAC,CAAC,KAAM,SAAS,CAAC,OAAO,SAAS,KAAK,WAAW,EAAE,GAAG,GAAG,KAAK,CAAC,GAAI;AACnH,YAAI,CAAC,MAAM,UAAU,SAAS,EAAE,EAAG,OAAM,UAAU,KAAK,EAAE;AAAA,MAC5D;AAAA,IACF;AACA,eAAW,KAAK,WAAY,KAAI,MAAM,CAAC,KAAK,OAAO,SAAS,KAAK,WAAW,EAAE,SAAS,KAAK,CAAC,KAAK,CAAC,MAAM,SAAS,SAAS,EAAE,QAAQ,EAAE,EAAG,OAAM,SAAS,KAAK,EAAE,QAAQ,EAAE;AAE1K,QAAI,MAAM,SAAS,UAAU,MAAM,SAAS,MAAM,QAAM,MAAM,UAAU,SAAS,EAAE,CAAC,EAAG,OAAM,gBAAgB,KAAK,IAAI,IAAI,IAAI;AAC9H,QAAI,KAAK,UAAU,KAAK,MAAM,OAAQ,OAAM,KAAK,UAAU,QAAQ;AACnE,WAAO,MAAM,iBAAiB,KAAK,IAAI;AAAA,EACzC;AAAA,EACA,kBAAkB,WAAW,OAAO,OAAO;AACzC,UAAM,KAAK,UAAU,QAAQ;AAC7B,UAAM,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,EAAE,IAAI,KAAK,EAAE;AACzC,QAAI,MAAM,SAAU,MAAK,KAAK,GAAG,EAAE,IAAI,KAAK,IAAI,UAAU,OAAO,KAAK,EAAE;AACxE,WAAO,KAAK,IAAI,GAAG,GAAG,KAAK,IAAI,UAAQ,KAAK,UAAU,IAAI,GAAG,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC;AAAA,EACpF;AAAA,EACA,YAAY,EAAE,OAAO,OAAO,UAAU,YAAY,kBAAkB,SAAS,GAAG;AAC9E,UAAM,QAAQ,IAAI,IAAI,SAAS,IAAI,OAAK,EAAE,IAAI,CAAC;AAC/C,UAAM,YAAY,SAAS,SAAS,KAAK,CAAC,GAAG,KAAK,EAAE,MAAM,OAAK,CAAC,qBAAqB,gCAAgC,wBAAwB,4BAA4B,EAAE,SAAS,CAAC,CAAC;AACtL,UAAM,UAAU,WAAW,IAAI,OAAK,KAAK,kBAAkB,GAAG,OAAO,KAAK,CAAC,EAAE,OAAO,QAAM,KAAK,CAAC;AAChG,UAAM,UAAU,QAAQ,SAAS,KAAK,IAAI,GAAG,OAAO,IAAI;AACxD,UAAM,YAAY,YAAY,SAAY,SAAY,UAAK,KAAK,IAAI,GAAG,KAAK,KAAK,UAAU,GAAI,CAAC,CAAC;AACjG,QAAI,CAAC,iBAAiB,OAAQ,QAAO,MAAM,WACvC,iNACA;AACJ,QAAI,MAAM,IAAI,4BAA4B,KAAK,UAAW,QAAO;AACjE,QAAI,UAAW,QAAO,uLAAiC,YAAY,yDAAY,SAAS,KAAK,EAAE;AAC/F,QAAI,YAAY,UAAa,QAAQ,UAAU,WAAW,QAAQ;AAChE,aAAO,SAAS,SAAS,2HAAuB,SAAS,KAAK,2EAAe,SAAS;AAAA,IACxF;AACA,QAAI,YAAY,OAAW,QAAO,2EAAe,SAAS;AAC1D,QAAI,CAAC,SAAS,UAAU,CAAC,UAAU,SAAS,EAAE,SAAS,QAAQ,EAAG,QAAO,6CAAU,aAAa,WAAW,WAAW,cAAI;AAC1H,WAAO;AAAA,EACT;AAAA,EACA,MAAM,KAAK,OAAO,QAAQ,WAAW,CAAC,GAAG;AACvC,UAAM,QAAQ,MAAM;AACpB,QAAI,CAAC,MAAM,QAAQ,MAAM,QAAQ,KAAK,CAAC,MAAM,SAAS,UAAU,MAAM,WAAW,KAAM,OAAM,IAAI,WAAW,KAAK,mCAAmC;AACpJ,UAAM,eAAe,KAAK,OAAO,OAAO,KAAK;AAC7C,QAAI,cAAc,UAAU;AAC1B,YAAM,UAAU,KAAK,cAAc,GAAG,MAAM;AAC5C,UAAI,CAAC,KAAK,OAAO,OAAO,KAAK,EAAG,OAAM,IAAI,WAAW,KAAK,+BAA+B,CAAC,GAAG,sFAAgB;AAAA,IAC/G;AACA,UAAM,SAAS,OAAO,OAAO,OAAO,kBAAkB,IAAI,MAAM,mBAAmB,KAAK,OAAO,OAAO,KAAK,GAAG;AAC9G,YAAQ,EAAE,GAAG,MAAM;AAAG,WAAO,MAAM;AACnC,QAAI,WAAW,UAAa,WAAW,KAAM,OAAM,mBAAmB;AACtE,QAAI,aAAa,KAAK,WAAW,KAAK;AACtC,UAAM,mBAAmB,CAAC,GAAG,UAAU;AACvC,UAAM,QAAQ,KAAK,OAAO,OAAO,KAAK,GAAG,WAAW,MAAM,YAAY;AACtE,UAAM,YAAY,QAAM,KAAK,UAAU,IAAI,GAAG,EAAE,QAAQ,EAAE,IAAI,KAAK,MAAM,KAAK,IAAI,MAAM,KAAK,UAAU,IAAI,GAAG,EAAE,QAAQ,EAAE,IAAI,KAAK,EAAE,KAAK,MAAM,KAAK,IAAI,MACnJ,CAAC,MAAM,aAAa,KAAK,UAAU,IAAI,GAAG,EAAE,QAAQ,EAAE,IAAI,KAAK,IAAI,EAAE,OAAO,KAAK,EAAE,KAAK,MAAM,KAAK,IAAI;AAC7G,QAAI,MAAM,yBAAyB,KAAK,SAAS;AAC/C,YAAM,QAAQ,IAAI,CAAC,GAAG,IAAI,IAAI,WAAW,OAAO,SAAS,EAAE,IAAI,OAAK,CAAC,EAAE,QAAQ,IAAI,EAAE,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,IAAI,OAAK;AACjH,cAAM,WAAW,KAAK,WAAW,IAAI,YAAY,EAAE,EAAE,EAAE;AACvD,eAAO,CAAC,YAAY,SAAS,SAAS,KAAK,IAAI,IAAI,SAAS,YAAY,MAAQ,KAAK,QAAQ,CAAC,IAAI;AAAA,MACpG,CAAC,CAAC;AACF,cAAQ,eAAe;AAAA,IACzB;AACA,QAAI,aAAa,WAAW;AAC1B,YAAM,QAAQ,IAAI,CAAC,GAAG,IAAI,IAAI,WAAW,OAAO,SAAS,EAAE,IAAI,OAAK,CAAC,EAAE,QAAQ,IAAI,EAAE,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,IAAI,OAAK,KAAK,UAAU,CAAC,CAAC,CAAC;AACrI,cAAQ,eAAe;AACvB,mBAAa,WAAW,OAAO,OAAK;AAAE,cAAM,UAAU,KAAK,WAAW,IAAI,YAAY,EAAE,QAAQ,EAAE,EAAE;AAAS,eAAO,SAAS,SAAS,aAAa,OAAO,SAAS,QAAQ,SAAS,KAAK,KAAK,IAAI,IAAI,QAAQ,YAAY,QAAU,CAAC,QAAQ;AAAA,MAAO,CAAC;AACrP,UAAI,CAAC,WAAW,OAAQ,OAAM,IAAI,WAAW,KAAK,4BAA4B,CAAC,GAAG,wGAAmB;AAAA,IACvG;AACA,UAAM,YAAY,KAAK,UAAU,EAAE,UAAU,SAAS,MAAM,QAAQ,CAAC;AACrE,QAAI,QAAQ,MAAM,MAAM;AACxB,QAAI,KAAK,aAAa,CAAC,UAAU,SAAS,EAAE,SAAS,QAAQ,GAAG;AAC9D,YAAM,QAAQ,KAAK,UAAU,MAAM,OAAO,SAAS;AACnD,YAAM,WAAW,QAAM,EAAE,QAAQ,KAAK,UAAU,MAAM,OAAO,EAAE,QAAQ,EAAE,EAAE,QAAQ,SAAS,KAAK,UAAU,IAAI,YAAY,EAAE,QAAQ,EAAE,EAAE,mBAAmB,EAAE;AAC9J,iBAAW,KAAK,WAAY,KAAI,CAAC,OAAO,OAAO,MAAM,OAAO,EAAE,QAAQ,EAAE,EAAG,QAAO,eAAe,MAAM,OAAO,EAAE,QAAQ,IAAI,EAAE,OAAO,SAAS,CAAC,GAAG,YAAY,MAAM,UAAU,MAAM,cAAc,KAAK,CAAC;AACxM,cAAQ,OAAK,CAAC,MAAM,MAAM,EAAE,QAAQ,EAAE,KAAK,SAAS,CAAC,EAAE,QAAQ,IAAI,MAAM,MAAM,EAAE,QAAQ,EAAE,EAAE,QAAQ,KAAK,aAAa,WAAW,EAAE,OAAO,cAAc,EAAE,OAAO;AAClK,qBAAe,MAAM,KAAK,aAAa,OAAO,OAAO,kBAAkB,KAAK;AAE5E,UAAI,WAAW,UAAU,WAAW,MAAM,OAAK,CAAC,MAAM,CAAC,CAAC,GAAG;AACzD,cAAM,KAAK,UAAU,QAAQ,OAAO,YAAY,SAAS;AACzD,aAAK,OAAO,OAAO,KAAK;AACxB,cAAM,UAAU,IAAI,IAAI,WAAW,IAAI,OAAK,EAAE,GAAG,CAAC;AAClD,qBAAa,KAAK,WAAW,KAAK,EAAE,OAAO,OAAK,QAAQ,IAAI,EAAE,GAAG,CAAC;AAAA,MACpE;AACA,mBAAa,WAAW,OAAO,KAAK;AACpC,UAAI,aAAa,YAAY,WAAW,KAAK,OAAK,KAAK,UAAU,MAAM,OAAO,EAAE,QAAQ,EAAE,EAAE,YAAY,CAAC,GAAG;AAE1G,qBAAa,WAAW,OAAO,OAAK,KAAK,UAAU,MAAM,OAAO,EAAE,QAAQ,EAAE,EAAE,cAAc,CAAC;AAAA,MAC/F;AAAA,IACF;AACA,qBAAiB,MAAM,KAAK,aAAa,OAAO,OAAO,kBAAkB,KAAK;AAC9E,UAAM,SAAS,OAAK,gBAAgB,CAAC,KAAK,UAAU,SAAS,KAAK,EAAE,UAAU,SAAS,EAAE,QAAQ,EAAE,IAAI,KAAK,WAAW,EAAE,SAAS,KAAK,IAAI;AAI3I,UAAM,gBAAgB,OAAK,OAAO,SAAS,OAAO,CAAC,CAAC;AAIpD,QAAI,cAAc;AAChB,YAAM,UAAU,WAAW,IAAI,CAAC,WAAW,WAAW,EAAE,WAAW,MAAM,EAAE;AAC3E,cAAQ,KAAK,CAAC,GAAG,MAAM,OAAO,cAAc,EAAE,SAAS,CAAC,IAAI,OAAO,cAAc,EAAE,SAAS,CAAC,KACxF,OAAO,EAAE,SAAS,IAAI,OAAO,EAAE,SAAS,KAAK,EAAE,QAAQ,EAAE,KAAK;AACnE,mBAAa,QAAQ,IAAI,WAAS,MAAM,SAAS;AAAA,IACnD;AAKA,QAAI,MAAM,iBAAiB,CAAC,MAAM,SAAU,cAAa,KAAK,iBAAiB,YAAY,eAAa,OAAO,SAAS,GAAG,eAAa;AACtI,YAAM,OAAO,MAAM,cAAc,UAAU,QAAQ,EAAE;AACrD,aAAO,SAAS,SAAY,SAAY;AAAA,IAC1C,CAAC;AACD,QAAI,MAAM,kBAAkB,CAAC,MAAM,YAAY,KAAK,UAAW,cAAa,KAAK,iBAAiB,OAAO,OAAO,YAAY,aAAa;AACzI,QAAI,aAAa,YAAY;AAC3B,UAAI,WAAW,WAAW,OAAO,SAAS;AAC1C,YAAM,UAAU,KAAK,IAAI,UAAU,GAAG,SAAS,IAAI,MAAM,CAAC;AAC1D,UAAI,OAAO,SAAS,OAAO,EAAG,YAAW,SAAS,OAAO,OAAK,OAAO,CAAC,MAAM,OAAO;AACnF,UAAI,SAAS,QAAQ;AACnB,YAAI,SAAS,KAAK,OAAO,IAAI,KAAK;AAClC,YAAI,QAAQ,cAAc,WAAW;AAAE,mBAAS,EAAE,WAAW,QAAQ,oBAAI,IAAI,EAAE;AAAG,eAAK,OAAO,IAAI,OAAO,MAAM;AAAA,QAAG;AAClH,YAAI,QAAQ,GAAG;AACf,mBAAW,KAAK,UAAU;AAAE,gBAAM,SAAS,EAAE,OAAO,UAAU;AAAG,mBAAS;AAAQ,iBAAO,OAAO,IAAI,EAAE,MAAM,OAAO,OAAO,IAAI,EAAE,GAAG,KAAK,KAAK,MAAM;AAAG,cAAI,CAAC,UAAU,OAAO,OAAO,IAAI,EAAE,GAAG,IAAI,OAAO,OAAO,IAAI,OAAO,GAAG,EAAG,UAAS;AAAA,QAAG;AAC3O,eAAO,OAAO,IAAI,OAAO,KAAK,OAAO,OAAO,IAAI,OAAO,GAAG,IAAI,KAAK;AACnE,qBAAa,CAAC,QAAQ,GAAG,WAAW,OAAO,OAAK,MAAM,MAAM,CAAC;AAAA,MAC/D;AAAA,IACF;AACA,UAAM,WAAW,CAAC;AAElB,UAAM,QAAQ,oBAAI,IAAI;AACtB,eAAW,aAAa,YAAY;AAClC,cAAQ,eAAe;AACvB,YAAM,EAAE,SAAS,QAAQ,IAAI,IAAI;AACjC,UAAI,CAAC,UAAU,SAAS,EAAG;AAC3B,UAAI,QAAQ,aAAa;AACzB,UAAI;AACF,cAAM,SAAS,MAAM,UAAU,KAAK,OAAO,OAAO,GAAG,MAAM;AAC3D,cAAM,UAAU,MAAM,UAAU,OAAO,OAAO,MAAM,GAAG,MAAM;AAC7D,cAAM,WAAW,MAAM,iBAAiB,QAAQ,OAAO,OAAK,YAAY,CAAC,EAAE,oBAAoB,MAAM,aAAa,IAAI;AACtH,cAAM,QAAQ,WAAW,OAAO,QAAQ,UAAU,UAAU,MAAS;AACrE,YAAI,CAAC,OAAO;AAAE,mBAAS,KAAK;AAAA,YAAE,SAAS,QAAQ;AAAA,YAAI,UAAU,QAAQ;AAAA,YAAU,QAAQ;AAAA,YACrF,MAAM,WAAW,OAAO,QAAQ,SAAS,UAAU,MAAS,IAAI,+BAC5D,WAAW,OAAO,QAAQ,OAAO,IAAI,iCAAiC;AAAA,UAAoB,CAAC;AAAG;AAAA,QAAU;AAC9G,YAAI,MAAM,YAAY,CAAC,YAAY,OAAO,KAAK,IAAI,CAAC,GAAG;AAAE,mBAAS,KAAK,EAAE,SAAS,QAAQ,IAAI,UAAU,QAAQ,UAAU,QAAQ,KAAK,MAAM,uBAAuB,CAAC;AAAG;AAAA,QAAU;AAClL,sBAAc,MAAM;AACpB,cAAM,SAAS,GAAG,QAAQ,EAAE,IAAI,MAAM,EAAE;AACxC,YAAI,MAAM,IAAI,MAAM,EAAG;AACvB,cAAM,IAAI,MAAM;AAChB,oBAAY,YAAY,IAAI;AAC5B,iBAAS,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,OAAO,OAAO,MAAM,GAAG,GAAG,QAAQ,EAAE,eAAe,MAAM,cAAc,CAAC,GAAG,MAAM;AAC3H,gBAAQ,eAAe;AACvB,YAAI,OAAO,IAAI;AACb,eAAK,OAAO,IAAI,OAAO,GAAG;AAC1B,eAAK,UAAU,EAAE,SAAS,QAAQ,IAAI,UAAU,QAAQ,UAAU,OAAO,OAAO,MAAM,IAAI,QAAQ,IAAI,CAAC;AACvG,gBAAM,WAAW,KAAK,YAAY,cAAc,OAAO,UAAU,OAAM,YAAW;AAChF,kBAAM,KAAK,UAAU,OAAO,EAAE,GAAG,SAAS,GAAG,UAAU,SAAS,QAAQ,IAAI,UAAU,QAAQ,UAAU,OAAO,OAAO,MAAM,IAAI,UAAU,MAAM,QAAQ,QAAQ,KAAK,MAAM,QAAQ,YAAY,MAAM,IAAI,CAAC;AAC1M,kBAAM,KAAK,aAAa,OAAO,OAAO,kBAAkB,KAAK;AAC7D,gBAAI,aAAa,aAAa,MAAM,sBAAuB,MAAK,KAAK,UAAU,OAAO,EAAE,KAAK,MAAM,KAAK,aAAa,OAAO,OAAO,kBAAkB,KAAK,CAAC,EAAE,MAAM,MAAM;AAAA,YAAC,CAAC;AAAA,UAC7K,GAAG,QAAQ,EAAE,UAAU,CAAC,IAAI,OAAO;AACnC,iBAAO,EAAE,UAAU,SAAS,QAAQ,IAAI,UAAU,QAAQ,SAAS;AAAA,QACrE;AAAA,MACF,SAAS,OAAO;AACd,gBAAQ,eAAe;AACvB,cAAM,WAAW,MAAM,UAAU,MAAM,SAAS,UAAU,sBAAsB,KAAK,MAAM,WAAW,EAAE,IAAI,CAAC;AAC7G,iBAAS,EAAE,IAAI,OAAO,QAAQ,OAAO,QAAQ,KAAK,KAAK,MAAM,MAAM,QAAQ,MAAM,SAAS,QAAQ,YAAY;AAAA,MAChH;AACA,YAAM,SAAS,OAAO,UAAU,OAAO,OAAO,UAAU,MAAM,OAAO,SAAS;AAC9E,YAAM,UAAU,EAAE,SAAS,QAAQ,IAAI,UAAU,QAAQ,UAAU,QAAQ,MAAM,OAAO,KAAK;AAC7F,eAAS,KAAK,OAAO;AACrB,YAAM,KAAK,WAAW,OAAO,EAAE,GAAG,SAAS,GAAG,UAAU,OAAO,OAAO,aAAa,IAAI,OAAO,QAAQ,cAAc,SAAY,OAAO,EAAE,SAAS,KAAK,IAAI,GAAG,YAAY,IAAI,IAAI,SAAS,EAAE,EAAE,CAAC;AAEhM,WAAK,UAAU,EAAE,GAAG,SAAS,MAAM,CAAC;AACpC,YAAM,YAAY,SAAS,OAAO,KAAK,OAAO;AAC9C,UAAI,CAAC,UAAW,OAAM,IAAI,WAAW,QAAQ,mBAAmB,UAAU,mLAAuC;AACjH,YAAM,QAAQ,CAAC,KAAK,KAAK,GAAG,EAAE,SAAS,MAAM,IAAI,MAAM,MAAM,YAAY,cAAc,GAAG,KAAK,IAAI,WAAW,KAAK;AACnH,WAAK,UAAU,IAAI,GAAG,QAAQ,EAAE,IAAI,KAAK,IAAI,KAAK,IAAI,IAAI,KAAK,OAAO,UAAU;AAAA,IAClF;AACA,UAAM,OAAO,KAAK,YAAY,EAAE,OAAO,OAAO,UAAU,YAAY,kBAAkB,SAAS,CAAC;AAChG,UAAM,IAAI,WAAW,KAAK,MAAM,WAAW,gCAAgC,0BAA0B,UAAU,IAAI;AAAA,EACrH;AACF;",
|
|
6
|
+
"names": ["input", "output", "group"]
|
|
7
|
+
}
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
RouteError,
|
|
23
23
|
abortable,
|
|
24
24
|
qoderContextModel
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-4L2CBGXN.js";
|
|
26
26
|
import {
|
|
27
27
|
beijingDay,
|
|
28
28
|
writePrivateJson
|
|
@@ -5418,4 +5418,4 @@ export {
|
|
|
5418
5418
|
refreshWorkBuddyCheckinCredential,
|
|
5419
5419
|
createWorkBuddyCheckin
|
|
5420
5420
|
};
|
|
5421
|
-
//# sourceMappingURL=chunk-
|
|
5421
|
+
//# sourceMappingURL=chunk-NZF36O5I.js.map
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
RouteError,
|
|
9
9
|
abortable
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-4L2CBGXN.js";
|
|
11
11
|
import {
|
|
12
12
|
REASONING_EFFORTS,
|
|
13
13
|
beijingDay,
|
|
@@ -329,4 +329,4 @@ async function collectCompletion(frames, model) {
|
|
|
329
329
|
export {
|
|
330
330
|
ApiService
|
|
331
331
|
};
|
|
332
|
-
//# sourceMappingURL=chunk-
|
|
332
|
+
//# sourceMappingURL=chunk-TM5XDMGY.js.map
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
refreshWorkBuddyCheckinCredential,
|
|
7
7
|
supportsCheckin,
|
|
8
8
|
workbuddyToken
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-NZF36O5I.js";
|
|
10
10
|
import {
|
|
11
11
|
discoverLocalAccounts,
|
|
12
12
|
importAccount,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
} from "./chunk-KWXLQJS5.js";
|
|
20
20
|
import {
|
|
21
21
|
ApiService
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-TM5XDMGY.js";
|
|
23
23
|
import {
|
|
24
24
|
hostIsLoopback
|
|
25
25
|
} from "./chunk-DNQPZMPF.js";
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
contextInfo,
|
|
29
29
|
matchModel,
|
|
30
30
|
resolveContext
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-4L2CBGXN.js";
|
|
32
32
|
import {
|
|
33
33
|
PROVIDERS,
|
|
34
34
|
PROVIDER_NAMES,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
import { createHash, randomBytes as randomBytes3, timingSafeEqual } from "node:crypto";
|
|
46
46
|
|
|
47
47
|
// package.json
|
|
48
|
-
var version = "0.6.
|
|
48
|
+
var version = "0.6.12";
|
|
49
49
|
|
|
50
50
|
// src/manager.mjs
|
|
51
51
|
import { readFile as readFile4, mkdir as mkdir2, mkdtemp as mkdtemp2, rm as rm3 } from "node:fs/promises";
|
|
@@ -251,7 +251,7 @@ import { join as join4 } from "node:path";
|
|
|
251
251
|
import { randomUUID } from "node:crypto";
|
|
252
252
|
import { createRequire } from "node:module";
|
|
253
253
|
import { pathToFileURL } from "node:url";
|
|
254
|
-
import { parse as parseYaml } from "yaml";
|
|
254
|
+
import { parse as parseYaml, parseDocument, isMap, isSeq, isScalar } from "yaml";
|
|
255
255
|
import { withFileLock, writeFileAtomic as writeFileAtomic2 } from "@deepseek-ai/dsh-atomic-write";
|
|
256
256
|
|
|
257
257
|
// src/plugin-reload.mjs
|
|
@@ -488,6 +488,40 @@ async function publicJson(url, fetchImpl, signal) {
|
|
|
488
488
|
return /^[a-f0-9]{40}$/i.test(text) ? { sha: text } : JSON.parse(text);
|
|
489
489
|
}
|
|
490
490
|
var short = (sha) => sha?.slice(0, 8);
|
|
491
|
+
var reviewedVersion = (row) => row.source.kind === "npm" && parseWorkBuddyVersion(row.latestVersion) ? `${row.source.package}@${row.latestVersion}` : void 0;
|
|
492
|
+
async function allowReviewedVersion(profile, row) {
|
|
493
|
+
const file = join4(profile.dir, "pnpm-workspace.yaml"), prefix = `${row.source.package}@`;
|
|
494
|
+
try {
|
|
495
|
+
await withFileLock(file, async () => {
|
|
496
|
+
let text;
|
|
497
|
+
try {
|
|
498
|
+
text = await readFile2(file, "utf8");
|
|
499
|
+
} catch (e) {
|
|
500
|
+
if (e.code !== "ENOENT") throw e;
|
|
501
|
+
text = "{}\n";
|
|
502
|
+
}
|
|
503
|
+
const doc = parseDocument(text), entries = doc.get("minimumReleaseAgeExclude");
|
|
504
|
+
if (doc.errors.length || !isMap(doc.contents) || entries !== void 0 && (!isSeq(entries) || entries.anchor || entries.items.some((x) => !isScalar(x) || typeof x.value !== "string" || x.anchor))) throw Error("invalid-policy");
|
|
505
|
+
const values = entries?.items.map((x) => x.value) ?? [];
|
|
506
|
+
const existing = values.filter((x) => x.startsWith(prefix));
|
|
507
|
+
const versions = [.../* @__PURE__ */ new Set([...existing.flatMap((x) => x.slice(prefix.length).split(/\s*\|\|\s*/)), row.latestVersion])];
|
|
508
|
+
const merged = prefix + versions.join(" || ");
|
|
509
|
+
if (existing.length === 1 && existing[0] === merged) return;
|
|
510
|
+
if (!entries) doc.set("minimumReleaseAgeExclude", [merged]);
|
|
511
|
+
else {
|
|
512
|
+
const first = entries.items.findIndex((x) => x.value.startsWith(prefix));
|
|
513
|
+
if (first < 0) entries.add(merged);
|
|
514
|
+
else {
|
|
515
|
+
entries.items[first].value = merged;
|
|
516
|
+
for (let i = entries.items.length - 1; i > first; i--) if (entries.items[i].value.startsWith(prefix)) entries.delete(i);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
await writeFileAtomic2(file, String(doc), { mode: 384 });
|
|
520
|
+
}, { waitMs: 12e4 });
|
|
521
|
+
} catch {
|
|
522
|
+
throw Error("\u65E0\u6CD5\u4FDD\u5B58\u6B64\u7248\u672C\u7684\u7B49\u5F85\u671F\u4F8B\u5916\u914D\u7F6E\uFF1B\u8BF7\u68C0\u67E5\u5F53\u524D DSH \u914D\u7F6E\u76EE\u5F55\u6743\u9650\u53CA pnpm-workspace.yaml \u683C\u5F0F\u3002\u672A\u5173\u95ED\u7B49\u5F85\u671F\u4FDD\u62A4\u3002");
|
|
523
|
+
}
|
|
524
|
+
}
|
|
491
525
|
var installFailed = (r) => !!(r.error || ["failed", "cancelled"].includes(r.application) || r.packageResult && r.packageResult.exitCode !== 0);
|
|
492
526
|
function installFailure(result) {
|
|
493
527
|
const text = [result.error?.diagnostic, result.packageResult?.output, result.packageResult?.kind].filter((v) => typeof v === "string").join("\n");
|
|
@@ -497,7 +531,7 @@ function installFailure(result) {
|
|
|
497
531
|
message = "\u5B89\u88C5\u5DF2\u53D6\u6D88\uFF0C\u53EF\u91CD\u65B0\u68C0\u67E5\u540E\u91CD\u8BD5\u3002";
|
|
498
532
|
} else if (/ERR_PNPM_(?:MINIMUM_RELEASE_AGE_VIOLATION|NO_MATURE_MATCHING_VERSION)|minimumReleaseAge/i.test(text)) {
|
|
499
533
|
reason = "release-age";
|
|
500
|
-
message = "\u65B0\
|
|
534
|
+
message = "\u65B0\u5305\u5C1A\u5728\u5B89\u88C5\u5668\u7B49\u5F85\u671F\u5185\u3002\u53EF\u5728\u300C\u67E5\u770B\u5E76\u66F4\u65B0\u300D\u4E2D\u52FE\u9009\u300C\u5141\u8BB8\u672C\u6B21\u6307\u5B9A\u7248\u672C\u7ACB\u5373\u5B89\u88C5\u300D\u540E\u91CD\u8BD5\uFF1B\u53EA\u653E\u884C\u786E\u8BA4\u7684\u63D2\u4EF6\u7248\u672C\uFF0C\u4F9D\u8D56\u4ECD\u9700\u6EE1\u8DB3\u7B49\u5F85\u671F\u3002\u4E5F\u53EF\u7B49\u5F85\u5230\u671F\u518D\u5B89\u88C5\u3002";
|
|
501
535
|
} else if (result.pendingBuilds?.length) {
|
|
502
536
|
reason = "build";
|
|
503
537
|
message = "\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\u3002";
|
|
@@ -536,7 +570,7 @@ async function registryVersion(service, profile, spec, signal, requestedRegistry
|
|
|
536
570
|
}
|
|
537
571
|
throw Error("npm \u67E5\u8BE2\u5931\u8D25\uFF1B\u8BF7\u68C0\u67E5 DSH \u7F51\u7EDC\u3001registry \u8BBE\u7F6E\u6216\u5305\u7684\u8BBF\u95EE\u6743\u9650");
|
|
538
572
|
}
|
|
539
|
-
async function
|
|
573
|
+
async function refreshProfilePlugin(service, profile, row, options2, signal) {
|
|
540
574
|
const require2 = createRequire(profile.installAnchor);
|
|
541
575
|
const { runProfilePnpm } = await import(pathToFileURL(require2.resolve("@deepseek-ai/dsh-plugin-manager/operations")).href);
|
|
542
576
|
const { registryPlan, attributeFailure } = await import(pathToFileURL(require2.resolve("@deepseek-ai/dsh-plugin-manager/registry")).href);
|
|
@@ -558,7 +592,7 @@ async function refreshGitPlugin(service, profile, row, options2, signal) {
|
|
|
558
592
|
try {
|
|
559
593
|
for (const registry of plan) {
|
|
560
594
|
signal.throwIfAborted();
|
|
561
|
-
const run = await runProfilePnpm({ ...profile, profile: profile.name }, ["update", row.name, ...registry ? [`--registry=${registry}`] : []], {
|
|
595
|
+
const run = await runProfilePnpm({ ...profile, profile: profile.name }, ["update", row.source.kind === "github" ? row.name : row.target, ...registry ? [`--registry=${registry}`] : []], {
|
|
562
596
|
execution: "service",
|
|
563
597
|
...profile.packageManager,
|
|
564
598
|
signal,
|
|
@@ -575,7 +609,7 @@ async function refreshGitPlugin(service, profile, row, options2, signal) {
|
|
|
575
609
|
...run.incompatible?.length ? { error: { code: "incompatible-version" } } : {}
|
|
576
610
|
};
|
|
577
611
|
await restore();
|
|
578
|
-
if (signal.aborted || attributeFailure(kind, run.output, { kind: "git", host: "github.com" }) !== "registry") break;
|
|
612
|
+
if (signal.aborted || attributeFailure(kind, run.output, row.source.kind === "github" ? { kind: "git", host: "github.com" } : { kind: "npm" }) !== "registry") break;
|
|
579
613
|
}
|
|
580
614
|
return result;
|
|
581
615
|
} catch (e) {
|
|
@@ -585,7 +619,7 @@ async function refreshGitPlugin(service, profile, row, options2, signal) {
|
|
|
585
619
|
}, { waitMs: 12e4 });
|
|
586
620
|
}
|
|
587
621
|
var PluginUpdates = class {
|
|
588
|
-
constructor({ service = () => void 0, profile = () => void 0, hmr = () => void 0, fetchImpl = (...args) => fetch(...args), lookup = registryVersion,
|
|
622
|
+
constructor({ service = () => void 0, profile = () => void 0, hmr = () => void 0, fetchImpl = (...args) => fetch(...args), lookup = registryVersion, refreshPackage = refreshProfilePlugin, onInstalled, stateFile, now = Date.now } = {}) {
|
|
589
623
|
this.stateFile = stateFile;
|
|
590
624
|
this.now = now;
|
|
591
625
|
this.dismissed = {};
|
|
@@ -598,7 +632,7 @@ var PluginUpdates = class {
|
|
|
598
632
|
this.rows = [];
|
|
599
633
|
this.abort = new AbortController();
|
|
600
634
|
this.lookup = lookup;
|
|
601
|
-
this.
|
|
635
|
+
this.refreshPackage = refreshPackage;
|
|
602
636
|
this.onInstalled = onInstalled;
|
|
603
637
|
}
|
|
604
638
|
async load() {
|
|
@@ -746,21 +780,27 @@ var PluginUpdates = class {
|
|
|
746
780
|
this.checkedAt = Date.now();
|
|
747
781
|
});
|
|
748
782
|
}
|
|
749
|
-
async installRow(row, registry) {
|
|
783
|
+
async installRow(row, registry, allowFreshVersions = []) {
|
|
750
784
|
const original = await jsonFile(join4(this.profile().dir, "package.json"));
|
|
751
785
|
if (original?.dependencies?.[row.name] !== row.spec) throw Error("\u5B89\u88C5\u6765\u6E90\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5");
|
|
752
786
|
const current = (await this.service().listBundles()).find((b) => b.name === row.name);
|
|
753
|
-
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");
|
|
787
|
+
if (!current || current.removable === false || 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");
|
|
788
|
+
if (allowFreshVersions.includes(reviewedVersion(row))) await allowReviewedVersion(this.profile(), row);
|
|
754
789
|
const options2 = { enabled: row.enabled, requestId: this.job.id, ...registry ? { registry } : {} };
|
|
755
790
|
let result;
|
|
756
|
-
|
|
791
|
+
const refresh = async () => {
|
|
757
792
|
this.gitAbort = new AbortController();
|
|
758
793
|
try {
|
|
759
|
-
|
|
794
|
+
return await this.refreshPackage(this.service(), this.profile(), row, options2, AbortSignal.any([this.abort.signal, this.gitAbort.signal]));
|
|
760
795
|
} finally {
|
|
761
796
|
this.gitAbort = void 0;
|
|
762
797
|
}
|
|
763
|
-
}
|
|
798
|
+
};
|
|
799
|
+
if (row.source.kind === "github") result = await refresh();
|
|
800
|
+
else {
|
|
801
|
+
result = await outsideActivation(this.hmr(), () => this.service().installBundle(row.target, options2));
|
|
802
|
+
if (result.error?.code === "already-installed") result = await refresh();
|
|
803
|
+
}
|
|
764
804
|
if (installFailed(result)) return { name: row.name, ...installFailure(result), expectedVersion: row.latestVersion };
|
|
765
805
|
const installed = (await this.service().listBundles()).find((b) => b.name === row.name);
|
|
766
806
|
if (row.source.kind === "npm" && installed?.version !== row.latestVersion) return {
|
|
@@ -781,10 +821,12 @@ var PluginUpdates = class {
|
|
|
781
821
|
const reloadPending = result.application === "restart-required" && this.onInstalled?.(row.name) === true;
|
|
782
822
|
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" };
|
|
783
823
|
}
|
|
784
|
-
update(names, registry) {
|
|
824
|
+
update(names, registry, allowFreshVersions = []) {
|
|
785
825
|
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");
|
|
786
826
|
const selected = names.map((name) => this.rows.find((r) => r.name === name));
|
|
787
827
|
if (selected.some((r) => !r || !["available", "failed"].includes(r.status) || !r.target || Date.now() - r.checkedAt > 6e5)) 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");
|
|
828
|
+
const reviewed = selected.map(reviewedVersion).filter(Boolean);
|
|
829
|
+
if (!Array.isArray(allowFreshVersions) || allowFreshVersions.length > selected.length || new Set(allowFreshVersions).size !== allowFreshVersions.length || allowFreshVersions.some((v) => typeof v !== "string" || !reviewed.includes(v))) throw Error("\u786E\u8BA4\u7684\u63D2\u4EF6\u7248\u672C\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u67E5\u770B\u5E76\u786E\u8BA4\u66F4\u65B0");
|
|
788
830
|
selected.sort((a, b) => Number(a.name === "dsh-multi-router") - Number(b.name === "dsh-multi-router"));
|
|
789
831
|
this.start("update", async (job) => {
|
|
790
832
|
job.total = selected.length;
|
|
@@ -793,7 +835,7 @@ var PluginUpdates = class {
|
|
|
793
835
|
job.current = row.name;
|
|
794
836
|
let result;
|
|
795
837
|
try {
|
|
796
|
-
result = await this.installRow(row, registry);
|
|
838
|
+
result = await this.installRow(row, registry, allowFreshVersions);
|
|
797
839
|
} catch (e) {
|
|
798
840
|
result = { name: row.name, status: "failed", message: e.message };
|
|
799
841
|
}
|
|
@@ -860,7 +902,7 @@ var PluginUpdates = class {
|
|
|
860
902
|
if (!this.flight) await this.list();
|
|
861
903
|
} else if (input.action === "plugins.dismiss") await this.dismiss(input.keys);
|
|
862
904
|
else if (input.action === "plugins.check") this.check();
|
|
863
|
-
else if (input.action === "plugins.update") this.update(input.names, input.registry);
|
|
905
|
+
else if (input.action === "plugins.update") this.update(input.names, input.registry, input.allowFreshVersions);
|
|
864
906
|
else if (input.action === "plugins.install") this.install(input.spec, input.registry);
|
|
865
907
|
else if (input.action === "plugins.cancel") {
|
|
866
908
|
if (this.job?.state === "running") {
|
|
@@ -2056,4 +2098,4 @@ export {
|
|
|
2056
2098
|
Manager,
|
|
2057
2099
|
managementHandler
|
|
2058
2100
|
};
|
|
2059
|
-
//# sourceMappingURL=chunk-
|
|
2101
|
+
//# sourceMappingURL=chunk-V37VG7MN.js.map
|