@mars-sea/dsh-commandcode-provider 0.14.2 → 0.14.3

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 CHANGED
@@ -4,6 +4,28 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.14.3] - 2026-10-19
8
+
9
+ ### Changed
10
+
11
+ - **发布包不再携带 sourcemap,体积减少约 16%(tarball 2.9 MB → 2.5 MB,解包 5.1 MB → 3.5 MB;文件数 18 → 16)。** `tsdown.config.ts` 的 `sourcemap: true` 会产出 `lib/index.js.map` 与 `lib/client.js.map`,而 `files` 直接收整个 `lib`,两份 map(1.63 MiB)因此进了 tarball。它们没有任何读取方:`lib/client.js` 是 WebView 直接执行的 CJS 包,`//# sourceMappingURL` 只是尾部注释;`scripts/verify-engine-load.mjs` 的审计用正则匹配 `import`/`require` **语句**,不匹配注释。本地 `npm run build` 照旧产出 map,调试能力不受影响。**用户侧无需做任何事**,运行时行为与公开导出面零变化(`lib/index.d.ts` 的 `export { ... }` 一行未改)。
12
+
13
+ - **长会话的历史分析报告更快(约 −28%~−33%)。** `buildAnalytics` 原先有两处对「事实 × 模型」的重复扫描:每模型小计对整表过滤 N 次,场景矩阵对每个(事实 × 目录模型)都查一次候选价格行(96 个模型共 480,000 次查找,查的是同一批行)。现改为先按模型分桶一次,并把定价算式收进 `cost-facts.requestCost()`、让场景循环把查价提到内层循环之外;`requestRates` 增加可选的高峰时段 memo(由调用方持有,不会活得比它的价格表更久)。两套独立测量给出同一量级:PR 作者脚本 5,000 条事实 × 96 个目录模型 42.17 ms → 30.36 ms,维护者本机用另一套合成数据复测 14.87 ms → 9.90 ms。**输出逐位不变**:分桶顺序与原 `Set` 顺序一致,排序本来就是按唯一 id 的全序(维护者另用 3,000 条确定性事实 × 96 个模型对比两版 JSON 输出,147,944 字节完全一致)。
14
+
15
+ - **图片请求里同一张图只编码一次 base64。** `readImageRequest()` 对每个(附件,编码目标)返回同一个缓存对象,但一条请求里同一张图会出现在多条历史消息中;三个 wire 编解码器原先各自按「出现次数」执行 `Buffer.from(version.data).toString('base64')`(1 MiB 载荷 0.738 ms/次)。现改为以该缓存对象为键的 `WeakMap`,保存原始 base64 与 data URL,副本生命周期跟随宿主自己的版本缓存。命中约 21 ns。
16
+
17
+ - **「查看模型用量、成本与性能分析」入口移到「账户用量」分组标题行**,紧邻「刷新」。它原先裸放在页面说明段与第一个分组之间,既无外边距也不属于任何分组,视觉上像是游离在版式之外;移到「账户用量」标题行后与服务着同一批用量/成本数据的「刷新」并列,也复用了该行既有的 `cc-spacer` 布局,不新增样式类。分析入口仍只在 Host 暴露面板接缝时出现,行为不变(切到面板的「模型分析」页签并打开面板)。
18
+
19
+ - **多账户轮换说明精简 2 处冗余用词**(中文 47 → 43 字,英文同步)。`账户操作立即生效。当前账户达到用量限额或密钥失效时,请求会按列表顺序自动切换到下一个可用账户。` → 去掉「用量」与「自动」后为:`账户操作立即生效。当前账户达到限额或密钥失效时,请求会按列表顺序切换到下一个可用账户。` 「按列表顺序切换」本身已表达自动性,`达到限额` 在账户上下文里仍是额度含意;英文侧 `usage limit` → `limit`,`switch` 原本就没有 `automatically`。**已知取舍**:同页单账户文案 `accountsHint` 仍用「用量限额」,两条说明的术语因此不完全一致。
20
+
21
+ ### Added
22
+
23
+ - **新增 `.gitattributes`:全部文本文件统一按 LF 检出与提交。** 仓库此前没有该文件,Windows 贡献者按 CRLF 检出后,sourcemap 的 `sourcesContent` 会内嵌带 CRLF 的源码,重建出的 `.map` 与提交里的不再逐字节相同,CI 的 `git diff --exit-code -- lib/` 守卫因此误报「产物过期」(2026-10-17 那次 CI 失败的根因)。实测对照:无该文件时 `core.autocrlf=true` 检出后 `src/adapter.ts` 有 3,482 行 CRLF、`lib/index.js` 有 11,817 行;加上后两者均为 0。图片与压缩包按 `binary` 排除在行尾转换之外。**本次加入时已跟踪文件 100% 是 LF,`git add --renormalize .` 未改写任何文件。**
24
+
25
+ ### Removed
26
+
27
+ - 两份 sourcemap(`lib/index.js.map`、`lib/client.js.map`)不再纳入版本控制。它们是 tsdown 产物里唯一在 CRLF 工作树上无法逐字节重建的文件,跟踪它们只会让「产物过期」守卫依赖工作树的行尾;移出 tarball 与版本控制后,该守卫在任意平台都只反映源码与产物的真实一致性。
28
+
7
29
  ## [0.14.2] - 2026-10-18
