@jeffreyjyz/opencode-command-code 0.2.4 → 0.2.5
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 +0 -66
- package/dist/sidebar/data.d.ts +9 -0
- package/dist/sidebar/rows.d.ts +50 -0
- package/dist/tui.d.ts +38 -1
- package/dist/tui.js +628 -45
- package/package.json +43 -30
- package/dist/usagelog.d.ts +0 -25
package/dist/index.js
CHANGED
|
@@ -544,65 +544,6 @@ async function loadModels(key) {
|
|
|
544
544
|
return { claude, open };
|
|
545
545
|
}
|
|
546
546
|
|
|
547
|
-
// src/usagelog.ts
|
|
548
|
-
import { appendFileSync, mkdirSync } from "fs";
|
|
549
|
-
import { homedir as homedir2 } from "os";
|
|
550
|
-
import { dirname, join } from "path";
|
|
551
|
-
function usageLogPath() {
|
|
552
|
-
if (process.env.MPC_USAGE_LOG)
|
|
553
|
-
return process.env.MPC_USAGE_LOG;
|
|
554
|
-
const base = process.env.XDG_CACHE_HOME ?? join(homedir2(), ".cache");
|
|
555
|
-
return join(base, "mpc", "usage.jsonl");
|
|
556
|
-
}
|
|
557
|
-
var logged = new Set;
|
|
558
|
-
var MAX_SEEN = 5000;
|
|
559
|
-
function numberOr(value) {
|
|
560
|
-
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
561
|
-
}
|
|
562
|
-
function logUsage(info) {
|
|
563
|
-
try {
|
|
564
|
-
if (!info || info.role !== "assistant" || !info.tokens)
|
|
565
|
-
return;
|
|
566
|
-
const completed = info.time?.completed;
|
|
567
|
-
if (!completed)
|
|
568
|
-
return;
|
|
569
|
-
if (info.id) {
|
|
570
|
-
if (logged.has(info.id))
|
|
571
|
-
return;
|
|
572
|
-
if (logged.size >= MAX_SEEN)
|
|
573
|
-
logged.clear();
|
|
574
|
-
logged.add(info.id);
|
|
575
|
-
}
|
|
576
|
-
const input = numberOr(info.tokens.input);
|
|
577
|
-
const output = numberOr(info.tokens.output);
|
|
578
|
-
const cacheRead = numberOr(info.tokens.cache?.read);
|
|
579
|
-
const cacheWrite = numberOr(info.tokens.cache?.write);
|
|
580
|
-
if (input + output + cacheRead + cacheWrite === 0)
|
|
581
|
-
return;
|
|
582
|
-
const line = JSON.stringify({
|
|
583
|
-
ts: new Date(completed).toISOString(),
|
|
584
|
-
provider: info.providerID,
|
|
585
|
-
model: info.modelID,
|
|
586
|
-
input,
|
|
587
|
-
cacheRead,
|
|
588
|
-
cacheWrite,
|
|
589
|
-
output,
|
|
590
|
-
costUsd: numberOr(info.cost),
|
|
591
|
-
messageID: info.id
|
|
592
|
-
});
|
|
593
|
-
const path = usageLogPath();
|
|
594
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
595
|
-
appendFileSync(path, `${line}
|
|
596
|
-
`);
|
|
597
|
-
} catch {}
|
|
598
|
-
}
|
|
599
|
-
function logEvent(event) {
|
|
600
|
-
const e = event;
|
|
601
|
-
if (e?.type !== "message.updated")
|
|
602
|
-
return;
|
|
603
|
-
logUsage(e.properties?.info);
|
|
604
|
-
}
|
|
605
|
-
|
|
606
547
|
// src/v2.ts
|
|
607
548
|
import { Plugin } from "@opencode/plugin";
|
|
608
549
|
var PLUGIN_ID = "command-code";
|
|
@@ -678,10 +619,6 @@ var commandCodeV2 = Plugin.define({
|
|
|
678
619
|
if (!localKey && !hasConnection) {
|
|
679
620
|
console.warn(`[command-code] no API key found. Run /connect and choose "${INTEGRATION_NAME}", or \`cmd login\` (~/.commandcode/auth.json), or set CMD_API_KEY.`);
|
|
680
621
|
}
|
|
681
|
-
try {
|
|
682
|
-
const events = ctx.event;
|
|
683
|
-
events?.subscribe?.((event) => logEvent(event));
|
|
684
|
-
} catch {}
|
|
685
622
|
await ctx.integration.transform((editor) => {
|
|
686
623
|
editor.update(INTEGRATION_ID, (integration) => {
|
|
687
624
|
if (integration.name === integration.id) {
|
|
@@ -836,9 +773,6 @@ var CommandCodePlugin = async (_input) => {
|
|
|
836
773
|
}
|
|
837
774
|
]
|
|
838
775
|
},
|
|
839
|
-
event: async ({ event }) => {
|
|
840
|
-
logEvent(event);
|
|
841
|
-
},
|
|
842
776
|
config: async (cfg) => {
|
|
843
777
|
cfg.provider ??= {};
|
|
844
778
|
const existing = (id) => cfg.provider?.[id] ?? {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ModelMeta, type Usage } from "./rows";
|
|
2
|
+
/** Parse `cmduse -1 --json` into the usage snapshot. */
|
|
3
|
+
export declare function parseUsageJson(text: string): Usage;
|
|
4
|
+
/** Parse `mpc --json` into per-model meta, CommandCode side only. */
|
|
5
|
+
export declare function parseMpcJson(text: string): Map<string, ModelMeta>;
|
|
6
|
+
/** mpc's catalog, cached on disk: it scrapes live docs over the network. */
|
|
7
|
+
export declare function loadMeta(): Promise<Map<string, ModelMeta>>;
|
|
8
|
+
/** One usage snapshot from cmduse. Throws when cmduse is missing or fails. */
|
|
9
|
+
export declare function loadUsage(): Promise<Usage>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type Category } from "../gating";
|
|
2
|
+
export type SidebarRow = [label: string, value: string];
|
|
3
|
+
export interface ModelMeta {
|
|
4
|
+
key: string;
|
|
5
|
+
name: string;
|
|
6
|
+
tier?: Category;
|
|
7
|
+
allowance?: number;
|
|
8
|
+
rates?: {
|
|
9
|
+
input: number;
|
|
10
|
+
output: number;
|
|
11
|
+
cacheRead: number;
|
|
12
|
+
cacheWrite?: number | null;
|
|
13
|
+
};
|
|
14
|
+
intelligence?: number;
|
|
15
|
+
tps?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface WindowUsage {
|
|
18
|
+
cap?: number;
|
|
19
|
+
used?: number;
|
|
20
|
+
resetAt?: number;
|
|
21
|
+
}
|
|
22
|
+
export interface Usage {
|
|
23
|
+
plan?: string;
|
|
24
|
+
monthlyCap?: number;
|
|
25
|
+
monthlyCredits?: number;
|
|
26
|
+
fiveHour?: WindowUsage;
|
|
27
|
+
weekly?: WindowUsage;
|
|
28
|
+
periodEnd?: string;
|
|
29
|
+
requests?: number;
|
|
30
|
+
cost?: number;
|
|
31
|
+
}
|
|
32
|
+
/** Money at credit scale: cents, but "$60" not "$60.00". */
|
|
33
|
+
export declare function money(value: number): string;
|
|
34
|
+
/** Rate scale needs more precision than credit scale ($0.0036). */
|
|
35
|
+
export declare function rate(value: number): string;
|
|
36
|
+
export declare function count(value: number): string;
|
|
37
|
+
/** "3h 12m" / "1d 20h" / "<1m" for a reset epoch. */
|
|
38
|
+
export declare function until(epoch: number | undefined, now?: number): string;
|
|
39
|
+
/** Plan + rolling windows + period totals, from a cmduse snapshot. */
|
|
40
|
+
export declare function usageRows(usage: Usage | undefined, now?: number): SidebarRow[];
|
|
41
|
+
/** Active model's allowance, rates and benchmarks, from mpc's catalog. */
|
|
42
|
+
export declare function modelRows(meta: ModelMeta | undefined): SidebarRow[];
|
|
43
|
+
/**
|
|
44
|
+
* Canonical key for a model id, mirroring mpc's normalizeKey: lowercase, drop
|
|
45
|
+
* the vendor prefix and any parenthetical, strip punctuation. Used to match the
|
|
46
|
+
* session's active model against the mpc catalog.
|
|
47
|
+
*/
|
|
48
|
+
export declare function modelKey(modelId: string): string;
|
|
49
|
+
/** Tier lookup for a model id, from the canonical gating snapshot. */
|
|
50
|
+
export declare function tierFor(modelId: string): Category | undefined;
|
package/dist/tui.d.ts
CHANGED
|
@@ -1,3 +1,40 @@
|
|
|
1
|
+
/** @jsxImportSource @opentui/solid */
|
|
2
|
+
import type { RGBA } from "@opentui/core";
|
|
1
3
|
import { Plugin } from "@opencode/plugin/tui";
|
|
2
|
-
|
|
4
|
+
interface V1Api {
|
|
5
|
+
slots: {
|
|
6
|
+
register: (config: {
|
|
7
|
+
order?: number;
|
|
8
|
+
slots: {
|
|
9
|
+
sidebar_content: (ctx: unknown, props: {
|
|
10
|
+
session_id: string;
|
|
11
|
+
}) => unknown;
|
|
12
|
+
};
|
|
13
|
+
}) => void;
|
|
14
|
+
};
|
|
15
|
+
state: {
|
|
16
|
+
session: {
|
|
17
|
+
get: (id: string) => {
|
|
18
|
+
model?: {
|
|
19
|
+
providerID: string;
|
|
20
|
+
id: string;
|
|
21
|
+
};
|
|
22
|
+
} | undefined;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
theme: {
|
|
26
|
+
current: {
|
|
27
|
+
text: RGBA;
|
|
28
|
+
textMuted: RGBA;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** v1 half — snake_case slot map registered through `api.slots`. */
|
|
33
|
+
export declare const tui: (api: V1Api) => Promise<void>;
|
|
34
|
+
export declare const commandCodeTui: Plugin.Definition;
|
|
35
|
+
declare const _default: {
|
|
36
|
+
tui: (api: V1Api) => Promise<void>;
|
|
37
|
+
id: string;
|
|
38
|
+
setup: (context: Plugin.Context) => Promise<Plugin.Cleanup | void> | Plugin.Cleanup | void;
|
|
39
|
+
};
|
|
3
40
|
export default _default;
|
package/dist/tui.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// src/tui.
|
|
2
|
+
// src/tui.tsx
|
|
3
|
+
import { memo as _$memo } from "@opentui/solid";
|
|
4
|
+
import { setProp as _$setProp } from "@opentui/solid";
|
|
5
|
+
import { effect as _$effect } from "@opentui/solid";
|
|
6
|
+
import { insert as _$insert } from "@opentui/solid";
|
|
7
|
+
import { createComponent as _$createComponent } from "@opentui/solid";
|
|
8
|
+
import { createTextNode as _$createTextNode } from "@opentui/solid";
|
|
9
|
+
import { insertNode as _$insertNode } from "@opentui/solid";
|
|
10
|
+
import { createElement as _$createElement } from "@opentui/solid";
|
|
3
11
|
import { Plugin } from "@opencode/plugin/tui";
|
|
12
|
+
import { For, Show, createMemo, createSignal, onCleanup } from "solid-js";
|
|
4
13
|
|
|
5
14
|
// src/cli.ts
|
|
6
15
|
import { spawn } from "child_process";
|
|
7
16
|
var CANDIDATES = ["cmduse", "/opt/homebrew/bin/cmduse", "/usr/local/bin/cmduse"];
|
|
8
17
|
var DEFAULT_ARGS = ["-1", "--plain"];
|
|
9
|
-
var SUBCOMMANDS = new Set([
|
|
10
|
-
"plans",
|
|
11
|
-
"models",
|
|
12
|
-
"daily",
|
|
13
|
-
"hourly",
|
|
14
|
-
"model",
|
|
15
|
-
"session",
|
|
16
|
-
"statusline",
|
|
17
|
-
"config"
|
|
18
|
-
]);
|
|
18
|
+
var SUBCOMMANDS = new Set(["plans", "models", "daily", "hourly", "model", "session", "statusline", "config"]);
|
|
19
19
|
function splitCliArgs(input) {
|
|
20
20
|
const out = [];
|
|
21
21
|
let cur = "";
|
|
@@ -71,13 +71,18 @@ function stderrTail(text) {
|
|
|
71
71
|
function runOnce(bin, args, opts) {
|
|
72
72
|
return new Promise((resolve, reject) => {
|
|
73
73
|
const child = spawn(bin, args, {
|
|
74
|
-
env: {
|
|
74
|
+
env: {
|
|
75
|
+
...process.env,
|
|
76
|
+
...opts.env ?? {}
|
|
77
|
+
},
|
|
75
78
|
stdio: ["ignore", "pipe", "pipe"]
|
|
76
79
|
});
|
|
77
80
|
const out = [];
|
|
78
81
|
const err = [];
|
|
79
82
|
const onAbort = () => child.kill("SIGTERM");
|
|
80
|
-
opts.signal?.addEventListener("abort", onAbort, {
|
|
83
|
+
opts.signal?.addEventListener("abort", onAbort, {
|
|
84
|
+
once: true
|
|
85
|
+
});
|
|
81
86
|
child.stdout.on("data", (d) => out.push(d));
|
|
82
87
|
child.stderr.on("data", (d) => err.push(d));
|
|
83
88
|
child.on("error", (e) => {
|
|
@@ -113,46 +118,618 @@ async function runCmduse(arg, opts = {}) {
|
|
|
113
118
|
throw e;
|
|
114
119
|
}
|
|
115
120
|
}
|
|
116
|
-
throw new Error(`cmduse binary not found (install: brew install JeffreyJYZ/tap/cmduse)${last instanceof Error && last.message !== last.name ? ` \u2014 ${last.message}` : ""}`, {
|
|
121
|
+
throw new Error(`cmduse binary not found (install: brew install JeffreyJYZ/tap/cmduse)${last instanceof Error && last.message !== last.name ? ` \u2014 ${last.message}` : ""}`, {
|
|
122
|
+
cause: last
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// src/sidebar/data.ts
|
|
127
|
+
import { spawn as spawn2 } from "child_process";
|
|
128
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
129
|
+
import { homedir } from "os";
|
|
130
|
+
import { dirname, join } from "path";
|
|
131
|
+
// ../core/gating.json
|
|
132
|
+
var gating_default = {
|
|
133
|
+
extractedAt: "2026-09-12T06:01:01.385Z",
|
|
134
|
+
cliVersion: "1.38.2",
|
|
135
|
+
categories: {
|
|
136
|
+
"claude-sonnet-5": "premium",
|
|
137
|
+
"claude-sonnet-4-6": "premium",
|
|
138
|
+
"claude-fable-5": "premium",
|
|
139
|
+
"claude-opus-5": "premium",
|
|
140
|
+
"claude-opus-4-8": "premium",
|
|
141
|
+
"claude-opus-4-7": "premium",
|
|
142
|
+
"claude-haiku-4-5-20251001": "premium",
|
|
143
|
+
"gpt-5.6-sol": "opensource",
|
|
144
|
+
"gpt-5.6-terra": "premium",
|
|
145
|
+
"gpt-5.6-luna": "opensource",
|
|
146
|
+
"gpt-5.5": "premium",
|
|
147
|
+
"gpt-5.4": "premium",
|
|
148
|
+
"gpt-5.3-codex": "premium",
|
|
149
|
+
"gpt-5.4-mini": "premium",
|
|
150
|
+
"google/gemini-3.5-flash": "premium",
|
|
151
|
+
"google/gemini-3.1-flash-lite": "premium",
|
|
152
|
+
"sakana/fugu-ultra": "premium",
|
|
153
|
+
"meta/muse-spark-1.1": "premium",
|
|
154
|
+
"meta/muse-spark-1.2": "opensource",
|
|
155
|
+
"meta/muse-spark-1.2-contributor": "opensource",
|
|
156
|
+
"xai/grok-4.5": "opensource",
|
|
157
|
+
"xai/grok-4.6": "opensource",
|
|
158
|
+
"google/gemini-3.7-flash": "opensource",
|
|
159
|
+
"z-ai/glm-5.3-flash": "opensource",
|
|
160
|
+
"tencent/hy4-preview": "opensource",
|
|
161
|
+
"tencent/hy3-paid": "opensource",
|
|
162
|
+
"tencent/Hy3": "opensource",
|
|
163
|
+
"MiniMaxAI/MiniMax-M3-Free": "opensource",
|
|
164
|
+
"MiniMaxAI/MiniMax-M3": "opensource",
|
|
165
|
+
"MiniMaxAI/MiniMax-M2.7": "opensource",
|
|
166
|
+
"minimax/minimax-m3-free": "opensource",
|
|
167
|
+
"minimax/minimax-m2.7-free": "opensource",
|
|
168
|
+
"MiniMaxAI/MiniMax-M2.5": "opensource",
|
|
169
|
+
"deepseek/deepseek-v4-pro": "opensource",
|
|
170
|
+
"deepseek/deepseek-v4-flash": "opensource",
|
|
171
|
+
"moonshotai/Kimi-K3": "opensource",
|
|
172
|
+
"moonshotai/Kimi-K2.7-Code": "opensource",
|
|
173
|
+
"moonshotai/Kimi-K2.7-Code-Highspeed": "opensource",
|
|
174
|
+
"moonshotai/Kimi-K2.6": "opensource",
|
|
175
|
+
"moonshotai/Kimi-K2.5": "opensource",
|
|
176
|
+
"zai-org/GLM-5.3": "opensource",
|
|
177
|
+
"zai-org/GLM-5.2": "opensource",
|
|
178
|
+
"zai-org/GLM-5.2-Fast": "opensource",
|
|
179
|
+
"zai-org/GLM-5.1": "opensource",
|
|
180
|
+
"zai-org/GLM-5": "opensource",
|
|
181
|
+
"xiaomi/mimo-v2.5-pro": "opensource",
|
|
182
|
+
"xiaomi/mimo-v2.5": "opensource",
|
|
183
|
+
"Qwen/Qwen3.6-Max-Preview": "opensource",
|
|
184
|
+
"Qwen/Qwen3.6-Plus": "opensource",
|
|
185
|
+
"Qwen/Qwen3.7-Max": "opensource",
|
|
186
|
+
"Qwen/Qwen3.7-Plus": "opensource",
|
|
187
|
+
"Qwen/Qwen3.8-Max": "opensource",
|
|
188
|
+
"Qwen/Qwen3.8-27B": "opensource",
|
|
189
|
+
"Qwen/Qwen3.8-Flash": "opensource",
|
|
190
|
+
"Qwen/Qwen3.7-Flash": "opensource",
|
|
191
|
+
"stepfun/Step-3.7-Flash": "opensource",
|
|
192
|
+
"stepfun/Step-3.5-Flash": "opensource",
|
|
193
|
+
"nvidia/nemotron-3-ultra-550b-a55b": "opensource",
|
|
194
|
+
"thinkingmachines/inkling": "opensource"
|
|
195
|
+
},
|
|
196
|
+
plans: {
|
|
197
|
+
"individual-go": {
|
|
198
|
+
allowedCategories: [
|
|
199
|
+
"opensource"
|
|
200
|
+
],
|
|
201
|
+
blockedModels: [
|
|
202
|
+
"vercel-ai-gateway:meta/muse-spark-1.2",
|
|
203
|
+
"vercel-ai-gateway:xai/grok-4.6",
|
|
204
|
+
"openrouter:google/gemini-3.7-flash",
|
|
205
|
+
"vercel-ai-gateway:gpt-5.6-sol"
|
|
206
|
+
]
|
|
207
|
+
},
|
|
208
|
+
"individual-goat": {
|
|
209
|
+
allowedCategories: [
|
|
210
|
+
"opensource"
|
|
211
|
+
],
|
|
212
|
+
blockedModels: []
|
|
213
|
+
},
|
|
214
|
+
"individual-pro": {
|
|
215
|
+
allowedCategories: [
|
|
216
|
+
"premium",
|
|
217
|
+
"opensource"
|
|
218
|
+
],
|
|
219
|
+
blockedModels: [
|
|
220
|
+
"anthropic:claude-fable-5",
|
|
221
|
+
"anthropic:claude-opus-5",
|
|
222
|
+
"anthropic:claude-opus-4-8",
|
|
223
|
+
"anthropic:claude-opus-4-7",
|
|
224
|
+
"anthropic:claude-opus-4-6",
|
|
225
|
+
"anthropic:claude-opus-4-5-20251101",
|
|
226
|
+
"vercel-ai-gateway:sakana/fugu-ultra"
|
|
227
|
+
]
|
|
228
|
+
},
|
|
229
|
+
"individual-pro-v1": {
|
|
230
|
+
allowedCategories: [
|
|
231
|
+
"premium",
|
|
232
|
+
"opensource"
|
|
233
|
+
],
|
|
234
|
+
blockedModels: [
|
|
235
|
+
"anthropic:claude-fable-5",
|
|
236
|
+
"anthropic:claude-opus-5",
|
|
237
|
+
"anthropic:claude-opus-4-8",
|
|
238
|
+
"anthropic:claude-opus-4-7",
|
|
239
|
+
"anthropic:claude-opus-4-6",
|
|
240
|
+
"anthropic:claude-opus-4-5-20251101",
|
|
241
|
+
"vercel-ai-gateway:sakana/fugu-ultra"
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
"individual-provider": {
|
|
245
|
+
allowedCategories: [
|
|
246
|
+
"premium",
|
|
247
|
+
"opensource"
|
|
248
|
+
],
|
|
249
|
+
blockedModels: []
|
|
250
|
+
},
|
|
251
|
+
"individual-max": {
|
|
252
|
+
allowedCategories: [
|
|
253
|
+
"premium",
|
|
254
|
+
"opensource"
|
|
255
|
+
],
|
|
256
|
+
blockedModels: []
|
|
257
|
+
},
|
|
258
|
+
"individual-ultra": {
|
|
259
|
+
allowedCategories: [
|
|
260
|
+
"premium",
|
|
261
|
+
"opensource"
|
|
262
|
+
],
|
|
263
|
+
blockedModels: []
|
|
264
|
+
},
|
|
265
|
+
"teams-pro": {
|
|
266
|
+
allowedCategories: [
|
|
267
|
+
"premium",
|
|
268
|
+
"opensource"
|
|
269
|
+
],
|
|
270
|
+
blockedModels: []
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
knownModels: [
|
|
274
|
+
"claude-sonnet-4-6",
|
|
275
|
+
"claude-fable-5",
|
|
276
|
+
"claude-opus-5",
|
|
277
|
+
"claude-opus-4-8",
|
|
278
|
+
"claude-opus-4-7",
|
|
279
|
+
"claude-haiku-4-5-20251001",
|
|
280
|
+
"gpt-5.6-sol",
|
|
281
|
+
"gpt-5.6-terra",
|
|
282
|
+
"gpt-5.6-luna",
|
|
283
|
+
"gpt-5.5",
|
|
284
|
+
"gpt-5.4",
|
|
285
|
+
"gpt-5.3-codex",
|
|
286
|
+
"gpt-5.4-mini",
|
|
287
|
+
"moonshotai/Kimi-K3",
|
|
288
|
+
"thinkingmachines/inkling",
|
|
289
|
+
"thinkingmachines/inkling-small",
|
|
290
|
+
"deepseek/deepseek-v4-pro",
|
|
291
|
+
"deepseek/deepseek-v4-flash",
|
|
292
|
+
"deepseek/deepseek-v4-flash-vision-exp",
|
|
293
|
+
"moonshotai/Kimi-K2.7-Code",
|
|
294
|
+
"moonshotai/Kimi-K2.7-Code-Highspeed",
|
|
295
|
+
"moonshotai/Kimi-K2.6",
|
|
296
|
+
"moonshotai/Kimi-K2.5",
|
|
297
|
+
"zai-org/GLM-5.3",
|
|
298
|
+
"z-ai/glm-5.3-flash",
|
|
299
|
+
"zai-org/GLM-5.2",
|
|
300
|
+
"zai-org/GLM-5.2-Fast",
|
|
301
|
+
"zai-org/GLM-5.1",
|
|
302
|
+
"zai-org/GLM-5",
|
|
303
|
+
"xiaomi/mimo-v2.5-pro",
|
|
304
|
+
"xiaomi/mimo-v2.5",
|
|
305
|
+
"stepfun/Step-3.7-Flash",
|
|
306
|
+
"stepfun/Step-3.5-Flash",
|
|
307
|
+
"tencent/hy4-preview",
|
|
308
|
+
"tencent/hy3-paid",
|
|
309
|
+
"tencent/Hy3",
|
|
310
|
+
"google/gemini-3.7-flash",
|
|
311
|
+
"google/gemini-3.6-flash",
|
|
312
|
+
"google/gemini-3.5-flash",
|
|
313
|
+
"google/gemini-3.5-flash-lite",
|
|
314
|
+
"google/gemini-3.1-flash-lite",
|
|
315
|
+
"sakana/fugu-ultra",
|
|
316
|
+
"xai/grok-4.5",
|
|
317
|
+
"xai/grok-4.6",
|
|
318
|
+
"meta/muse-spark-1.1",
|
|
319
|
+
"meta/muse-spark-1.2",
|
|
320
|
+
"meta/muse-spark-1.2-contributor",
|
|
321
|
+
"nvidia/nemotron-3-ultra-550b-a55b",
|
|
322
|
+
"poolside/laguna-s-2.1-free",
|
|
323
|
+
"inclusionai/ling-3.0-flash-free",
|
|
324
|
+
"minimax/minimax-m3-free",
|
|
325
|
+
"minimax/minimax-m2.7-free",
|
|
326
|
+
"claude-sonnet-5",
|
|
327
|
+
"MiniMaxAI/MiniMax-M3-Free",
|
|
328
|
+
"MiniMaxAI/MiniMax-M3",
|
|
329
|
+
"MiniMaxAI/MiniMax-M2.7",
|
|
330
|
+
"MiniMaxAI/MiniMax-M2.5",
|
|
331
|
+
"Qwen/Qwen3.6-Max-Preview",
|
|
332
|
+
"Qwen/Qwen3.6-Plus",
|
|
333
|
+
"Qwen/Qwen3.7-Max",
|
|
334
|
+
"Qwen/Qwen3.7-Plus",
|
|
335
|
+
"Qwen/Qwen3.8-Max",
|
|
336
|
+
"Qwen/Qwen3.8-27B",
|
|
337
|
+
"Qwen/Qwen3.8-Flash",
|
|
338
|
+
"Qwen/Qwen3.7-Flash"
|
|
339
|
+
],
|
|
340
|
+
aliases: {
|
|
341
|
+
"claude-sonnet-4-20250514": "claude-sonnet-4-6",
|
|
342
|
+
"claude-sonnet-4-5-20250929": "claude-sonnet-4-6",
|
|
343
|
+
"claude-opus-4-5-20251101": "claude-opus-4-7",
|
|
344
|
+
"claude-opus-4-6": "claude-opus-4-7",
|
|
345
|
+
"claude-haiku-4-5": "claude-haiku-4-5-20251001"
|
|
346
|
+
},
|
|
347
|
+
hardBlocked: {
|
|
348
|
+
"individual-goat": [
|
|
349
|
+
"meta/muse-spark-1.1",
|
|
350
|
+
"google/gemini-3.5-flash",
|
|
351
|
+
"google/gemini-3.6-flash",
|
|
352
|
+
"google/gemini-3.5-flash-lite",
|
|
353
|
+
"google/gemini-3.1-flash-lite"
|
|
354
|
+
],
|
|
355
|
+
"individual-go": [
|
|
356
|
+
"meta/muse-spark-1.1",
|
|
357
|
+
"google/gemini-3.5-flash",
|
|
358
|
+
"google/gemini-3.6-flash",
|
|
359
|
+
"google/gemini-3.5-flash-lite",
|
|
360
|
+
"google/gemini-3.1-flash-lite",
|
|
361
|
+
"meta/muse-spark-1.2",
|
|
362
|
+
"meta/muse-spark-1.2-contributor",
|
|
363
|
+
"meta/muse-spark-1.3",
|
|
364
|
+
"meta/muse-spark-1.3-contributor"
|
|
365
|
+
]
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
// src/gating.ts
|
|
370
|
+
var MODEL_CATEGORIES = gating_default.categories;
|
|
371
|
+
var PLAN_RULES = gating_default.plans;
|
|
372
|
+
var HARD_BLOCKED = gating_default.hardBlocked;
|
|
373
|
+
var KNOWN_MODELS = gating_default.knownModels;
|
|
374
|
+
var MODEL_ALIASES = gating_default.aliases;
|
|
375
|
+
var GATE_EXTRACTED_AT = gating_default.extractedAt;
|
|
376
|
+
var GATE_CLI_VERSION = gating_default.cliVersion;
|
|
377
|
+
function findKnown(s) {
|
|
378
|
+
const k = s.toLowerCase();
|
|
379
|
+
return KNOWN_MODELS.find((m) => m.toLowerCase() === k);
|
|
380
|
+
}
|
|
381
|
+
function canonicalizeModelId(model) {
|
|
382
|
+
const stripDate = (s) => s.replace(/[-@]\d{8}$/, "");
|
|
383
|
+
const direct = findKnown(model);
|
|
384
|
+
if (direct)
|
|
385
|
+
return direct;
|
|
386
|
+
const aliased = MODEL_ALIASES[model.toLowerCase()];
|
|
387
|
+
if (aliased)
|
|
388
|
+
return findKnown(aliased) ?? model;
|
|
389
|
+
return findKnown(stripDate(model)) ?? model;
|
|
117
390
|
}
|
|
118
391
|
|
|
119
|
-
// src/
|
|
120
|
-
var
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
392
|
+
// src/sidebar/rows.ts
|
|
393
|
+
var TIER_DISPLAY = {
|
|
394
|
+
opensource: "open source",
|
|
395
|
+
premium: "premium"
|
|
396
|
+
};
|
|
397
|
+
function money(value) {
|
|
398
|
+
const rounded = Math.round(value * 100) / 100;
|
|
399
|
+
return `$${Number.isInteger(rounded) ? rounded : rounded.toFixed(2)}`;
|
|
400
|
+
}
|
|
401
|
+
function rate(value) {
|
|
402
|
+
if (value === 0)
|
|
403
|
+
return "$0";
|
|
404
|
+
return `$${Number(value.toFixed(4))}`;
|
|
405
|
+
}
|
|
406
|
+
function count(value) {
|
|
407
|
+
if (value >= 1e6)
|
|
408
|
+
return `${(value / 1e6).toFixed(1)}M`;
|
|
409
|
+
if (value >= 1000)
|
|
410
|
+
return `${(value / 1000).toFixed(1)}K`;
|
|
411
|
+
return String(Math.round(value));
|
|
412
|
+
}
|
|
413
|
+
function until(epoch, now = Date.now()) {
|
|
414
|
+
if (!epoch)
|
|
415
|
+
return "";
|
|
416
|
+
const secs = Math.max(0, Math.round((epoch - now) / 1000));
|
|
417
|
+
if (secs < 60)
|
|
418
|
+
return "<1m";
|
|
419
|
+
const mins = Math.floor(secs / 60);
|
|
420
|
+
if (mins < 60)
|
|
421
|
+
return `${mins}m`;
|
|
422
|
+
const hours = Math.floor(mins / 60);
|
|
423
|
+
if (hours < 24)
|
|
424
|
+
return mins % 60 ? `${hours}h ${mins % 60}m` : `${hours}h`;
|
|
425
|
+
const days = Math.floor(hours / 24);
|
|
426
|
+
return hours % 24 ? `${days}d ${hours % 24}h` : `${days}d`;
|
|
427
|
+
}
|
|
428
|
+
function windowRow(label, w, now) {
|
|
429
|
+
if (!w || typeof w.cap !== "number" || w.cap <= 0)
|
|
430
|
+
return;
|
|
431
|
+
const used = typeof w.used === "number" ? w.used : 0;
|
|
432
|
+
const pct = Math.round(used / w.cap * 100);
|
|
433
|
+
const reset = until(w.resetAt, now);
|
|
434
|
+
return [label, `${money(used)} / ${money(w.cap)} (${pct}%)${reset ? ` \xB7 resets ${reset}` : ""}`];
|
|
435
|
+
}
|
|
436
|
+
function usageRows(usage, now = Date.now()) {
|
|
437
|
+
if (!usage)
|
|
438
|
+
return [];
|
|
439
|
+
const rows = [];
|
|
440
|
+
if (usage.plan) {
|
|
441
|
+
const credits = typeof usage.monthlyCap === "number" ? ` \xB7 $${usage.monthlyCap}/mo credits` : "";
|
|
442
|
+
rows.push(["Plan", `${usage.plan}${credits}`]);
|
|
443
|
+
}
|
|
444
|
+
if (typeof usage.monthlyCap === "number" && typeof usage.monthlyCredits === "number") {
|
|
445
|
+
const used = usage.monthlyCap - usage.monthlyCredits;
|
|
446
|
+
const pct = usage.monthlyCap > 0 ? Math.round(used / usage.monthlyCap * 100) : 0;
|
|
447
|
+
rows.push(["Monthly", `${money(used)} / ${money(usage.monthlyCap)} (${pct}%)`]);
|
|
448
|
+
}
|
|
449
|
+
const five = windowRow("5-hour", usage.fiveHour, now);
|
|
450
|
+
if (five)
|
|
451
|
+
rows.push(five);
|
|
452
|
+
const week = windowRow("Weekly", usage.weekly, now);
|
|
453
|
+
if (week)
|
|
454
|
+
rows.push(week);
|
|
455
|
+
if (typeof usage.requests === "number" || typeof usage.cost === "number") {
|
|
456
|
+
const parts = [];
|
|
457
|
+
if (typeof usage.requests === "number")
|
|
458
|
+
parts.push(`${count(usage.requests)} requests`);
|
|
459
|
+
if (typeof usage.cost === "number")
|
|
460
|
+
parts.push(money(usage.cost));
|
|
461
|
+
rows.push(["Period", parts.join(" \xB7 ")]);
|
|
462
|
+
}
|
|
463
|
+
return rows;
|
|
464
|
+
}
|
|
465
|
+
function modelRows(meta) {
|
|
466
|
+
if (!meta)
|
|
467
|
+
return [];
|
|
468
|
+
const rows = [["Model", meta.name]];
|
|
469
|
+
if (meta.tier)
|
|
470
|
+
rows.push(["Tier", TIER_DISPLAY[meta.tier]]);
|
|
471
|
+
if (typeof meta.allowance === "number")
|
|
472
|
+
rows.push(["Allowance", `${money(meta.allowance)}/mo`]);
|
|
473
|
+
if (meta.rates) {
|
|
474
|
+
rows.push(["Rates", `${rate(meta.rates.input)}/${rate(meta.rates.output)} in/out`]);
|
|
475
|
+
rows.push(["Cache read", rate(meta.rates.cacheRead)]);
|
|
476
|
+
}
|
|
477
|
+
if (typeof meta.intelligence === "number")
|
|
478
|
+
rows.push(["Intelligence", String(meta.intelligence)]);
|
|
479
|
+
if (typeof meta.tps === "number")
|
|
480
|
+
rows.push(["Tok/s", String(meta.tps)]);
|
|
481
|
+
return rows;
|
|
482
|
+
}
|
|
483
|
+
function modelKey(modelId) {
|
|
484
|
+
const bare = modelId.toLowerCase().replace(/\([^)]*\)/g, " ");
|
|
485
|
+
const tail = bare.split("/").pop() ?? bare;
|
|
486
|
+
return tail.replace(/[^a-z0-9]+/g, "");
|
|
487
|
+
}
|
|
488
|
+
function tierFor(modelId) {
|
|
489
|
+
return MODEL_CATEGORIES[canonicalizeModelId(modelId)];
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// src/sidebar/data.ts
|
|
493
|
+
var CMDUSE = ["cmduse", "/opt/homebrew/bin/cmduse", "/usr/local/bin/cmduse"];
|
|
494
|
+
var MPC = ["mpc", join(homedir(), ".bun/bin/mpc"), "/opt/homebrew/bin/mpc"];
|
|
495
|
+
var CACHE_TTL_MS = 6 * 60 * 60 * 1000;
|
|
496
|
+
function run(bin, args) {
|
|
497
|
+
return new Promise((resolve, reject) => {
|
|
498
|
+
const child = spawn2(bin, args, {
|
|
499
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
500
|
+
});
|
|
501
|
+
const out = [];
|
|
502
|
+
const err = [];
|
|
503
|
+
child.stdout.on("data", (d) => out.push(d));
|
|
504
|
+
child.stderr.on("data", (d) => err.push(d));
|
|
505
|
+
child.on("error", reject);
|
|
506
|
+
child.on("close", (code) => code === 0 ? resolve(Buffer.concat(out).toString("utf8")) : reject(new Error(`${bin} ${args.join(" ")}: exit ${code} ${Buffer.concat(err).toString("utf8").slice(-200)}`)));
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
async function runFirst(candidates, args) {
|
|
510
|
+
let last;
|
|
511
|
+
for (const bin of candidates) {
|
|
512
|
+
try {
|
|
513
|
+
return await run(bin, args);
|
|
514
|
+
} catch (e) {
|
|
515
|
+
last = e;
|
|
516
|
+
if (e?.code !== "ENOENT")
|
|
517
|
+
throw e;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
throw last instanceof Error ? last : new Error(`${candidates[0]} not found`);
|
|
521
|
+
}
|
|
522
|
+
function parseUsageJson(text) {
|
|
523
|
+
const raw = JSON.parse(text);
|
|
524
|
+
const win = (v) => {
|
|
525
|
+
if (!v || typeof v !== "object")
|
|
526
|
+
return;
|
|
527
|
+
const w = v;
|
|
528
|
+
return {
|
|
529
|
+
cap: typeof w.cap === "number" ? w.cap : undefined,
|
|
530
|
+
used: typeof w.used === "number" ? w.used : undefined,
|
|
531
|
+
resetAt: typeof w.resetAt === "number" ? w.resetAt : undefined
|
|
532
|
+
};
|
|
533
|
+
};
|
|
534
|
+
const summary = raw.summary ?? {};
|
|
535
|
+
return {
|
|
536
|
+
plan: typeof raw.plan === "string" ? raw.plan : undefined,
|
|
537
|
+
monthlyCap: typeof raw.monthlyCap === "number" ? raw.monthlyCap : undefined,
|
|
538
|
+
monthlyCredits: typeof raw.monthlyCredits === "number" ? raw.monthlyCredits : undefined,
|
|
539
|
+
fiveHour: win(raw.fiveHour),
|
|
540
|
+
weekly: win(raw.weekly),
|
|
541
|
+
periodEnd: typeof raw.periodEnd === "string" ? raw.periodEnd : undefined,
|
|
542
|
+
requests: typeof summary.requests === "number" ? summary.requests : undefined,
|
|
543
|
+
cost: typeof summary.cost === "number" ? summary.cost : undefined
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
function parseMpcJson(text) {
|
|
547
|
+
const body = JSON.parse(text);
|
|
548
|
+
const meta = new Map;
|
|
549
|
+
for (const row of body.rows ?? []) {
|
|
550
|
+
const cc = row.cc;
|
|
551
|
+
if (!cc || !row.name)
|
|
552
|
+
continue;
|
|
553
|
+
const entry = {
|
|
554
|
+
key: row.key ?? modelKey(row.name),
|
|
555
|
+
name: row.name,
|
|
556
|
+
allowance: cc.allowance,
|
|
557
|
+
rates: cc.pricing,
|
|
558
|
+
intelligence: cc.ability ?? undefined,
|
|
559
|
+
tps: cc.tps ?? undefined
|
|
560
|
+
};
|
|
561
|
+
meta.set(entry.key, entry);
|
|
562
|
+
meta.set(modelKey(row.name), entry);
|
|
563
|
+
}
|
|
564
|
+
return meta;
|
|
565
|
+
}
|
|
566
|
+
function cachePath() {
|
|
567
|
+
const base = process.env.XDG_CACHE_HOME ?? join(homedir(), ".cache");
|
|
568
|
+
return join(base, "command-code", "cc-catalog.json");
|
|
569
|
+
}
|
|
570
|
+
async function loadMeta() {
|
|
571
|
+
try {
|
|
572
|
+
const cached = JSON.parse(await readFile(cachePath(), "utf8"));
|
|
573
|
+
if (cached.fetchedAt && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
|
|
574
|
+
return new Map(cached.rows ?? []);
|
|
575
|
+
}
|
|
576
|
+
} catch {}
|
|
577
|
+
const meta = parseMpcJson(await runFirst(MPC, ["--json"]));
|
|
578
|
+
try {
|
|
579
|
+
const path = cachePath();
|
|
580
|
+
await mkdir(dirname(path), {
|
|
581
|
+
recursive: true
|
|
582
|
+
});
|
|
583
|
+
await writeFile(path, JSON.stringify({
|
|
584
|
+
fetchedAt: Date.now(),
|
|
585
|
+
rows: [...meta]
|
|
586
|
+
}));
|
|
587
|
+
} catch {}
|
|
588
|
+
return meta;
|
|
589
|
+
}
|
|
590
|
+
async function loadUsage() {
|
|
591
|
+
return parseUsageJson(await runFirst(CMDUSE, ["-1", "--json", "--plain"]));
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// src/tui.tsx
|
|
595
|
+
var ID = "command-code.tui";
|
|
596
|
+
var POLL_MS = 30000;
|
|
597
|
+
function Panel(props) {
|
|
598
|
+
return _$createComponent(Show, {
|
|
599
|
+
get when() {
|
|
600
|
+
return props.rows().length > 0;
|
|
601
|
+
},
|
|
602
|
+
get children() {
|
|
603
|
+
var _el$ = _$createElement("box"), _el$2 = _$createElement("text"), _el$3 = _$createElement("b");
|
|
604
|
+
_$insertNode(_el$, _el$2);
|
|
605
|
+
_$insertNode(_el$2, _el$3);
|
|
606
|
+
_$insertNode(_el$3, _$createTextNode(`Command Code`));
|
|
607
|
+
_$insert(_el$, _$createComponent(For, {
|
|
608
|
+
get each() {
|
|
609
|
+
return props.rows();
|
|
610
|
+
},
|
|
611
|
+
children: (row) => (() => {
|
|
612
|
+
var _el$5 = _$createElement("text");
|
|
613
|
+
_$insert(_el$5, (() => {
|
|
614
|
+
var _c$ = _$memo(() => !!row[1]);
|
|
615
|
+
return () => _c$() ? `${row[0]}: ${row[1]}` : row[0];
|
|
616
|
+
})());
|
|
617
|
+
_$effect((_$p) => _$setProp(_el$5, "fg", props.muted(), _$p));
|
|
618
|
+
return _el$5;
|
|
619
|
+
})()
|
|
620
|
+
}), null);
|
|
621
|
+
_$effect((_$p) => _$setProp(_el$2, "fg", props.text(), _$p));
|
|
622
|
+
return _el$;
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
function useRows(activeModelId, active) {
|
|
627
|
+
const [usage, setUsage] = createSignal([]);
|
|
628
|
+
const [meta, setMeta] = createSignal(new Map);
|
|
629
|
+
loadMeta().then(setMeta).catch(() => {});
|
|
630
|
+
const refresh = async () => {
|
|
631
|
+
try {
|
|
632
|
+
setUsage(usageRows(await loadUsage()));
|
|
633
|
+
} catch {}
|
|
634
|
+
};
|
|
635
|
+
refresh();
|
|
636
|
+
const timer = setInterval(() => void refresh(), POLL_MS);
|
|
637
|
+
onCleanup(() => clearInterval(timer));
|
|
638
|
+
return createMemo(() => {
|
|
639
|
+
if (!active())
|
|
640
|
+
return [];
|
|
641
|
+
const id = activeModelId();
|
|
642
|
+
const found = id ? meta().get(modelKey(id)) ?? meta().get(id) : undefined;
|
|
643
|
+
const model = found ? {
|
|
644
|
+
...found,
|
|
645
|
+
tier: found.tier ?? (id ? tierFor(id) : undefined)
|
|
646
|
+
} : undefined;
|
|
647
|
+
return [...usage(), ...modelRows(model)];
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
var isOurs = (providerID) => Boolean(providerID?.startsWith("command-code"));
|
|
651
|
+
function PanelV1(props) {
|
|
652
|
+
const current = () => props.api.state.session.get(props.sessionID)?.model;
|
|
653
|
+
const rows = useRows(() => current()?.id, () => isOurs(current()?.providerID));
|
|
654
|
+
return _$createComponent(Panel, {
|
|
655
|
+
rows,
|
|
656
|
+
text: () => props.api.theme.current.text,
|
|
657
|
+
muted: () => props.api.theme.current.textMuted
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
var tui = async (api) => {
|
|
661
|
+
api.slots.register({
|
|
662
|
+
order: 200,
|
|
663
|
+
slots: {
|
|
664
|
+
sidebar_content(_ctx, props) {
|
|
665
|
+
return _$createComponent(PanelV1, {
|
|
666
|
+
api,
|
|
667
|
+
get sessionID() {
|
|
668
|
+
return props.session_id;
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
});
|
|
674
|
+
};
|
|
675
|
+
function PanelV2(props) {
|
|
676
|
+
const {
|
|
677
|
+
ctx
|
|
678
|
+
} = props;
|
|
679
|
+
const current = () => ctx.data.session.get(props.sessionID)?.model;
|
|
680
|
+
const rows = useRows(() => current()?.id, () => isOurs(current()?.providerID));
|
|
681
|
+
return _$createComponent(Panel, {
|
|
682
|
+
rows,
|
|
683
|
+
text: () => ctx.theme.text.default,
|
|
684
|
+
muted: () => ctx.theme.text.subdued
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
var commandCodeTui = Plugin.define({
|
|
688
|
+
id: ID,
|
|
689
|
+
setup(ctx) {
|
|
690
|
+
ctx.ui.slot({
|
|
691
|
+
append: "sidebar.content",
|
|
692
|
+
render: (input) => _$createComponent(PanelV2, {
|
|
693
|
+
ctx,
|
|
694
|
+
get sessionID() {
|
|
695
|
+
return input.sessionID;
|
|
696
|
+
}
|
|
697
|
+
})
|
|
698
|
+
});
|
|
699
|
+
ctx.ui.slot({
|
|
124
700
|
append: "app",
|
|
125
701
|
render: () => {
|
|
126
|
-
|
|
702
|
+
ctx.keymap.layer(() => ({
|
|
127
703
|
mode: "global",
|
|
128
704
|
priority: 10,
|
|
129
|
-
commands: [
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
await context.ui.dialog.alert({
|
|
150
|
-
title: "Command Code usage",
|
|
151
|
-
message: text.trimEnd()
|
|
705
|
+
commands: [{
|
|
706
|
+
id: "command-code.cmd-usage",
|
|
707
|
+
title: "Command Code usage",
|
|
708
|
+
group: "Command Code",
|
|
709
|
+
slash: {
|
|
710
|
+
name: "cmd-usage",
|
|
711
|
+
arguments: true
|
|
712
|
+
},
|
|
713
|
+
enabled: () => true,
|
|
714
|
+
suggested: true,
|
|
715
|
+
run: async (input) => {
|
|
716
|
+
let text;
|
|
717
|
+
try {
|
|
718
|
+
text = await runCmduse(input ?? "");
|
|
719
|
+
} catch (error) {
|
|
720
|
+
ctx.ui.toast.show({
|
|
721
|
+
title: "cmd-usage failed",
|
|
722
|
+
message: error instanceof Error ? error.message : String(error),
|
|
723
|
+
variant: "error"
|
|
152
724
|
});
|
|
725
|
+
return;
|
|
153
726
|
}
|
|
727
|
+
await ctx.ui.dialog.alert({
|
|
728
|
+
title: "Command Code usage",
|
|
729
|
+
message: text.trimEnd()
|
|
730
|
+
});
|
|
154
731
|
}
|
|
155
|
-
],
|
|
732
|
+
}],
|
|
156
733
|
bindings: ["command-code.cmd-usage"]
|
|
157
734
|
}));
|
|
158
735
|
return null;
|
|
@@ -160,6 +737,12 @@ var tui_default = Plugin.define({
|
|
|
160
737
|
});
|
|
161
738
|
}
|
|
162
739
|
});
|
|
740
|
+
var tui_default = {
|
|
741
|
+
...commandCodeTui,
|
|
742
|
+
tui
|
|
743
|
+
};
|
|
163
744
|
export {
|
|
164
|
-
|
|
745
|
+
commandCodeTui,
|
|
746
|
+
tui_default as default,
|
|
747
|
+
tui
|
|
165
748
|
};
|
package/package.json
CHANGED
|
@@ -1,32 +1,45 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
2
|
+
"name": "@jeffreyjyz/opencode-command-code",
|
|
3
|
+
"version": "0.2.5",
|
|
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
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./dist/index.js",
|
|
10
|
+
"./tui": "./dist/tui.js"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "rm -rf dist && bun build src/index.ts --outdir dist --target bun --external @opencode-ai/plugin --external @opencode/plugin --external @opencode/plugin/tui && bun scripts/build-tui.ts && tsc -p tsconfig.build.json",
|
|
14
|
+
"test": "bun test",
|
|
15
|
+
"typecheck": "tsc --noEmit",
|
|
16
|
+
"build:tui": "bun scripts/build-tui.ts"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@opencode-ai/plugin": "*",
|
|
20
|
+
"@opencode/plugin": "^2.0.11",
|
|
21
|
+
"@opentui/core": "^0.5.4",
|
|
22
|
+
"@opentui/solid": "^0.5.4",
|
|
23
|
+
"solid-js": "1.9.12"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/bun": "latest",
|
|
27
|
+
"typescript": "^5"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"tui.js",
|
|
32
|
+
"LICENSE"
|
|
33
|
+
],
|
|
34
|
+
"keywords": [
|
|
35
|
+
"opencode",
|
|
36
|
+
"command-code",
|
|
37
|
+
"plugin",
|
|
38
|
+
"provider",
|
|
39
|
+
"ai-sdk"
|
|
40
|
+
],
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
}
|
|
32
45
|
}
|
package/dist/usagelog.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export interface UsageMessage {
|
|
2
|
-
id?: string;
|
|
3
|
-
role?: string;
|
|
4
|
-
providerID?: string;
|
|
5
|
-
modelID?: string;
|
|
6
|
-
cost?: number;
|
|
7
|
-
tokens?: {
|
|
8
|
-
input?: number;
|
|
9
|
-
output?: number;
|
|
10
|
-
cache?: {
|
|
11
|
-
read?: number;
|
|
12
|
-
write?: number;
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
time?: {
|
|
16
|
-
created?: number;
|
|
17
|
-
completed?: number;
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
/** `$MPC_USAGE_LOG`, else `$XDG_CACHE_HOME/mpc/usage.jsonl`, else `~/.cache/…`. */
|
|
21
|
-
export declare function usageLogPath(): string;
|
|
22
|
-
/** Append one JSONL line for a finished assistant message. Never throws. */
|
|
23
|
-
export declare function logUsage(info: UsageMessage | undefined): void;
|
|
24
|
-
/** Narrow an opencode event down to an assistant message update. */
|
|
25
|
-
export declare function logEvent(event: unknown): void;
|