@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/access.d.ts +2 -1
- package/dist/api.d.ts +0 -1
- package/dist/cli.d.ts +14 -0
- package/dist/constants/binaries.d.ts +6 -0
- package/dist/constants/cli.d.ts +17 -0
- package/dist/constants/endpoints.d.ts +6 -0
- package/dist/constants/gating.d.ts +22 -0
- package/dist/constants/models.d.ts +29 -0
- package/dist/constants/paths.d.ts +18 -0
- package/dist/constants/providers.d.ts +32 -0
- package/dist/constants/sidebar.d.ts +33 -0
- package/dist/constants/timing.d.ts +13 -0
- package/dist/gating.d.ts +1 -19
- package/dist/index.d.ts +2 -2
- package/dist/index.js +237 -77
- package/dist/provider/index.d.ts +0 -1
- package/dist/sidebar/data.d.ts +13 -10
- package/dist/sidebar/prefs.d.ts +5 -3
- package/dist/sidebar/rows.d.ts +17 -4
- package/dist/sidebar/windows.d.ts +0 -4
- package/dist/sidebar/zen.d.ts +0 -6
- package/dist/tui.d.ts +1 -1
- package/dist/tui.js +141 -71
- package/dist/v2.d.ts +2 -16
- package/package.json +2 -2
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.
|
|
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: "^
|
|
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/
|
|
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: {
|
|
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
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
var
|
|
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(
|
|
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(
|
|
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(`${
|
|
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 <
|
|
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
|
|
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 ??
|
|
3808
|
-
return
|
|
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(
|
|
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 [
|
|
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 [
|
|
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 [
|
|
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 [
|
|
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 [
|
|
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 = [
|
|
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
|
-
{
|
|
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 =
|
|
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: {
|
|
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({
|
|
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
|
|
4601
|
-
import { join as
|
|
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 ??
|
|
4607
|
-
return
|
|
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(
|
|
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: {
|
|
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 = {
|
|
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: {
|
|
5052
|
+
input: {
|
|
5053
|
+
...MODEL_CAPABILITIES.input,
|
|
5054
|
+
image: true
|
|
5055
|
+
}
|
|
4913
5056
|
} : {}
|
|
4914
5057
|
},
|
|
4915
5058
|
cost: costFor(m.id),
|
|
4916
|
-
limit: {
|
|
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 ?? "", {
|
|
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
|
}
|
package/dist/provider/index.d.ts
CHANGED
|
@@ -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;
|
package/dist/sidebar/data.d.ts
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
import {
|
|
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
|
-
/**
|
|
27
|
-
|
|
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>;
|
package/dist/sidebar/prefs.d.ts
CHANGED
|
@@ -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
|
|
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 `
|
|
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;
|