dsh-codearts 1.2.4 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.mts CHANGED
@@ -1347,6 +1347,24 @@ interface UsageSnapshot {
1347
1347
  byAccountToday: Record<string, UsageTotals>;
1348
1348
  /** 账本覆盖的天数(便于「数据从哪天开始」的说明)。 */
1349
1349
  days: number;
1350
+ /**
1351
+ * 最近 {@link TREND_DAYS} 天(含今天,按日期升序)的每日合计;没账目的日子补 0。
1352
+ *
1353
+ * 补 0 而不是跳过:横轴要固定 7 格,否则「昨天没跑」和「昨天丢了」看不出区别。
1354
+ */
1355
+ recentDays: {
1356
+ date: string;
1357
+ totals: UsageTotals;
1358
+ }[];
1359
+ /**
1360
+ * 今天 0 点到 23 点的逐小时合计(固定 24 项,还没到的钟点补 0)。
1361
+ *
1362
+ * 命中率曲线用它 —— 一次长会话把命中率拉低、隔一小时又回来,按天的粒度看不见。
1363
+ */
1364
+ todayByHour: {
1365
+ hour: number;
1366
+ totals: UsageTotals;
1367
+ }[];
1350
1368
  /** 最近一次记账时间(epoch ms)。 */
1351
1369
  lastAt?: number;
1352
1370
  }
@@ -1385,10 +1403,21 @@ declare class CodeArtsUsageTracker {
1385
1403
  noteRequest(accountId: string, model: string, at?: number): void;
1386
1404
  /** 记一次 usage 帧。 */
1387
1405
  noteUsage(accountId: string, model: string, raw: RawUsage | undefined, at?: number): void;
1388
- /** 丢弃保留期之外的天(按日期键比较即可,YYYY-MM-DD 是字典序)。 */
1406
+ /** 一天里的逐小时桶,第一次写的时候才建(老账本没有这个键)。 */
1407
+ private hoursOf;
1408
+ /**
1409
+ * 丢弃保留期之外的天(按日期键比较即可,YYYY-MM-DD 是字典序)。
1410
+ *
1411
+ * 顺带把两天之前的**小时桶**清掉:逐小时数据只有「今天按小时」在画,留着只是
1412
+ * 让 60 天的账本多出一个数量级的体积。
1413
+ */
1389
1414
  private prune;
1390
1415
  /** 当前快照(卡片与 CLI 都读它)。 */
1391
1416
  snapshot(at?: number): UsageSnapshot;
1417
+ /** 最近 TREND_DAYS 天的每日合计(按日期升序,缺账目的日子补 0)。 */
1418
+ private recentDaysOf;
1419
+ /** 今天 0 点起的 24 个钟点(还没到的小时补 0,横轴才有固定的 24 格)。 */
1420
+ private todayByHourOf;
1392
1421
  private scheduleSave;
1393
1422
  /** 立即落盘(关停时调用,别丢最后几秒的账)。 */
1394
1423
  flush(): Promise<void>;
@@ -1615,6 +1644,13 @@ interface Config {
1615
1644
  showCreditDock?: boolean;
1616
1645
  /** 等上游开流时那行「排队第 N 位」是否显示。缺省 = 显示。 */
1617
1646
  showQueueDock?: boolean;
1647
+ /**
1648
+ * 是否在 DSH 侧边栏的图标列里加一个 CodeArts 图标(点开在中间列显示整页版卡片)。
1649
+ *
1650
+ * 缺省 = **不显示**:图标列是全宿主共用的资源,每个插件都默认占一格很快就会挤满,
1651
+ * 而「设置 → 插件」里本来就能看到同一张卡片,所以这一格交给用户自己决定要不要。
1652
+ */
1653
+ showSidebarPanel?: boolean;
1618
1654
  }
1619
1655
  declare const Config: z<Config>;
1620
1656
  declare function apply(ctx: Context, rawConfig: Config): void;
package/lib/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as upstreamErrorMessage, B as modelUnavailableReason, C as isWelfareClaimedStatus, D as prepareChatBody, E as pickDailyWelfareCampaign, F as filterEnabledModels, G as codeartsAuthPath, H as CodeArtsCredentialStore, I as forgetModelUnavailable, K as startLogin, L as isBenefitBlocked, M as FALLBACK_CODEARTS_MODELS, N as clearBenefitBlocked, O as rateLimitFrame, P as creditRatioLabel, R as isBenefitModel, S as isTpmLimit, T as modelUnavailableReasonText, U as MANUAL_ACCOUNT_ID, V as CodeArtsAccountStore, W as codeartsAccountsPath, _ as isIamTokenError, a as SNAP_HOST, b as isParamInvalidFrame, c as claimDailyWelfare, d as fetchCallerIdentity, f as fetchModels, g as isConcurrencyCap, h as firstFrameError, i as refreshCatalog, j as CodeArtsCatalog, k as signedGet, l as clearQueueStatus, m as fetchWelfareCampaigns, n as codeartsUsagePath, o as canonicalModel, p as fetchQueueStatus, r as discoverModels, s as chatStream, t as CodeArtsUsageTracker, u as degradeTokenCeiling, v as isModelNotAccessible, w as maxTokensCeilingFor, x as isQueueableRate, y as isNotMultimodal, z as markModelUnavailable } from "./usage-DGIuT79_.mjs";
1
+ import { A as upstreamErrorMessage, B as modelUnavailableReason, C as isWelfareClaimedStatus, D as prepareChatBody, E as pickDailyWelfareCampaign, F as filterEnabledModels, G as codeartsAuthPath, H as CodeArtsCredentialStore, I as forgetModelUnavailable, K as startLogin, L as isBenefitBlocked, M as FALLBACK_CODEARTS_MODELS, N as clearBenefitBlocked, O as rateLimitFrame, P as creditRatioLabel, R as isBenefitModel, S as isTpmLimit, T as modelUnavailableReasonText, U as MANUAL_ACCOUNT_ID, V as CodeArtsAccountStore, W as codeartsAccountsPath, _ as isIamTokenError, a as SNAP_HOST, b as isParamInvalidFrame, c as claimDailyWelfare, d as fetchCallerIdentity, f as fetchModels, g as isConcurrencyCap, h as firstFrameError, i as refreshCatalog, j as CodeArtsCatalog, k as signedGet, l as clearQueueStatus, m as fetchWelfareCampaigns, n as codeartsUsagePath, o as canonicalModel, p as fetchQueueStatus, r as discoverModels, s as chatStream, t as CodeArtsUsageTracker, u as degradeTokenCeiling, v as isModelNotAccessible, w as maxTokensCeilingFor, x as isQueueableRate, y as isNotMultimodal, z as markModelUnavailable } from "./usage-4B0o-CQN.mjs";
2
2
  import { i as lazyApi, r as createProvider } from "./models-CgKCibpk.mjs";
