@jeffreyjyz/opencode-command-code 0.2.9 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/catalog.d.ts +29 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3257 -17
- package/dist/provider/index.d.ts +22 -0
- package/dist/provider/stream.d.ts +21 -0
- package/dist/provider/wire.d.ts +22 -0
- package/dist/sidebar/windows.d.ts +10 -0
- package/dist/tui.d.ts +3 -3
- package/dist/tui.js +25 -8
- package/dist/v2.d.ts +12 -5
- package/package.json +9 -6
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { LanguageModelV3 } from "@ai-sdk/provider";
|
|
2
|
+
import { type WireLane } from "./wire";
|
|
3
|
+
export declare const DEFAULT_BASE_URL = "https://api.commandcode.ai";
|
|
4
|
+
export interface CommandCodeProviderOptions {
|
|
5
|
+
/** Bearer key; the v2 host passes the resolved connection credential here. */
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
baseURL?: string;
|
|
8
|
+
/** Extra headers (host-supplied), merged last. */
|
|
9
|
+
headers?: Record<string, string>;
|
|
10
|
+
/** Reasoning effort the host wants (`providerOptions.commandcode.reasoning`). */
|
|
11
|
+
reasoningEffort?: string;
|
|
12
|
+
/** Injected for tests. */
|
|
13
|
+
fetch?: typeof fetch;
|
|
14
|
+
}
|
|
15
|
+
export interface CommandCodeProvider {
|
|
16
|
+
languageModel(modelId: string): LanguageModelV3;
|
|
17
|
+
}
|
|
18
|
+
/** Claude models use the Anthropic wire; everything else chat completions. */
|
|
19
|
+
export declare function laneOf(modelId: string): WireLane;
|
|
20
|
+
/** True when the model advertises image input; the caller passes the table in. */
|
|
21
|
+
export type ImagesFor = (modelId: string) => boolean;
|
|
22
|
+
export declare function createCommandCode(options?: CommandCodeProviderOptions, images?: ImagesFor): CommandCodeProvider;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { LanguageModelV3FinishReason, LanguageModelV3StreamPart, LanguageModelV3Usage } from "@ai-sdk/provider";
|
|
2
|
+
type Part = LanguageModelV3StreamPart;
|
|
3
|
+
/** Split an SSE byte stream into JSON events, tolerating partial chunks. */
|
|
4
|
+
export declare function sseDecoder(onEvent: (event: Record<string, unknown>) => void): (text: string) => void;
|
|
5
|
+
/** Wire stop reason → unified v3 finish reason; unknown reasons completed. */
|
|
6
|
+
export declare function finishReason(raw: string | undefined): LanguageModelV3FinishReason;
|
|
7
|
+
/** Anthropic `message_start`/`message_delta` usage → v3 usage. */
|
|
8
|
+
export declare function anthropicUsage(raw: Record<string, unknown>): LanguageModelV3Usage;
|
|
9
|
+
/** OpenAI usage → v3 usage (`prompt_tokens_details.cached_tokens` is cache read). */
|
|
10
|
+
export declare function openaiUsage(raw: Record<string, unknown>): LanguageModelV3Usage;
|
|
11
|
+
export interface Reducer {
|
|
12
|
+
/** Feed one parsed SSE event; returns the parts it produced. */
|
|
13
|
+
feed(event: Record<string, unknown>): Part[];
|
|
14
|
+
/** Close open parts when the transport ends (abort/error). */
|
|
15
|
+
close(): Part[];
|
|
16
|
+
}
|
|
17
|
+
/** Anthropic Messages reducer. */
|
|
18
|
+
export declare function anthropicReducer(): Reducer;
|
|
19
|
+
/** OpenAI Chat Completions reducer. */
|
|
20
|
+
export declare function openaiReducer(): Reducer;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { LanguageModelV3Prompt } from "@ai-sdk/provider";
|
|
2
|
+
export type WireLane = "anthropic" | "openai";
|
|
3
|
+
/** The subset of tools we serialize (V3 FunctionTool already matches). */
|
|
4
|
+
export interface WireTool {
|
|
5
|
+
name: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
inputSchema: unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface WireOptions {
|
|
10
|
+
maxOutputTokens?: number;
|
|
11
|
+
temperature?: number;
|
|
12
|
+
tools?: WireTool[];
|
|
13
|
+
/** Wire extension both gates honour (`reasoning_effort`). */
|
|
14
|
+
reasoningEffort?: string;
|
|
15
|
+
/** Whether the model advertises image input (catalog-derived). */
|
|
16
|
+
images: boolean;
|
|
17
|
+
}
|
|
18
|
+
/** Anthropic body: POST /provider/v1/messages. */
|
|
19
|
+
export declare function anthropicBody(model: string, prompt: LanguageModelV3Prompt, options: WireOptions): Record<string, unknown>;
|
|
20
|
+
/** OpenAI body: POST /provider/v1/chat/completions. */
|
|
21
|
+
export declare function openaiBody(model: string, prompt: LanguageModelV3Prompt, options: WireOptions): Record<string, unknown>;
|
|
22
|
+
export declare function requestBody(lane: WireLane, model: string, prompt: LanguageModelV3Prompt, options: WireOptions): Record<string, unknown>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** 5-hour window length in seconds. Mirrors cmduse_core::FIVE_HOUR_SECS. */
|
|
2
|
+
export declare const FIVE_HOUR_SECS: number;
|
|
3
|
+
/** Weekly window length in seconds. Mirrors cmduse_core::WEEKLY_SECS. */
|
|
4
|
+
export declare const WEEKLY_SECS: number;
|
|
5
|
+
/**
|
|
6
|
+
* Percentage of a rolling window that has elapsed, or undefined when the
|
|
7
|
+
* window has not started (or has no reset time). `nowSecs` is whole seconds —
|
|
8
|
+
* the same unit cmduse-core's vectors pin.
|
|
9
|
+
*/
|
|
10
|
+
export declare function elapsedPct(resetAtMs: number | undefined, durSecs: number, nowSecs: number): number | undefined;
|
package/dist/tui.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @jsxImportSource @opentui/solid */
|
|
2
2
|
import type { RGBA } from "@opentui/core";
|
|
3
|
-
import { Plugin } from "@opencode/plugin/tui";
|
|
3
|
+
import type { Plugin as TuiPluginNs } from "@opencode/plugin/tui";
|
|
4
4
|
interface V1Api {
|
|
5
5
|
slots: {
|
|
6
6
|
register: (config: {
|
|
@@ -31,10 +31,10 @@ interface V1Api {
|
|
|
31
31
|
}
|
|
32
32
|
/** v1 half — snake_case slot map registered through `api.slots`. */
|
|
33
33
|
export declare const tui: (api: V1Api) => Promise<void>;
|
|
34
|
-
export declare const commandCodeTui:
|
|
34
|
+
export declare const commandCodeTui: TuiPluginNs.Definition;
|
|
35
35
|
declare const _default: {
|
|
36
36
|
tui: (api: V1Api) => Promise<void>;
|
|
37
37
|
id: string;
|
|
38
|
-
setup: (context:
|
|
38
|
+
setup: (context: TuiPluginNs.Context) => Promise<TuiPluginNs.Cleanup | void> | TuiPluginNs.Cleanup | void;
|
|
39
39
|
};
|
|
40
40
|
export default _default;
|
package/dist/tui.js
CHANGED
|
@@ -8,7 +8,6 @@ import { createComponent as _$createComponent } from "@opentui/solid";
|
|
|
8
8
|
import { createTextNode as _$createTextNode } from "@opentui/solid";
|
|
9
9
|
import { insertNode as _$insertNode } from "@opentui/solid";
|
|
10
10
|
import { createElement as _$createElement } from "@opentui/solid";
|
|
11
|
-
import { Plugin } from "@opencode/plugin/tui";
|
|
12
11
|
import { For, Show, createEffect, createMemo, createSignal, onCleanup } from "solid-js";
|
|
13
12
|
|
|
14
13
|
// src/cli.ts
|
|
@@ -389,6 +388,22 @@ function canonicalizeModelId(model) {
|
|
|
389
388
|
return findKnown(stripDate(model)) ?? model;
|
|
390
389
|
}
|
|
391
390
|
|
|
391
|
+
// src/sidebar/windows.ts
|
|
392
|
+
var FIVE_HOUR_SECS = 5 * 3600;
|
|
393
|
+
var WEEKLY_SECS = 7 * 86400;
|
|
394
|
+
function elapsedPct(resetAtMs, durSecs, nowSecs) {
|
|
395
|
+
if (typeof resetAtMs !== "number" || !Number.isFinite(resetAtMs))
|
|
396
|
+
return;
|
|
397
|
+
const resetSecs = Math.floor(resetAtMs / 1000);
|
|
398
|
+
if (resetSecs < durSecs)
|
|
399
|
+
return;
|
|
400
|
+
const start = resetSecs - durSecs;
|
|
401
|
+
if (nowSecs < start)
|
|
402
|
+
return;
|
|
403
|
+
const pct = (nowSecs - start) / durSecs * 100;
|
|
404
|
+
return Math.round(Math.min(100, Math.max(0, pct)));
|
|
405
|
+
}
|
|
406
|
+
|
|
392
407
|
// src/sidebar/rows.ts
|
|
393
408
|
var TIER_DISPLAY = {
|
|
394
409
|
opensource: "open source",
|
|
@@ -425,13 +440,15 @@ function until(epoch, now = Date.now()) {
|
|
|
425
440
|
const days = Math.floor(hours / 24);
|
|
426
441
|
return hours % 24 ? `${days}d ${hours % 24}h` : `${days}d`;
|
|
427
442
|
}
|
|
428
|
-
function windowRow(label, w, now) {
|
|
443
|
+
function windowRow(label, w, now, durSecs) {
|
|
429
444
|
if (!w || typeof w.cap !== "number" || w.cap <= 0)
|
|
430
445
|
return;
|
|
431
446
|
const used = typeof w.used === "number" ? w.used : 0;
|
|
432
447
|
const pct = Math.round(used / w.cap * 100);
|
|
448
|
+
const elapsed = elapsedPct(w.resetAt, durSecs, Math.floor(now / 1000));
|
|
433
449
|
const reset = until(w.resetAt, now);
|
|
434
|
-
|
|
450
|
+
const parts = [`${money(used)} / ${money(w.cap)} (${pct}%)`, ...elapsed === undefined ? [] : [`${elapsed}% elapsed`], ...reset ? [`resets ${reset}`] : []];
|
|
451
|
+
return [label, parts.join(" \xB7 ")];
|
|
435
452
|
}
|
|
436
453
|
function usageRows(usage, now = Date.now()) {
|
|
437
454
|
if (!usage)
|
|
@@ -446,10 +463,10 @@ function usageRows(usage, now = Date.now()) {
|
|
|
446
463
|
const pct = usage.monthlyCap > 0 ? Math.round(used / usage.monthlyCap * 100) : 0;
|
|
447
464
|
rows.push(["Monthly", `${money(used)} / ${money(usage.monthlyCap)} (${pct}%)`]);
|
|
448
465
|
}
|
|
449
|
-
const five = windowRow("5-hour", usage.fiveHour, now);
|
|
466
|
+
const five = windowRow("5-hour", usage.fiveHour, now, FIVE_HOUR_SECS);
|
|
450
467
|
if (five)
|
|
451
468
|
rows.push(five);
|
|
452
|
-
const week = windowRow("Weekly", usage.weekly, now);
|
|
469
|
+
const week = windowRow("Weekly", usage.weekly, now, WEEKLY_SECS);
|
|
453
470
|
if (week)
|
|
454
471
|
rows.push(week);
|
|
455
472
|
if (typeof usage.requests === "number" || typeof usage.cost === "number") {
|
|
@@ -468,7 +485,7 @@ function modelRows(meta, usage) {
|
|
|
468
485
|
const rows = [["Model", meta.name]];
|
|
469
486
|
if (usage) {
|
|
470
487
|
const spent = usage.cost > 0 ? ` \xB7 ${money(usage.cost)}` : "";
|
|
471
|
-
rows.push(["Usage", `${count(usage.requests)} req${spent}`]);
|
|
488
|
+
rows.push(["Usage (this model)", `${count(usage.requests)} req${spent}`]);
|
|
472
489
|
}
|
|
473
490
|
if (meta.tier)
|
|
474
491
|
rows.push(["Tier", TIER_DISPLAY[meta.tier]]);
|
|
@@ -764,7 +781,7 @@ function PanelV2(props) {
|
|
|
764
781
|
muted: () => ctx.theme.text.subdued
|
|
765
782
|
});
|
|
766
783
|
}
|
|
767
|
-
var commandCodeTui =
|
|
784
|
+
var commandCodeTui = {
|
|
768
785
|
id: ID,
|
|
769
786
|
setup(ctx) {
|
|
770
787
|
ctx.ui.slot({
|
|
@@ -815,7 +832,7 @@ var commandCodeTui = Plugin.define({
|
|
|
815
832
|
}
|
|
816
833
|
});
|
|
817
834
|
}
|
|
818
|
-
}
|
|
835
|
+
};
|
|
819
836
|
var tui_default = {
|
|
820
837
|
...commandCodeTui,
|
|
821
838
|
tui
|
package/dist/v2.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Plugin } from "@opencode/plugin";
|
|
1
|
+
import type { Plugin as PluginNs } from "@opencode/plugin";
|
|
2
2
|
import { type CmdModel } from "./models";
|
|
3
3
|
export declare const PLUGIN_ID = "command-code";
|
|
4
4
|
export declare const PROVIDER_BASE = "https://api.commandcode.ai/provider/v1";
|
|
@@ -15,9 +15,10 @@ type Lane = {
|
|
|
15
15
|
reasoningField?: string;
|
|
16
16
|
};
|
|
17
17
|
export type { Lane };
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
*
|
|
18
|
+
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').";
|
|
19
|
+
/** API/known model → v2 Model.Info. Capabilities, variants and $/1M cost all
|
|
20
|
+
* come from the generated catalog (the listing API publishes none of them);
|
|
21
|
+
* only the open lane needs the reasoning round-trip field. */
|
|
21
22
|
export declare function toV2Model(m: CmdModel, lane: Lane): unknown;
|
|
22
23
|
/** Instant static seed from gating.json's known model ids, split by wire lane.
|
|
23
24
|
* Replaced by the gated live list once the background fetch lands; also the
|
|
@@ -37,4 +38,10 @@ type CredentialContext = {
|
|
|
37
38
|
* back to CMD_API_KEY / ~/.commandcode/auth.json. Resolved per call — a
|
|
38
39
|
* /connect mid-session must be picked up. */
|
|
39
40
|
export declare function credentialKey(ctx: CredentialContext): Promise<string | undefined>;
|
|
40
|
-
|
|
41
|
+
/**
|
|
42
|
+
* opencode validates the plugin *by decoding* the default export against its
|
|
43
|
+
* own `Plugin` interface (identity `define` on both sides), so the package is
|
|
44
|
+
* only needed for types. Keeps the runtime dependency surface to opencode's
|
|
45
|
+
* own rewrite list (@opentui/*, solid-js).
|
|
46
|
+
*/
|
|
47
|
+
export declare const commandCodeV2: PluginNs.Plugin;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jeffreyjyz/opencode-command-code",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
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",
|
|
@@ -13,18 +13,21 @@
|
|
|
13
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
14
|
"test": "bun test",
|
|
15
15
|
"typecheck": "tsc --noEmit",
|
|
16
|
-
"build:tui": "bun scripts/build-tui.ts"
|
|
16
|
+
"build:tui": "bun scripts/build-tui.ts",
|
|
17
|
+
"extract:catalog": "bun scripts/extract-catalog.ts"
|
|
17
18
|
},
|
|
18
19
|
"dependencies": {
|
|
19
|
-
"@opencode-ai/plugin": "*",
|
|
20
|
-
"@opencode/plugin": "^2.0.11",
|
|
21
20
|
"@opentui/core": "^0.5.4",
|
|
22
21
|
"@opentui/solid": "^0.5.4",
|
|
23
|
-
"solid-js": "1.9.12"
|
|
22
|
+
"solid-js": "1.9.12",
|
|
23
|
+
"zod": "4.1.8"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@types/bun": "latest",
|
|
27
|
-
"typescript": "^5"
|
|
27
|
+
"typescript": "^5",
|
|
28
|
+
"@opencode-ai/plugin": "*",
|
|
29
|
+
"@opencode/plugin": "^2.0.11",
|
|
30
|
+
"@ai-sdk/provider": "3.0.8"
|
|
28
31
|
},
|
|
29
32
|
"files": [
|
|
30
33
|
"dist",
|