@jeffreyjyz/opencode-command-code 0.5.16 → 0.5.19
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/cli.d.ts +11 -0
- package/dist/constants/binaries.d.ts +2 -0
- package/dist/constants/providers.d.ts +8 -0
- package/dist/constants/timing.d.ts +5 -0
- package/dist/index.js +64 -1
- package/dist/sidebar/ark.d.ts +72 -0
- package/dist/sidebar/data.d.ts +8 -0
- package/dist/sidebar/useRows.d.ts +6 -1
- package/dist/tui.js +286 -15
- package/package.json +1 -1
package/dist/cli.d.ts
CHANGED
|
@@ -10,6 +10,9 @@ export declare function mpcCandidates(env?: Record<string, string | undefined>):
|
|
|
10
10
|
/** Same lookup for ocuse, the OpenCode Go/Zen reader shipped in the cmd-usage
|
|
11
11
|
* crate: `OCUSE_BIN` wins when set, then the homebrew fallbacks. */
|
|
12
12
|
export declare function ocuseCandidates(env?: Record<string, string | undefined>): string[];
|
|
13
|
+
/** Same lookup for arkuse, the Volcengine ARK Agent Plan reader in the same
|
|
14
|
+
* crate: `ARKUSE_BIN` wins when set, then the homebrew fallbacks. */
|
|
15
|
+
export declare function arkuseCandidates(env?: Record<string, string | undefined>): string[];
|
|
13
16
|
/** Shell-words split: whitespace-separated, with single/double quoting and
|
|
14
17
|
* backslash escapes ("--tz +05:30", arg='a b'). Unterminated quotes close at
|
|
15
18
|
* end of input. */
|
|
@@ -28,6 +31,10 @@ export declare function buildMpcArgs(arg: string): string[];
|
|
|
28
31
|
* watch loop and would never return, so empty input never passes through.
|
|
29
32
|
*/
|
|
30
33
|
export declare function ocuseArgs(arg: string | undefined): string;
|
|
34
|
+
/** The arg the arkuse_usage tool and the /arkuse-usage dialog pass on: the
|
|
35
|
+
* agent's (or slash) args when given, else `-1`. A bare arkuse is the live
|
|
36
|
+
* watch loop and would never return. */
|
|
37
|
+
export declare function arkuseArgs(arg: string | undefined): string;
|
|
31
38
|
export type RunOptions = {
|
|
32
39
|
signal?: AbortSignal;
|
|
33
40
|
/** Extra env for the child (CMD_API_KEY when the plugin resolved one). */
|
|
@@ -58,3 +65,7 @@ export declare function runMpc(arg: string | readonly string[], opts?: RunOption
|
|
|
58
65
|
* hint is the same brew formula. A string arg is shell-split, an array used
|
|
59
66
|
* as-is. */
|
|
60
67
|
export declare function runOcuse(arg: string | readonly string[], opts?: RunOptions): Promise<string>;
|
|
68
|
+
/** Run arkuse and return its plain-text stdout (Volcengine ARK usage). Same
|
|
69
|
+
* contract as runCmduse; arkuse ships in the cmd-usage crate, so its install
|
|
70
|
+
* hint is the same brew formula. */
|
|
71
|
+
export declare function runArkuse(arg: string | readonly string[], opts?: RunOptions): Promise<string>;
|
|
@@ -4,3 +4,5 @@ export declare const CMDUSE_BIN_CANDIDATES: readonly string[];
|
|
|
4
4
|
export declare const MPC_BIN_CANDIDATES: readonly string[];
|
|
5
5
|
/** Fallback lookup paths for ocuse (OCUSE_BIN wins when set). */
|
|
6
6
|
export declare const OCUSE_BIN_CANDIDATES: readonly string[];
|
|
7
|
+
/** Fallback lookup paths for arkuse (ARKUSE_BIN wins when set). */
|
|
8
|
+
export declare const ARKUSE_BIN_CANDIDATES: readonly string[];
|
|
@@ -11,12 +11,16 @@ export declare const GO_PROVIDER_ID = "opencode-go";
|
|
|
11
11
|
/** OpenCode Zen provider id and its `opencode-zen` alias prefix. */
|
|
12
12
|
export declare const ZEN_PROVIDER_ID = "opencode";
|
|
13
13
|
export declare const ZEN_PROVIDER_PREFIX = "opencode-zen";
|
|
14
|
+
/** Volcengine ARK Agent Plan provider id (what opencode records for its rows). */
|
|
15
|
+
export declare const ARK_PROVIDER_ID = "agent-plan";
|
|
14
16
|
/** TUI plugin id (stable contract; test/tui.test.ts pins it). */
|
|
15
17
|
export declare const TUI_ID = "command-code.tui";
|
|
16
18
|
/** The v2 /cmd-usage slash command id (registered and bound in tui.tsx). */
|
|
17
19
|
export declare const CMD_USAGE_COMMAND_ID = "command-code.cmd-usage";
|
|
18
20
|
/** The v2 /ocuse-usage slash command id (registered and bound in tui.tsx). */
|
|
19
21
|
export declare const OCUSE_USAGE_COMMAND_ID = "command-code.ocuse-usage";
|
|
22
|
+
/** The v2 /arkuse-usage slash command id (registered and bound in tui.tsx). */
|
|
23
|
+
export declare const ARKUSE_USAGE_COMMAND_ID = "command-code.arkuse-usage";
|
|
20
24
|
/** The cmd_usage tool description, shared by the v1 and v2 halves. */
|
|
21
25
|
export declare const TOOL_DESCRIPTION = "Fetch live Command Code plan/usage: plan name, monthly credits, 5-hour & weekly windows, billing-period summary. Pass arg='plans' for the plan comparison table only, or extra cmduse flags (e.g. '--tz +05:30 daily').";
|
|
22
26
|
/** The mpc_prices tool description, shared by the v1 and v2 halves. */
|
|
@@ -27,6 +31,10 @@ export declare const MPC_TOOL_ARG_DESCRIPTION = "Optional mpc flags: '--model <r
|
|
|
27
31
|
export declare const OCUSE_TOOL_DESCRIPTION = "Fetch live OpenCode Go/Zen usage: the account's window meters, per-model spend against limits, 5-hour & weekly windows, billing-period summary. Defaults to the one-shot dashboard; pass extra ocuse flags for more (e.g. '--plan go-plus', 'daily', '--json').";
|
|
28
32
|
/** The ocuse_usage `arg` description, shared by the v1 and v2 halves. */
|
|
29
33
|
export declare const OCUSE_TOOL_ARG_DESCRIPTION = "Optional: extra ocuse flags (e.g. '--plan go-plus', 'daily', '--json'); empty means the one-shot dashboard";
|
|
34
|
+
/** The arkuse_usage tool description, shared by the v1 and v2 halves. */
|
|
35
|
+
export declare const ARKUSE_TOOL_DESCRIPTION = "Fetch live Volcengine ARK Agent Plan usage in AFP: the plan's 5-hour/weekly/monthly meters from arkcli, this machine's per-model AFP, and the reconciliation between them. Defaults to the one-shot dashboard; pass extra arkuse flags for more (e.g. 'daily', '--plan medium', '--json').";
|
|
36
|
+
/** The arkuse_usage `arg` description, shared by the v1 and v2 halves. */
|
|
37
|
+
export declare const ARKUSE_TOOL_ARG_DESCRIPTION = "Optional: extra arkuse flags (e.g. '--plan medium', '--profile <name>', 'daily', '--json'); empty means the one-shot dashboard";
|
|
30
38
|
export type Lane = {
|
|
31
39
|
id: "command-code-anthropic" | "command-code-openai";
|
|
32
40
|
name: string;
|
|
@@ -11,3 +11,8 @@ export declare const MODELS_CACHE_TTL_MS: number;
|
|
|
11
11
|
export declare const CATALOG_CACHE_TTL_MS: number;
|
|
12
12
|
/** Re-read window for the sidebar colour prefs file (src/sidebar/prefs.ts). */
|
|
13
13
|
export declare const PREFS_CACHE_MS = 5000;
|
|
14
|
+
/** Process-lifetime cache for the ARK sidebar snapshot: every `arkuse` run
|
|
15
|
+
* shells out to `arkcli` for the plan meters, so polling it at the 5s cadence
|
|
16
|
+
* would be one control-plane round-trip per tick. A minute keeps the meters
|
|
17
|
+
* fresh enough while the store-backed rows still update on the poll. */
|
|
18
|
+
export declare const ARK_SNAPSHOT_TTL_MS = 60000;
|
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.5.
|
|
2417
|
+
version: "0.5.19",
|
|
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",
|
|
@@ -3242,6 +3242,11 @@ var OCUSE_BIN_CANDIDATES = [
|
|
|
3242
3242
|
"/opt/homebrew/bin/ocuse",
|
|
3243
3243
|
"/usr/local/bin/ocuse"
|
|
3244
3244
|
];
|
|
3245
|
+
var ARKUSE_BIN_CANDIDATES = [
|
|
3246
|
+
"arkuse",
|
|
3247
|
+
"/opt/homebrew/bin/arkuse",
|
|
3248
|
+
"/usr/local/bin/arkuse"
|
|
3249
|
+
];
|
|
3245
3250
|
|
|
3246
3251
|
// src/constants/cli.ts
|
|
3247
3252
|
var DEFAULT_ARGS = ["-1", "--plain"];
|
|
@@ -3273,6 +3278,11 @@ function ocuseCandidates(env = process.env) {
|
|
|
3273
3278
|
return candidates.filter((bin) => Boolean(bin));
|
|
3274
3279
|
}
|
|
3275
3280
|
var OCUSE_CANDIDATES = ocuseCandidates();
|
|
3281
|
+
function arkuseCandidates(env = process.env) {
|
|
3282
|
+
const candidates = [env.ARKUSE_BIN, ...ARKUSE_BIN_CANDIDATES];
|
|
3283
|
+
return candidates.filter((bin) => Boolean(bin));
|
|
3284
|
+
}
|
|
3285
|
+
var ARKUSE_CANDIDATES = arkuseCandidates();
|
|
3276
3286
|
function splitCliArgs(input) {
|
|
3277
3287
|
const out = [];
|
|
3278
3288
|
let cur = "";
|
|
@@ -3328,6 +3338,9 @@ function buildMpcArgs(arg) {
|
|
|
3328
3338
|
function ocuseArgs(arg) {
|
|
3329
3339
|
return arg !== undefined && arg.trim() !== "" ? arg : "-1";
|
|
3330
3340
|
}
|
|
3341
|
+
function arkuseArgs(arg) {
|
|
3342
|
+
return arg !== undefined && arg.trim() !== "" ? arg : "-1";
|
|
3343
|
+
}
|
|
3331
3344
|
function stderrTail(text) {
|
|
3332
3345
|
const lines = text.trimEnd().split(`
|
|
3333
3346
|
`);
|
|
@@ -3428,6 +3441,21 @@ async function runOcuse(arg, opts = {}) {
|
|
|
3428
3441
|
}
|
|
3429
3442
|
throw new Error(`ocuse binary not found (install: brew install JeffreyJYZ/tap/cmduse)${last instanceof Error && last.message !== last.name ? ` \u2014 ${last.message}` : ""}`, { cause: last });
|
|
3430
3443
|
}
|
|
3444
|
+
async function runArkuse(arg, opts = {}) {
|
|
3445
|
+
const args = resolveArgs(arg, splitCliArgs);
|
|
3446
|
+
const candidates = opts.candidates ?? ARKUSE_CANDIDATES;
|
|
3447
|
+
let last;
|
|
3448
|
+
for (const bin of candidates) {
|
|
3449
|
+
try {
|
|
3450
|
+
return await runOnce(bin, args, opts, "arkuse");
|
|
3451
|
+
} catch (e) {
|
|
3452
|
+
last = e;
|
|
3453
|
+
if (e?.code !== "ENOENT")
|
|
3454
|
+
throw e;
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
3457
|
+
throw new Error(`arkuse binary not found (install: brew install JeffreyJYZ/tap/cmduse)${last instanceof Error && last.message !== last.name ? ` \u2014 ${last.message}` : ""}`, { cause: last });
|
|
3458
|
+
}
|
|
3431
3459
|
|
|
3432
3460
|
// src/constants/models.ts
|
|
3433
3461
|
var MODEL_CAPABILITIES = {
|
|
@@ -3458,6 +3486,8 @@ var MPC_TOOL_DESCRIPTION = "Per-model price comparison: what a model costs per r
|
|
|
3458
3486
|
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";
|
|
3459
3487
|
var OCUSE_TOOL_DESCRIPTION = "Fetch live OpenCode Go/Zen usage: the account's window meters, per-model spend against limits, 5-hour & weekly windows, billing-period summary. Defaults to the one-shot dashboard; pass extra ocuse flags for more (e.g. '--plan go-plus', 'daily', '--json').";
|
|
3460
3488
|
var OCUSE_TOOL_ARG_DESCRIPTION = "Optional: extra ocuse flags (e.g. '--plan go-plus', 'daily', '--json'); empty means the one-shot dashboard";
|
|
3489
|
+
var ARKUSE_TOOL_DESCRIPTION = "Fetch live Volcengine ARK Agent Plan usage in AFP: the plan's 5-hour/weekly/monthly meters from arkcli, this machine's per-model AFP, and the reconciliation between them. Defaults to the one-shot dashboard; pass extra arkuse flags for more (e.g. 'daily', '--plan medium', '--json').";
|
|
3490
|
+
var ARKUSE_TOOL_ARG_DESCRIPTION = "Optional: extra arkuse flags (e.g. '--plan medium', '--profile <name>', 'daily', '--json'); empty means the one-shot dashboard";
|
|
3461
3491
|
var LANES = [
|
|
3462
3492
|
{
|
|
3463
3493
|
id: "command-code-anthropic",
|
|
@@ -5015,6 +5045,26 @@ var commandCodeV2 = {
|
|
|
5015
5045
|
};
|
|
5016
5046
|
}
|
|
5017
5047
|
});
|
|
5048
|
+
editor.add({
|
|
5049
|
+
name: "arkuse_usage",
|
|
5050
|
+
description: ARKUSE_TOOL_DESCRIPTION,
|
|
5051
|
+
input: {
|
|
5052
|
+
type: "object",
|
|
5053
|
+
properties: {
|
|
5054
|
+
arg: {
|
|
5055
|
+
type: "string",
|
|
5056
|
+
description: ARKUSE_TOOL_ARG_DESCRIPTION
|
|
5057
|
+
}
|
|
5058
|
+
},
|
|
5059
|
+
additionalProperties: false
|
|
5060
|
+
},
|
|
5061
|
+
async execute(input) {
|
|
5062
|
+
const arg = typeof input?.arg === "string" ? input.arg : undefined;
|
|
5063
|
+
return {
|
|
5064
|
+
content: await runArkuse(arkuseArgs(arg))
|
|
5065
|
+
};
|
|
5066
|
+
}
|
|
5067
|
+
});
|
|
5018
5068
|
});
|
|
5019
5069
|
let hasConnection = false;
|
|
5020
5070
|
let connectionMs = 0;
|
|
@@ -5231,6 +5281,10 @@ var CommandCodePlugin = async (_input) => {
|
|
|
5231
5281
|
description: "Show OpenCode Go/Zen usage: account meters and per-model spend",
|
|
5232
5282
|
template: "Call the ocuse_usage tool and present its markdown output verbatim to the user. If the tool errors, the Go key is missing or has no subscription \u2014 usage still shows where the store has it. $ARGUMENTS"
|
|
5233
5283
|
};
|
|
5284
|
+
cfg.command["arkuse-usage"] = {
|
|
5285
|
+
description: "Show Volcengine ARK Agent Plan usage: AFP meters per model",
|
|
5286
|
+
template: "Call the arkuse_usage tool and present its markdown output verbatim to the user. If the tool errors, arkcli or its agent-plan profile is missing \u2014 usage still shows where the store has it. $ARGUMENTS"
|
|
5287
|
+
};
|
|
5234
5288
|
},
|
|
5235
5289
|
provider: {
|
|
5236
5290
|
id: ANTHROPIC.id,
|
|
@@ -5276,6 +5330,15 @@ var CommandCodePlugin = async (_input) => {
|
|
|
5276
5330
|
async execute(args) {
|
|
5277
5331
|
return runOcuse(ocuseArgs(args.arg));
|
|
5278
5332
|
}
|
|
5333
|
+
}),
|
|
5334
|
+
arkuse_usage: tool({
|
|
5335
|
+
description: ARKUSE_TOOL_DESCRIPTION,
|
|
5336
|
+
args: {
|
|
5337
|
+
arg: string2().optional().describe(ARKUSE_TOOL_ARG_DESCRIPTION)
|
|
5338
|
+
},
|
|
5339
|
+
async execute(args) {
|
|
5340
|
+
return runArkuse(arkuseArgs(args.arg));
|
|
5341
|
+
}
|
|
5279
5342
|
})
|
|
5280
5343
|
}
|
|
5281
5344
|
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { type SidebarRow } from "./rows";
|
|
2
|
+
export interface ArkTotals {
|
|
3
|
+
afp: number;
|
|
4
|
+
requests: number;
|
|
5
|
+
tokensIn: number;
|
|
6
|
+
tokensOut: number;
|
|
7
|
+
cacheRead: number;
|
|
8
|
+
}
|
|
9
|
+
/** One of the plan's own meters (`arkuse`'s `account` block). Every field is
|
|
10
|
+
* optional-ish by parsing: a malformed meter must not raise a cap flag. */
|
|
11
|
+
export interface ArkMeter {
|
|
12
|
+
status: string;
|
|
13
|
+
percent: number;
|
|
14
|
+
used: number;
|
|
15
|
+
total: number;
|
|
16
|
+
resetAt?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ArkModel {
|
|
19
|
+
id: string;
|
|
20
|
+
coef: number;
|
|
21
|
+
fiveHour: ArkTotals;
|
|
22
|
+
weekly: ArkTotals;
|
|
23
|
+
month: ArkTotals;
|
|
24
|
+
}
|
|
25
|
+
/** This store's own view of one window (`arkuse`'s `windows` block): AFP against
|
|
26
|
+
* the plan's published quota, the percentage that yields, and the boundary the
|
|
27
|
+
* row counts down to. Present even when no meter answered, which is what keeps
|
|
28
|
+
* a panel row from degrading to AFP alone. */
|
|
29
|
+
export interface ArkWindow {
|
|
30
|
+
quota?: number;
|
|
31
|
+
percent?: number;
|
|
32
|
+
resetAt?: number;
|
|
33
|
+
}
|
|
34
|
+
export interface ArkUsage {
|
|
35
|
+
plan: string;
|
|
36
|
+
profile?: string;
|
|
37
|
+
periodStart?: number;
|
|
38
|
+
periodEndAt?: number;
|
|
39
|
+
summary: ArkTotals & {
|
|
40
|
+
yuan?: number;
|
|
41
|
+
};
|
|
42
|
+
fiveHour: ArkTotals;
|
|
43
|
+
weekly: ArkTotals;
|
|
44
|
+
month: ArkTotals;
|
|
45
|
+
daily?: ArkTotals;
|
|
46
|
+
windows?: {
|
|
47
|
+
fiveHour?: ArkWindow;
|
|
48
|
+
weekly?: ArkWindow;
|
|
49
|
+
monthly?: ArkWindow;
|
|
50
|
+
};
|
|
51
|
+
account?: {
|
|
52
|
+
fiveHour: ArkMeter;
|
|
53
|
+
daily?: ArkMeter;
|
|
54
|
+
weekly: ArkMeter;
|
|
55
|
+
monthly: ArkMeter;
|
|
56
|
+
};
|
|
57
|
+
accountError?: string;
|
|
58
|
+
afpPerRequest?: number;
|
|
59
|
+
reconciledPct?: number;
|
|
60
|
+
/** Keyed by model id, the same key the session's model id uses. */
|
|
61
|
+
models: Map<string, ArkModel>;
|
|
62
|
+
}
|
|
63
|
+
/** Parse `arkuse -1 --json`. A malformed body reads as an empty snapshot, never
|
|
64
|
+
* as a fabricated plan. */
|
|
65
|
+
export declare function parseArkJson(text: string): ArkUsage;
|
|
66
|
+
/**
|
|
67
|
+
* The ARK panel: plan, the window meters, a rule, then the active model's own
|
|
68
|
+
* AFP for the period. `fallbackName` is the session's model id, which is the
|
|
69
|
+
* key `arkuse` uses, so the model block renders even when nothing else knows the
|
|
70
|
+
* name.
|
|
71
|
+
*/
|
|
72
|
+
export declare function arkRows(usage: ArkUsage | undefined, fallbackName?: string): SidebarRow[];
|
package/dist/sidebar/data.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type OcPlan } from "../constants/sidebar";
|
|
2
|
+
import { type ArkUsage } from "./ark";
|
|
2
3
|
import { type ModelMeta, type Usage } from "./rows";
|
|
3
4
|
import { type ZenUsage } from "./zen";
|
|
4
5
|
/** Parse `cmduse -1 --json` into the usage snapshot. */
|
|
@@ -39,3 +40,10 @@ export declare function loadUsage(): Promise<Usage>;
|
|
|
39
40
|
* caller then omits the panel.
|
|
40
41
|
*/
|
|
41
42
|
export declare function loadZen(plan?: OcPlan): Promise<ZenUsage>;
|
|
43
|
+
/**
|
|
44
|
+
* One Volcengine ARK snapshot from `arkuse -1 --json`: the plan's own meters
|
|
45
|
+
* (through `arkcli`) plus this store's AFP per model. Cached for a minute
|
|
46
|
+
* because the spawn costs a control-plane round-trip; throws when `arkuse` is
|
|
47
|
+
* missing or fails, and the caller then keeps the last snapshot.
|
|
48
|
+
*/
|
|
49
|
+
export declare function loadArk(): Promise<ArkUsage>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ArkUsage } from "./ark";
|
|
1
2
|
import { type ModelMeta, type ModelUsage, type SidebarRow, type Usage } from "./rows";
|
|
2
3
|
import { type ZenUsage } from "./zen";
|
|
3
4
|
/**
|
|
@@ -6,7 +7,7 @@ import { type ZenUsage } from "./zen";
|
|
|
6
7
|
* resolved the new session's model; it must not be read as someone else's, or
|
|
7
8
|
* the panel blanks and refetches on every tab change.
|
|
8
9
|
*/
|
|
9
|
-
export type SessionKind = "ours" | "go" | "zen" | "other" | "unknown";
|
|
10
|
+
export type SessionKind = "ours" | "go" | "zen" | "ark" | "other" | "unknown";
|
|
10
11
|
export declare function sessionKind(providerID: string | undefined): SessionKind;
|
|
11
12
|
/** The section's title, per family. */
|
|
12
13
|
export declare function panelTitle(kind: SessionKind): string;
|
|
@@ -40,4 +41,8 @@ export declare function seededMeta(): Map<string, ModelMeta>;
|
|
|
40
41
|
export declare function rememberZen(usage: ZenUsage): void;
|
|
41
42
|
/** The remembered Go/Zen snapshot, or undefined on the first panel. */
|
|
42
43
|
export declare function seededZen(): ZenUsage | undefined;
|
|
44
|
+
/** Keep an ARK snapshot for the next panel that needs it. */
|
|
45
|
+
export declare function rememberArk(usage: ArkUsage): void;
|
|
46
|
+
/** The remembered ARK snapshot, or undefined on the first panel. */
|
|
47
|
+
export declare function seededArk(): ArkUsage | undefined;
|
|
43
48
|
export declare function useRows(activeModelId: () => string | undefined, providerID: () => string | undefined, sessionID: () => string | undefined): import("solid-js").Accessor<SidebarRow[]>;
|
package/dist/tui.js
CHANGED
|
@@ -11,6 +11,7 @@ import { join } from "path";
|
|
|
11
11
|
var CMDUSE_BIN_CANDIDATES = ["cmduse", "/opt/homebrew/bin/cmduse", "/usr/local/bin/cmduse"];
|
|
12
12
|
var MPC_BIN_CANDIDATES = ["mpc", join(homedir(), ".bun/bin/mpc"), "/opt/homebrew/bin/mpc"];
|
|
13
13
|
var OCUSE_BIN_CANDIDATES = ["ocuse", "/opt/homebrew/bin/ocuse", "/usr/local/bin/ocuse"];
|
|
14
|
+
var ARKUSE_BIN_CANDIDATES = ["arkuse", "/opt/homebrew/bin/arkuse", "/usr/local/bin/arkuse"];
|
|
14
15
|
|
|
15
16
|
// src/constants/cli.ts
|
|
16
17
|
var DEFAULT_ARGS = ["-1", "--plain"];
|
|
@@ -37,6 +38,11 @@ function ocuseCandidates(env = process.env) {
|
|
|
37
38
|
return candidates.filter((bin) => Boolean(bin));
|
|
38
39
|
}
|
|
39
40
|
var OCUSE_CANDIDATES = ocuseCandidates();
|
|
41
|
+
function arkuseCandidates(env = process.env) {
|
|
42
|
+
const candidates = [env.ARKUSE_BIN, ...ARKUSE_BIN_CANDIDATES];
|
|
43
|
+
return candidates.filter((bin) => Boolean(bin));
|
|
44
|
+
}
|
|
45
|
+
var ARKUSE_CANDIDATES = arkuseCandidates();
|
|
40
46
|
function splitCliArgs(input) {
|
|
41
47
|
const out = [];
|
|
42
48
|
let cur = "";
|
|
@@ -92,6 +98,9 @@ function buildMpcArgs(arg) {
|
|
|
92
98
|
function ocuseArgs(arg) {
|
|
93
99
|
return arg !== undefined && arg.trim() !== "" ? arg : "-1";
|
|
94
100
|
}
|
|
101
|
+
function arkuseArgs(arg) {
|
|
102
|
+
return arg !== undefined && arg.trim() !== "" ? arg : "-1";
|
|
103
|
+
}
|
|
95
104
|
function stderrTail(text) {
|
|
96
105
|
const lines = text.trimEnd().split(`
|
|
97
106
|
`);
|
|
@@ -203,15 +212,34 @@ async function runOcuse(arg, opts = {}) {
|
|
|
203
212
|
cause: last
|
|
204
213
|
});
|
|
205
214
|
}
|
|
215
|
+
async function runArkuse(arg, opts = {}) {
|
|
216
|
+
const args = resolveArgs(arg, splitCliArgs);
|
|
217
|
+
const candidates = opts.candidates ?? ARKUSE_CANDIDATES;
|
|
218
|
+
let last;
|
|
219
|
+
for (const bin of candidates) {
|
|
220
|
+
try {
|
|
221
|
+
return await runOnce(bin, args, opts, "arkuse");
|
|
222
|
+
} catch (e) {
|
|
223
|
+
last = e;
|
|
224
|
+
if (e?.code !== "ENOENT")
|
|
225
|
+
throw e;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
throw new Error(`arkuse binary not found (install: brew install JeffreyJYZ/tap/cmduse)${last instanceof Error && last.message !== last.name ? ` \u2014 ${last.message}` : ""}`, {
|
|
229
|
+
cause: last
|
|
230
|
+
});
|
|
231
|
+
}
|
|
206
232
|
|
|
207
233
|
// src/constants/providers.ts
|
|
208
234
|
var PROVIDER_ID_PREFIX = "command-code";
|
|
209
235
|
var GO_PROVIDER_ID = "opencode-go";
|
|
210
236
|
var ZEN_PROVIDER_ID = "opencode";
|
|
211
237
|
var ZEN_PROVIDER_PREFIX = "opencode-zen";
|
|
238
|
+
var ARK_PROVIDER_ID = "agent-plan";
|
|
212
239
|
var TUI_ID = "command-code.tui";
|
|
213
240
|
var CMD_USAGE_COMMAND_ID = "command-code.cmd-usage";
|
|
214
241
|
var OCUSE_USAGE_COMMAND_ID = "command-code.ocuse-usage";
|
|
242
|
+
var ARKUSE_USAGE_COMMAND_ID = "command-code.arkuse-usage";
|
|
215
243
|
|
|
216
244
|
// src/sidebar/panel.tsx
|
|
217
245
|
import { createComponent as _$createComponent } from "@opentui/solid";
|
|
@@ -926,6 +954,7 @@ var CHILD_TIMEOUT_MS = 30000;
|
|
|
926
954
|
var MODELS_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
927
955
|
var CATALOG_CACHE_TTL_MS = 60 * 60 * 1000;
|
|
928
956
|
var PREFS_CACHE_MS = 5000;
|
|
957
|
+
var ARK_SNAPSHOT_TTL_MS = 60000;
|
|
929
958
|
|
|
930
959
|
// src/sidebar/prefs.ts
|
|
931
960
|
var cached;
|
|
@@ -2095,13 +2124,196 @@ function minPlan(id) {
|
|
|
2095
2124
|
return MODEL_CATALOG[id]?.minPlan ?? null;
|
|
2096
2125
|
}
|
|
2097
2126
|
|
|
2127
|
+
// src/sidebar/ark.ts
|
|
2128
|
+
function totals(value) {
|
|
2129
|
+
const v = value ?? {};
|
|
2130
|
+
const num = (key) => typeof v[key] === "number" ? v[key] : 0;
|
|
2131
|
+
return {
|
|
2132
|
+
afp: num("afp"),
|
|
2133
|
+
requests: num("requests"),
|
|
2134
|
+
tokensIn: num("tokensIn"),
|
|
2135
|
+
tokensOut: num("tokensOut"),
|
|
2136
|
+
cacheRead: num("cacheRead")
|
|
2137
|
+
};
|
|
2138
|
+
}
|
|
2139
|
+
function meter(value) {
|
|
2140
|
+
const v = value && typeof value === "object" ? value : {};
|
|
2141
|
+
return {
|
|
2142
|
+
status: typeof v.status === "string" ? v.status : "ok",
|
|
2143
|
+
percent: typeof v.percent === "number" ? v.percent : 0,
|
|
2144
|
+
used: typeof v.used === "number" ? v.used : 0,
|
|
2145
|
+
total: typeof v.total === "number" ? v.total : 0,
|
|
2146
|
+
resetAt: typeof v.resetAt === "number" ? v.resetAt : undefined
|
|
2147
|
+
};
|
|
2148
|
+
}
|
|
2149
|
+
function storeWindow(value) {
|
|
2150
|
+
if (!value || typeof value !== "object")
|
|
2151
|
+
return;
|
|
2152
|
+
const v = value;
|
|
2153
|
+
return {
|
|
2154
|
+
quota: typeof v.quota === "number" ? v.quota : undefined,
|
|
2155
|
+
percent: typeof v.percent === "number" ? v.percent : undefined,
|
|
2156
|
+
resetAt: typeof v.resetAt === "number" ? v.resetAt : undefined
|
|
2157
|
+
};
|
|
2158
|
+
}
|
|
2159
|
+
function parseArkJson(text) {
|
|
2160
|
+
let body;
|
|
2161
|
+
try {
|
|
2162
|
+
body = JSON.parse(text);
|
|
2163
|
+
} catch {
|
|
2164
|
+
body = {};
|
|
2165
|
+
}
|
|
2166
|
+
const account = body.account ?? {};
|
|
2167
|
+
const models = new Map;
|
|
2168
|
+
const rawModels = body.models ?? {};
|
|
2169
|
+
for (const [id, raw] of Object.entries(rawModels)) {
|
|
2170
|
+
const m = raw ?? {};
|
|
2171
|
+
models.set(id, {
|
|
2172
|
+
id,
|
|
2173
|
+
coef: typeof m.coef === "number" ? m.coef : 0,
|
|
2174
|
+
fiveHour: totals(m.fiveHour),
|
|
2175
|
+
weekly: totals(m.weekly),
|
|
2176
|
+
month: totals(m.month)
|
|
2177
|
+
});
|
|
2178
|
+
}
|
|
2179
|
+
const summary = body.summary ?? {};
|
|
2180
|
+
const windows = body.windows ?? {};
|
|
2181
|
+
return {
|
|
2182
|
+
plan: typeof body.plan === "string" ? body.plan : "medium",
|
|
2183
|
+
profile: typeof body.profile === "string" ? body.profile : undefined,
|
|
2184
|
+
periodStart: typeof body.periodStart === "number" ? body.periodStart : undefined,
|
|
2185
|
+
periodEndAt: typeof body.periodEndAt === "number" ? body.periodEndAt : undefined,
|
|
2186
|
+
summary: {
|
|
2187
|
+
...totals(summary),
|
|
2188
|
+
yuan: typeof summary.yuan === "number" ? summary.yuan : undefined
|
|
2189
|
+
},
|
|
2190
|
+
fiveHour: totals(body.fiveHour),
|
|
2191
|
+
weekly: totals(body.weekly),
|
|
2192
|
+
month: totals(body.monthly),
|
|
2193
|
+
daily: body.daily ? totals(body.daily) : undefined,
|
|
2194
|
+
windows: body.windows ? {
|
|
2195
|
+
fiveHour: storeWindow(windows.fiveHour),
|
|
2196
|
+
weekly: storeWindow(windows.weekly),
|
|
2197
|
+
monthly: storeWindow(windows.monthly)
|
|
2198
|
+
} : undefined,
|
|
2199
|
+
account: body.account ? {
|
|
2200
|
+
fiveHour: meter(account.fiveHour),
|
|
2201
|
+
daily: account.daily ? meter(account.daily) : undefined,
|
|
2202
|
+
weekly: meter(account.weekly),
|
|
2203
|
+
monthly: meter(account.monthly)
|
|
2204
|
+
} : undefined,
|
|
2205
|
+
accountError: typeof body.accountError === "string" && body.accountError ? body.accountError : undefined,
|
|
2206
|
+
afpPerRequest: typeof body.afpPerRequest === "number" ? body.afpPerRequest : undefined,
|
|
2207
|
+
reconciledPct: typeof body.reconciledPct === "number" ? body.reconciledPct : undefined,
|
|
2208
|
+
models
|
|
2209
|
+
};
|
|
2210
|
+
}
|
|
2211
|
+
function monthPeriod(usage) {
|
|
2212
|
+
const {
|
|
2213
|
+
periodStart,
|
|
2214
|
+
periodEndAt
|
|
2215
|
+
} = usage;
|
|
2216
|
+
if (typeof periodStart !== "number" || typeof periodEndAt !== "number")
|
|
2217
|
+
return;
|
|
2218
|
+
const durSecs = Math.round((periodEndAt - periodStart) / 1000);
|
|
2219
|
+
if (durSecs <= 0)
|
|
2220
|
+
return;
|
|
2221
|
+
return {
|
|
2222
|
+
resetAt: periodEndAt,
|
|
2223
|
+
durSecs
|
|
2224
|
+
};
|
|
2225
|
+
}
|
|
2226
|
+
function afp(value) {
|
|
2227
|
+
return `${grouped(Math.round(value))} AFP`;
|
|
2228
|
+
}
|
|
2229
|
+
function grouped(value) {
|
|
2230
|
+
return String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
2231
|
+
}
|
|
2232
|
+
function brief(value) {
|
|
2233
|
+
const rounded = Math.round(value);
|
|
2234
|
+
const trim = (n) => n.toFixed(1).replace(/\.0$/, "");
|
|
2235
|
+
if (rounded >= 1e6)
|
|
2236
|
+
return `${trim(rounded / 1e6)}M`;
|
|
2237
|
+
if (rounded >= 1000)
|
|
2238
|
+
return `${trim(rounded / 1000)}K`;
|
|
2239
|
+
return String(rounded);
|
|
2240
|
+
}
|
|
2241
|
+
function meterRows(label, meter, local, now, durSecs) {
|
|
2242
|
+
const pct = meter.percent;
|
|
2243
|
+
const pctText = Number.isInteger(pct) ? String(pct) : pct.toFixed(1);
|
|
2244
|
+
return windowRows(label, {
|
|
2245
|
+
cap: meter.total > 0 ? meter.total : undefined,
|
|
2246
|
+
used: meter.used,
|
|
2247
|
+
resetAt: meter.resetAt,
|
|
2248
|
+
sharePct: pct,
|
|
2249
|
+
exceeded: pct >= 100 || meter.status !== "ok"
|
|
2250
|
+
}, now, durSecs, `${afp(local.afp)} local${local.requests > 0 ? ` \xB7 ${count(local.requests)} req` : ""}`, (used, cap) => `${brief(used)}/${brief(cap)} (${pctText}%)`);
|
|
2251
|
+
}
|
|
2252
|
+
function localRows(label, totals, window, now, durSecs) {
|
|
2253
|
+
const quota = window?.quota;
|
|
2254
|
+
const percent = window?.percent;
|
|
2255
|
+
if (typeof quota !== "number" || quota <= 0 || typeof percent !== "number") {
|
|
2256
|
+
const detail = totals.requests > 0 ? ` \xB7 ${count(totals.requests)} req` : "";
|
|
2257
|
+
return [[label, `${afp(totals.afp)}${detail}`, "base"]];
|
|
2258
|
+
}
|
|
2259
|
+
const pctText = percent.toFixed(1);
|
|
2260
|
+
return windowRows(label, {
|
|
2261
|
+
cap: quota,
|
|
2262
|
+
used: totals.afp,
|
|
2263
|
+
resetAt: window?.resetAt,
|
|
2264
|
+
sharePct: percent,
|
|
2265
|
+
exceeded: percent >= 100
|
|
2266
|
+
}, now, durSecs, `${count(totals.requests)} req`, (used, cap) => `${brief(used)}/${brief(cap)} (${pctText}% est.)`);
|
|
2267
|
+
}
|
|
2268
|
+
function arkRows(usage, fallbackName) {
|
|
2269
|
+
if (!usage)
|
|
2270
|
+
return [];
|
|
2271
|
+
const now = Date.now();
|
|
2272
|
+
const rows = [["Plan", clip(`${usage.plan} \xB7 AFP plan${usage.profile ? ` \xB7 ${usage.profile}` : ""}`, valueWidth("Plan")), "base", true]];
|
|
2273
|
+
if (usage.accountError) {
|
|
2274
|
+
rows.push(["", clip(`usage API: ${usage.accountError}`, valueWidth("")), "warn"]);
|
|
2275
|
+
}
|
|
2276
|
+
const period = monthPeriod(usage);
|
|
2277
|
+
if (usage.account) {
|
|
2278
|
+
const account = usage.account;
|
|
2279
|
+
rows.push(...meterRows("5-hour", account.fiveHour, usage.fiveHour, now, FIVE_HOUR_SECS));
|
|
2280
|
+
if (account.daily) {
|
|
2281
|
+
rows.push(...meterRows("Daily", account.daily, usage.daily ?? usage.month, now, 86400));
|
|
2282
|
+
}
|
|
2283
|
+
rows.push(...meterRows("Weekly", account.weekly, usage.weekly, now, WEEKLY_SECS));
|
|
2284
|
+
rows.push(...meterRows("Monthly", account.monthly, usage.month, now, period?.durSecs ?? 0));
|
|
2285
|
+
} else {
|
|
2286
|
+
const windows = usage.windows;
|
|
2287
|
+
rows.push(...localRows("5-hour", usage.fiveHour, windows?.fiveHour, now, FIVE_HOUR_SECS));
|
|
2288
|
+
rows.push(...localRows("Weekly", usage.weekly, windows?.weekly, now, WEEKLY_SECS));
|
|
2289
|
+
rows.push(...localRows("Monthly", usage.month, windows?.monthly, now, period?.durSecs ?? 0));
|
|
2290
|
+
}
|
|
2291
|
+
const yuan = typeof usage.summary.yuan === "number" ? ` (${money(usage.summary.yuan)})` : "";
|
|
2292
|
+
rows.push(["Period", clip(`${count(usage.summary.requests)} requests \xB7 ${afp(usage.summary.afp)}${yuan}`, valueWidth("Period")), "base"]);
|
|
2293
|
+
if (typeof usage.afpPerRequest === "number" && usage.afpPerRequest > 0) {
|
|
2294
|
+
const drift = typeof usage.reconciledPct === "number" ? ` \xB7 ${usage.reconciledPct >= 0 ? "+" : ""}${usage.reconciledPct.toFixed(1)}% vs meter` : "";
|
|
2295
|
+
rows.push(["", clip(`${usage.afpPerRequest.toFixed(0)} AFP/request${drift}`, valueWidth("")), "muted"]);
|
|
2296
|
+
}
|
|
2297
|
+
rows.push(separator());
|
|
2298
|
+
if (!fallbackName)
|
|
2299
|
+
return rows;
|
|
2300
|
+
const model = usage.models.get(fallbackName);
|
|
2301
|
+
rows.push(["Model", clip(fallbackName, valueWidth("Model")), "strong", true]);
|
|
2302
|
+
rows.push(["AFP (this model)", model ? clip(`${afp(model.month.afp)} \xB7 ${count(model.month.requests)} req`, valueWidth("AFP (this model)")) : "no usage in this period", "base"]);
|
|
2303
|
+
if (model && usage.summary.afp > 0) {
|
|
2304
|
+
const share = model.month.afp / usage.summary.afp * 100;
|
|
2305
|
+
rows.push(["", clip(`${share.toFixed(1)}% of the period \xB7 coef ${model.coef.toFixed(2)}`, Math.min(ROW_WIDTH, valueWidth(""))), "muted"]);
|
|
2306
|
+
}
|
|
2307
|
+
return rows;
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2098
2310
|
// src/sidebar/data.ts
|
|
2099
2311
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
2100
2312
|
import { homedir as homedir3 } from "os";
|
|
2101
2313
|
import { dirname, join as join3 } from "path";
|
|
2102
2314
|
|
|
2103
2315
|
// src/sidebar/zen.ts
|
|
2104
|
-
function
|
|
2316
|
+
function totals2(value) {
|
|
2105
2317
|
const v = value ?? {};
|
|
2106
2318
|
const num = (key) => typeof v[key] === "number" ? v[key] : 0;
|
|
2107
2319
|
return {
|
|
@@ -2110,7 +2322,7 @@ function totals(value) {
|
|
|
2110
2322
|
tokens: num("tokens")
|
|
2111
2323
|
};
|
|
2112
2324
|
}
|
|
2113
|
-
function
|
|
2325
|
+
function meter2(value) {
|
|
2114
2326
|
const v = value ?? {};
|
|
2115
2327
|
return {
|
|
2116
2328
|
status: typeof v.status === "string" ? v.status : "ok",
|
|
@@ -2133,9 +2345,9 @@ function parseZenJson(text) {
|
|
|
2133
2345
|
id: raw.id,
|
|
2134
2346
|
provider: typeof raw.provider === "string" ? raw.provider : "",
|
|
2135
2347
|
limit: typeof raw.limit === "number" ? raw.limit : undefined,
|
|
2136
|
-
fiveHour:
|
|
2137
|
-
weekly:
|
|
2138
|
-
month:
|
|
2348
|
+
fiveHour: totals2(raw.fiveHour),
|
|
2349
|
+
weekly: totals2(raw.weekly),
|
|
2350
|
+
month: totals2(raw.month)
|
|
2139
2351
|
});
|
|
2140
2352
|
}
|
|
2141
2353
|
const top = body.totals ?? {};
|
|
@@ -2144,20 +2356,20 @@ function parseZenJson(text) {
|
|
|
2144
2356
|
periodEndAt: typeof body.periodEndAt === "number" ? body.periodEndAt : undefined,
|
|
2145
2357
|
source: typeof body.source === "string" ? body.source : undefined,
|
|
2146
2358
|
account: body.account ? {
|
|
2147
|
-
rolling:
|
|
2148
|
-
weekly:
|
|
2149
|
-
monthly:
|
|
2359
|
+
rolling: meter2(body.account.rolling),
|
|
2360
|
+
weekly: meter2(body.account.weekly),
|
|
2361
|
+
monthly: meter2(body.account.monthly)
|
|
2150
2362
|
} : undefined,
|
|
2151
2363
|
accountError: typeof body.accountError === "string" && body.accountError ? body.accountError : undefined,
|
|
2152
2364
|
totals: {
|
|
2153
|
-
fiveHour:
|
|
2154
|
-
weekly:
|
|
2155
|
-
month:
|
|
2365
|
+
fiveHour: totals2(top.fiveHour),
|
|
2366
|
+
weekly: totals2(top.weekly),
|
|
2367
|
+
month: totals2(top.month)
|
|
2156
2368
|
},
|
|
2157
2369
|
models
|
|
2158
2370
|
};
|
|
2159
2371
|
}
|
|
2160
|
-
function
|
|
2372
|
+
function monthPeriod2(usage) {
|
|
2161
2373
|
const {
|
|
2162
2374
|
periodStart,
|
|
2163
2375
|
periodEndAt
|
|
@@ -2213,7 +2425,7 @@ function zenRows(usage, meta, modelUsage, session, fallbackName, windows) {
|
|
|
2213
2425
|
const mine = usage.models.get(modelKey(fallbackName ?? "")) ?? (meta ? usage.models.get(modelKey(meta.name)) : undefined);
|
|
2214
2426
|
const limit = oc?.allowance ?? mine?.limit;
|
|
2215
2427
|
const cap = mine ? limit : undefined;
|
|
2216
|
-
const period =
|
|
2428
|
+
const period = monthPeriod2(usage);
|
|
2217
2429
|
if (usage.account) {
|
|
2218
2430
|
rows.push(...zenMeterRows("5-hour", usage.account.rolling, now, FIVE_HOUR_SECS, usage.totals.fiveHour.cost));
|
|
2219
2431
|
rows.push(...zenMeterRows("Weekly", usage.account.weekly, now, WEEKLY_SECS, usage.totals.weekly.cost));
|
|
@@ -2370,6 +2582,19 @@ async function loadUsage() {
|
|
|
2370
2582
|
async function loadZen(plan = OC_PLAN_DEFAULT) {
|
|
2371
2583
|
return parseZenJson(await runOcuse(zenArgs(plan), SIDEBAR_OPTS));
|
|
2372
2584
|
}
|
|
2585
|
+
var arkCache;
|
|
2586
|
+
async function loadArk() {
|
|
2587
|
+
const now = Date.now();
|
|
2588
|
+
if (arkCache && now - arkCache.at < ARK_SNAPSHOT_TTL_MS) {
|
|
2589
|
+
return arkCache.usage;
|
|
2590
|
+
}
|
|
2591
|
+
const usage = parseArkJson(await runArkuse("-1 --json", SIDEBAR_OPTS));
|
|
2592
|
+
arkCache = {
|
|
2593
|
+
at: now,
|
|
2594
|
+
usage
|
|
2595
|
+
};
|
|
2596
|
+
return usage;
|
|
2597
|
+
}
|
|
2373
2598
|
|
|
2374
2599
|
// src/sidebar/usageDb.ts
|
|
2375
2600
|
import { Database } from "bun:sqlite";
|
|
@@ -2561,16 +2786,20 @@ function sessionKind(providerID) {
|
|
|
2561
2786
|
return "go";
|
|
2562
2787
|
if (providerID === ZEN_PROVIDER_ID || providerID.startsWith(ZEN_PROVIDER_PREFIX))
|
|
2563
2788
|
return "zen";
|
|
2789
|
+
if (providerID.startsWith(ARK_PROVIDER_ID))
|
|
2790
|
+
return "ark";
|
|
2564
2791
|
return "other";
|
|
2565
2792
|
}
|
|
2566
2793
|
function shows(kind) {
|
|
2567
|
-
return kind === "ours" || kind === "go" || kind === "zen";
|
|
2794
|
+
return kind === "ours" || kind === "go" || kind === "zen" || kind === "ark";
|
|
2568
2795
|
}
|
|
2569
2796
|
function panelTitle(kind) {
|
|
2570
2797
|
if (kind === "ours")
|
|
2571
2798
|
return "Command Code";
|
|
2572
2799
|
if (kind === "zen")
|
|
2573
2800
|
return "OpenCode Zen";
|
|
2801
|
+
if (kind === "ark")
|
|
2802
|
+
return "Volcengine ARK";
|
|
2574
2803
|
return "OpenCode Go";
|
|
2575
2804
|
}
|
|
2576
2805
|
var lastSnapshot;
|
|
@@ -2613,9 +2842,17 @@ function rememberZen(usage) {
|
|
|
2613
2842
|
function seededZen() {
|
|
2614
2843
|
return lastZen;
|
|
2615
2844
|
}
|
|
2845
|
+
var lastArk;
|
|
2846
|
+
function rememberArk(usage) {
|
|
2847
|
+
lastArk = usage;
|
|
2848
|
+
}
|
|
2849
|
+
function seededArk() {
|
|
2850
|
+
return lastArk;
|
|
2851
|
+
}
|
|
2616
2852
|
function useRows(activeModelId, providerID, sessionID) {
|
|
2617
2853
|
const [usage, setUsage] = createSignal(seededRows());
|
|
2618
2854
|
const [zen, setZen] = createSignal(seededZen());
|
|
2855
|
+
const [ark, setArk] = createSignal(seededArk());
|
|
2619
2856
|
const [meta, setMeta] = createSignal(seededMeta());
|
|
2620
2857
|
const [modelUsage, setModelUsage] = createSignal(lastModelUsage);
|
|
2621
2858
|
const [sessionUsage, setSessionUsage] = createSignal();
|
|
@@ -2671,6 +2908,10 @@ function useRows(activeModelId, providerID, sessionID) {
|
|
|
2671
2908
|
setZen(snapshot);
|
|
2672
2909
|
refreshModelUsage(activeModelId());
|
|
2673
2910
|
refreshModelWindows(activeModelId());
|
|
2911
|
+
} else if (kind === "ark") {
|
|
2912
|
+
const snapshot = await loadArk();
|
|
2913
|
+
rememberArk(snapshot);
|
|
2914
|
+
setArk(snapshot);
|
|
2674
2915
|
}
|
|
2675
2916
|
} catch {} finally {
|
|
2676
2917
|
inFlight = false;
|
|
@@ -2715,6 +2956,9 @@ function useRows(activeModelId, providerID, sessionID) {
|
|
|
2715
2956
|
if (kind === "go" || kind === "zen") {
|
|
2716
2957
|
return zenRows(zen(), found, usageFor(id), sessionUsage(), fallbackName, modelWindows());
|
|
2717
2958
|
}
|
|
2959
|
+
if (kind === "ark") {
|
|
2960
|
+
return arkRows(ark(), fallbackName);
|
|
2961
|
+
}
|
|
2718
2962
|
const model = found ? {
|
|
2719
2963
|
...found,
|
|
2720
2964
|
tier: found.tier ?? (id ? tierFor(id) : undefined),
|
|
@@ -2834,8 +3078,35 @@ var commandCodeTui = {
|
|
|
2834
3078
|
message: text.trimEnd()
|
|
2835
3079
|
});
|
|
2836
3080
|
}
|
|
3081
|
+
}, {
|
|
3082
|
+
id: ARKUSE_USAGE_COMMAND_ID,
|
|
3083
|
+
title: "Volcengine ARK usage",
|
|
3084
|
+
group: "Command Code",
|
|
3085
|
+
slash: {
|
|
3086
|
+
name: "arkuse-usage",
|
|
3087
|
+
arguments: true
|
|
3088
|
+
},
|
|
3089
|
+
enabled: () => true,
|
|
3090
|
+
suggested: true,
|
|
3091
|
+
run: async (input) => {
|
|
3092
|
+
let text;
|
|
3093
|
+
try {
|
|
3094
|
+
text = await runArkuse(arkuseArgs(input));
|
|
3095
|
+
} catch (error) {
|
|
3096
|
+
ctx.ui.toast.show({
|
|
3097
|
+
title: "arkuse-usage failed",
|
|
3098
|
+
message: error instanceof Error ? error.message : String(error),
|
|
3099
|
+
variant: "error"
|
|
3100
|
+
});
|
|
3101
|
+
return;
|
|
3102
|
+
}
|
|
3103
|
+
await ctx.ui.dialog.alert({
|
|
3104
|
+
title: "Volcengine ARK usage",
|
|
3105
|
+
message: text.trimEnd()
|
|
3106
|
+
});
|
|
3107
|
+
}
|
|
2837
3108
|
}],
|
|
2838
|
-
bindings: [CMD_USAGE_COMMAND_ID, OCUSE_USAGE_COMMAND_ID]
|
|
3109
|
+
bindings: [CMD_USAGE_COMMAND_ID, OCUSE_USAGE_COMMAND_ID, ARKUSE_USAGE_COMMAND_ID]
|
|
2839
3110
|
}));
|
|
2840
3111
|
}
|
|
2841
3112
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jeffreyjyz/opencode-command-code",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.19",
|
|
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",
|