@jeffreyjyz/opencode-command-code 0.3.19 → 0.5.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.
@@ -21,11 +21,11 @@ export type SidebarRow = [
21
21
  export declare function pctTone(pct: number): Tone;
22
22
  /**
23
23
  * The sidebar is 42 columns wide with 2+2 padding, and our panel keeps one more
24
- * column clear on the right, so a rendered row must stay within this. Rows that
25
- * cannot fit are split across an indented continuation (`""` label) rather than
26
- * wrapping in the host's renderer, which is what made the panel look broken.
24
+ * column clear on the right, so a rendered row must stay within ROW_WIDTH.
25
+ * Rows that cannot fit are split across an indented continuation (`""` label)
26
+ * rather than wrapping in the host's renderer, which is what made the panel
27
+ * look broken.
27
28
  */
28
- export declare const ROW_WIDTH = 37;
29
29
  /** A horizontal rule between blocks. */
30
30
  export declare function separator(): SidebarRow;
31
31
  /** Truncate to `width`, ellipsis included. */
@@ -43,6 +43,8 @@ export interface ModelMeta {
43
43
  /** Cheapest plan that serves the model, from the generated catalog. */
44
44
  minPlan?: string | null;
45
45
  allowance?: number;
46
+ /** Unbounded on the CommandCode side: read `free`, not `allowance`, which may still carry a catalog figure. */
47
+ free?: boolean;
46
48
  rates?: {
47
49
  input: number;
48
50
  output: number;
@@ -67,6 +69,8 @@ export interface ModelMeta {
67
69
  provider?: string;
68
70
  plan?: string;
69
71
  allowance?: number;
72
+ /** Unbounded on the OpenCode Go side: its allowance is 0 by convention. */
73
+ free?: boolean;
70
74
  rates?: {
71
75
  input: number;
72
76
  output: number;
@@ -112,6 +116,15 @@ export interface Usage {
112
116
  }
113
117
  /** Money at credit scale: cents, but "$60" not "$60.00". */
114
118
  export declare function money(value: number): string;
119
+ /**
120
+ * A monthly allowance as it appears on the panel. A free/unbounded model has no
121
+ * budget to divide — mpc reports `free: true` — so it reads `∞` rather than the
122
+ * misleading `$0/mo` (0 is not a budget). `free` decides, so this holds whether
123
+ * the allowance is 0 (OpenCode Go's free rows) or a catalog figure
124
+ * (CommandCode's). Both sides call this, so a free CommandCode model and a free
125
+ * OpenCode Go one render alike.
126
+ */
127
+ export declare function allowanceLabel(limit: number, free?: boolean): string;
115
128
  /** Rate scale needs more precision than credit scale ($0.0036). */
116
129
  export declare function rate(value: number): string;
117
130
  export declare function count(value: number): string;
@@ -1,7 +1,3 @@
1
- /** 5-hour window length in seconds. Mirrors cmduse_core::FIVE_HOUR_SECS. */
2
- export declare const FIVE_HOUR_SECS: number;
3
- /** Weekly window length in seconds. Mirrors cmduse_core::WEEKLY_SECS. */
4
- export declare const WEEKLY_SECS: number;
5
1
  /**
6
2
  * Percentage of a rolling window that has elapsed, or undefined when the
7
3
  * window has not started (or has no reset time). `nowSecs` is whole seconds —
@@ -1,10 +1,4 @@
1
1
  import { type ModelMeta, type ModelUsage, type SidebarRow } from "./rows";
2
- /** Go's documented per-model window shares of the monthly allowance. */
3
- export declare const GO_WINDOW_SHARE: {
4
- readonly fiveHour: 0.2;
5
- readonly weekly: 0.5;
6
- readonly month: 1;
7
- };
8
2
  export interface ZenTotals {
9
3
  requests: number;
10
4
  cost: number;
package/dist/tui.d.ts CHANGED
@@ -33,8 +33,8 @@ interface V1Api {
33
33
  export declare const tui: (api: V1Api) => Promise<void>;
34
34
  export declare const commandCodeTui: TuiPluginNs.Definition;
35
35
  declare const _default: {
36
- tui: (api: V1Api) => Promise<void>;
37
36
  id: string;
38
37
  setup: (context: TuiPluginNs.Context) => Promise<TuiPluginNs.Cleanup | void> | TuiPluginNs.Cleanup | void;
38
+ tui: typeof tui;
39
39
  };
40
40
  export default _default;
package/dist/tui.js CHANGED
@@ -4,13 +4,33 @@ 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"]);
29
+ function mpcCandidates(env = process.env) {
30
+ const candidates = [env.MPC_BIN, ...MPC_BIN_CANDIDATES];
31
+ return candidates.filter((bin) => Boolean(bin));
32
+ }
33
+ var MPC_CANDIDATES = mpcCandidates();
14
34
  function splitCliArgs(input) {
15
35
  const out = [];
16
36
  let cur = "";
@@ -52,7 +72,7 @@ function splitCliArgs(input) {
52
72
  function buildCmduseArgs(arg) {
53
73
  const tokens = splitCliArgs(arg);
54
74
  if (!tokens.length)
55
- return DEFAULT_ARGS;
75
+ return [...DEFAULT_ARGS];
56
76
  if (tokens.some((t) => SUBCOMMANDS.has(t)))
57
77
  return tokens;
58
78
  return [...DEFAULT_ARGS, ...tokens];
@@ -63,7 +83,7 @@ function stderrTail(text) {
63
83
  return lines.slice(-3).join(`
64
84
  `).slice(-400);
65
85
  }
66
- function runOnce(bin, args, opts) {
86
+ function runOnce(bin, args, opts, name = "cmduse") {
67
87
  return new Promise((resolve, reject) => {
68
88
  const child = spawn(bin, args, {
69
89
  env: {
@@ -88,13 +108,13 @@ function runOnce(bin, args, opts) {
88
108
  opts.signal?.removeEventListener("abort", onAbort);
89
109
  const stdout = Buffer.concat(out).toString("utf8");
90
110
  if (opts.signal?.aborted) {
91
- reject(new Error("cmduse invocation aborted"));
111
+ reject(new Error(`${name} invocation aborted`));
92
112
  } else if (code === 0) {
93
113
  resolve(stdout);
94
114
  } else {
95
115
  const why = signal ? `killed by ${signal}` : `exit ${code}`;
96
116
  const tail = stderrTail(Buffer.concat(err).toString("utf8"));
97
- reject(new Error(`cmduse ${args.join(" ")}: ${why}${tail ? `
117
+ reject(new Error(`${name} ${args.join(" ")}: ${why}${tail ? `
98
118
  ${tail}` : ""}`));
99
119
  }
100
120
  });
@@ -118,6 +138,13 @@ async function runCmduse(arg, opts = {}) {
118
138
  });
119
139
  }
120
140
 
141
+ // src/constants/providers.ts
142
+ var PROVIDER_ID_PREFIX = "command-code";
143
+ var GO_PROVIDER_ID = "opencode-go";
144
+ var ZEN_PROVIDER_ID = "opencode";
145
+ var ZEN_PROVIDER_PREFIX = "opencode-zen";
146
+ var TUI_ID = "command-code.tui";
147
+
121
148
  // src/sidebar/panel.tsx
122
149
  import { createComponent as _$createComponent } from "@opentui/solid";
123
150
  import { insertNode as _$insertNode } from "@opentui/solid";
@@ -451,7 +478,7 @@ var gating_default = {
451
478
  }
452
479
  };
453
480
 
454
- // src/gating.ts
481
+ // src/constants/gating.ts
455
482
  var MODEL_CATEGORIES = gating_default.categories;
456
483
  var PLAN_RULES = gating_default.plans;
457
484
  var HARD_BLOCKED = gating_default.hardBlocked;
@@ -459,6 +486,28 @@ var KNOWN_MODELS = gating_default.knownModels;
459
486
  var MODEL_ALIASES = gating_default.aliases;
460
487
  var GATE_EXTRACTED_AT = gating_default.extractedAt;
461
488
  var GATE_CLI_VERSION = gating_default.cliVersion;
489
+
490
+ // src/constants/sidebar.ts
491
+ var ROW_WIDTH = 37;
492
+ var TIER_DISPLAY = {
493
+ opensource: "open source",
494
+ premium: "premium"
495
+ };
496
+ var OC_PLANS = ["go", "go-plus"];
497
+ var OC_PLAN_DEFAULT = "go";
498
+ var GO_WINDOW_SHARE = {
499
+ fiveHour: 0.2,
500
+ weekly: 0.5,
501
+ month: 1
502
+ };
503
+ var FIVE_HOUR_SECS = 5 * 3600;
504
+ var WEEKLY_SECS = 7 * 86400;
505
+ var PREF_DEFAULTS = {
506
+ colors: false,
507
+ ocPlan: OC_PLAN_DEFAULT
508
+ };
509
+
510
+ // src/gating.ts
462
511
  function findKnown(s) {
463
512
  const k = s.toLowerCase();
464
513
  return KNOWN_MODELS.find((m) => m.toLowerCase() === k);
@@ -475,8 +524,6 @@ function canonicalizeModelId(model) {
475
524
  }
476
525
 
477
526
  // src/sidebar/windows.ts
478
- var FIVE_HOUR_SECS = 5 * 3600;
479
- var WEEKLY_SECS = 7 * 86400;
480
527
  function elapsedPct(resetAtMs, durSecs, nowSecs) {
481
528
  if (typeof resetAtMs !== "number" || !Number.isFinite(resetAtMs))
482
529
  return;
@@ -526,7 +573,6 @@ function pctTone(pct) {
526
573
  return "warn";
527
574
  return "ok";
528
575
  }
529
- var ROW_WIDTH = 37;
530
576
  function separator() {
531
577
  return ["\u2500".repeat(ROW_WIDTH), "", "muted"];
532
578
  }
@@ -541,14 +587,13 @@ function parts(row) {
541
587
  return [` ${row[1]}`, ""];
542
588
  return [row[1] ? `${row[0]}: ` : row[0], row[1]];
543
589
  }
544
- var TIER_DISPLAY = {
545
- opensource: "open source",
546
- premium: "premium"
547
- };
548
590
  function money(value) {
549
591
  const rounded = Math.round(value * 100) / 100;
550
592
  return `$${Number.isInteger(rounded) ? rounded : rounded.toFixed(2)}`;
551
593
  }
594
+ function allowanceLabel(limit, free) {
595
+ return free === true || limit <= 0 ? "\u221E" : `${money(limit)}/mo`;
596
+ }
552
597
  function rate(value) {
553
598
  if (value === 0)
554
599
  return "$0";
@@ -656,7 +701,7 @@ function modelRows(meta, usage, session, fallbackName) {
656
701
  else if (meta.minPlan)
657
702
  rows.push(["Min plan", meta.minPlan, "base"]);
658
703
  if (typeof meta.allowance === "number")
659
- rows.push(["Allowance", `${money(meta.allowance)}/mo`, "base"]);
704
+ rows.push(["Allowance", allowanceLabel(meta.allowance, meta.free), "base"]);
660
705
  if (meta.deal) {
661
706
  const ends = meta.deal.ends?.match(/([A-Z][a-z]{2})[a-z]*\s+(\d{1,2})/);
662
707
  rows.push(["Deal", ends ? `${meta.deal.badge} \xB7 ends ${ends[1]} ${ends[2]}` : meta.deal.badge, "ok"]);
@@ -790,41 +835,71 @@ function Panel(props) {
790
835
 
791
836
  // src/sidebar/prefs.ts
792
837
  import { readFileSync } from "fs";
793
- import { homedir } from "os";
794
- import { join } from "path";
795
- var DEFAULTS = {
796
- colors: false
797
- };
798
- var CACHE_MS = 5000;
838
+ import { homedir as homedir2 } from "os";
839
+ import { join as join2 } from "path";
840
+
841
+ // src/constants/paths.ts
842
+ var CACHE_DIR = "command-code";
843
+ function ccCatalogFile(plan) {
844
+ return `cc-catalog-${plan}.json`;
845
+ }
846
+ var OPENCODE_DIR = "opencode";
847
+ var OPENCODE_DB_FILE = "opencode.db";
848
+ var PREFS_FILE = "command-code.json";
849
+
850
+ // src/constants/timing.ts
851
+ var POLL_MS = 5000;
852
+ var CHILD_TIMEOUT_MS = 30000;
853
+ var MODELS_CACHE_TTL_MS = 5 * 60 * 1000;
854
+ var CATALOG_CACHE_TTL_MS = 60 * 60 * 1000;
855
+ var PREFS_CACHE_MS = 5000;
856
+
857
+ // src/sidebar/prefs.ts
799
858
  var cached;
800
859
  function prefsPath(env = process.env) {
801
- const base = env.XDG_CONFIG_HOME ?? join(homedir(), ".config");
802
- return join(base, "opencode", "command-code.json");
860
+ const base = env.XDG_CONFIG_HOME ?? join2(homedir2(), ".config");
861
+ return join2(base, OPENCODE_DIR, PREFS_FILE);
862
+ }
863
+ function planFrom(value, source) {
864
+ if (value === undefined)
865
+ return;
866
+ if (typeof value === "string" && OC_PLANS.includes(value)) {
867
+ return value;
868
+ }
869
+ console.warn(`[command-code] ignoring unknown OpenCode plan ${JSON.stringify(value)} (${source}); using "${OC_PLAN_DEFAULT}"`);
870
+ return;
803
871
  }
804
872
  function parsePrefs(raw) {
805
- const value = raw?.colors;
873
+ const obj = raw;
806
874
  return {
807
- colors: value === true
875
+ colors: obj?.colors === true,
876
+ ocPlan: planFrom(obj?.ocPlan, "file") ?? OC_PLAN_DEFAULT
808
877
  };
809
878
  }
810
879
  function loadPrefs(env = process.env, now = Date.now()) {
811
- if (cached && now - cached.at < CACHE_MS)
880
+ if (cached && now - cached.at < PREFS_CACHE_MS)
812
881
  return cached.prefs;
882
+ let prefs = PREF_DEFAULTS;
883
+ try {
884
+ prefs = parsePrefs(JSON.parse(readFileSync(prefsPath(env), "utf8")));
885
+ } catch {}
813
886
  const flag = env.CMD_COLORS;
814
- let prefs = DEFAULTS;
815
887
  if (flag === "1" || flag === "true")
816
888
  prefs = {
889
+ ...prefs,
817
890
  colors: true
818
891
  };
819
892
  else if (flag === "0" || flag === "false")
820
893
  prefs = {
894
+ ...prefs,
821
895
  colors: false
822
896
  };
823
- else {
824
- try {
825
- prefs = parsePrefs(JSON.parse(readFileSync(prefsPath(env), "utf8")));
826
- } catch {}
827
- }
897
+ const envPlan = planFrom(env.CMD_OC_PLAN, "CMD_OC_PLAN");
898
+ if (envPlan !== undefined)
899
+ prefs = {
900
+ ...prefs,
901
+ ocPlan: envPlan
902
+ };
828
903
  cached = {
829
904
  at: now,
830
905
  prefs
@@ -1950,15 +2025,10 @@ function minPlan(id) {
1950
2025
  // src/sidebar/data.ts
1951
2026
  import { spawn as spawn2 } from "child_process";
1952
2027
  import { mkdir, readFile, writeFile } from "fs/promises";
1953
- import { homedir as homedir2 } from "os";
1954
- import { dirname, join as join2 } from "path";
2028
+ import { homedir as homedir3 } from "os";
2029
+ import { dirname, join as join3 } from "path";
1955
2030
 
1956
2031
  // src/sidebar/zen.ts
1957
- var GO_WINDOW_SHARE = {
1958
- fiveHour: 0.2,
1959
- weekly: 0.5,
1960
- month: 1
1961
- };
1962
2032
  function totals(value) {
1963
2033
  const v = value ?? {};
1964
2034
  const num = (key) => typeof v[key] === "number" ? v[key] : 0;
@@ -2035,7 +2105,7 @@ function zenRows(usage, meta, session, fallbackName) {
2035
2105
  if (!meta)
2036
2106
  return rows;
2037
2107
  if (typeof limit === "number") {
2038
- rows.push(["Allowance", `${money(limit)}/mo`, "base"]);
2108
+ rows.push(["Allowance", allowanceLabel(limit, oc?.free), "base"]);
2039
2109
  }
2040
2110
  if (oc?.rates) {
2041
2111
  const cache = [`cache read ${rate(oc.rates.cacheRead)}`];
@@ -2055,14 +2125,8 @@ function zenRows(usage, meta, session, fallbackName) {
2055
2125
 
2056
2126
  // src/sidebar/data.ts
2057
2127
  var CMDUSE = cmduseCandidates();
2058
- var MPC = ["mpc", join2(homedir2(), ".bun/bin/mpc"), "/opt/homebrew/bin/mpc"];
2059
- var OCUSE = [process.env.OCUSE_BIN, "ocuse", "/opt/homebrew/bin/ocuse", "/usr/local/bin/ocuse"].filter((bin) => Boolean(bin));
2060
- var CACHE_TTL_MS = 60 * 60 * 1000;
2061
- var SPAWN_OPTIONS = {
2062
- stdio: ["ignore", "pipe", "pipe"],
2063
- detached: true
2064
- };
2065
- var CHILD_TIMEOUT_MS = 30000;
2128
+ var MPC = MPC_BIN_CANDIDATES;
2129
+ var OCUSE = [process.env.OCUSE_BIN, ...OCUSE_BIN_CANDIDATES].filter((bin) => Boolean(bin));
2066
2130
  function run(bin, args) {
2067
2131
  return new Promise((resolve, reject) => {
2068
2132
  const child = spawn2(bin, args, SPAWN_OPTIONS);
@@ -2147,6 +2211,7 @@ function parseMpcJson(text) {
2147
2211
  key: row.key ?? modelKey(row.name),
2148
2212
  name: row.name,
2149
2213
  allowance: cc?.allowance,
2214
+ free: cc?.free === true ? true : undefined,
2150
2215
  rates: cc?.pricing,
2151
2216
  intelligence: cc?.ability ?? undefined,
2152
2217
  tps: cc?.tps ?? undefined,
@@ -2158,6 +2223,7 @@ function parseMpcJson(text) {
2158
2223
  provider: oc.provider,
2159
2224
  plan: oc.plan,
2160
2225
  allowance: oc.allowance,
2226
+ free: oc.free === true ? true : undefined,
2161
2227
  rates: oc.pricing,
2162
2228
  ability: oc.ability ?? undefined,
2163
2229
  tps: oc.tps ?? undefined
@@ -2168,20 +2234,26 @@ function parseMpcJson(text) {
2168
2234
  }
2169
2235
  return meta;
2170
2236
  }
2171
- function cachePath() {
2172
- const base = process.env.XDG_CACHE_HOME ?? join2(homedir2(), ".cache");
2173
- return join2(base, "command-code", "cc-catalog.json");
2237
+ function cachePath(plan) {
2238
+ const base = process.env.XDG_CACHE_HOME ?? join3(homedir3(), ".cache");
2239
+ return join3(base, CACHE_DIR, ccCatalogFile(plan));
2174
2240
  }
2175
- async function loadMeta() {
2241
+ function metaArgs(plan) {
2242
+ return ["--json", "--shape", "off", "--oc-plan", plan];
2243
+ }
2244
+ function zenArgs(plan) {
2245
+ return ["-1", "--json", "--plan", plan];
2246
+ }
2247
+ async function loadMeta(plan = OC_PLAN_DEFAULT) {
2176
2248
  try {
2177
- const cached = JSON.parse(await readFile(cachePath(), "utf8"));
2178
- if (cached.fetchedAt && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
2249
+ const cached = JSON.parse(await readFile(cachePath(plan), "utf8"));
2250
+ if (cached.fetchedAt && Date.now() - cached.fetchedAt < CATALOG_CACHE_TTL_MS) {
2179
2251
  return new Map(cached.rows ?? []);
2180
2252
  }
2181
2253
  } catch {}
2182
- const meta = parseMpcJson(await runFirst(MPC, ["--json"]));
2254
+ const meta = parseMpcJson(await runFirst(MPC, metaArgs(plan)));
2183
2255
  try {
2184
- const path = cachePath();
2256
+ const path = cachePath(plan);
2185
2257
  await mkdir(dirname(path), {
2186
2258
  recursive: true
2187
2259
  });
@@ -2195,19 +2267,19 @@ async function loadMeta() {
2195
2267
  async function loadUsage() {
2196
2268
  return requireSnapshot(parseUsageJson(await runFirst(CMDUSE, ["-1", "--json", "--plain"])));
2197
2269
  }
2198
- async function loadZen() {
2199
- return parseZenJson(await runFirst(OCUSE, ["-1", "--json"]));
2270
+ async function loadZen(plan = OC_PLAN_DEFAULT) {
2271
+ return parseZenJson(await runFirst(OCUSE, zenArgs(plan)));
2200
2272
  }
2201
2273
 
2202
2274
  // src/sidebar/usageDb.ts
2203
2275
  import { Database } from "bun:sqlite";
2204
- import { homedir as homedir3 } from "os";
2205
- import { join as join3 } from "path";
2276
+ import { homedir as homedir4 } from "os";
2277
+ import { join as join4 } from "path";
2206
2278
  function usageDbPath() {
2207
2279
  if (process.env.OPENCODE_DB)
2208
2280
  return process.env.OPENCODE_DB;
2209
- const base = process.env.XDG_DATA_HOME ?? join3(homedir3(), ".local", "share");
2210
- return join3(base, "opencode", "opencode.db");
2281
+ const base = process.env.XDG_DATA_HOME ?? join4(homedir4(), ".local", "share");
2282
+ return join4(base, OPENCODE_DIR, OPENCODE_DB_FILE);
2211
2283
  }
2212
2284
  function usage(value) {
2213
2285
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
@@ -2333,15 +2405,14 @@ function loadSessionUsage(sessionID, path = usageDbPath()) {
2333
2405
  }
2334
2406
 
2335
2407
  // src/sidebar/useRows.ts
2336
- var POLL_MS = 5000;
2337
2408
  function sessionKind(providerID) {
2338
2409
  if (!providerID)
2339
2410
  return "unknown";
2340
- if (providerID.startsWith("command-code"))
2411
+ if (providerID.startsWith(PROVIDER_ID_PREFIX))
2341
2412
  return "ours";
2342
- if (providerID.startsWith("opencode-go"))
2413
+ if (providerID.startsWith(GO_PROVIDER_ID))
2343
2414
  return "go";
2344
- if (providerID === "opencode" || providerID.startsWith("opencode-zen"))
2415
+ if (providerID === ZEN_PROVIDER_ID || providerID.startsWith(ZEN_PROVIDER_PREFIX))
2345
2416
  return "zen";
2346
2417
  return "other";
2347
2418
  }
@@ -2396,7 +2467,7 @@ function useRows(activeModelId, providerID, sessionID) {
2396
2467
  const [sessionUsage, setSessionUsage] = createSignal();
2397
2468
  const [wasOurs, setWasOurs] = createSignal(false);
2398
2469
  const refreshMeta = () => {
2399
- loadMeta().then((next) => {
2470
+ loadMeta(loadPrefs().ocPlan).then((next) => {
2400
2471
  rememberMeta(next);
2401
2472
  if (next.size > 0)
2402
2473
  setMeta(next);
@@ -2431,7 +2502,7 @@ function useRows(activeModelId, providerID, sessionID) {
2431
2502
  setUsage(usageRows(snapshot));
2432
2503
  refreshModelUsage(activeModelId());
2433
2504
  } else if (kind === "go" || kind === "zen") {
2434
- setZen(await loadZen());
2505
+ setZen(await loadZen(loadPrefs().ocPlan));
2435
2506
  }
2436
2507
  } catch {} finally {
2437
2508
  inFlight = false;
@@ -2481,7 +2552,6 @@ function useRows(activeModelId, providerID, sessionID) {
2481
2552
  }
2482
2553
 
2483
2554
  // src/tui.tsx
2484
- var ID = "command-code.tui";
2485
2555
  var themed = (colors) => loadPrefs().colors ? colors : mono(colors);
2486
2556
  function PanelV1(props) {
2487
2557
  const current = () => props.api.state.session.get(props.sessionID)?.model;
@@ -2520,7 +2590,7 @@ function PanelV2(props) {
2520
2590
  });
2521
2591
  }
2522
2592
  var commandCodeTui = {
2523
- id: ID,
2593
+ id: TUI_ID,
2524
2594
  setup(ctx) {
2525
2595
  ctx.ui.slot({
2526
2596
  append: "sidebar.content",
package/dist/v2.d.ts CHANGED
@@ -1,21 +1,6 @@
1
1
  import type { Plugin as PluginNs } from "@opencode/plugin";
2
+ import { type Lane } from "./constants/providers";
2
3
  import { type CmdModel } from "./models";
3
- export declare const PLUGIN_ID = "command-code";
4
- export declare const PROVIDER_BASE = "https://api.commandcode.ai/provider/v1";
5
- /** Shared integration backing both lanes' credentials (/connect + env). */
6
- export declare const INTEGRATION_ID = "command-code";
7
- export declare const INTEGRATION_NAME = "Command Code";
8
- type Lane = {
9
- id: "command-code-anthropic" | "command-code-openai";
10
- name: string;
11
- /** v2 runtime package (first-party, distinct from the v1 `npm` value). */
12
- pkg: string;
13
- /** Wire field reasoning must round-trip through on the openai-compatible
14
- * lane; v2 spells the old `interleaved: {field}` as `compatibility`. */
15
- reasoningField?: string;
16
- };
17
- export type { Lane };
18
- export declare const TOOL_DESCRIPTION = "Fetch live Command Code plan/usage: plan name, monthly credits, 5-hour & weekly windows, billing-period summary. Pass arg='plans' for the plan comparison table only, or extra cmduse flags (e.g. '--tz +05:30 daily').";
19
4
  /** API/known model → v2 Model.Info. Capabilities, variants and $/1M cost all
20
5
  * come from the generated catalog (the listing API publishes none of them);
21
6
  * only the open lane needs the reasoning round-trip field. */
@@ -51,3 +36,4 @@ export declare function credentialKey(ctx: CredentialContext): Promise<string |
51
36
  * own rewrite list (@opentui/*, solid-js).
52
37
  */
53
38
  export declare const commandCodeV2: PluginNs.Plugin;
39
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeffreyjyz/opencode-command-code",
3
- "version": "0.3.19",
3
+ "version": "0.5.0",
4
4
  "description": "Command Code provider + usage dashboard for opencode: two providers (Anthropic wire for Claude, OpenAI wire for everything else) against api.commandcode.ai, live model list, plan gating, /cmd-usage. Requires the cmduse CLI for usage rendering.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -24,7 +24,7 @@
24
24
  },
25
25
  "devDependencies": {
26
26
  "@types/bun": "latest",
27
- "typescript": "^5",
27
+ "typescript": "^7",
28
28
  "@opencode-ai/plugin": "*",
29
29
  "@opencode/plugin": "^2.0.11",
30
30
  "@ai-sdk/provider": "3.0.8"