@jeffreyjyz/opencode-command-code 0.3.15 → 0.3.16
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 +1 -1
- package/dist/sidebar/data.d.ts +11 -1
- package/dist/sidebar/rows.d.ts +16 -2
- package/dist/sidebar/useRows.d.ts +7 -1
- package/dist/sidebar/zen.d.ts +5 -2
- package/dist/tui.js +67 -20
- package/package.json +1 -1
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.
|
|
2417
|
+
version: "0.3.16",
|
|
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",
|
package/dist/sidebar/data.d.ts
CHANGED
|
@@ -9,6 +9,14 @@ import { type ZenUsage } from "./zen";
|
|
|
9
9
|
export declare const SPAWN_OPTIONS: Parameters<typeof spawn>[2];
|
|
10
10
|
/** Parse `cmduse -1 --json` into the usage snapshot. */
|
|
11
11
|
export declare function parseUsageJson(text: string): Usage;
|
|
12
|
+
/**
|
|
13
|
+
* A snapshot is only usable when cmduse actually reached the account API.
|
|
14
|
+
* `-1 --json` exits 0 on failure and then carries the defaults (plan "Free", no
|
|
15
|
+
* windows) beside an `error`; painting that over a good snapshot is what made
|
|
16
|
+
* the Monthly row flash during an outage. Throw so the caller keeps the last
|
|
17
|
+
* snapshot, exactly as it does when the CLI is missing.
|
|
18
|
+
*/
|
|
19
|
+
export declare function requireSnapshot(usage: Usage): Usage;
|
|
12
20
|
/**
|
|
13
21
|
* Parse `mpc --json` into per-model meta: the CommandCode fields at the top
|
|
14
22
|
* level and the OpenCode Go / Zen side under `oc`, so one lookup serves either
|
|
@@ -17,7 +25,9 @@ export declare function parseUsageJson(text: string): Usage;
|
|
|
17
25
|
export declare function parseMpcJson(text: string): Map<string, ModelMeta>;
|
|
18
26
|
/** mpc's catalog, cached on disk: it scrapes live docs over the network. */
|
|
19
27
|
export declare function loadMeta(): Promise<Map<string, ModelMeta>>;
|
|
20
|
-
/** One usage snapshot from cmduse. Throws when cmduse is missing
|
|
28
|
+
/** One usage snapshot from cmduse. Throws when cmduse is missing, fails, or
|
|
29
|
+
* returns the errored defaults its JSON carries when the account API is
|
|
30
|
+
* unreachable (see `requireSnapshot`). */
|
|
21
31
|
export declare function loadUsage(): Promise<Usage>;
|
|
22
32
|
/**
|
|
23
33
|
* One OpenCode Go / Zen snapshot from ocuse, which reads opencode's own store
|
package/dist/sidebar/rows.d.ts
CHANGED
|
@@ -101,6 +101,14 @@ export interface Usage {
|
|
|
101
101
|
periodEnd?: string;
|
|
102
102
|
requests?: number;
|
|
103
103
|
cost?: number;
|
|
104
|
+
/**
|
|
105
|
+
* cmduse's own fetch error. `cmduse -1 --json` still exits 0 when the account
|
|
106
|
+
* API is unreachable, and then publishes the *defaults* (plan "Free", no
|
|
107
|
+
* windows) beside this string — the human renderer hides that fake frame, and
|
|
108
|
+
* a consumer must too, or it paints "Free" with no Monthly row over a good
|
|
109
|
+
* snapshot. See `loadUsage`.
|
|
110
|
+
*/
|
|
111
|
+
error?: string;
|
|
104
112
|
}
|
|
105
113
|
/** Money at credit scale: cents, but "$60" not "$60.00". */
|
|
106
114
|
export declare function money(value: number): string;
|
|
@@ -113,8 +121,14 @@ export declare function until(epoch: number | undefined, now?: number): string;
|
|
|
113
121
|
export declare function usageRows(usage: Usage | undefined, now?: number): SidebarRow[];
|
|
114
122
|
/** Active model's allowance, rates and benchmarks, from mpc's catalog; its
|
|
115
123
|
* period usage (when the store has it) rides directly under the model name, and
|
|
116
|
-
* this session's own totals under that (0.4.0).
|
|
117
|
-
|
|
124
|
+
* this session's own totals under that (0.4.0).
|
|
125
|
+
*
|
|
126
|
+
* `fallbackName` keeps the block on screen when the catalog is unavailable: the
|
|
127
|
+
* `Usage (this model)`/`Session` rows come from the local store and need no
|
|
128
|
+
* network, so an outage must not hide them behind a failed mpc spawn. The name
|
|
129
|
+
* is the only thing borrowed, and it is the session's own id when no catalog
|
|
130
|
+
* row names the model. */
|
|
131
|
+
export declare function modelRows(meta: ModelMeta | undefined, usage?: ModelUsage, session?: ModelUsage, fallbackName?: string): SidebarRow[];
|
|
118
132
|
/**
|
|
119
133
|
* Canonical key for a model id, mirroring mpc's normalizeKey: lowercase, drop
|
|
120
134
|
* the vendor prefix and any parenthetical, strip punctuation. Used to match the
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ModelUsage, type SidebarRow, type Usage } from "./rows";
|
|
1
|
+
import { type ModelMeta, type ModelUsage, type SidebarRow, type Usage } from "./rows";
|
|
2
2
|
/**
|
|
3
3
|
* Which family a session's provider belongs to, as far as this panel is
|
|
4
4
|
* concerned. `unknown` is the frame during a session switch, before the host has
|
|
@@ -24,4 +24,10 @@ export declare function rememberModelUsage(id: string, usage: ModelUsage): void;
|
|
|
24
24
|
* beats blanking it, the same call `wasOurs` makes for the account block.
|
|
25
25
|
*/
|
|
26
26
|
export declare function seededModelUsage(id: string | undefined): ModelUsage | undefined;
|
|
27
|
+
/** Keep a catalog for the next panel that needs it. An empty map is never
|
|
28
|
+
* remembered: it cannot be distinguished from "mpc returned nothing" and would
|
|
29
|
+
* wipe a good catalog. */
|
|
30
|
+
export declare function rememberMeta(meta: Map<string, ModelMeta>): void;
|
|
31
|
+
/** Rows to paint before mpc's catalog is read again. */
|
|
32
|
+
export declare function seededMeta(): Map<string, ModelMeta>;
|
|
27
33
|
export declare function useRows(activeModelId: () => string | undefined, providerID: () => string | undefined, sessionID: () => string | undefined): import("solid-js").Accessor<SidebarRow[]>;
|
package/dist/sidebar/zen.d.ts
CHANGED
|
@@ -32,5 +32,8 @@ export interface ZenUsage {
|
|
|
32
32
|
}
|
|
33
33
|
/** Parse `ocuse -1 --json`. Anything malformed reads as "no usage". */
|
|
34
34
|
export declare function parseZenJson(text: string): ZenUsage;
|
|
35
|
-
/** The OpenCode Go / Zen panel: period windows, a rule, then the active model.
|
|
36
|
-
|
|
35
|
+
/** The OpenCode Go / Zen panel: period windows, a rule, then the active model.
|
|
36
|
+
* Like `modelRows`, `fallbackName` (the session's own id) keeps the model block
|
|
37
|
+
* — and the local `Session` figure — on screen when mpc's catalog is
|
|
38
|
+
* unreachable; only the catalog-derived rows then drop out. */
|
|
39
|
+
export declare function zenRows(usage: ZenUsage | undefined, meta: ModelMeta | undefined, session?: ModelUsage, fallbackName?: string): SidebarRow[];
|
package/dist/tui.js
CHANGED
|
@@ -603,10 +603,11 @@ function usageRows(usage, now = Date.now()) {
|
|
|
603
603
|
}
|
|
604
604
|
return rows;
|
|
605
605
|
}
|
|
606
|
-
function modelRows(meta, usage, session) {
|
|
607
|
-
|
|
606
|
+
function modelRows(meta, usage, session, fallbackName) {
|
|
607
|
+
const name = meta?.name ?? fallbackName;
|
|
608
|
+
if (!name)
|
|
608
609
|
return [];
|
|
609
|
-
const rows = [["Model", clip(
|
|
610
|
+
const rows = [["Model", clip(name, valueWidth("Model")), "strong", true]];
|
|
610
611
|
if (usage) {
|
|
611
612
|
rows.push(["Usage (this model)", `${count(usage.requests)} req`, "base"]);
|
|
612
613
|
const spend = usage.cost > 0 ? money(usage.cost) : "";
|
|
@@ -619,6 +620,8 @@ function modelRows(meta, usage, session) {
|
|
|
619
620
|
const spent = session.cost > 0 ? ` \xB7 ${money(session.cost)}` : "";
|
|
620
621
|
rows.push(["Session", `${count(session.requests)} req${spent}`, "base"]);
|
|
621
622
|
}
|
|
623
|
+
if (!meta)
|
|
624
|
+
return rows;
|
|
622
625
|
if (meta.tier)
|
|
623
626
|
rows.push(["Tier", TIER_DISPLAY[meta.tier], "base"]);
|
|
624
627
|
else if (meta.minPlan)
|
|
@@ -1927,7 +1930,7 @@ function windowRows2(label, spent, limit, share) {
|
|
|
1927
1930
|
rows.push(["", `${count(spent.requests)} req`, "muted"]);
|
|
1928
1931
|
return rows;
|
|
1929
1932
|
}
|
|
1930
|
-
function zenRows(usage, meta, session) {
|
|
1933
|
+
function zenRows(usage, meta, session, fallbackName) {
|
|
1931
1934
|
if (!usage)
|
|
1932
1935
|
return [];
|
|
1933
1936
|
const oc = meta?.oc;
|
|
@@ -1939,13 +1942,16 @@ function zenRows(usage, meta, session) {
|
|
|
1939
1942
|
rows.push(...windowRows2("Month", mine?.month ?? usage.totals.month, limit, GO_WINDOW_SHARE.month));
|
|
1940
1943
|
rows.push(["Period", `${count(usage.totals.month.requests)} requests \xB7 ${money(usage.totals.month.cost)}`, "base"]);
|
|
1941
1944
|
rows.push(separator());
|
|
1942
|
-
|
|
1945
|
+
const name = meta?.name ?? fallbackName;
|
|
1946
|
+
if (!name)
|
|
1943
1947
|
return rows;
|
|
1944
|
-
rows.push(["Model", clip(
|
|
1948
|
+
rows.push(["Model", clip(name, valueWidth("Model")), "strong", true]);
|
|
1945
1949
|
if (session) {
|
|
1946
1950
|
const spent = session.cost > 0 ? ` \xB7 ${money(session.cost)}` : "";
|
|
1947
1951
|
rows.push(["Session", `${count(session.requests)} req${spent}`, "base"]);
|
|
1948
1952
|
}
|
|
1953
|
+
if (!meta)
|
|
1954
|
+
return rows;
|
|
1949
1955
|
if (typeof limit === "number") {
|
|
1950
1956
|
rows.push(["Allowance", `${money(limit)}/mo`, "base"]);
|
|
1951
1957
|
}
|
|
@@ -1974,15 +1980,31 @@ var SPAWN_OPTIONS = {
|
|
|
1974
1980
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1975
1981
|
detached: true
|
|
1976
1982
|
};
|
|
1983
|
+
var CHILD_TIMEOUT_MS = 30000;
|
|
1977
1984
|
function run(bin, args) {
|
|
1978
1985
|
return new Promise((resolve, reject) => {
|
|
1979
1986
|
const child = spawn2(bin, args, SPAWN_OPTIONS);
|
|
1980
1987
|
const out = [];
|
|
1981
1988
|
const err = [];
|
|
1989
|
+
let settled = false;
|
|
1990
|
+
const timer = setTimeout(() => {
|
|
1991
|
+
if (settled)
|
|
1992
|
+
return;
|
|
1993
|
+
settled = true;
|
|
1994
|
+
child.kill();
|
|
1995
|
+
reject(new Error(`${bin} ${args.join(" ")}: timed out after ${CHILD_TIMEOUT_MS}ms`));
|
|
1996
|
+
}, CHILD_TIMEOUT_MS);
|
|
1997
|
+
const done = (fn) => {
|
|
1998
|
+
if (settled)
|
|
1999
|
+
return;
|
|
2000
|
+
settled = true;
|
|
2001
|
+
clearTimeout(timer);
|
|
2002
|
+
fn();
|
|
2003
|
+
};
|
|
1982
2004
|
child.stdout?.on("data", (d) => out.push(d));
|
|
1983
2005
|
child.stderr?.on("data", (d) => err.push(d));
|
|
1984
|
-
child.on("error", reject);
|
|
1985
|
-
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)}`)));
|
|
2006
|
+
child.on("error", (e) => done(() => reject(e)));
|
|
2007
|
+
child.on("close", (code) => done(() => code === 0 ? resolve(Buffer.concat(out).toString("utf8")) : reject(new Error(`${bin} ${args.join(" ")}: exit ${code} ${Buffer.concat(err).toString("utf8").slice(-200)}`))));
|
|
1986
2008
|
});
|
|
1987
2009
|
}
|
|
1988
2010
|
async function runFirst(candidates, args) {
|
|
@@ -2022,9 +2044,15 @@ function parseUsageJson(text) {
|
|
|
2022
2044
|
periodStartAt: typeof raw.periodStartAt === "number" ? raw.periodStartAt : undefined,
|
|
2023
2045
|
periodEndAt: typeof raw.periodEndAt === "number" ? raw.periodEndAt : undefined,
|
|
2024
2046
|
requests: typeof summary.requests === "number" ? summary.requests : undefined,
|
|
2025
|
-
cost: typeof summary.cost === "number" ? summary.cost : undefined
|
|
2047
|
+
cost: typeof summary.cost === "number" ? summary.cost : undefined,
|
|
2048
|
+
error: typeof raw.error === "string" && raw.error ? raw.error : undefined
|
|
2026
2049
|
};
|
|
2027
2050
|
}
|
|
2051
|
+
function requireSnapshot(usage) {
|
|
2052
|
+
if (usage.error)
|
|
2053
|
+
throw new Error(usage.error);
|
|
2054
|
+
return usage;
|
|
2055
|
+
}
|
|
2028
2056
|
function parseMpcJson(text) {
|
|
2029
2057
|
const body = JSON.parse(text);
|
|
2030
2058
|
const meta = new Map;
|
|
@@ -2083,7 +2111,7 @@ async function loadMeta() {
|
|
|
2083
2111
|
return meta;
|
|
2084
2112
|
}
|
|
2085
2113
|
async function loadUsage() {
|
|
2086
|
-
return parseUsageJson(await runFirst(CMDUSE, ["-1", "--json", "--plain"]));
|
|
2114
|
+
return requireSnapshot(parseUsageJson(await runFirst(CMDUSE, ["-1", "--json", "--plain"])));
|
|
2087
2115
|
}
|
|
2088
2116
|
async function loadZen() {
|
|
2089
2117
|
return parseZenJson(await runFirst(OCUSE, ["-1", "--json"]));
|
|
@@ -2266,15 +2294,27 @@ function seededModelUsage(id) {
|
|
|
2266
2294
|
return lastModelUsage.usage;
|
|
2267
2295
|
return lastModelUsage.key === modelKey(id) ? lastModelUsage.usage : undefined;
|
|
2268
2296
|
}
|
|
2297
|
+
var lastMeta;
|
|
2298
|
+
function rememberMeta(meta) {
|
|
2299
|
+
if (meta.size > 0)
|
|
2300
|
+
lastMeta = meta;
|
|
2301
|
+
}
|
|
2302
|
+
function seededMeta() {
|
|
2303
|
+
return lastMeta ?? new Map;
|
|
2304
|
+
}
|
|
2269
2305
|
function useRows(activeModelId, providerID, sessionID) {
|
|
2270
2306
|
const [usage, setUsage] = createSignal(seededRows());
|
|
2271
2307
|
const [zen, setZen] = createSignal();
|
|
2272
|
-
const [meta, setMeta] = createSignal(
|
|
2308
|
+
const [meta, setMeta] = createSignal(seededMeta());
|
|
2273
2309
|
const [modelUsage, setModelUsage] = createSignal(lastModelUsage);
|
|
2274
2310
|
const [sessionUsage, setSessionUsage] = createSignal();
|
|
2275
2311
|
const [wasOurs, setWasOurs] = createSignal(false);
|
|
2276
2312
|
const refreshMeta = () => {
|
|
2277
|
-
loadMeta().then(
|
|
2313
|
+
loadMeta().then((next) => {
|
|
2314
|
+
rememberMeta(next);
|
|
2315
|
+
if (next.size > 0)
|
|
2316
|
+
setMeta(next);
|
|
2317
|
+
}).catch(() => {});
|
|
2278
2318
|
};
|
|
2279
2319
|
refreshMeta();
|
|
2280
2320
|
const refreshModelUsage = (id) => {
|
|
@@ -2285,13 +2325,17 @@ function useRows(activeModelId, providerID, sessionID) {
|
|
|
2285
2325
|
rememberModelUsage(id, fresh);
|
|
2286
2326
|
setModelUsage(lastModelUsage);
|
|
2287
2327
|
};
|
|
2328
|
+
let inFlight = false;
|
|
2288
2329
|
const refresh = async () => {
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
if (session)
|
|
2293
|
-
setSessionUsage(loadSessionUsage(session) ?? undefined);
|
|
2330
|
+
if (inFlight)
|
|
2331
|
+
return;
|
|
2332
|
+
inFlight = true;
|
|
2294
2333
|
try {
|
|
2334
|
+
const kind = sessionKind(providerID());
|
|
2335
|
+
const session = sessionID();
|
|
2336
|
+
refreshMeta();
|
|
2337
|
+
if (session)
|
|
2338
|
+
setSessionUsage(loadSessionUsage(session) ?? undefined);
|
|
2295
2339
|
if (kind === "ours") {
|
|
2296
2340
|
const snapshot = await loadUsage();
|
|
2297
2341
|
rememberSnapshot(snapshot);
|
|
@@ -2300,7 +2344,9 @@ function useRows(activeModelId, providerID, sessionID) {
|
|
|
2300
2344
|
} else if (kind === "go" || kind === "zen") {
|
|
2301
2345
|
setZen(await loadZen());
|
|
2302
2346
|
}
|
|
2303
|
-
} catch {}
|
|
2347
|
+
} catch {} finally {
|
|
2348
|
+
inFlight = false;
|
|
2349
|
+
}
|
|
2304
2350
|
};
|
|
2305
2351
|
createEffect(() => {
|
|
2306
2352
|
const kind = sessionKind(providerID());
|
|
@@ -2331,15 +2377,16 @@ function useRows(activeModelId, providerID, sessionID) {
|
|
|
2331
2377
|
return [];
|
|
2332
2378
|
const id = activeModelId();
|
|
2333
2379
|
const found = id ? meta().get(modelKey(id)) ?? meta().get(id) : undefined;
|
|
2380
|
+
const fallbackName = id ? id.split("/").pop() ?? id : undefined;
|
|
2334
2381
|
if (kind === "go" || kind === "zen") {
|
|
2335
|
-
return zenRows(zen(), found, sessionUsage());
|
|
2382
|
+
return zenRows(zen(), found, sessionUsage(), fallbackName);
|
|
2336
2383
|
}
|
|
2337
2384
|
const model = found ? {
|
|
2338
2385
|
...found,
|
|
2339
2386
|
tier: found.tier ?? (id ? tierFor(id) : undefined),
|
|
2340
2387
|
minPlan: id ? minPlan(id) : undefined
|
|
2341
2388
|
} : undefined;
|
|
2342
|
-
return [...usage(), separator(), ...modelRows(model, usageFor(id), sessionUsage())];
|
|
2389
|
+
return [...usage(), separator(), ...modelRows(model, usageFor(id), sessionUsage(), fallbackName)];
|
|
2343
2390
|
});
|
|
2344
2391
|
}
|
|
2345
2392
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jeffreyjyz/opencode-command-code",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.16",
|
|
4
4
|
"description": "Command Code provider + usage dashboard for opencode: two providers (Anthropic wire for Claude, OpenAI wire for everything else) against api.commandcode.ai, live model list, plan gating, /cmd-usage. Requires the cmduse CLI for usage rendering.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|