@mars-sea/dsh-commandcode-provider 0.3.0 → 0.4.0

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.js CHANGED
@@ -9,6 +9,7 @@ import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-sett
9
9
  import { existsSync, readFileSync } from "node:fs";
10
10
  import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
11
11
  import { randomUUID } from "node:crypto";
12
+ import { TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
12
13
  //#region src/adapter.ts
13
14
  /**
14
15
  * DeepSeek Harness LLM adapter for the Command Code Provider API.
@@ -359,6 +360,89 @@ function compareByPlan(a, b) {
359
360
  if (nameDiff !== 0) return nameDiff;
360
361
  return a.id.localeCompare(b.id);
361
362
  }
363
+ /**
364
+ * Subscription plan table, synced from the official CLI bundle's plan maps
365
+ * (`Nn`/`$n` in command-code@1.26.0 `dist/cli.mjs`): subscription `planId`
366
+ * prefix → display name and the plan's monthly credit total. This is the
367
+ * account's own subscription (from `/alpha/billing/subscriptions`) — distinct
368
+ * from {@link KNOWN_PLANS}, which maps catalog models to their minimum tier.
369
+ *
370
+ * `tierWeight` is plugin-added (not from the CLI maps): the plan's rank on
371
+ * the {@link PLAN_ORDER} scale, used by the picker's plan filter
372
+ * ({@link modelVisibleInPlan}) to hide models above the account's tier.
373
+ */
374
+ const KNOWN_SUBSCRIPTION_PLANS = {
375
+ "individual-go": {
376
+ name: "Go",
377
+ monthlyCredits: 10,
378
+ tierWeight: 0
379
+ },
380
+ "individual-goat": {
381
+ name: "GOAT",
382
+ monthlyCredits: 70,
383
+ tierWeight: 1
384
+ },
385
+ "individual-pro": {
386
+ name: "Pro",
387
+ monthlyCredits: 30,
388
+ tierWeight: 2
389
+ },
390
+ "individual-pro-v1": {
391
+ name: "Pro",
392
+ monthlyCredits: 80,
393
+ tierWeight: 2
394
+ },
395
+ "individual-provider": {
396
+ name: "Provider",
397
+ monthlyCredits: 15,
398
+ tierWeight: 3
399
+ },
400
+ "individual-max": {
401
+ name: "Max",
402
+ monthlyCredits: 150,
403
+ tierWeight: 4
404
+ },
405
+ "individual-ultra": {
406
+ name: "Ultra",
407
+ monthlyCredits: 300,
408
+ tierWeight: 4
409
+ },
410
+ "teams-pro": {
411
+ name: "Teams Pro",
412
+ monthlyCredits: 40,
413
+ tierWeight: 2
414
+ }
415
+ };
416
+ /** Plan-id prefixes, longest first — the CLI's prefix-match order. */
417
+ const SUBSCRIPTION_PLAN_PREFIXES = Object.keys(KNOWN_SUBSCRIPTION_PLANS).sort((a, b) => b.length - a.length);
418
+ /**
419
+ * Resolve a subscription `planId` (e.g. `individual-pro-v1`) to its display
420
+ * name and monthly credit total, mirroring the CLI's `getPlanInfo`:
421
+ * normalize (lowercase, `_` → `-`), then longest-prefix match so
422
+ * `individual-pro-v1` wins over `individual-pro`. Unknown ids return
423
+ * `undefined`.
424
+ */
425
+ function subscriptionPlanInfo(planId) {
426
+ const normalized = planId.toLowerCase().replace(/_/g, "-");
427
+ const prefix = SUBSCRIPTION_PLAN_PREFIXES.find((candidate) => normalized.startsWith(candidate));
428
+ return prefix === void 0 ? void 0 : KNOWN_SUBSCRIPTION_PLANS[prefix];
429
+ }
430
+ /**
431
+ * Whether the picker lists `modelId` for an account with the given billing
432
+ * access. Fails open at every uncertainty: no billing data, an unknown plan,
433
+ * or a model outside {@link KNOWN_PLANS} all keep the model visible — the
434
+ * server remains the final gate (`403 MODEL_NOT_IN_PLAN`).
435
+ */
436
+ function modelVisibleInPlan(modelId, access) {
437
+ if (access === void 0) return true;
438
+ if (access.onDemandCredits > 0) return true;
439
+ if (access.tierWeight === void 0) return true;
440
+ const tier = KNOWN_PLANS[modelId];
441
+ if (tier === void 0) return true;
442
+ const weight = PLAN_ORDER[tier];
443
+ if (weight === void 0) return true;
444
+ return weight <= access.tierWeight;
445
+ }
362
446
  const KNOWN_DEALS = {
363
447
  "google/gemini-3.7-flash": {
364
448
  label: "50% off",
@@ -412,6 +496,18 @@ const COMMAND_CODE_CLI_VERSION = "1.26.0";
412
496
  const DEFAULT_API_BASE = "https://api.commandcode.ai";
413
497
  const DEFAULT_GENERATE_MAX_TOKENS = 64e3;
414
498
  const DEFAULT_MAX_OUTPUT_TOKENS = 65536;
499
+ const MODELS_TIMEOUT_MS = 1e4;
500
+ /** How long the picker's plan-filter billing facts stay cached before refetching. */
501
+ const BILLING_ACCESS_TTL_MS = 3e5;
502
+ /**
503
+ * Subscription statuses the CLI treats as live (`Mr` in command-code's
504
+ * cli.mjs): the plan gate applies only under one of these.
505
+ */
506
+ const ACTIVE_SUBSCRIPTION_STATUSES = /* @__PURE__ */ new Set([
507
+ "active",
508
+ "trialing",
509
+ "past_due"
510
+ ]);
415
511
  /** Head-of-request timeout: how long to wait for the first response byte. */
416
512
  const DEFAULT_REQUEST_TIMEOUT_MS = 6e4;
417
513
  /** Stream idle timeout: a generation that stalls this long is a dead connection. */
@@ -484,6 +580,15 @@ function numberValue(value) {
484
580
  function booleanValue(value) {
485
581
  return typeof value === "boolean" ? value : void 0;
486
582
  }
583
+ /** Parse a billing-period timestamp (ISO string or millis) into millis; 0 when absent/invalid. */
584
+ function periodEndValue(value) {
585
+ const asNumber = numberValue(value);
586
+ if (asNumber !== void 0) return asNumber;
587
+ const asString = stringValue(value);
588
+ if (asString === void 0) return 0;
589
+ const parsed = Date.parse(asString);
590
+ return Number.isNaN(parsed) ? 0 : parsed;
591
+ }
487
592
  /**
488
593
  * Terminal stream-error markers from the official CLI (`Xw` in command-code's
489
594
  * cli.mjs): these always mean "retrying cannot succeed", so the adapter must
@@ -684,6 +789,8 @@ var CommandCodeAdapter = class extends LlmAdapter {
684
789
  catalog = [];
685
790
  fetchImpl;
686
791
  resolveAttachments;
792
+ billingAccess;
793
+ billingAccessInflight;
687
794
  constructor(deps) {
688
795
  super();
689
796
  this.deps = deps;
@@ -722,7 +829,9 @@ var CommandCodeAdapter = class extends LlmAdapter {
722
829
  return this.catalog;
723
830
  }
724
831
  async listModels(provider) {
725
- return (await this.loadCatalog()).map((model) => {
832
+ const catalog = await this.loadCatalog();
833
+ const access = this.deps.options().filterModelsByPlan === false ? void 0 : await this.loadBillingAccess();
834
+ return catalog.filter((model) => modelVisibleInPlan(model.id, access)).map((model) => {
726
835
  const vision = KNOWN_IMAGE_MODELS.has(model.id);
727
836
  return {
728
837
  provider,
@@ -753,27 +862,96 @@ var CommandCodeAdapter = class extends LlmAdapter {
753
862
  })) } } : {}
754
863
  };
755
864
  }
865
+ /** The headers every authenticated account endpoint shares. */
866
+ async accountHeaders() {
867
+ const connection = this.deps.options();
868
+ return {
869
+ Authorization: `Bearer ${await this.deps.resolveApiKey(connection)}`,
870
+ "x-command-code-version": COMMAND_CODE_CLI_VERSION,
871
+ "x-cli-environment": "production",
872
+ ...attributionHeaders()
873
+ };
874
+ }
875
+ /**
876
+ * The billing facts behind the picker's plan filter, cached for
877
+ * {@link BILLING_ACCESS_TTL_MS} and shared across concurrent callers.
878
+ * `undefined` means "unknown — show everything" (fail-open).
879
+ */
880
+ async loadBillingAccess() {
881
+ const cached = this.billingAccess;
882
+ if (cached !== void 0 && Date.now() - cached.at < 3e5) return cached.value;
883
+ this.billingAccessInflight ??= this.fetchBillingAccess().then((value) => {
884
+ this.billingAccess = {
885
+ value,
886
+ at: Date.now()
887
+ };
888
+ return value;
889
+ }).finally(() => {
890
+ this.billingAccessInflight = void 0;
891
+ });
892
+ return this.billingAccessInflight;
893
+ }
756
894
  /**
757
- * Fetch account, usage, and credit state from the Command Code account
758
- * endpoints (`/alpha/whoami`, `/alpha/usage/summary`, `/alpha/billing/credits`).
895
+ * The billing facts behind the picker's plan filter, mirroring the CLI's
896
+ * `createBilling` flow: whoami yields the org id, then the subscriptions
897
+ * and credits endpoints answer in parallel. The plan id is honored only
898
+ * when the subscription reports an active-ish status (the CLI's rule); when
899
+ * the subscriptions endpoint fails entirely, `credits.planId` is the
900
+ * fallback (the CLI stamps plan identity from it too). Any failure resolves
901
+ * to `undefined` (fail-open) rather than breaking the picker.
902
+ */
903
+ async fetchBillingAccess() {
904
+ try {
905
+ const connection = this.deps.options();
906
+ const headers = await this.accountHeaders();
907
+ const base = connection.apiBase;
908
+ const getJson = async (path) => {
909
+ const response = await this.fetchImpl(`${base}${path}`, {
910
+ headers,
911
+ signal: AbortSignal.timeout(MODELS_TIMEOUT_MS)
912
+ });
913
+ if (!response.ok) return void 0;
914
+ const parsed = await response.json();
915
+ return isRecord(parsed) ? parsed : void 0;
916
+ };
917
+ const whoami = await getJson("/alpha/whoami");
918
+ const orgData = whoami && isRecord(whoami.org) ? whoami.org : void 0;
919
+ const orgId = orgData === void 0 ? void 0 : stringValue(orgData.id);
920
+ const [subscription, credits] = await Promise.all([getJson(orgId === void 0 ? "/alpha/billing/subscriptions" : `/alpha/billing/subscriptions?orgId=${encodeURIComponent(orgId)}`), getJson("/alpha/billing/credits")]);
921
+ const subData = subscription && isRecord(subscription.data) ? subscription.data : void 0;
922
+ const creditsData = credits && isRecord(credits.credits) ? credits.credits : void 0;
923
+ if (subData === void 0 && creditsData === void 0) return void 0;
924
+ let planId;
925
+ if (subData !== void 0) {
926
+ const status = stringValue(subData.status);
927
+ if (status !== void 0 && ACTIVE_SUBSCRIPTION_STATUSES.has(status)) planId = stringValue(subData.planId);
928
+ } else planId = stringValue(creditsData?.planId);
929
+ return {
930
+ tierWeight: planId === void 0 ? void 0 : subscriptionPlanInfo(planId)?.tierWeight,
931
+ onDemandCredits: (numberValue(creditsData?.purchasedCredits) ?? 0) + (numberValue(creditsData?.freeCredits) ?? 0)
932
+ };
933
+ } catch {
934
+ return;
935
+ }
936
+ }
937
+ /**
938
+ * Fetch account, usage, credit, and subscription state from the Command
939
+ * Code account endpoints (`/alpha/whoami`, `/alpha/usage/summary`,
940
+ * `/alpha/billing/credits`, `/alpha/billing/subscriptions`).
759
941
  * Each endpoint degrades independently: a failed one lands in `failures`
760
942
  * while the rest still report, so a transient outage never blanks the whole
761
943
  * view. Requires a usable API key (throws `MISSING_CREDENTIAL` otherwise).
762
944
  */
763
945
  async getUsage() {
764
- const connection = this.deps.options();
765
- const apiKey = await this.deps.resolveApiKey(connection);
766
- const base = connection.apiBase;
767
- const headers = {
768
- Authorization: `Bearer ${apiKey}`,
769
- "x-command-code-version": COMMAND_CODE_CLI_VERSION,
770
- "x-cli-environment": "production",
771
- ...attributionHeaders()
772
- };
946
+ const base = this.deps.options().apiBase;
947
+ const headers = await this.accountHeaders();
773
948
  const failures = [];
774
949
  const getJson = async (path) => {
775
950
  try {
776
- const response = await this.fetchImpl(`${base}${path}`, { headers });
951
+ const response = await this.fetchImpl(`${base}${path}`, {
952
+ headers,
953
+ signal: AbortSignal.timeout(MODELS_TIMEOUT_MS)
954
+ });
777
955
  if (!response.ok) {
778
956
  failures.push(`${path}: HTTP ${response.status}`);
779
957
  return;
@@ -793,6 +971,8 @@ var CommandCodeAdapter = class extends LlmAdapter {
793
971
  name: stringValue(whoamiData.name) ?? "",
794
972
  userName: stringValue(whoamiData.userName) ?? ""
795
973
  };
974
+ const orgData = whoami && isRecord(whoami.org) ? whoami.org : void 0;
975
+ const orgId = orgData === void 0 ? void 0 : stringValue(orgData.id);
796
976
  const usage = await getJson("/alpha/usage/summary");
797
977
  if (usage) report.usage = {
798
978
  totalCount: numberValue(usage.totalCount) ?? 0,
@@ -827,6 +1007,19 @@ var CommandCodeAdapter = class extends LlmAdapter {
827
1007
  resetAt: numberValue(weekly?.resetAt) ?? 0
828
1008
  }
829
1009
  };
1010
+ const subscription = await getJson(orgId === void 0 ? "/alpha/billing/subscriptions" : `/alpha/billing/subscriptions?orgId=${encodeURIComponent(orgId)}`);
1011
+ const subData = subscription && isRecord(subscription.data) ? subscription.data : void 0;
1012
+ const planId = stringValue(subData?.planId) ?? stringValue(creditsData?.planId);
1013
+ if (subData !== void 0 || planId !== void 0) {
1014
+ const info = planId === void 0 ? void 0 : subscriptionPlanInfo(planId);
1015
+ report.plan = {
1016
+ planId: planId ?? "",
1017
+ name: info?.name ?? planId ?? "",
1018
+ status: stringValue(subData?.status) ?? "",
1019
+ monthlyCredits: info?.monthlyCredits ?? null,
1020
+ currentPeriodEnd: periodEndValue(subData?.currentPeriodEnd)
1021
+ };
1022
+ }
830
1023
  return report;
831
1024
  }
832
1025
  async *stream(options) {
@@ -1190,6 +1383,12 @@ function renderReport(report) {
1190
1383
  const lines = [];
1191
1384
  const account = report.account ? ` (${report.account.userName || report.account.name})` : "";
1192
1385
  lines.push(`📊 Command Code 用量${account}`, "");
1386
+ if (report.plan && report.plan.name !== "") {
1387
+ const p = report.plan;
1388
+ const status = p.status !== "" && p.status !== "active" ? ` (${p.status})` : "";
1389
+ const period = p.currentPeriodEnd > 0 ? ` · 账期截止 ${new Date(p.currentPeriodEnd).toLocaleDateString()}` : "";
1390
+ lines.push(` 📦 套餐 ${p.name}${status}${period}`, "");
1391
+ }
1193
1392
  if (report.usage) {
1194
1393
  const u = report.usage;
1195
1394
  lines.push("── 请求 ──────────────────────────────", ` 💬 请求 ${u.completedCount} 次 / 失败 ${u.failedCount} 成功率 ${u.successRate}%`, ` 💰 花费 ${money(u.totalCost)} (${moneyShort(u.totalCredits)} credits)`, ` 🔤 Token ${tokensCompact(u.totalTokensIn)} 入 / ${tokensCompact(u.totalTokensOut)} 出`, "");
@@ -1230,6 +1429,167 @@ function applyCommands(ctx, deps) {
1230
1429
  ctx.commands.register(commandDefinition(deps));
1231
1430
  }
1232
1431
  //#endregion
1432
+ //#region src/usage-wire.ts
1433
+ /** The npm package identity both contribution registrations claim. */
1434
+ const USAGE_REMOTE_PACKAGE = "@mars-sea/dsh-commandcode-provider";
1435
+ /** Canonical `<namespace>/<method>` endpoint of the usage report Remote. */
1436
+ const USAGE_REPORT_ENDPOINT = "commandcode/report";
1437
+ /** Reject one boundary value with a field-naming error. */
1438
+ function reject(field) {
1439
+ throw new TypeError(`commandcode/report result: invalid ${field}`);
1440
+ }
1441
+ /** Read one required finite number field (`field` is the dotted error label). */
1442
+ function numberField(source, key, field) {
1443
+ const value = source[key];
1444
+ if (typeof value !== "number" || !Number.isFinite(value)) reject(field);
1445
+ return value;
1446
+ }
1447
+ /** Read one required string field (`field` is the dotted error label). */
1448
+ function stringField(source, key, field) {
1449
+ const value = source[key];
1450
+ if (typeof value !== "string") reject(field);
1451
+ return value;
1452
+ }
1453
+ /** Read one required boolean field (`field` is the dotted error label). */
1454
+ function booleanField(source, key, field) {
1455
+ const value = source[key];
1456
+ if (typeof value !== "boolean") reject(field);
1457
+ return value;
1458
+ }
1459
+ /** Narrow an unknown value to a plain record, or reject. */
1460
+ function record(value, field) {
1461
+ if (typeof value !== "object" || value === null || Array.isArray(value)) reject(field);
1462
+ return value;
1463
+ }
1464
+ /** Validate one window-limit block (`fiveHour` / `weekly`). */
1465
+ function windowLimit(value, field) {
1466
+ const source = record(value, field);
1467
+ return {
1468
+ used: numberField(source, "used", `${field}.used`),
1469
+ cap: numberField(source, "cap", `${field}.cap`),
1470
+ exceeded: booleanField(source, "exceeded", `${field}.exceeded`),
1471
+ resetAt: numberField(source, "resetAt", `${field}.resetAt`)
1472
+ };
1473
+ }
1474
+ /**
1475
+ * Parse one untrusted boundary value into a {@link CommandCodeUsageReport}.
1476
+ * Optional sections stay optional; every present field is shape-checked so a
1477
+ * malformed frame fails the boundary instead of rendering garbage.
1478
+ */
1479
+ function parseUsageReport(value) {
1480
+ const source = record(value, "report");
1481
+ const failures = source.failures;
1482
+ if (!Array.isArray(failures) || failures.some((entry) => typeof entry !== "string")) reject("failures");
1483
+ const report = { failures };
1484
+ if (source.account !== void 0) {
1485
+ const account = record(source.account, "account");
1486
+ report.account = {
1487
+ id: stringField(account, "id", "account.id"),
1488
+ name: stringField(account, "name", "account.name"),
1489
+ userName: stringField(account, "userName", "account.userName")
1490
+ };
1491
+ }
1492
+ if (source.usage !== void 0) {
1493
+ const usage = record(source.usage, "usage");
1494
+ report.usage = {
1495
+ totalCount: numberField(usage, "totalCount", "usage.totalCount"),
1496
+ totalCost: numberField(usage, "totalCost", "usage.totalCost"),
1497
+ successRate: numberField(usage, "successRate", "usage.successRate"),
1498
+ completedCount: numberField(usage, "completedCount", "usage.completedCount"),
1499
+ failedCount: numberField(usage, "failedCount", "usage.failedCount"),
1500
+ totalTokensIn: numberField(usage, "totalTokensIn", "usage.totalTokensIn"),
1501
+ totalTokensOut: numberField(usage, "totalTokensOut", "usage.totalTokensOut"),
1502
+ totalCredits: numberField(usage, "totalCredits", "usage.totalCredits"),
1503
+ periodBasis: stringField(usage, "periodBasis", "usage.periodBasis")
1504
+ };
1505
+ }
1506
+ if (source.credits !== void 0) {
1507
+ const credits = record(source.credits, "credits");
1508
+ report.credits = {
1509
+ monthlyCredits: numberField(credits, "monthlyCredits", "credits.monthlyCredits"),
1510
+ purchasedCredits: numberField(credits, "purchasedCredits", "credits.purchasedCredits"),
1511
+ freeCredits: numberField(credits, "freeCredits", "credits.freeCredits"),
1512
+ fiveHour: windowLimit(credits.fiveHour, "credits.fiveHour"),
1513
+ weekly: windowLimit(credits.weekly, "credits.weekly")
1514
+ };
1515
+ }
1516
+ if (source.plan !== void 0) {
1517
+ const plan = record(source.plan, "plan");
1518
+ const monthly = plan.monthlyCredits;
1519
+ if (monthly !== null && (typeof monthly !== "number" || !Number.isFinite(monthly))) reject("plan.monthlyCredits");
1520
+ report.plan = {
1521
+ planId: stringField(plan, "planId", "plan.planId"),
1522
+ name: stringField(plan, "name", "plan.name"),
1523
+ status: stringField(plan, "status", "plan.status"),
1524
+ monthlyCredits: monthly,
1525
+ currentPeriodEnd: numberField(plan, "currentPeriodEnd", "plan.currentPeriodEnd")
1526
+ };
1527
+ }
1528
+ return report;
1529
+ }
1530
+ /**
1531
+ * The strict result codec both halves attach to the descriptor. Hand-rolled:
1532
+ * the client bundle may not require a schema library, and `TypertSchema` is
1533
+ * deliberately minimal so one `parse` function satisfies it.
1534
+ */
1535
+ const usageReportSchema = { parse: parseUsageReport };
1536
+ /** The Host-face contribution registered on `ctx.typert`. */
1537
+ const USAGE_HOST_CONTRIBUTION = {
1538
+ package: USAGE_REMOTE_PACKAGE,
1539
+ face: "host",
1540
+ schemas: [],
1541
+ invocations: [{
1542
+ id: `${USAGE_REMOTE_PACKAGE}#${USAGE_REPORT_ENDPOINT}`,
1543
+ service: "commandcodeUsage",
1544
+ namespace: "commandcode",
1545
+ method: "report",
1546
+ invocation: { kind: "direct" },
1547
+ parameters: [],
1548
+ result: {
1549
+ mode: "strict",
1550
+ typeSymbol: `${USAGE_REMOTE_PACKAGE}#CommandCodeUsageReport`,
1551
+ schema: usageReportSchema
1552
+ }
1553
+ }]
1554
+ };
1555
+ //#endregion
1556
+ //#region src/usage-remote.ts
1557
+ /**
1558
+ * The Remote receiver: a Cordis service the Gateway resolves by key
1559
+ * (`commandcodeUsage`) and binds to the wire namespace (`commandcode`). The
1560
+ * base class stamps the `typertRemote` binding the Gateway validates on every
1561
+ * dispatch; no decorators are needed because the descriptor is registered
1562
+ * explicitly (strict path) rather than discovered from source markers.
1563
+ */
1564
+ var CommandCodeUsageService = class extends TypertRemoteService {
1565
+ deps;
1566
+ constructor(ctx, deps) {
1567
+ super(ctx, "commandcodeUsage", { namespace: "commandcode" });
1568
+ this.deps = deps;
1569
+ }
1570
+ /**
1571
+ * Account, usage, and credit state for the settings page's account card.
1572
+ * Degrades per endpoint like the `/commandcode` command (failures land in
1573
+ * `report.failures`); throws `MISSING_CREDENTIAL` when no key resolves, which
1574
+ * the Gateway folds into the failure branch the page renders as a hint.
1575
+ */
1576
+ async report() {
1577
+ return this.deps.adapter.getUsage();
1578
+ }
1579
+ };
1580
+ /**
1581
+ * Provide the usage service and register its Remote descriptor. The registry
1582
+ * contribution is tied to this fiber's lifetime: the registry's own
1583
+ * `register()` effect would otherwise outlive the plugin.
1584
+ */
1585
+ function applyUsageRemote(ctx, deps) {
1586
+ ctx.inject(["typert"], (remoteCtx) => {
1587
+ new CommandCodeUsageService(remoteCtx, deps);
1588
+ const unregister = remoteCtx.typert.register(USAGE_HOST_CONTRIBUTION);
1589
+ remoteCtx.effect(() => () => void unregister(), "dsh-commandcode-provider: usage remote");
1590
+ });
1591
+ }
1592
+ //#endregion
1233
1593
  //#region src/index.ts
1234
1594
  /**
1235
1595
  * dsh-commandcode-provider — DeepSeek Harness LLM provider plugin for Command
@@ -1273,7 +1633,8 @@ const Config = z.object({
1273
1633
  workingDir: z.string(),
1274
1634
  modelsCachePath: z.string(),
1275
1635
  requestTimeoutMs: z.number().min(1).max(MAX_TIMER_DELAY_MS),
1276
- streamIdleTimeoutMs: z.number().min(1).max(MAX_TIMER_DELAY_MS)
1636
+ streamIdleTimeoutMs: z.number().min(1).max(MAX_TIMER_DELAY_MS),
1637
+ filterModelsByPlan: z.boolean()
1277
1638
  });
1278
1639
  /**
1279
1640
  * The one explicit resolve step from raw config to validated connection
@@ -1288,7 +1649,8 @@ function resolveAdapterOptions(config) {
1288
1649
  workingDir: config.workingDir ?? process.cwd(),
1289
1650
  modelsCachePath: config.modelsCachePath ?? DEFAULT_MODELS_CACHE_PATH,
1290
1651
  requestTimeoutMs: config.requestTimeoutMs ?? 6e4,
1291
- streamIdleTimeoutMs: config.streamIdleTimeoutMs ?? 3e5
1652
+ streamIdleTimeoutMs: config.streamIdleTimeoutMs ?? 3e5,
1653
+ filterModelsByPlan: config.filterModelsByPlan ?? true
1292
1654
  };
1293
1655
  }
1294
1656
  function apply(ctx, config) {
@@ -1338,6 +1700,7 @@ function apply(ctx, config) {
1338
1700
  ctx.inject(["commands"], (commandCtx) => {
1339
1701
  applyCommands(commandCtx, { adapter });
1340
1702
  });
1703
+ applyUsageRemote(ctx, { adapter });
1341
1704
  installSettingsSection(ctx, NS, Config, config, {
1342
1705
  setSource: (source) => {
1343
1706
  current = source;
@@ -1346,6 +1709,6 @@ function apply(ctx, config) {
1346
1709
  });
1347
1710
  }
1348
1711
  //#endregion
1349
- export { COMMAND_CODE_CLI_VERSION, CommandCodeAdapter, Config, DEFAULT_API_BASE, DEFAULT_GENERATE_MAX_TOKENS, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_MODELS_CACHE_PATH, DEFAULT_REQUEST_TIMEOUT_MS, DEFAULT_STREAM_IDLE_TIMEOUT_MS, KNOWN_DEALS, KNOWN_EFFORTS, KNOWN_IMAGE_MODELS, KNOWN_PEAK_PRICING, KNOWN_PLANS, KNOWN_THINKING_MODELS, PLAN_LABELS, PLAN_ORDER, PROVIDER, apply, applyCommands, capabilityDescription, commandDefinition, compareByPlan, dealLabel, formatContext, inject, name, peakPricingLabel, peakPricingState, planLabel, projectSlugFromPath, resolveAdapterOptions, resolveAuthFileApiKey };
1712
+ export { BILLING_ACCESS_TTL_MS, COMMAND_CODE_CLI_VERSION, CommandCodeAdapter, CommandCodeUsageService, Config, DEFAULT_API_BASE, DEFAULT_GENERATE_MAX_TOKENS, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_MODELS_CACHE_PATH, DEFAULT_REQUEST_TIMEOUT_MS, DEFAULT_STREAM_IDLE_TIMEOUT_MS, KNOWN_DEALS, KNOWN_EFFORTS, KNOWN_IMAGE_MODELS, KNOWN_PEAK_PRICING, KNOWN_PLANS, KNOWN_SUBSCRIPTION_PLANS, KNOWN_THINKING_MODELS, PLAN_LABELS, PLAN_ORDER, PROVIDER, USAGE_REPORT_ENDPOINT, apply, applyCommands, applyUsageRemote, capabilityDescription, commandDefinition, compareByPlan, dealLabel, formatContext, inject, modelVisibleInPlan, name, peakPricingLabel, peakPricingState, planLabel, projectSlugFromPath, resolveAdapterOptions, resolveAuthFileApiKey, subscriptionPlanInfo, usageReportSchema };
1350
1713
 
1351
1714
  //# sourceMappingURL=index.js.map