3
3
  import z from "@deepseek-ai/schemastery";
4
4
  import { randomBytes, timingSafeEqual } from "node:crypto";
@@ -1527,10 +1527,14 @@ function modelBadgesOf(models) {
1527
1527
  };
1528
1528
  });
1529
1529
  }
1530
- /** 开关的默认值:没有 settings provider(或老配置没这两个键)时保持原有行为 —— 都显示。 */
1530
+ /**
1531
+ * 开关的默认值:没有 settings provider(或老配置没这两个键)时保持原有行为 ——
1532
+ * 底部两行都显示;侧边栏相反,缺省不开(那一格是所有插件共用的全局座位)。
1533
+ */
1531
1534
  const DEFAULT_DOCK_FLAGS = {
1532
1535
  credits: true,
1533
- queue: true
1536
+ queue: true,
1537
+ sidebar: false
1534
1538
  };
1535
1539
  /**
1536
1540
  * 把逐账号的领取结果汇总成一条:HTTP 层只看 ok,卡片看 results 逐号展示。
@@ -1646,6 +1650,8 @@ function usageOf(deps) {
1646
1650
  byModelToday: snapshot?.byModelToday ?? [],
1647
1651
  byAccountToday: snapshot?.byAccountToday ?? {},
1648
1652
  days: snapshot?.days ?? 0,
1653
+ recentDays: snapshot?.recentDays ?? [],
1654
+ todayByHour: snapshot?.todayByHour ?? [],
1649
1655
  ...snapshot?.lastAt === void 0 ? {} : { lastAt: snapshot.lastAt },
1650
1656
  slots: slotsOf(deps)
1651
1657
  };
@@ -1761,9 +1767,13 @@ function dockHandler(deps) {
1761
1767
  }
1762
1768
  try {
1763
1769
  const body = JSON.parse(await readBody(req));
1764
- const touched = ["credits", "queue"].filter((key) => body[key] !== void 0);
1770
+ const touched = [
1771
+ "credits",
1772
+ "queue",
1773
+ "sidebar"
1774
+ ].filter((key) => body[key] !== void 0);
1765
1775
  if (touched.length === 0 || touched.some((key) => typeof body[key] !== "boolean")) {
1766
- json(res, 400, { error: "expected {\"credits\"?: boolean, \"queue\"?: boolean}" });
1776
+ json(res, 400, { error: "expected {\"credits\"?: boolean, \"queue\"?: boolean, \"sidebar\"?: boolean}" });
1767
1777
  return;
1768
1778
  }
1769
1779
  if (!await deps.setDock(Object.fromEntries(touched.map((key) => [key, body[key]])))) {
@@ -2404,7 +2414,8 @@ function unwrapConfig(value) {
2404
2414
  const Config = z.object({
2405
2415
  enabledModels: z.array(z.string()).description("Model ids offered in the model pickers (empty means every model)").volatile(),
2406
2416
  showCreditDock: z.boolean().default(true).description("Show the remaining-credits line under the chat input box").volatile(),
2407
- showQueueDock: z.boolean().default(true).description("Show the upstream queue position under the chat input box").volatile()
2417
+ showQueueDock: z.boolean().default(true).description("Show the upstream queue position under the chat input box").volatile(),
2418
+ showSidebarPanel: z.boolean().default(false).description("Show a CodeArts icon in the DSH sidebar icon column, opening this page in the middle column").volatile()
2408
2419
  });
2409
2420
  function settingsCompatNamespace(ctx) {
2410
2421
  return resolveSettingsNamespaceCompat(ctx, ctx.get("settings"), CODEARTS_SETTINGS_NS);
@@ -2479,14 +2490,16 @@ function apply(ctx, rawConfig) {
2479
2490
  };
2480
2491
  const dock = () => ({
2481
2492
  credits: current().showCreditDock !== false,
2482
- queue: current().showQueueDock !== false
2493
+ queue: current().showQueueDock !== false,
2494
+ sidebar: current().showSidebarPanel === true
2483
2495
  });
2484
2496
  const setDock = async (patch) => {
2485
2497
  const settings = ctx.get("settings");
2486
2498
  if (settings === void 0) return false;
2487
2499
  await settings.update(settingsCompatNamespace(ctx), {
2488
2500
  ...patch.credits === void 0 ? {} : { showCreditDock: patch.credits },
2489
- ...patch.queue === void 0 ? {} : { showQueueDock: patch.queue }
2501
+ ...patch.queue === void 0 ? {} : { showQueueDock: patch.queue },
2502
+ ...patch.sidebar === void 0 ? {} : { showSidebarPanel: patch.sidebar }
2490
2503
  });
2491
2504
  return true;
2492
2505
  };
@@ -2769,6 +2769,14 @@ function localDateKey(at = Date.now()) {
2769
2769
  const p = (n) => String(n).padStart(2, "0");
2770
2770
  return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`;
2771
2771
  }
2772
+ /** 本地小时键 `00`..`23`(同样按本地时间切,跨零点的那一小时不会错位)。 */
2773
+ function localHourKey(at = Date.now()) {
2774
+ return localHourKeyOfHour(new Date(at).getHours());
2775
+ }
2776
+ /** 0..23 -> `00`..`23`(小时桶的键)。 */
2777
+ function localHourKeyOfHour(hour) {
2778
+ return String(hour).padStart(2, "0");
2779
+ }
2772
2780
  function positiveInt(value) {
2773
2781
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
2774
2782
  }
