@jeffreyjyz/opencode-command-code 0.3.18 → 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/dist/tui.js CHANGED
@@ -4,13 +4,28 @@ import { createComponent as _$createComponent2 } from "@opentui/solid";
4
4
 
5
5
  // src/cli.ts
6
6
  import { spawn } from "child_process";
7
+
8
+ // src/constants/binaries.ts
9
+ import { homedir } from "os";
10
+ import { join } from "path";
11
+ var CMDUSE_BIN_CANDIDATES = ["cmduse", "/opt/homebrew/bin/cmduse", "/usr/local/bin/cmduse"];
12
+ var MPC_BIN_CANDIDATES = ["mpc", join(homedir(), ".bun/bin/mpc"), "/opt/homebrew/bin/mpc"];
13
+ var OCUSE_BIN_CANDIDATES = ["ocuse", "/opt/homebrew/bin/ocuse", "/usr/local/bin/ocuse"];
14
+
15
+ // src/constants/cli.ts
16
+ var DEFAULT_ARGS = ["-1", "--plain"];
17
+ var SUBCOMMANDS = new Set(["plans", "models", "daily", "hourly", "model", "session", "statusline", "config"]);
18
+ var SPAWN_OPTIONS = {
19
+ stdio: ["ignore", "pipe", "pipe"],
20
+ detached: true
21
+ };
22
+
23
+ // src/cli.ts
7
24
  function cmduseCandidates(env = process.env) {
8
- const candidates = [env.CMDUSE_BIN, "cmduse", "/opt/homebrew/bin/cmduse", "/usr/local/bin/cmduse"];
25
+ const candidates = [env.CMDUSE_BIN, ...CMDUSE_BIN_CANDIDATES];
9
26
  return candidates.filter((bin) => Boolean(bin));
10
27
  }
11
28
  var CANDIDATES = cmduseCandidates();