8
30
 
9
31
  ### Changed
package/lib/client.js CHANGED
@@ -3237,7 +3237,7 @@ window.__ModuleLoader__.load({
3237
3237
  cardRouteActive: "已启用",
3238
3238
  cardLoadingHint: "正在读取 Command Code 配置…",
3239
3239
  cardRegistrationHint: "此卡片由 Command Code 插件提供,正在等待设置页装配,稍后即可显示完整内容。",
3240
- accountsRotationHint: "账户操作立即生效。当前账户达到用量限额或密钥失效时,请求会按列表顺序自动切换到下一个可用账户。",
3240
+ accountsRotationHint: "账户操作立即生效。当前账户达到限额或密钥失效时,请求会按列表顺序切换到下一个可用账户。",
3241
3241
  accountModeAuto: "使用方式:自动切换(按列表顺序)",
3242
3242
  accountModePinned: "使用方式:固定使用「{name}」,不可用时仍会自动切换",
3243
3243
  accountStatusPinned: "已固定",
@@ -3463,7 +3463,7 @@ window.__ModuleLoader__.load({
3463
3463
  cardRouteActive: "Active",
3464
3464
  cardLoadingHint: "Loading the Command Code configuration…",
3465
3465
  cardRegistrationHint: "This card is contributed by the Command Code plugin and is waiting for the settings page to finish assembling.",
3466
- accountsRotationHint: "Account actions apply immediately. When the current account hits its usage limit or its key stops working, requests switch to the next usable account in list order.",
3466
+ accountsRotationHint: "Account actions apply immediately. When the current account hits its limit or its key stops working, requests switch to the next usable account in list order.",
3467
3467
  accountModeAuto: "Mode: switch automatically (list order)",
3468
3468
  accountModePinned: "Mode: pinned to \"{name}\", still switching when it is unavailable",
3469
3469
  accountStatusPinned: "Pinned",
@@ -3704,7 +3704,7 @@ window.__ModuleLoader__.load({
3704
3704
  }
3705
3705
  //#endregion
3706
3706
  //#region package.json
3707
- var version = "0.14.2";
3707
+ var version = "0.14.3";
3708
3708
  var repository = {
3709
3709
  "type": "git",
3710
3710
  "url": "git+https://github.com/Mars-Sea/dsh-commandcode-provider.git"
@@ -5554,7 +5554,7 @@ window.__ModuleLoader__.load({
5554
5554
  * each, with its status and quota inline — so one account's facts no longer
5555
5555
  * have to be cross-read across separate surfaces.
5556
5556
  */
5557
- function AccountsCard({ t, state, usage, login, disabled, actions, onRefresh, createEnrollment }) {
5557
+ function AccountsCard({ t, state, usage, login, disabled, actions, onRefresh, openAnalytics, createEnrollment }) {
5558
5558
  const [adding, setAdding] = (0, react.useState)(false);
5559
5559
  const [enrollment] = (0, react.useState)(createEnrollment);
5560
5560
  const snapshot = (0, react.useSyncExternalStore)(enrollment.store.subscribe, enrollment.store.getSnapshot);
@@ -5582,6 +5582,12 @@ window.__ModuleLoader__.load({
5582
5582
  children: t("accountsTitle")
5583
5583
  }),
5584
5584
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "cc-spacer" }),
5585
+ openAnalytics ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
5586
+ variant: "ghost",
5587
+ size: "sm",
5588
+ onClick: openAnalytics,
5589
+ children: t("openAnalytics")
5590
+ }) : null,
5585
5591
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5586
5592
  type: "button",
5587
5593
  className: "cc-linkButton",
@@ -5929,12 +5935,6 @@ window.__ModuleLoader__.load({
5929
5935
  className: "cc-intro",
5930
5936
  children: t("intro")
5931
5937
  }),
5932
- props.openAnalytics ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
5933
- variant: "ghost",
5934
- size: "sm",
5935
- onClick: props.openAnalytics,
5936
- children: t("openAnalytics")
5937
- }) : null,
5938
5938
  !state.writable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5939
5939
  className: "cc-readOnly",
5940
5940
  role: "status",
@@ -5948,6 +5948,7 @@ window.__ModuleLoader__.load({
5948
5948
  disabled,
5949
5949
  actions,
5950
5950
  onRefresh: props.refreshUsage,
5951
+ openAnalytics: props.openAnalytics,
5951
5952
  createEnrollment: props.createEnrollment
5952
5953
  }),
5953
5954
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelsCard, {
@@ -8376,10 +8377,16 @@ window.__ModuleLoader__.load({
8376
8377
  * today, so the combination becoming real is visible before it reaches a user.
8377
8378
  * This ordering is a latent choice, not a verified upstream rule.
8378
8379
  */
8379
- function requestRates(price, at, contextTokens, table) {
8380
+ function requestRates(price, at, contextTokens, table, peakHourCache) {
8380
8381
  const tier = price.contextTiers?.find((tier) => tier.maxContext === void 0 || contextTokens <= tier.maxContext);
8381
8382
  if (tier !== void 0) return tier;
8382
- return price.peak !== void 0 && at !== null && peakHour(at, table.peakHours) ? price.peak : price;
8383
+ if (price.peak === void 0 || at === null) return price;
8384
+ let peak = peakHourCache?.get(at);
8385
+ if (peak === void 0) {
8386
+ peak = peakHour(at, table.peakHours);
8387
+ peakHourCache?.set(at, peak);
8388
+ }
8389
+ return peak ? price.peak : price;
8383
8390
  }
8384
8391
  /** Cache version and wire guard: changing bands/rates must refold historical groups. */
8385
8392
  function pricingKey(table) {
package/lib/index.d.ts CHANGED
@@ -207,7 +207,13 @@ interface CommandCodeConnectionOptions {
207
207
  * text-only request never depends on the attachment seam.
208
208
  */
209
209
  type ResolveAttachments = () => AttachmentStore | undefined;
210
- /** What the rotation hook knows about the request it is rotating within. */
210
+ /**
211
+ * What the rotation hook knows about the request it is rotating within.
212
+ *
213
+ * Not exported: the only consumer is the `rotateApiKey` shape below, so the
214
+ * name never reaches the published `.d.ts` and the package's `exports` map
215
+ * leaves no deep-import path to it.
216
+ */
211
217
  interface AccountRotationContext {
212
218
  /** Every API key this request has already used, just-rejected key included. */
213
219
  tried: readonly string[];
@@ -265,13 +271,13 @@ interface CommandCodeAdapterDeps<C extends CommandCodeConnectionOptions = Comman
265
271
  */
266
272
  imageOffload?: SurfaceImagePolicy;
267
273
  }
268
- /** Account identity from `/alpha/whoami`. */
274
+ /** Account identity from `/alpha/whoami`; reached only through `CommandCodeUsageReport`. */
269
275
  interface CommandCodeAccount {
270
276
  id: string;
271
277
  name: string;
272
278
  userName: string;
273
279
  }
274
- /** Usage summary from `/alpha/usage/summary`. */
280
+ /** Usage summary from `/alpha/usage/summary`; reached only through `CommandCodeUsageReport`. */
275
281
  interface CommandCodeUsage {
276
282
  totalCount: number;
277
283
  totalCost: number;
@@ -326,7 +332,7 @@ interface CommandCodeCredits {
326
332
  resetAt: number;
327
333
  };
328
334
  }
329
- /** Subscription plan state from `/alpha/billing/subscriptions`. */
335
+ /** Subscription plan state from `/alpha/billing/subscriptions`; reached only through `CommandCodeUsageReport`. */
330
336
  interface CommandCodePlan {
331
337
  /** Raw subscription plan id (e.g. `individual-pro`); empty when unreported. */
332
338
  planId: string;
package/lib/index.js CHANGED
@@ -38,10 +38,30 @@ function peakHour(at, windows) {
38
38
  * today, so the combination becoming real is visible before it reaches a user.
39
39
  * This ordering is a latent choice, not a verified upstream rule.
40
40
  */
41
- function requestRates(price, at, contextTokens, table) {
41
+ function requestRates(price, at, contextTokens, table, peakHourCache) {
42
42
  const tier = price.contextTiers?.find((tier) => tier.maxContext === void 0 || contextTokens <= tier.maxContext);
43
43
  if (tier !== void 0) return tier;
44
- return price.peak !== void 0 && at !== null && peakHour(at, table.peakHours) ? price.peak : price;
44
+ if (price.peak === void 0 || at === null) return price;
45
+ let peak = peakHourCache?.get(at);
46
+ if (peak === void 0) {
47
+ peak = peakHour(at, table.peakHours);
48
+ peakHourCache?.set(at, peak);
49
+ }
50
+ return peak ? price.peak : price;
51
+ }
52
+ /**
53
+ * Price one request's token buckets against an already-resolved price row.
54
+ *
55
+ * Split out of the report's per-model lookup so a caller that prices the same
56
+ * candidate model against every fact — the analytics scenario matrix — resolves
57
+ * the price row once per model instead of once per (fact, model) pair. The
58
+ * arithmetic lives here alone so the two callers cannot drift.
59
+ */
60
+ function requestCost(tokens, price, at, table, peakHourCache) {
61
+ if (price.free === true) return 0;
62
+ const r = requestRates(price, at, tokens.uncachedInputTokens + tokens.cacheReadTokens + tokens.cacheWriteTokens, table, peakHourCache);
63
+ if (tokens.cacheWriteTokens > 0 && r.cacheWriteCost === void 0) return void 0;
64
+ return (tokens.uncachedInputTokens * r.inputCost + tokens.outputTokens * r.outputCost + tokens.cacheReadTokens * r.cacheReadCost + tokens.cacheWriteTokens * (r.cacheWriteCost ?? 0)) / 1e6;
45
65
  }
46
66
  /** Cache version and wire guard: changing bands/rates must refold historical groups. */
47
67
  function pricingKey(table) {
@@ -3257,6 +3277,7 @@ function foldRequests(session, log) {
3257
3277
  }
3258
3278
  return facts;
3259
3279
  }
3280
+ /** The zeroed accumulator `aggregate` adds into. Internal: nothing outside this module reads it. */
3260
3281
  const emptyMetrics = () => ({
3261
3282
  sessions: 0,
3262
3283
  requests: 0,
@@ -3277,17 +3298,13 @@ const emptyMetrics = () => ({
3277
3298
  decodeMs: 0,
3278
3299
  decodeTokens: 0
3279
3300
  });
3280
- function priceRequest(f, id, table, prices) {
3301
+ function priceRequest(f, id, table, prices, peakHourCache) {
3281
3302
  if (!f.tokens) return void 0;
3282
3303
  const price = prices.get(id);
3283
3304
  if (!price) return void 0;
3284
- if (price.free === true) return 0;
3285
- const context = f.tokens.uncachedInputTokens + f.tokens.cacheReadTokens + f.tokens.cacheWriteTokens;
3286
- const r = requestRates(price, f.at, context, table);
3287
- if (f.tokens.cacheWriteTokens > 0 && r.cacheWriteCost === void 0) return void 0;
3288
- return (f.tokens.uncachedInputTokens * r.inputCost + f.tokens.outputTokens * r.outputCost + f.tokens.cacheReadTokens * r.cacheReadCost + f.tokens.cacheWriteTokens * (r.cacheWriteCost ?? 0)) / 1e6;
3305
+ return requestCost(f.tokens, price, f.at, table, peakHourCache);
3289
3306
  }
3290
- function aggregate(facts, table, prices) {
3307
+ function aggregate(facts, table, prices, peakHourCache) {
3291
3308
  const m = emptyMetrics();
3292
3309
  m.sessions = new Set(facts.map((f) => f.session)).size;
3293
3310
  for (const f of facts) {
@@ -3298,7 +3315,7 @@ function aggregate(facts, table, prices) {
3298
3315
  m.usageSamples++;
3299
3316
  for (const k of COST_TOKEN_KEYS) m.tokens[k] += f.tokens[k];
3300
3317
  }
3301
- const cost = priceRequest(f, f.model, table, prices);
3318
+ const cost = priceRequest(f, f.model, table, prices, peakHourCache);
3302
3319
  if (cost !== void 0) {
3303
3320
  m.pricedRequests++;
3304
3321
  m.cost += cost;
@@ -3323,13 +3340,21 @@ function buildAnalytics(facts, query, table, catalog, now = Date.now()) {
3323
3340
  const selected = query.mode === "range" ? facts.filter((f) => f.at >= query.from && f.at < query.to) : facts;
3324
3341
  const prices = /* @__PURE__ */ new Map();
3325
3342
  for (const p of table.models) for (const id of [p.id, p.slug]) if (!prices.has(id)) prices.set(id, p);
3326
- const totals = aggregate(selected, table, prices);
3327
- const models = [...new Set(selected.map((f) => f.model))].map((id) => ({
3343
+ const peakHourCache = /* @__PURE__ */ new Map();
3344
+ const totals = aggregate(selected, table, prices, peakHourCache);
3345
+ const byModel = /* @__PURE__ */ new Map();
3346
+ for (const f of selected) {
3347
+ const bucket = byModel.get(f.model);
3348
+ if (bucket === void 0) byModel.set(f.model, [f]);
3349
+ else bucket.push(f);
3350
+ }
3351
+ const models = [...byModel].map(([id, bucket]) => ({
3328
3352
  id,
3329
- ...aggregate(selected.filter((f) => f.model === id), table, prices)
3353
+ ...aggregate(bucket, table, prices, peakHourCache)
3330
3354
  })).sort((a, b) => b.cost - a.cost || a.id.localeCompare(b.id));
3331
3355
  const scenarios = catalog.map((model) => {
3332
3356
  let cost = 0, pricedRequests = 0, excludedRequests = 0, unknownRequests = 0;
3357
+ const price = prices.get(model.id);
3333
3358
  for (const f of selected) {
3334
3359
  if (!f.tokens) {
3335
3360
  unknownRequests++;
@@ -3340,7 +3365,7 @@ function buildAnalytics(facts, query, table, catalog, now = Date.now()) {
3340
3365
  excludedRequests++;
3341
3366
  continue;
3342
3367
  }
3343
- const priced = priceRequest(f, model.id, table, prices);
3368
+ const priced = price === void 0 ? void 0 : requestCost(f.tokens, price, f.at, table, peakHourCache);
3344
3369
  if (priced === void 0) unknownRequests++;
3345
3370
  else {
3346
3371
  cost += priced;
@@ -6307,9 +6332,16 @@ const DEFAULT_API_BASE = "https://api.commandcode.ai";
6307
6332
  * under the historical name so existing importers are unaffected.
6308
6333
  */
6309
6334
  const DEFAULT_GENERATE_MAX_TOKENS = MAX_OUTPUT_TOKEN_LIMIT;
6335
+ /** Catalog fetch budget. Internal: both call sites are in this module. */
6310
6336
  const MODELS_TIMEOUT_MS = 1e4;
6311
6337
  /** How long the picker's plan-filter billing facts stay cached before refetching. */
6312
6338
  const BILLING_ACCESS_TTL_MS = 3e5;
6339
+ /**
6340
+ * How long a learned CLI-only protocol preference stays cached per account.
6341
+ * After this TTL a request may probe Provider API again, so an upgraded Go
6342
+ * account can recover without a restart.
6343
+ */
6344
+ const PROTOCOL_CACHE_TTL_MS = 9e5;
6313
6345
  /** The entry-plan tier weight (`individual-go` in KNOWN_SUBSCRIPTION_PLANS). */
6314
6346
  const GO_TIER_WEIGHT = 0;
6315
6347
  /** Hard cap on account rotations within one request (one attempt per distinct key). */
@@ -6960,6 +6992,31 @@ function priceRequestImage(block, model, imageCapable) {
6960
6992
  };
6961
6993
  }
6962
6994
  /**
6995
+ * Base64 payloads keyed by the cached request version itself.
6996
+ *
6997
+ * `readImageRequest()` returns one codec object per (attachment, encoder
6998
+ * target) and `requestImages()` reuses that same object for every occurrence in
6999
+ * one generation, but a history that carries an image also replays it in every
7000
+ * later message. Encoding per occurrence therefore re-base64s the same
7001
+ * multi-megabyte buffer once per replay — the single most expensive
7002
+ * per-occurrence step of an image request. Keying on the object makes an
7003
+ * occurrence a map hit, and the WeakMap ties the copy's lifetime to the
7004
+ * harness's own version cache rather than to this plugin.
7005
+ */
7006
+ const encodedRequestImages = /* @__PURE__ */ new WeakMap();
7007
+ function encodedRequestImage(version) {
7008
+ let encoded = encodedRequestImages.get(version);
7009
+ if (encoded === void 0) {
7010
+ const base64 = Buffer.from(version.data).toString("base64");
7011
+ encoded = {
7012
+ base64,
7013
+ dataUrl: `data:${version.mediaType};base64,${base64}`
7014
+ };
7015
+ encodedRequestImages.set(version, encoded);
7016
+ }
7017
+ return encoded;
7018
+ }
7019
+ /**
6963
7020
  * Convert one image reference to the final `/alpha/generate` wire format.
6964
7021
  * The official CLI accepts a base64 source internally, then toWireMessages()
6965
7022
  * sends a data URL plus mimeType. Use the request version's media type because
@@ -6969,7 +7026,7 @@ async function imageToCommandCode(ref, readImage) {
6969
7026
  const version = await readImage(ref);
6970
7027
  return {
6971
7028
  type: "image",
6972
- image: `data:${version.mediaType};base64,${Buffer.from(version.data).toString("base64")}`,
7029
+ image: encodedRequestImage(version).dataUrl,
6973
7030
  mimeType: version.mediaType
6974
7031
  };
6975
7032
  }
@@ -7102,10 +7159,9 @@ async function messagesToCC(messages, readImage) {
7102
7159
  * `{ type: 'image_url', image_url: { url: 'data:...;base64,...' } }`.
7103
7160
  */
7104
7161
  async function imageToOpenAI(ref, readImage) {
7105
- const version = await readImage(ref);
7106
7162
  return {
7107
7163
  type: "image_url",
7108
- image_url: { url: `data:${version.mediaType};base64,${Buffer.from(version.data).toString("base64")}` }
7164
+ image_url: { url: encodedRequestImage(await readImage(ref)).dataUrl }
7109
7165
  };
7110
7166
  }
7111
7167
  /**
@@ -7172,7 +7228,7 @@ async function imageToMessages(ref, readImage) {
7172
7228
  source: {
7173
7229
  type: "base64",
7174
7230
  media_type: version.mediaType,
7175
- data: Buffer.from(version.data).toString("base64")
7231
+ data: encodedRequestImage(version).base64
7176
7232
  }
7177
7233
  };
7178
7234
  }
@@ -8174,7 +8230,7 @@ var CommandCodeAdapter = class CommandCodeAdapter extends LlmAdapter {
8174
8230
  /** Cached protocol decision for a key, or undefined when expired/unknown. */
8175
8231
  cachedProtocol(apiBase, apiKey) {
8176
8232
  const hit = this.protocolCache.get(this.accountCacheKey(apiBase, apiKey));
8177
- if (hit === void 0 || Date.now() - hit.at >= 9e5) return void 0;
8233
+ if (hit === void 0 || Date.now() - hit.at >= PROTOCOL_CACHE_TTL_MS) return void 0;
8178
8234
  return hit.protocol;
8179
8235
  }
8180
8236
  rememberProtocol(apiBase, apiKey, protocol) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mars-sea/dsh-commandcode-provider",
3
- "version": "0.14.2",
3
+ "version": "0.14.3",
4
4
  "description": "Unofficial DeepSeek Harness LLM provider plugin for Command Code, ported from pi-commandcode-provider (MIT). Registers the 'commandcode' provider route with a Models-page card and live model catalog.",
5
5
  "icon": "./icon.svg",
6
6
  "type": "module",
@@ -39,6 +39,7 @@
39
39
  },
40
40
  "files": [
41
41
  "lib",
42
+ "!lib/**/*.map",
42
43
  "assets",
43
44
  "icon.svg",
44
45
  "locale",