@@ -2879,9 +2887,14 @@ var CodeArtsUsageTracker = class {
2879
2887
  if (typeof day !== "object" || day === null) continue;
2880
2888
  const models = normalizeStore(day.models);
2881
2889
  const accounts = normalizeStore(day.accounts);
2882
- this.days.set(date, {
2890
+ const hours = day.hours;
2891
+ this.days.set(date, hours === void 0 ? {
2883
2892
  models,
2884
2893
  accounts
2894
+ } : {
2895
+ models,
2896
+ accounts,
2897
+ hours: normalizeStore(hours)
2885
2898
  });
2886
2899
  }
2887
2900
  this.prune(this.now());
@@ -2915,6 +2928,7 @@ var CodeArtsUsageTracker = class {
2915
2928
  const day = this.day(localDateKey(at));
2916
2929
  addTotals(this.bucket(day.models, model), { requests: 1 });
2917
2930
  addTotals(this.bucket(day.accounts, accountId), { requests: 1 });
2931
+ addTotals(this.bucket(this.hoursOf(day), localHourKey(at)), { requests: 1 });
2918
2932
  this.lastAt = at;
2919
2933
  this.prune(at);
2920
2934
  this.scheduleSave();
@@ -2926,15 +2940,28 @@ var CodeArtsUsageTracker = class {
2926
2940
  const day = this.day(localDateKey(at));
2927
2941
  addTotals(this.bucket(day.models, model), usage);
2928
2942
  addTotals(this.bucket(day.accounts, accountId), usage);
2943
+ addTotals(this.bucket(this.hoursOf(day), localHourKey(at)), usage);
2929
2944
  this.lastAt = at;
2930
2945
  this.prune(at);
2931
2946
  this.scheduleSave();
2932
2947
  }
2933
- /** 丢弃保留期之外的天(按日期键比较即可,YYYY-MM-DD 是字典序)。 */
2948
+ /** 一天里的逐小时桶,第一次写的时候才建(老账本没有这个键)。 */
2949
+ hoursOf(day) {
2950
+ day.hours ??= {};
2951
+ return day.hours;
2952
+ }
2953
+ /**
2954
+ * 丢弃保留期之外的天(按日期键比较即可,YYYY-MM-DD 是字典序)。
2955
+ *
2956
+ * 顺带把两天之前的**小时桶**清掉:逐小时数据只有「今天按小时」在画,留着只是
2957
+ * 让 60 天的账本多出一个数量级的体积。
2958
+ */
2934
2959
  prune(at) {
2935
2960
  if (this.days.size === 0) return;
2936
2961
  const cutoff = localDateKey(at - 5184e6);
2937
- for (const date of [...this.days.keys()]) if (date < cutoff) this.days.delete(date);
2962
+ const hourCutoff = localDateKey(at - 1728e5);
2963
+ for (const [date, day] of [...this.days.entries()]) if (date < cutoff) this.days.delete(date);
2964
+ else if (date < hourCutoff && day.hours !== void 0) delete day.hours;
2938
2965
  }
2939
2966
  /** 当前快照(卡片与 CLI 都读它)。 */
2940
2967
  snapshot(at = this.now()) {
@@ -2961,9 +2988,36 @@ var CodeArtsUsageTracker = class {
2961
2988
  })).sort((a, b) => b.totals.totalTokens - a.totals.totalTokens || (a.id < b.id ? -1 : 1)),
2962
2989
  byAccountToday: Object.fromEntries(Object.entries(today?.accounts ?? {}).map(([id, totals]) => [id, { ...totals }])),
2963
2990
  days: this.days.size,
2991
+ recentDays: this.recentDaysOf(at),
2992
+ todayByHour: this.todayByHourOf(today, at),
2964
2993
  ...this.lastAt === void 0 ? {} : { lastAt: this.lastAt }
2965
2994
  };
2966
2995
  }