12
- var DEFAULT_ARGS = ["-1", "--plain"];
13
- var SUBCOMMANDS = new Set(["plans", "models", "daily", "hourly", "model", "session", "statusline", "config"]);
14
29
  function splitCliArgs(input) {
15
30
  const out = [];
16
31
  let cur = "";
@@ -52,7 +67,7 @@ function splitCliArgs(input) {
52
67
  function buildCmduseArgs(arg) {
53
68
  const tokens = splitCliArgs(arg);
54
69
  if (!tokens.length)
55
- return DEFAULT_ARGS;
70
+ return [...DEFAULT_ARGS];
56
71
  if (tokens.some((t) => SUBCOMMANDS.has(t)))
57
72
  return tokens;
58
73
  return [...DEFAULT_ARGS, ...tokens];
@@ -118,6 +133,13 @@ async function runCmduse(arg, opts = {}) {
118
133
  });
119
134
  }
120
135
 
136
+ // src/constants/providers.ts
137
+ var PROVIDER_ID_PREFIX = "command-code";
138
+ var GO_PROVIDER_ID = "opencode-go";
139
+ var ZEN_PROVIDER_ID = "opencode";
140
+ var ZEN_PROVIDER_PREFIX = "opencode-zen";
141
+ var TUI_ID = "command-code.tui";
142
+
121
143
  // src/sidebar/panel.tsx
122
144
  import { createComponent as _$createComponent } from "@opentui/solid";
123
145
  import { insertNode as _$insertNode } from "@opentui/solid";
@@ -131,9 +153,10 @@ import { RGBA } from "@opentui/core";
131
153
  import { For, Show } from "solid-js";
132
154
  // ../core/gating.json
133
155
  var gating_default = {
134
- extractedAt: "2026-09-27T06:27:06.878Z",
135
- cliVersion: "1.66.0",
156
+ extractedAt: "2026-10-03T05:21:43.847Z",
157
+ cliVersion: "1.74.1",
136
158
  categories: {
159
+ "claude-sonnet-5-5": "opensource",
137
160
  "claude-sonnet-5": "premium",
138
161
  "claude-sonnet-4-6": "premium",
139
162
  "claude-fable-5-1": "premium",
@@ -147,6 +170,7 @@ var gating_default = {
147
170
  "gpt-5.6-terra": "premium",
148
171
  "gpt-5.6-luna": "opensource",
149
172
  "gpt-6-astra": "premium",
173
+ "gpt-6.1-sol": "premium",
150
174
  "gpt-6-sol": "premium",
151
175
  "gpt-6-luna": "opensource",
152
176
  "gpt-5.5": "premium",
@@ -180,6 +204,7 @@ var gating_default = {
180
204
  "deepseek/deepseek-v4-pro": "opensource",
181
205
  "deepseek/deepseek-v4-flash": "opensource",
182
206
  "deepseek/deepseek-v4.1-flash": "opensource",
207
+ "deepseek/deepseek-v4.1-flash-fast": "opensource",
183
208
  "moonshotai/Kimi-K3": "opensource",
184
209
  "moonshotai/Kimi-K2.7-Code": "opensource",
185
210
  "moonshotai/Kimi-K2.7-Code-Highspeed": "opensource",
@@ -208,6 +233,7 @@ var gating_default = {
208
233
  "meituan/LongCat-2.0": "opensource",
209
234
  "meituan/LongCat-2.0:free": "opensource",
210
235
  "inclusionai/ling-3.0-flash-sante:free": "opensource",
236
+ "inclusionai/ling-3.1-flash:free": "opensource",
211
237
  "stepfun/Step-5-Preview": "opensource",
212
238
  "stepfun/Step-3.7-Flash": "opensource",
213
239
  "stepfun/Step-3.5-Flash": "opensource",
@@ -229,7 +255,24 @@ var gating_default = {
229
255
  "vercel-ai-gateway:xiaomi/mimo-v2.6-pro-ultraspeed",
230
256
  "openrouter:google/gemini-3.7-flash",
231
257
  "vercel-ai-gateway:google/gemini-3.8-flash",
232
- "vercel-ai-gateway:gpt-5.6-sol"
258
+ "vercel-ai-gateway:gpt-5.6-sol",
259
+ "anthropic:claude-sonnet-5-5"
260
+ ]
261
+ },
262
+ "individual-go-v1": {
263
+ allowedCategories: [
264
+ "opensource"
265
+ ],
266
+ blockedModels: [
267
+ "vercel-ai-gateway:meta/muse-spark-1.2",
268
+ "vercel-ai-gateway:meta/muse-spark-1.3",
269
+ "vercel-ai-gateway:xai/grok-4.6",
270
+ "vercel-ai-gateway:xai/grok-4.7",
271
+ "vercel-ai-gateway:xiaomi/mimo-v2.6-pro-ultraspeed",
272
+ "openrouter:google/gemini-3.7-flash",
273
+ "vercel-ai-gateway:google/gemini-3.8-flash",
274
+ "vercel-ai-gateway:gpt-5.6-sol",
275
+ "anthropic:claude-sonnet-5-5"
233
276
  ]
234
277
  },
235
278
  "individual-goat": {
@@ -253,6 +296,7 @@ var gating_default = {
253
296
  "anthropic:claude-opus-4-6",
254
297
  "anthropic:claude-opus-4-5-20251101",
255
298
  "openai:gpt-6-astra",
299
+ "openai:gpt-6.1-sol",
256
300
  "vercel-ai-gateway:sakana/fugu-ultra"
257
301
  ]
258
302
  },
@@ -271,6 +315,7 @@ var gating_default = {
271
315
  "anthropic:claude-opus-4-6",
272
316
  "anthropic:claude-opus-4-5-20251101",
273
317
  "openai:gpt-6-astra",
318
+ "openai:gpt-6.1-sol",
274
319
  "vercel-ai-gateway:sakana/fugu-ultra"
275
320
  ]
276
321
  },
@@ -279,7 +324,9 @@ var gating_default = {
279
324
  "premium",
280
325
  "opensource"
281
326
  ],
282
- blockedModels: []
327
+ blockedModels: [
328
+ "openai:gpt-6.1-sol"
329
+ ]
283
330
  },
284
331
  "individual-max": {
285
332
  allowedCategories: [
@@ -304,6 +351,7 @@ var gating_default = {
304
351
  }
305
352
  },
306
353
  knownModels: [
354
+ "claude-sonnet-5",
307
355
  "claude-sonnet-4-6",
308
356
  "claude-fable-5-1",
309
357
  "claude-fable-5",
@@ -313,6 +361,7 @@ var gating_default = {
313
361
  "claude-opus-4-7",
314
362
  "claude-haiku-4-5-20251001",
315
363
  "gpt-6-astra",
364
+ "gpt-6.1-sol",
316
365
  "gpt-6-sol",
317
366
  "gpt-6-luna",
318
367
  "gpt-5.6-sol",
@@ -330,6 +379,7 @@ var gating_default = {
330
379
  "deepseek/deepseek-v4-flash-vision-exp",
331
380
  "deepseek/deepseek-v4-flash-fast",
332
381
  "deepseek/deepseek-v4.1-flash",
382
+ "deepseek/deepseek-v4.1-flash-fast",
333
383
  "moonshotai/Kimi-K2.7-Code",
334
384
  "moonshotai/Kimi-K2.7-Code-Highspeed",
335
385
  "moonshotai/Kimi-K2.6",
@@ -375,9 +425,10 @@ var gating_default = {
375
425
  "poolside/laguna-s-2.1-free",
376
426
  "inclusionai/ling-3.0-flash-free",
377
427
  "inclusionai/ling-3.0-flash-sante:free",
428
+ "inclusionai/ling-3.1-flash:free",
378
429
  "stealth/space-bunny-alpha",
379
430
  "stealth/pixel-canary",
380
- "claude-sonnet-5",
431
+ "claude-sonnet-5-5",
381
432
  "MiniMaxAI/MiniMax-M3-Free",
382
433
  "MiniMaxAI/MiniMax-M3",
383
434
  "MiniMaxAI/MiniMax-M2.7",
@@ -422,7 +473,7 @@ var gating_default = {
422
473
  }
423
474
  };
424
475
 
425
- // src/gating.ts
476
+ // src/constants/gating.ts
426
477
  var MODEL_CATEGORIES = gating_default.categories;
427
478
  var PLAN_RULES = gating_default.plans;
428
479
  var HARD_BLOCKED = gating_default.hardBlocked;
@@ -430,6 +481,28 @@ var KNOWN_MODELS = gating_default.knownModels;
430
481
  var MODEL_ALIASES = gating_default.aliases;
431
482
  var GATE_EXTRACTED_AT = gating_default.extractedAt;
432
483
  var GATE_CLI_VERSION = gating_default.cliVersion;
484
+
485
+ // src/constants/sidebar.ts
486
+ var ROW_WIDTH = 37;
487
+ var TIER_DISPLAY = {
488
+ opensource: "open source",
489
+ premium: "premium"
490
+ };
491
+ var OC_PLANS = ["go", "go-plus"];
492
+ var OC_PLAN_DEFAULT = "go";
493
+ var GO_WINDOW_SHARE = {
494
+ fiveHour: 0.2,
495
+ weekly: 0.5,
496
+ month: 1
497
+ };
498
+ var FIVE_HOUR_SECS = 5 * 3600;
499
+ var WEEKLY_SECS = 7 * 86400;
500
+ var PREF_DEFAULTS = {
501
+ colors: false,
502
+ ocPlan: OC_PLAN_DEFAULT
503
+ };
504
+
505
+ // src/gating.ts
433
506
  function findKnown(s) {
434
507
  const k = s.toLowerCase();
435
508
  return KNOWN_MODELS.find((m) => m.toLowerCase() === k);
@@ -446,8 +519,6 @@ function canonicalizeModelId(model) {
446
519
  }
447
520
 
448
521
  // src/sidebar/windows.ts
449
- var FIVE_HOUR_SECS = 5 * 3600;
450
- var WEEKLY_SECS = 7 * 86400;
451
522
  function elapsedPct(resetAtMs, durSecs, nowSecs) {
452
523
  if (typeof resetAtMs !== "number" || !Number.isFinite(resetAtMs))
453
524
  return;
@@ -497,7 +568,6 @@ function pctTone(pct) {
497
568
  return "warn";
498
569
  return "ok";
499
570
  }
500
- var ROW_WIDTH = 37;
501
571
  function separator() {
502
572
  return ["\u2500".repeat(ROW_WIDTH), "", "muted"];
503
573
  }
@@ -512,14 +582,13 @@ function parts(row) {
512
582
  return [` ${row[1]}`, ""];
513
583
  return [row[1] ? `${row[0]}: ` : row[0], row[1]];
514
584
  }
515
- var TIER_DISPLAY = {
516
- opensource: "open source",
517
- premium: "premium"
518
- };
519
585
  function money(value) {
520
586
  const rounded = Math.round(value * 100) / 100;
521
587
  return `$${Number.isInteger(rounded) ? rounded : rounded.toFixed(2)}`;
522
588
  }
589
+ function allowanceLabel(limit, free) {
590
+ return free === true || limit <= 0 ? "\u221E" : `${money(limit)}/mo`;
591
+ }
523
592
  function rate(value) {
524
593
  if (value === 0)
525
594
  return "$0";
@@ -611,7 +680,7 @@ function modelRows(meta, usage, session, fallbackName) {
611
680
  if (usage) {
612
681
  rows.push(["Usage (this model)", `${count(usage.requests)} req`, "base"]);
613
682
  const spend = usage.cost > 0 ? money(usage.cost) : "";
614
- const share = usage.cost > 0 && session && session.cost > 0 ? `${Math.round(usage.cost / session.cost * 100)}% of session` : "";
683
+ const share = usage.cost > 0 && session && session.cost > 0 ? `${Math.min(100, Math.round(usage.cost / session.cost * 100))}% of session` : "";
615
684
  const detail = [spend, share].filter(Boolean).join(" \xB7 ");
616
685
  if (detail)
617
686
  rows.push(["", detail, "muted"]);
@@ -627,7 +696,7 @@ function modelRows(meta, usage, session, fallbackName) {
627
696
  else if (meta.minPlan)
628
697
  rows.push(["Min plan", meta.minPlan, "base"]);
629
698
  if (typeof meta.allowance === "number")
630
- rows.push(["Allowance", `${money(meta.allowance)}/mo`, "base"]);
699
+ rows.push(["Allowance", allowanceLabel(meta.allowance, meta.free), "base"]);
631
700
  if (meta.deal) {
632
701
  const ends = meta.deal.ends?.match(/([A-Z][a-z]{2})[a-z]*\s+(\d{1,2})/);
633
702
  rows.push(["Deal", ends ? `${meta.deal.badge} \xB7 ends ${ends[1]} ${ends[2]}` : meta.deal.badge, "ok"]);
@@ -761,41 +830,71 @@ function Panel(props) {
761
830
 
762
831
  // src/sidebar/prefs.ts
763
832
  import { readFileSync } from "fs";
764
- import { homedir } from "os";
765
- import { join } from "path";
766
- var DEFAULTS = {
767
- colors: false
768
- };
769
- var CACHE_MS = 5000;
833
+ import { homedir as homedir2 } from "os";
834
+ import { join as join2 } from "path";
835
+
836
+ // src/constants/paths.ts
837
+ var CACHE_DIR = "command-code";
838
+ function ccCatalogFile(plan) {
839
+ return `cc-catalog-${plan}.json`;
840
+ }
841
+ var OPENCODE_DIR = "opencode";
842
+ var OPENCODE_DB_FILE = "opencode.db";
843
+ var PREFS_FILE = "command-code.json";
844
+
845
+ // src/constants/timing.ts
846
+ var POLL_MS = 5000;
847
+ var CHILD_TIMEOUT_MS = 30000;
848
+ var MODELS_CACHE_TTL_MS = 5 * 60 * 1000;
849
+ var CATALOG_CACHE_TTL_MS = 60 * 60 * 1000;
850
+ var PREFS_CACHE_MS = 5000;
851
+
852
+ // src/sidebar/prefs.ts
770
853
  var cached;
771
854
  function prefsPath(env = process.env) {
772
- const base = env.XDG_CONFIG_HOME ?? join(homedir(), ".config");
773
- return join(base, "opencode", "command-code.json");
855
+ const base = env.XDG_CONFIG_HOME ?? join2(homedir2(), ".config");
856
+ return join2(base, OPENCODE_DIR, PREFS_FILE);
857
+ }
858
+ function planFrom(value, source) {
859
+ if (value === undefined)
860
+ return;
861
+ if (typeof value === "string" && OC_PLANS.includes(value)) {
862
+ return value;
863
+ }
864
+ console.warn(`[command-code] ignoring unknown OpenCode plan ${JSON.stringify(value)} (${source}); using "${OC_PLAN_DEFAULT}"`);
865
+ return;
774
866
  }
775
867
  function parsePrefs(raw) {
776
- const value = raw?.colors;
868
+ const obj = raw;
777
869
  return {
778
- colors: value === true
870
+ colors: obj?.colors === true,
871
+ ocPlan: planFrom(obj?.ocPlan, "file") ?? OC_PLAN_DEFAULT
779
872
  };
780
873
  }
781
874
  function loadPrefs(env = process.env, now = Date.now()) {
782
- if (cached && now - cached.at < CACHE_MS)
875
+ if (cached && now - cached.at < PREFS_CACHE_MS)
783
876
  return cached.prefs;
877
+ let prefs = PREF_DEFAULTS;
878
+ try {
879
+ prefs = parsePrefs(JSON.parse(readFileSync(prefsPath(env), "utf8")));
880
+ } catch {}
784
881
  const flag = env.CMD_COLORS;
785
- let prefs = DEFAULTS;
786
882
  if (flag === "1" || flag === "true")
787
883
  prefs = {
884
+ ...prefs,
788
885
  colors: true
789
886
  };
790
887
  else if (flag === "0" || flag === "false")
791
888
  prefs = {
889
+ ...prefs,
792
890
  colors: false
793
891
  };
794
- else {
795
- try {
796
- prefs = parsePrefs(JSON.parse(readFileSync(prefsPath(env), "utf8")));
797
- } catch {}
798
- }
892
+ const envPlan = planFrom(env.CMD_OC_PLAN, "CMD_OC_PLAN");
893
+ if (envPlan !== undefined)
894
+ prefs = {
895
+ ...prefs,
896
+ ocPlan: envPlan
897
+ };
799
898
  cached = {
800
899
  at: now,
801
900
  prefs
@@ -925,10 +1024,23 @@ var MODEL_CATALOG = {
925
1024
  modalities: ["text", "image"],
926
1025
  minPlan: "Pro"
927
1026
  },
1027
+ "claude-sonnet-5-5": {
1028
+ name: "Claude Sonnet 5.5",
1029
+ context: 1e6,
1030
+ efforts: ["low", "medium", "high", "xhigh", "max"],
1031
+ cost: {
1032
+ input: 2,
1033
+ output: 10,
1034
+ cacheRead: 0.2,
1035
+ cacheWrite: 2.5
1036
+ },
1037
+ modalities: ["text", "image"],
1038
+ minPlan: "GOAT"
1039
+ },
928
1040
  "deepseek/deepseek-v4-flash": {
929
1041
  name: "DeepSeek V4 Flash (latest)",
930
1042
  context: 1e6,
931
- efforts: ["high", "max"],
1043
+ efforts: ["off", "high", "max"],
932
1044
  cost: {
933
1045
  input: 0.15,
934
1046
  output: 0.6,
@@ -954,7 +1066,7 @@ var MODEL_CATALOG = {
954
1066
  "deepseek/deepseek-v4-flash-vision-exp": {
955
1067
  name: "DeepSeek V4 Flash Vision (exp)",
956
1068
  context: 1e6,
957
- efforts: ["high", "max"],
1069
+ efforts: ["off", "high", "max"],
958
1070
  cost: {
959
1071
  input: 0.15,
960
1072
  output: 0.6,
@@ -967,7 +1079,7 @@ var MODEL_CATALOG = {
967
1079
  "deepseek/deepseek-v4-pro": {
968
1080
  name: "DeepSeek V4 Pro (latest)",
969
1081
  context: 1e6,
970
- efforts: ["high", "max"],
1082
+ efforts: ["off", "high", "max"],
971
1083
  cost: {
972
1084
  input: 0.66,
973
1085
  output: 1.98,
@@ -980,7 +1092,7 @@ var MODEL_CATALOG = {
980
1092
  "deepseek/deepseek-v4.1-flash": {
981
1093
  name: "DeepSeek V4.1 Flash",
982
1094
  context: 1e6,
983
- efforts: ["low", "high", "max"],
1095
+ efforts: ["off", "low", "high", "max"],
984
1096
  cost: {
985
1097
  input: 0.15,
986
1098
  output: 0.6,
@@ -990,6 +1102,19 @@ var MODEL_CATALOG = {
990
1102
  modalities: ["text", "image"],
991
1103
  minPlan: "Go"
992
1104
  },
1105
+ "deepseek/deepseek-v4.1-flash-fast": {
1106
+ name: "DeepSeek V4.1 Flash Fast",
1107
+ context: 1e6,
1108
+ efforts: ["off", "low", "high", "max"],
1109
+ cost: {
1110
+ input: 0.16,
1111
+ output: 0.58,
1112
+ cacheRead: 0.016,
1113
+ cacheWrite: 0
1114
+ },
1115
+ modalities: ["text", "image"],
1116
+ minPlan: "Go"
1117
+ },
993
1118
  "google/gemini-3.1-flash-lite": {
994
1119
  name: "Gemini 3.1 Flash Lite",
995
1120
  context: 1e6,
@@ -1198,6 +1323,19 @@ var MODEL_CATALOG = {
1198
1323
  modalities: ["text", "image"],
1199
1324
  minPlan: "Pro"
1200
1325
  },
1326
+ "gpt-6.1-sol": {
1327
+ name: "GPT-6.1 Sol",
1328
+ context: 1050000,
1329
+ efforts: ["low", "medium", "high", "xhigh", "max"],
1330
+ cost: {
1331
+ input: 2,
1332
+ output: 10,
1333
+ cacheRead: 0.1,
1334
+ cacheWrite: 2.5
1335
+ },
1336
+ modalities: ["text", "image"],
1337
+ minPlan: "Max"
1338
+ },
1201
1339
  "inclusionai/ling-3.0-flash-sante:free": {
1202
1340
  name: "Ling 3.0 Flash Sante",
1203
1341
  context: 262000,
@@ -1211,6 +1349,19 @@ var MODEL_CATALOG = {
1211
1349
  modalities: ["text"],
1212
1350
  minPlan: "Go"
1213
1351
  },
1352
+ "inclusionai/ling-3.1-flash:free": {
1353
+ name: "Ling 3.1 Flash",
1354
+ context: 262000,
1355
+ efforts: ["low", "medium", "high"],
1356
+ cost: {
1357
+ input: 0,
1358
+ output: 0,
1359
+ cacheRead: 0,
1360
+ cacheWrite: 0
1361
+ },
1362
+ modalities: ["text"],
1363
+ minPlan: "Go"
1364
+ },
1214
1365
  "meituan/LongCat-2.0": {
1215
1366
  name: "LongCat 2.0",
1216
1367
  context: 1050000,
@@ -1565,7 +1716,7 @@ var MODEL_CATALOG = {
1565
1716
  "stealth/space-bunny-alpha": {
1566
1717
  name: "Space Bunny Alpha",
1567
1718
  context: 1e6,
1568
- efforts: ["low", "medium", "high"],
1719
+ efforts: ["low", "medium", "high", "max"],
1569
1720
  cost: {
1570
1721
  input: 0,
1571
1722
  output: 0,
@@ -1697,9 +1848,9 @@ var MODEL_CATALOG = {
1697
1848
  context: 500000,
1698
1849
  efforts: ["low", "medium", "high", "xhigh"],
1699
1850
  cost: {
1700
- input: 1.2,
1701
- output: 3.6,
1702
- cacheRead: 0.3,
1851
+ input: 2,
1852
+ output: 6,
1853
+ cacheRead: 0.5,
1703
1854
  cacheWrite: 0
1704
1855
  },
1705
1856
  modalities: ["text", "image"],
@@ -1869,15 +2020,10 @@ function minPlan(id) {
1869
2020
  // src/sidebar/data.ts
1870
2021
  import { spawn as spawn2 } from "child_process";
1871
2022
  import { mkdir, readFile, writeFile } from "fs/promises";
1872
- import { homedir as homedir2 } from "os";
1873
- import { dirname, join as join2 } from "path";
2023
+ import { homedir as homedir3 } from "os";
2024
+ import { dirname, join as join3 } from "path";
1874
2025
 
1875
2026
  // src/sidebar/zen.ts
1876
- var GO_WINDOW_SHARE = {
1877
- fiveHour: 0.2,
1878
- weekly: 0.5,
1879
- month: 1
1880
- };
1881
2027
  function totals(value) {
1882
2028
  const v = value ?? {};
1883
2029
  const num = (key) => typeof v[key] === "number" ? v[key] : 0;
@@ -1937,9 +2083,10 @@ function zenRows(usage, meta, session, fallbackName) {
1937
2083
  const rows = [["Plan", `${oc?.plan ?? "Go"} \xB7 limits per model`, "base"]];
1938
2084
  const mine = meta ? usage.models.get(modelKey(meta.name)) : undefined;
1939
2085
  const limit = oc?.allowance ?? mine?.limit;
1940
- rows.push(...windowRows2("5-hour", mine?.fiveHour ?? usage.totals.fiveHour, limit, GO_WINDOW_SHARE.fiveHour));
1941
- rows.push(...windowRows2("Weekly", mine?.weekly ?? usage.totals.weekly, limit, GO_WINDOW_SHARE.weekly));
1942
- rows.push(...windowRows2("Month", mine?.month ?? usage.totals.month, limit, GO_WINDOW_SHARE.month));
2086
+ const cap = mine ? limit : undefined;
2087
+ rows.push(...windowRows2("5-hour", mine?.fiveHour ?? usage.totals.fiveHour, cap, GO_WINDOW_SHARE.fiveHour));
2088
+ rows.push(...windowRows2("Weekly", mine?.weekly ?? usage.totals.weekly, cap, GO_WINDOW_SHARE.weekly));
2089
+ rows.push(...windowRows2("Month", mine?.month ?? usage.totals.month, cap, GO_WINDOW_SHARE.month));
1943
2090
  rows.push(["Period", `${count(usage.totals.month.requests)} requests \xB7 ${money(usage.totals.month.cost)}`, "base"]);
1944
2091
  rows.push(separator());
1945
2092
  const name = meta?.name ?? fallbackName;
@@ -1953,7 +2100,7 @@ function zenRows(usage, meta, session, fallbackName) {
1953
2100
  if (!meta)
1954
2101
  return rows;
1955
2102
  if (typeof limit === "number") {
1956
- rows.push(["Allowance", `${money(limit)}/mo`, "base"]);
2103
+ rows.push(["Allowance", allowanceLabel(limit, oc?.free), "base"]);
1957
2104
  }
1958
2105
  if (oc?.rates) {
1959
2106
  const cache = [`cache read ${rate(oc.rates.cacheRead)}`];
@@ -1973,14 +2120,8 @@ function zenRows(usage, meta, session, fallbackName) {
1973
2120
 
1974
2121
  // src/sidebar/data.ts
1975
2122
  var CMDUSE = cmduseCandidates();
1976
- var MPC = ["mpc", join2(homedir2(), ".bun/bin/mpc"), "/opt/homebrew/bin/mpc"];
1977
- var OCUSE = [process.env.OCUSE_BIN, "ocuse", "/opt/homebrew/bin/ocuse", "/usr/local/bin/ocuse"].filter((bin) => Boolean(bin));
1978
- var CACHE_TTL_MS = 60 * 60 * 1000;
1979
- var SPAWN_OPTIONS = {
1980
- stdio: ["ignore", "pipe", "pipe"],
1981
- detached: true
1982
- };
1983
- var CHILD_TIMEOUT_MS = 30000;
2123
+ var MPC = MPC_BIN_CANDIDATES;
2124
+ var OCUSE = [process.env.OCUSE_BIN, ...OCUSE_BIN_CANDIDATES].filter((bin) => Boolean(bin));
1984
2125
  function run(bin, args) {
1985
2126
  return new Promise((resolve, reject) => {
1986
2127
  const child = spawn2(bin, args, SPAWN_OPTIONS);
@@ -2065,6 +2206,7 @@ function parseMpcJson(text) {
2065
2206
  key: row.key ?? modelKey(row.name),
2066
2207
  name: row.name,
2067
2208
  allowance: cc?.allowance,
2209
+ free: cc?.free === true ? true : undefined,
2068
2210
  rates: cc?.pricing,
2069
2211
  intelligence: cc?.ability ?? undefined,
2070
2212
  tps: cc?.tps ?? undefined,
@@ -2076,6 +2218,7 @@ function parseMpcJson(text) {
2076
2218
  provider: oc.provider,
2077
2219
  plan: oc.plan,
2078
2220
  allowance: oc.allowance,
2221
+ free: oc.free === true ? true : undefined,
2079
2222
  rates: oc.pricing,
2080
2223
  ability: oc.ability ?? undefined,
2081
2224
  tps: oc.tps ?? undefined
@@ -2086,20 +2229,26 @@ function parseMpcJson(text) {
2086
2229
  }
2087
2230
  return meta;
2088
2231
  }
2089
- function cachePath() {
2090
- const base = process.env.XDG_CACHE_HOME ?? join2(homedir2(), ".cache");
2091
- return join2(base, "command-code", "cc-catalog.json");
2232
+ function cachePath(plan) {
2233
+ const base = process.env.XDG_CACHE_HOME ?? join3(homedir3(), ".cache");
2234
+ return join3(base, CACHE_DIR, ccCatalogFile(plan));
2092
2235
  }
2093
- async function loadMeta() {
2236
+ function metaArgs(plan) {
2237
+ return ["--json", "--shape", "off", "--oc-plan", plan];
2238
+ }
2239
+ function zenArgs(plan) {
2240
+ return ["-1", "--json", "--plan", plan];
2241
+ }
2242
+ async function loadMeta(plan = OC_PLAN_DEFAULT) {
2094
2243
  try {
2095
- const cached = JSON.parse(await readFile(cachePath(), "utf8"));
2096
- if (cached.fetchedAt && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
2244
+ const cached = JSON.parse(await readFile(cachePath(plan), "utf8"));
2245
+ if (cached.fetchedAt && Date.now() - cached.fetchedAt < CATALOG_CACHE_TTL_MS) {
2097
2246
  return new Map(cached.rows ?? []);
2098
2247
  }
2099
2248
  } catch {}
2100
- const meta = parseMpcJson(await runFirst(MPC, ["--json"]));
2249
+ const meta = parseMpcJson(await runFirst(MPC, metaArgs(plan)));
2101
2250
  try {
2102
- const path = cachePath();
2251
+ const path = cachePath(plan);
2103
2252
  await mkdir(dirname(path), {
2104
2253
  recursive: true
2105
2254
  });
@@ -2113,19 +2262,19 @@ async function loadMeta() {
2113
2262
  async function loadUsage() {
2114
2263
  return requireSnapshot(parseUsageJson(await runFirst(CMDUSE, ["-1", "--json", "--plain"])));
2115
2264
  }
2116
- async function loadZen() {
2117
- return parseZenJson(await runFirst(OCUSE, ["-1", "--json"]));
2265
+ async function loadZen(plan = OC_PLAN_DEFAULT) {
2266
+ return parseZenJson(await runFirst(OCUSE, zenArgs(plan)));
2118
2267
  }
2119
2268
 
2120
2269
  // src/sidebar/usageDb.ts
2121
2270
  import { Database } from "bun:sqlite";
2122
- import { homedir as homedir3 } from "os";
2123
- import { join as join3 } from "path";
2271
+ import { homedir as homedir4 } from "os";
2272
+ import { join as join4 } from "path";
2124
2273
  function usageDbPath() {
2125
2274
  if (process.env.OPENCODE_DB)
2126
2275
  return process.env.OPENCODE_DB;
2127
- const base = process.env.XDG_DATA_HOME ?? join3(homedir3(), ".local", "share");
2128
- return join3(base, "opencode", "opencode.db");
2276
+ const base = process.env.XDG_DATA_HOME ?? join4(homedir4(), ".local", "share");
2277
+ return join4(base, OPENCODE_DIR, OPENCODE_DB_FILE);
2129
2278
  }
2130
2279
  function usage(value) {
2131
2280
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
@@ -2251,15 +2400,14 @@ function loadSessionUsage(sessionID, path = usageDbPath()) {
2251
2400
  }
2252
2401
 
2253
2402
  // src/sidebar/useRows.ts
2254
- var POLL_MS = 5000;
2255
2403
  function sessionKind(providerID) {
2256
2404
  if (!providerID)
2257
2405
  return "unknown";
2258
- if (providerID.startsWith("command-code"))
2406
+ if (providerID.startsWith(PROVIDER_ID_PREFIX))
2259
2407
  return "ours";
2260
- if (providerID.startsWith("opencode-go"))
2408
+ if (providerID.startsWith(GO_PROVIDER_ID))
2261
2409
  return "go";
2262
- if (providerID === "opencode" || providerID.startsWith("opencode-zen"))
2410
+ if (providerID === ZEN_PROVIDER_ID || providerID.startsWith(ZEN_PROVIDER_PREFIX))
2263
2411
  return "zen";
2264
2412
  return "other";
2265
2413
  }
@@ -2281,15 +2429,19 @@ function seededRows() {
2281
2429
  return lastSnapshot ? usageRows(lastSnapshot) : [];
2282
2430
  }
2283
2431
  var lastModelUsage;
2284
- function rememberModelUsage(id, usage) {
2432
+ function rememberModelUsage(id, usage, session) {
2285
2433
  lastModelUsage = {
2286
2434
  key: modelKey(id),
2435
+ session,
2287
2436
  usage
2288
2437
  };
2289
2438
  }
2290
- function seededModelUsage(id) {
2439
+ function seededModelUsage(id, session) {
2291
2440
  if (!lastModelUsage)
2292
2441
  return;
2442
+ if (session !== undefined && lastModelUsage.session !== undefined && lastModelUsage.session !== session) {
2443
+ return;
2444
+ }
2293
2445
  if (id === undefined)
2294
2446
  return lastModelUsage.usage;
2295
2447
  return lastModelUsage.key === modelKey(id) ? lastModelUsage.usage : undefined;
@@ -2310,7 +2462,7 @@ function useRows(activeModelId, providerID, sessionID) {
2310
2462
  const [sessionUsage, setSessionUsage] = createSignal();
2311
2463
  const [wasOurs, setWasOurs] = createSignal(false);
2312
2464
  const refreshMeta = () => {
2313
- loadMeta().then((next) => {
2465
+ loadMeta(loadPrefs().ocPlan).then((next) => {
2314
2466
  rememberMeta(next);
2315
2467
  if (next.size > 0)
2316
2468
  setMeta(next);
@@ -2320,9 +2472,12 @@ function useRows(activeModelId, providerID, sessionID) {
2320
2472
  const refreshModelUsage = (id) => {
2321
2473
  if (!id)
2322
2474
  return;
2323
- const fresh = loadModelUsage(id, 0, usageDbPath(), sessionID());
2475
+ const session = sessionID();
2476
+ if (!session)
2477
+ return;
2478
+ const fresh = loadModelUsage(id, 0, usageDbPath(), session);
2324
2479
  if (fresh)
2325
- rememberModelUsage(id, fresh);
2480
+ rememberModelUsage(id, fresh, session);
2326
2481
  setModelUsage(lastModelUsage);
2327
2482
  };
2328
2483
  let inFlight = false;
@@ -2342,7 +2497,7 @@ function useRows(activeModelId, providerID, sessionID) {
2342
2497
  setUsage(usageRows(snapshot));
2343
2498
  refreshModelUsage(activeModelId());
2344
2499
  } else if (kind === "go" || kind === "zen") {
2345
- setZen(await loadZen());
2500
+ setZen(await loadZen(loadPrefs().ocPlan));
2346
2501
  }
2347
2502
  } catch {} finally {
2348
2503
  inFlight = false;
@@ -2365,11 +2520,12 @@ function useRows(activeModelId, providerID, sessionID) {
2365
2520
  refreshModelUsage(id);
2366
2521
  });
2367
2522
  const usageFor = (id) => {
2523
+ const session = sessionID();
2368
2524
  const seen = modelUsage();
2369
- if (seen && (id === undefined || seen.key === modelKey(id))) {
2525
+ if (seen && (id === undefined || seen.key === modelKey(id)) && (seen.session === undefined || session === undefined || seen.session === session)) {
2370
2526
  return seen.usage;
2371
2527
  }
2372
- return seededModelUsage(id);
2528
+ return seededModelUsage(id, session);
2373
2529
  };
2374
2530
  return createMemo(() => {
2375
2531
  const kind = sessionKind(providerID());
@@ -2391,7 +2547,6 @@ function useRows(activeModelId, providerID, sessionID) {
2391
2547
  }
2392
2548
 
2393
2549
  // src/tui.tsx
2394
- var ID = "command-code.tui";
2395
2550
  var themed = (colors) => loadPrefs().colors ? colors : mono(colors);
2396
2551
  function PanelV1(props) {
2397
2552
  const current = () => props.api.state.session.get(props.sessionID)?.model;
@@ -2430,7 +2585,7 @@ function PanelV2(props) {
2430
2585
  });
2431
2586
  }
2432
2587
  var commandCodeTui = {
2433
- id: ID,
2588
+ id: TUI_ID,
2434
2589
  setup(ctx) {
2435
2590
  ctx.ui.slot({
2436
2591
  append: "sidebar.content",