@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.
package/dist/index.js CHANGED
@@ -2414,7 +2414,7 @@ function superRefine(fn) {
2414
2414
  // package.json
2415
2415
  var package_default = {
2416
2416
  name: "@jeffreyjyz/opencode-command-code",
2417
- version: "0.3.19",
2417
+ version: "0.5.0",
2418
2418
  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.",
2419
2419
  type: "module",
2420
2420
  main: "dist/index.js",
@@ -2438,7 +2438,7 @@ var package_default = {
2438
2438
  },
2439
2439
  devDependencies: {
2440
2440
  "@types/bun": "latest",
2441
- typescript: "^5",
2441
+ typescript: "^7",
2442
2442
  "@opencode-ai/plugin": "*",
2443
2443
  "@opencode/plugin": "^2.0.11",
2444
2444
  "@ai-sdk/provider": "3.0.8"
@@ -2461,8 +2461,12 @@ var package_default = {
2461
2461
  }
2462
2462
  };
2463
2463
 
2464
- // src/api.ts
2464
+ // src/constants/endpoints.ts
2465
2465
  var API_BASE = "https://api.commandcode.ai";
2466
+ var PROVIDER_BASE = `${API_BASE}/provider/v1`;
2467
+ var DEFAULT_BASE_URL = API_BASE;
2468
+
2469
+ // src/api.ts
2466
2470
  function authHeaders(key) {
2467
2471
  return { Authorization: `Bearer ${key}`, Accept: "application/json" };
2468
2472
  }
@@ -2935,7 +2939,12 @@ var MODEL_CATALOG = {
2935
2939
  name: "Qwen 3.7 Flash",
2936
2940
  context: 1e6,
2937
2941
  efforts: null,
2938
- cost: { input: 0.03, output: 0.13, cacheRead: 0.006, cacheWrite: 0.038 },
2942
+ cost: {
2943
+ input: 0.03,
2944
+ output: 0.13,
2945
+ cacheRead: 0.006,
2946
+ cacheWrite: 0.038
2947
+ },
2939
2948
  modalities: ["text", "image"],
2940
2949
  minPlan: "Go"
2941
2950
  },
@@ -3207,17 +3216,24 @@ function reasoningVariants(id) {
3207
3216
 
3208
3217
  // src/cli.ts
3209
3218
  import { spawn } from "child_process";
3210
- function cmduseCandidates(env = process.env) {
3211
- const candidates = [
3212
- env.CMDUSE_BIN,
3213
- "cmduse",
3214
- "/opt/homebrew/bin/cmduse",
3215
- "/usr/local/bin/cmduse"
3216
- ];
3217
- return candidates.filter((bin) => Boolean(bin));
3218
- }
3219
- var CANDIDATES = cmduseCandidates();
3219
+
3220
+ // src/constants/binaries.ts
3221
+ import { homedir } from "os";
3222
+ import { join } from "path";
3223
+ var CMDUSE_BIN_CANDIDATES = [
3224
+ "cmduse",
3225
+ "/opt/homebrew/bin/cmduse",
3226
+ "/usr/local/bin/cmduse"
3227
+ ];
3228
+ var MPC_BIN_CANDIDATES = [
3229
+ "mpc",
3230
+ join(homedir(), ".bun/bin/mpc"),
3231
+ "/opt/homebrew/bin/mpc"
3232
+ ];
3233
+
3234
+ // src/constants/cli.ts
3220
3235
  var DEFAULT_ARGS = ["-1", "--plain"];
3236
+ var MPC_DEFAULT_ARGS = ["--minimal"];
3221
3237
  var SUBCOMMANDS = new Set([
3222
3238
  "plans",
3223
3239
  "models",
@@ -3228,6 +3244,18 @@ var SUBCOMMANDS = new Set([
3228
3244
  "statusline",
3229
3245
  "config"
3230
3246
  ]);
3247
+
3248
+ // src/cli.ts
3249
+ function cmduseCandidates(env = process.env) {
3250
+ const candidates = [env.CMDUSE_BIN, ...CMDUSE_BIN_CANDIDATES];
3251
+ return candidates.filter((bin) => Boolean(bin));
3252
+ }
3253
+ var CANDIDATES = cmduseCandidates();
3254
+ function mpcCandidates(env = process.env) {
3255
+ const candidates = [env.MPC_BIN, ...MPC_BIN_CANDIDATES];
3256
+ return candidates.filter((bin) => Boolean(bin));
3257
+ }
3258
+ var MPC_CANDIDATES = mpcCandidates();
3231
3259
  function splitCliArgs(input) {
3232
3260
  const out = [];
3233
3261
  let cur = "";
@@ -3269,18 +3297,24 @@ function splitCliArgs(input) {
3269
3297
  function buildCmduseArgs(arg) {
3270
3298
  const tokens = splitCliArgs(arg);
3271
3299
  if (!tokens.length)
3272
- return DEFAULT_ARGS;
3300
+ return [...DEFAULT_ARGS];
3273
3301
  if (tokens.some((t) => SUBCOMMANDS.has(t)))
3274
3302
  return tokens;
3275
3303
  return [...DEFAULT_ARGS, ...tokens];
3276
3304
  }
3305
+ function buildMpcArgs(arg) {
3306
+ const tokens = splitCliArgs(arg);
3307
+ if (!tokens.length)
3308
+ return [...MPC_DEFAULT_ARGS];
3309
+ return tokens;
3310
+ }
3277
3311
  function stderrTail(text) {
3278
3312
  const lines = text.trimEnd().split(`
3279
3313
  `);
3280
3314
  return lines.slice(-3).join(`
3281
3315
  `).slice(-400);
3282
3316
  }
3283
- function runOnce(bin, args, opts) {
3317
+ function runOnce(bin, args, opts, name = "cmduse") {
3284
3318
  return new Promise((resolve, reject) => {
3285
3319
  const child = spawn(bin, args, {
3286
3320
  env: { ...process.env, ...opts.env ?? {} },
@@ -3300,13 +3334,13 @@ function runOnce(bin, args, opts) {
3300
3334
  opts.signal?.removeEventListener("abort", onAbort);
3301
3335
  const stdout = Buffer.concat(out).toString("utf8");
3302
3336
  if (opts.signal?.aborted) {
3303
- reject(new Error("cmduse invocation aborted"));
3337
+ reject(new Error(`${name} invocation aborted`));
3304
3338
  } else if (code === 0) {
3305
3339
  resolve(stdout);
3306
3340
  } else {
3307
3341
  const why = signal ? `killed by ${signal}` : `exit ${code}`;
3308
3342
  const tail = stderrTail(Buffer.concat(err).toString("utf8"));
3309
- reject(new Error(`cmduse ${args.join(" ")}: ${why}${tail ? `
3343
+ reject(new Error(`${name} ${args.join(" ")}: ${why}${tail ? `
3310
3344
  ${tail}` : ""}`));
3311
3345
  }
3312
3346
  });
@@ -3327,10 +3361,66 @@ async function runCmduse(arg, opts = {}) {
3327
3361
  }
3328
3362
  throw new Error(`cmduse binary not found (install: brew install JeffreyJYZ/tap/cmduse)${last instanceof Error && last.message !== last.name ? ` \u2014 ${last.message}` : ""}`, { cause: last });
3329
3363
  }
3364
+ async function runMpc(arg, opts = {}) {
3365
+ const args = buildMpcArgs(arg);
3366
+ const candidates = opts.candidates ?? MPC_CANDIDATES;
3367
+ let last;
3368
+ for (const bin of candidates) {
3369
+ try {
3370
+ return await runOnce(bin, args, opts, "mpc");
3371
+ } catch (e) {
3372
+ last = e;
3373
+ if (e?.code !== "ENOENT")
3374
+ throw e;
3375
+ }
3376
+ }
3377
+ throw new Error(`mpc binary not found (install: bun add -g @jeffreyjyz/mpc)${last instanceof Error && last.message !== last.name ? ` \u2014 ${last.message}` : ""}`, { cause: last });
3378
+ }
3379
+
3380
+ // src/constants/models.ts
3381
+ var MODEL_CAPABILITIES = {
3382
+ temperature: true,
3383
+ reasoning: true,
3384
+ attachment: false,
3385
+ toolcall: true,
3386
+ input: { text: true, audio: false, image: false, video: false, pdf: false },
3387
+ output: {
3388
+ text: true,
3389
+ audio: false,
3390
+ image: false,
3391
+ video: false,
3392
+ pdf: false
3393
+ }
3394
+ };
3395
+ var DEFAULT_CONTEXT_LENGTH = 128000;
3396
+ var DEFAULT_OUTPUT_TOKENS = 32000;
3397
+ var DEFAULT_MAX_TOKENS = 64000;
3398
+
3399
+ // src/constants/providers.ts
3400
+ var PROVIDER_ID_PREFIX = "command-code";
3401
+ var PLUGIN_ID = PROVIDER_ID_PREFIX;
3402
+ var INTEGRATION_ID = PROVIDER_ID_PREFIX;
3403
+ var INTEGRATION_NAME = "Command Code";
3404
+ var 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').";
3405
+ var MPC_TOOL_DESCRIPTION = "Per-model price comparison: what a model costs per request ($/1M input, output and cache rates) and per month (request allowance) on each Command Code (cc) and OpenCode Go (oc) plan side, plus ability, Tok/s, the cheaper-side verdict and running deals. Pass '--model <regex>' to filter rows, '--minimal' | '--medium' | '--detail' for table width, '--json' for the full structured rows, '--cc-plan' / '--oc-plan' to pick a plan, or '--usage' to project real usage.";
3406
+ var MPC_TOOL_ARG_DESCRIPTION = "Optional mpc flags: '--model <regex>' filters rows, '--minimal' | '--medium' | '--detail' set table width, '--json' for full structured rows, '--cc-plan'/'--oc-plan' pick a plan, '--usage' projects real usage";
3407
+ var LANES = [
3408
+ {
3409
+ id: "command-code-anthropic",
3410
+ name: "Command Code (Anthropic)",
3411
+ pkg: "@opencode/ai/providers/anthropic"
3412
+ },
3413
+ {
3414
+ id: "command-code-openai",
3415
+ name: "Command Code (OpenAI)",
3416
+ pkg: "@opencode/ai/providers/openai-compatible",
3417
+ reasoningField: "reasoning_content"
3418
+ }
3419
+ ];
3330
3420
 
3331
3421
  // src/key.ts
3332
3422
  import { readFile } from "fs/promises";
3333
- import { homedir } from "os";
3423
+ import { homedir as homedir2 } from "os";
3334
3424
  async function resolveKey(getAuth) {
3335
3425
  const env = process.env.CMD_API_KEY;
3336
3426
  if (env)
@@ -3341,7 +3431,7 @@ async function resolveKey(getAuth) {
3341
3431
  return auth.key;
3342
3432
  } catch {}
3343
3433
  try {
3344
- const text = await readFile(`${homedir()}/.commandcode/auth.json`, "utf8");
3434
+ const text = await readFile(`${homedir2()}/.commandcode/auth.json`, "utf8");
3345
3435
  const v = JSON.parse(text);
3346
3436
  if (typeof v.apiKey === "string" && v.apiKey)
3347
3437
  return v.apiKey;
@@ -3670,7 +3760,7 @@ var gating_default = {
3670
3760
  }
3671
3761
  };
3672
3762
 
3673
- // src/gating.ts
3763
+ // src/constants/gating.ts
3674
3764
  var MODEL_CATEGORIES = gating_default.categories;
3675
3765
  var PLAN_RULES = gating_default.plans;
3676
3766
  var HARD_BLOCKED = gating_default.hardBlocked;
@@ -3679,6 +3769,8 @@ var MODEL_ALIASES = gating_default.aliases;
3679
3769
  var GATE_EXTRACTED_AT = gating_default.extractedAt;
3680
3770
  var GATE_CLI_VERSION = gating_default.cliVersion;
3681
3771
  var GATE_STALE_DAYS = 30;
3772
+
3773
+ // src/gating.ts
3682
3774
  var staleWarned = false;
3683
3775
  function warnIfGatingStale() {
3684
3776
  if (staleWarned || !GATE_EXTRACTED_AT)
@@ -3745,8 +3837,11 @@ function siblingCategory(model) {
3745
3837
  return best ? MODEL_CATEGORIES[best] : undefined;
3746
3838
  }
3747
3839
 
3840
+ // src/constants/timing.ts
3841
+ var MODELS_CACHE_TTL_MS = 5 * 60 * 1000;
3842
+ var CATALOG_CACHE_TTL_MS = 60 * 60 * 1000;
3843
+
3748
3844
  // src/models.ts
3749
- var CACHE_TTL_MS = 5 * 60 * 1000;
3750
3845
  var cache = null;
3751
3846
  function isClaude(id) {
3752
3847
  const bare = id.includes("/") ? id.slice(id.lastIndexOf("/") + 1) : id;
@@ -3762,8 +3857,8 @@ function splitModels(models) {
3762
3857
  async function loadModels(key) {
3763
3858
  warnIfGatingStale();
3764
3859
  let models;
3765
- const fresh = cache && cache.key === key && Date.now() - cache.at < CACHE_TTL_MS;
3766
- if (fresh) {
3860
+ const fresh = cache && cache.key === key && Date.now() - cache.at < MODELS_CACHE_TTL_MS;
3861
+ if (fresh && cache) {
3767
3862
  models = cache.models;
3768
3863
  } else {
3769
3864
  try {
@@ -3801,11 +3896,18 @@ async function loadModels(key) {
3801
3896
 
3802
3897
  // src/modelsCache.ts
3803
3898
  import { mkdir, readFile as readFile2, writeFile } from "fs/promises";
3804
- import { homedir as homedir2 } from "os";
3805
- import { join } from "path";
3899
+ import { homedir as homedir3 } from "os";
3900
+ import { join as join2 } from "path";
3901
+
3902
+ // src/constants/paths.ts
3903
+ var CACHE_DIR = "command-code";
3904
+ var MODELS_CACHE_FILE = "models.json";
3905
+ var STARTUP_LOG_FILE = "startup.log";
3906
+
3907
+ // src/modelsCache.ts
3806
3908
  function cachePath() {
3807
- const base = process.env.XDG_CACHE_HOME ?? join(homedir2(), ".cache");
3808
- return join(base, "command-code", "models.json");
3909
+ const base = process.env.XDG_CACHE_HOME ?? join2(homedir3(), ".cache");
3910
+ return join2(base, CACHE_DIR, MODELS_CACHE_FILE);
3809
3911
  }
3810
3912
  async function readModelsCache() {
3811
3913
  try {
@@ -3820,7 +3922,7 @@ async function readModelsCache() {
3820
3922
  async function writeModelsCache(cache) {
3821
3923
  try {
3822
3924
  const path = cachePath();
3823
- await mkdir(join(path, ".."), { recursive: true });
3925
+ await mkdir(join2(path, ".."), { recursive: true });
3824
3926
  await writeFile(path, JSON.stringify(cache));
3825
3927
  } catch {}
3826
3928
  }
@@ -3914,7 +4016,9 @@ function anthropicReducer() {
3914
4016
  const open = (index, kind) => {
3915
4017
  const id = `${kind === "text" ? "text" : "reasoning"}-${index}`;
3916
4018
  blocks.set(index, { type: kind, id });
3917
- return [{ type: kind === "text" ? "text-start" : "reasoning-start", id }];
4019
+ return [
4020
+ { type: kind === "text" ? "text-start" : "reasoning-start", id }
4021
+ ];
3918
4022
  };
3919
4023
  return {
3920
4024
  feed(event) {
@@ -3936,7 +4040,13 @@ function anthropicReducer() {
3936
4040
  if (blockType === "tool_use") {
3937
4041
  const id = text(block.id) || `tool-${index}`;
3938
4042
  blocks.set(index, { type: "tool_use", id });
3939
- return [{ type: "tool-input-start", id, toolName: text(block.name) }];
4043
+ return [
4044
+ {
4045
+ type: "tool-input-start",
4046
+ id,
4047
+ toolName: text(block.name)
4048
+ }
4049
+ ];
3940
4050
  }
3941
4051
  blocks.set(index, { type: "other", id: `block-${index}` });
3942
4052
  return [];
@@ -3949,17 +4059,29 @@ function anthropicReducer() {
3949
4059
  if (textDelta) {
3950
4060
  const parts = block?.type === "text" ? [] : open(index, "text");
3951
4061
  const id = blocks.get(index)?.id ?? `text-${index}`;
3952
- return [...parts, { type: "text-delta", id, delta: textDelta }];
4062
+ return [
4063
+ ...parts,
4064
+ { type: "text-delta", id, delta: textDelta }
4065
+ ];
3953
4066
  }
3954
4067
  const thinking = text(delta.thinking);
3955
4068
  if (thinking) {
3956
4069
  const parts = block?.type === "thinking" ? [] : open(index, "thinking");
3957
4070
  const id = blocks.get(index)?.id ?? `reasoning-${index}`;
3958
- return [...parts, { type: "reasoning-delta", id, delta: thinking }];
4071
+ return [
4072
+ ...parts,
4073
+ { type: "reasoning-delta", id, delta: thinking }
4074
+ ];
3959
4075
  }
3960
4076
  const partial = text(delta.partial_json);
3961
4077
  if (partial && block?.type === "tool_use") {
3962
- return [{ type: "tool-input-delta", id: block.id, delta: partial }];
4078
+ return [
4079
+ {
4080
+ type: "tool-input-delta",
4081
+ id: block.id,
4082
+ delta: partial
4083
+ }
4084
+ ];
3963
4085
  }
3964
4086
  return [];
3965
4087
  }
@@ -4176,7 +4298,11 @@ function openaiReducer() {
4176
4298
  return parts;
4177
4299
  },
4178
4300
  close() {
4179
- const parts = [...closeReasoning(), ...closeText(), ...flushTools()];
4301
+ const parts = [
4302
+ ...closeReasoning(),
4303
+ ...closeText(),
4304
+ ...flushTools()
4305
+ ];
4180
4306
  if (pending && !finished) {
4181
4307
  finished = true;
4182
4308
  parts.push({
@@ -4191,7 +4317,6 @@ function openaiReducer() {
4191
4317
  }
4192
4318
 
4193
4319
  // src/provider/wire.ts
4194
- var DEFAULT_MAX_TOKENS = 64000;
4195
4320
  function capTokens(value) {
4196
4321
  const n = typeof value === "number" && Number.isFinite(value) ? value : DEFAULT_MAX_TOKENS;
4197
4322
  return Math.min(n, DEFAULT_MAX_TOKENS);
@@ -4345,7 +4470,11 @@ function anthropicBody(model, prompt, options) {
4345
4470
  };
4346
4471
  if (system)
4347
4472
  body.system = [
4348
- { type: "text", text: system, cache_control: { type: "ephemeral" } }
4473
+ {
4474
+ type: "text",
4475
+ text: system,
4476
+ cache_control: { type: "ephemeral" }
4477
+ }
4349
4478
  ];
4350
4479
  if (options.tools?.length) {
4351
4480
  body.tools = options.tools.map((t) => ({
@@ -4443,7 +4572,6 @@ function requestBody(lane, model, prompt, options) {
4443
4572
  }
4444
4573
 
4445
4574
  // src/provider/index.ts
4446
- var DEFAULT_BASE_URL = "https://api.commandcode.ai";
4447
4575
  function laneOf(modelId) {
4448
4576
  const bare = modelId.includes("/") ? modelId.slice(modelId.lastIndexOf("/") + 1) : modelId;
4449
4577
  return bare.toLowerCase().startsWith("claude") ? "anthropic" : "openai";
@@ -4507,10 +4635,11 @@ function createCommandCode(options = {}, images = () => false) {
4507
4635
  const detail = await response.text().catch(() => "");
4508
4636
  throw new Error(`command-code ${lane} ${response.status}: ${detail.slice(0, 300)}`);
4509
4637
  }
4638
+ const responseBody = response.body;
4510
4639
  const reducer = lane === "anthropic" ? anthropicReducer() : openaiReducer();
4511
4640
  const stream = new ReadableStream({
4512
4641
  async start(controller) {
4513
- const reader = response.body.getReader();
4642
+ const reader = responseBody.getReader();
4514
4643
  const decoder = new TextDecoder;
4515
4644
  const emit = (parts) => {
4516
4645
  for (const part of parts)
@@ -4546,7 +4675,12 @@ function createCommandCode(options = {}, images = () => false) {
4546
4675
  raw: "unknown"
4547
4676
  };
4548
4677
  let usage = {
4549
- inputTokens: { total: 0, noCache: 0, cacheRead: 0, cacheWrite: 0 },
4678
+ inputTokens: {
4679
+ total: 0,
4680
+ noCache: 0,
4681
+ cacheRead: 0,
4682
+ cacheWrite: 0
4683
+ },
4550
4684
  outputTokens: { total: 0, text: 0, reasoning: 0 }
4551
4685
  };
4552
4686
  const textOf = {};
@@ -4559,7 +4693,10 @@ function createCommandCode(options = {}, images = () => false) {
4559
4693
  if (part.type === "text-delta")
4560
4694
  textOf[String(part.id)] = (textOf[String(part.id)] ?? "") + String(part.delta);
4561
4695
  else if (part.type === "reasoning-delta") {
4562
- content.push({ type: "reasoning", text: String(part.delta) });
4696
+ content.push({
4697
+ type: "reasoning",
4698
+ text: String(part.delta)
4699
+ });
4563
4700
  } else if (part.type === "tool-input-start") {
4564
4701
  toolsById.set(String(part.id), {
4565
4702
  name: String(part.toolName),
@@ -4597,43 +4734,25 @@ function createCommandCode(options = {}, images = () => false) {
4597
4734
 
4598
4735
  // src/startupLog.ts
4599
4736
  import { appendFile, mkdir as mkdir2 } from "fs/promises";
4600
- import { homedir as homedir3 } from "os";
4601
- import { join as join2 } from "path";
4737
+ import { homedir as homedir4 } from "os";
4738
+ import { join as join3 } from "path";
4602
4739
  function setupTimingLine(t) {
4603
4740
  return `setup: key=${t.key}ms register=${t.register}ms connection=${t.connection}ms refresh=${t.refresh}ms models=${t.models}`;
4604
4741
  }
4605
4742
  function startupLogPath() {
4606
- const base = process.env.XDG_CACHE_HOME ?? join2(homedir3(), ".cache");
4607
- return join2(base, "command-code", "startup.log");
4743
+ const base = process.env.XDG_CACHE_HOME ?? join3(homedir4(), ".cache");
4744
+ return join3(base, CACHE_DIR, STARTUP_LOG_FILE);
4608
4745
  }
4609
4746
  async function writeStartupLine(line) {
4610
4747
  try {
4611
4748
  const path = startupLogPath();
4612
- await mkdir2(join2(path, ".."), { recursive: true });
4749
+ await mkdir2(join3(path, ".."), { recursive: true });
4613
4750
  await appendFile(path, `[${new Date().toISOString()}] ${line}
4614
4751
  `);
4615
4752
  } catch {}
4616
4753
  }
4617
4754
 
4618
4755
  // src/v2.ts
4619
- var PLUGIN_ID = "command-code";
4620
- var PROVIDER_BASE = "https://api.commandcode.ai/provider/v1";
4621
- var INTEGRATION_ID = "command-code";
4622
- var INTEGRATION_NAME = "Command Code";
4623
- var LANES = [
4624
- {
4625
- id: "command-code-anthropic",
4626
- name: "Command Code (Anthropic)",
4627
- pkg: "@opencode/ai/providers/anthropic"
4628
- },
4629
- {
4630
- id: "command-code-openai",
4631
- name: "Command Code (OpenAI)",
4632
- pkg: "@opencode/ai/providers/openai-compatible",
4633
- reasoningField: "reasoning_content"
4634
- }
4635
- ];
4636
- var 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').";
4637
4756
  function costEntry(id) {
4638
4757
  const cost = modelCost(id);
4639
4758
  return cost ? [
@@ -4662,7 +4781,10 @@ function toV2Model(m, lane) {
4662
4781
  cost: costEntry(m.id),
4663
4782
  status: "active",
4664
4783
  enabled: true,
4665
- limit: { context: m.contextLength || 128000, output: 32000 },
4784
+ limit: {
4785
+ context: m.contextLength || DEFAULT_CONTEXT_LENGTH,
4786
+ output: DEFAULT_OUTPUT_TOKENS
4787
+ },
4666
4788
  ...lane.reasoningField ? { compatibility: { reasoningField: lane.reasoningField } } : {}
4667
4789
  };
4668
4790
  return info;
@@ -4759,7 +4881,10 @@ var commandCodeV2 = {
4759
4881
  if (provider.package === "")
4760
4882
  provider.package = lane.pkg;
4761
4883
  provider.activation = localKey ? "enabled" : "auto";
4762
- provider.settings = { ...provider.settings, baseURL: PROVIDER_BASE };
4884
+ provider.settings = {
4885
+ ...provider.settings,
4886
+ baseURL: PROVIDER_BASE
4887
+ };
4763
4888
  if (localKey && provider.settings.apiKey === undefined) {
4764
4889
  provider.settings.apiKey = localKey;
4765
4890
  }
@@ -4793,6 +4918,29 @@ var commandCodeV2 = {
4793
4918
  };
4794
4919
  }
4795
4920
  });
4921
+ editor.add({
4922
+ name: "mpc_prices",
4923
+ description: MPC_TOOL_DESCRIPTION,
4924
+ input: {
4925
+ type: "object",
4926
+ properties: {
4927
+ arg: {
4928
+ type: "string",
4929
+ description: MPC_TOOL_ARG_DESCRIPTION
4930
+ }
4931
+ },
4932
+ additionalProperties: false
4933
+ },
4934
+ async execute(input) {
4935
+ const arg = typeof input?.arg === "string" ? input.arg : "";
4936
+ const key = await credentialKey(ctx);
4937
+ return {
4938
+ content: await runMpc(arg, {
4939
+ env: key ? { CMD_API_KEY: key } : undefined
4940
+ })
4941
+ };
4942
+ }
4943
+ });
4796
4944
  });
4797
4945
  let hasConnection = false;
4798
4946
  let connectionMs = 0;
@@ -4880,14 +5028,6 @@ var PROVIDER_NPM = `${package_default.name}@${package_default.version}`;
4880
5028
  function tool(input) {
4881
5029
  return input;
4882
5030
  }
4883
- var MODEL_CAPABILITIES = {
4884
- temperature: true,
4885
- reasoning: true,
4886
- attachment: false,
4887
- toolcall: true,
4888
- input: { text: true, audio: false, image: false, video: false, pdf: false },
4889
- output: { text: true, audio: false, image: false, video: false, pdf: false }
4890
- };
4891
5031
  function costFor(id) {
4892
5032
  const cost = modelCost(id);
4893
5033
  return {
@@ -4909,11 +5049,17 @@ function toModelDefs(models, providerID, npm, interleaved = false) {
4909
5049
  interleaved,
4910
5050
  ...supportsImage(m.id) ? {
4911
5051
  attachment: true,
4912
- input: { ...MODEL_CAPABILITIES.input, image: true }
5052
+ input: {
5053
+ ...MODEL_CAPABILITIES.input,
5054
+ image: true
5055
+ }
4913
5056
  } : {}
4914
5057
  },
4915
5058
  cost: costFor(m.id),
4916
- limit: { context: m.contextLength || 128000, output: 32000 },
5059
+ limit: {
5060
+ context: m.contextLength || DEFAULT_CONTEXT_LENGTH,
5061
+ output: DEFAULT_OUTPUT_TOKENS
5062
+ },
4917
5063
  status: "active",
4918
5064
  options: {},
4919
5065
  headers: {},
@@ -5026,7 +5172,21 @@ var CommandCodePlugin = async (_input) => {
5026
5172
  },
5027
5173
  async execute(args) {
5028
5174
  const key = await resolveKey();
5029
- return runCmduse(args.arg ?? "", { env: { CMD_API_KEY: key } });
5175
+ return runCmduse(args.arg ?? "", {
5176
+ env: { CMD_API_KEY: key }
5177
+ });
5178
+ }
5179
+ }),
5180
+ mpc_prices: tool({
5181
+ description: MPC_TOOL_DESCRIPTION,
5182
+ args: {
5183
+ arg: string2().optional().describe(MPC_TOOL_ARG_DESCRIPTION)
5184
+ },
5185
+ async execute(args) {
5186
+ const key = await resolveKey();
5187
+ return runMpc(args.arg ?? "", {
5188
+ env: { CMD_API_KEY: key }
5189
+ });
5030
5190
  }
5031
5191
  })
5032
5192
  }
@@ -1,6 +1,5 @@
1
1
  import type { LanguageModelV3 } from "@ai-sdk/provider";
2
2
  import { type WireLane } from "./wire";
3
- export declare const DEFAULT_BASE_URL = "https://api.commandcode.ai";
4
3
  export interface CommandCodeProviderOptions {
5
4
  /** Bearer key; the v2 host passes the resolved connection credential here. */
6
5
  apiKey?: string;
@@ -1,12 +1,6 @@
1
- import { spawn } from "node:child_process";
1
+ import { type OcPlan } from "../constants/sidebar";
2
2
  import { type ModelMeta, type Usage } from "./rows";
3
3
  import { type ZenUsage } from "./zen";
4
- /** `detached` is load-bearing, not tidiness: it starts the child in its own
5
- * session, so it has no controlling terminal. cmduse's snapshot() paints a
6
- * "fetching usage…" spinner straight to /dev/tty — piping stdout/stderr does
7
- * not stop it — which would corrupt the opencode TUI this process inherits its
8
- * tty from. Detaching makes that open fail; stdout/stderr stay piped. */
9
- export declare const SPAWN_OPTIONS: Parameters<typeof spawn>[2];
10
4
  /** Parse `cmduse -1 --json` into the usage snapshot. */
11
5
  export declare function parseUsageJson(text: string): Usage;
12
6
  /**
@@ -23,8 +17,17 @@ export declare function requireSnapshot(usage: Usage): Usage;
23
17
  * kind of session. Rows that carry only one side are kept.
24
18
  */
25
19
  export declare function parseMpcJson(text: string): Map<string, ModelMeta>;
26
- /** mpc's catalog, cached on disk: it scrapes live docs over the network. */
27
- export declare function loadMeta(): Promise<Map<string, ModelMeta>>;
20
+ /**
21
+ * mpc's args for the per-model catalog. `--shape off` is the recursion break
22
+ * (mpc's default `--shape auto` spawns reqshape, which spawns mpc back), never
23
+ * dropped; `--oc-plan` selects which Go plan's per-model allowance is baked in.
24
+ */
25
+ export declare function metaArgs(plan: OcPlan): string[];
26
+ /** ocuse's args: `--plan` selects the Go plan's per-model limits. */
27
+ export declare function zenArgs(plan: OcPlan): string[];
28
+ /** mpc's catalog, cached on disk: it scrapes live docs over the network. The
29
+ * cache is per plan, since mpc bakes that plan's per-model allowance into it. */
30
+ export declare function loadMeta(plan?: OcPlan): Promise<Map<string, ModelMeta>>;
28
31
  /** One usage snapshot from cmduse. Throws when cmduse is missing, fails, or
29
32
  * returns the errored defaults its JSON carries when the account API is
30
33
  * unreachable (see `requireSnapshot`). */
@@ -34,4 +37,4 @@ export declare function loadUsage(): Promise<Usage>;
34
37
  * (those providers have no usage API). Throws when ocuse is missing or fails,
35
38
  * and the caller then omits the panel.
36
39
  */
37
- export declare function loadZen(): Promise<ZenUsage>;
40
+ export declare function loadZen(plan?: OcPlan): Promise<ZenUsage>;
@@ -1,10 +1,12 @@
1
+ import { type OcPlan } from "../constants/sidebar";
1
2
  export interface Prefs {
2
3
  colors: boolean;
4
+ /** OpenCode Go plan the sidebar renders per-model limits for. */
5
+ ocPlan: OcPlan;
3
6
  }
4
- export declare const DEFAULTS: Prefs;
5
7
  /** Preferences live beside opencode's own config, XDG layout honoured. */
6
8
  export declare function prefsPath(env?: NodeJS.ProcessEnv): string;
7
- /** Only a literal `true` enables colour, so a typo cannot turn the panel on. */
9
+ /** Only a literal `true` enables colour; an unknown plan falls back to `go`. */
8
10
  export declare function parsePrefs(raw: unknown): Prefs;
9
- /** Env override, then the file, then the default. Cached for `CACHE_MS`. */
11
+ /** Env override, then the file, then the default. Cached for `PREFS_CACHE_MS`. */
10
12
  export declare function loadPrefs(env?: NodeJS.ProcessEnv, now?: number): Prefs;