2996
+ /** 最近 TREND_DAYS 天的每日合计(按日期升序,缺账目的日子补 0)。 */
2997
+ recentDaysOf(at) {
2998
+ const out = [];
2999
+ for (let back = 6; back >= 0; back -= 1) {
3000
+ const date = localDateKey(at - back * 864e5);
3001
+ const day = this.days.get(date);
3002
+ out.push({
3003
+ date,
3004
+ totals: day === void 0 ? emptyTotals() : sumOf(day.models)
3005
+ });
3006
+ }
3007
+ return out;
3008
+ }
3009
+ /** 今天 0 点起的 24 个钟点(还没到的小时补 0,横轴才有固定的 24 格)。 */
3010
+ todayByHourOf(today, at) {
3011
+ const hours = today?.hours ?? {};
3012
+ const currentHour = new Date(at).getHours();
3013
+ return Array.from({ length: 24 }, (_, hour) => {
3014
+ const totals = hours[localHourKeyOfHour(hour)];
3015
+ return {
3016
+ hour,
3017
+ totals: hour > currentHour || totals === void 0 ? emptyTotals() : { ...totals }
3018
+ };
3019
+ });
3020
+ }
2967
3021
  scheduleSave() {
2968
3022
  if (this.path === void 0) return;
2969
3023
  if (this.saveTimer !== void 0) return;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "dsh-codearts",
3
3
  "displayName": "DSH CodeArts Connect",
4
4
  "description": "把华为云 CodeArts 接入 DeepSeek Harness —— 内置 OAuth2 登录(PKCE + DPoP),登录后即可在 DSH 对话窗口使用 CodeArts 的模型。",
5
- "version": "1.2.4",
5
+ "version": "1.2.6",
6
6
  "packageManager": "pnpm@11.24.0",
7
7
  "author": "elegant01",
8
8
  "keywords": [