@jeffreyjyz/opencode-command-code 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/access.d.ts CHANGED
@@ -1,20 +1,10 @@
1
1
  import { canonicalizeModelId, PLAN_RULES } from "./gating";
2
-
3
2
  export { canonicalizeModelId, PLAN_RULES };
4
3
  export type PlanLike = {
5
- planId: string;
6
- purchasedCredits: number;
7
- freeCredits: number;
4
+ planId: string;
5
+ purchasedCredits: number;
6
+ freeCredits: number;
8
7
  };
9
- export declare function evaluateModelAccess(
10
- model: string,
11
- plan: PlanLike,
12
- ): {
13
- allowed: boolean;
8
+ export declare function evaluateModelAccess(model: string, plan: PlanLike): {
9
+ allowed: boolean;
14
10
  };
15
- /** Filter a live model list down to what the plan allows. */
16
- export declare function filterByPlan<
17
- T extends {
18
- id: string;
19
- },
20
- >(models: T[], plan: PlanLike): T[];
package/dist/api.d.ts CHANGED
@@ -1,59 +1,53 @@
1
+ export declare const API_BASE = "https://api.commandcode.ai";
1
2
  export declare function authHeaders(key: string): Record<string, string>;
2
- export declare function getJson(
3
- path: string,
4
- key: string,
5
- timeoutMs?: number,
6
- ): Promise<unknown>;
3
+ export declare function getJson(path: string, key: string, timeoutMs?: number): Promise<unknown>;
7
4
  export type Whoami = {
8
- success: boolean;
9
- user?: {
10
- name?: string;
11
- userName?: string;
12
- };
5
+ success: boolean;
6
+ user?: {
7
+ name?: string;
8
+ userName?: string;
9
+ };
13
10
  };
14
11
  export type SubData = {
15
- status: string;
16
- planId: string;
17
- currentPeriodStart?: string;
18
- currentPeriodEnd?: string;
12
+ status: string;
13
+ planId: string;
14
+ currentPeriodStart?: string;
15
+ currentPeriodEnd?: string;
19
16
  };
20
17
  export type Window = {
21
- used: number;
22
- cap: number;
23
- exceeded?: boolean;
24
- resetAt?: number;
18
+ used: number;
19
+ cap: number;
20
+ exceeded?: boolean;
21
+ resetAt?: number;
25
22
  };
26
23
  export type Credits = {
27
- credits: {
28
- monthlyCredits: number;
29
- purchasedCredits?: number;
30
- freeCredits?: number;
31
- };
32
- windowLimits?: {
33
- fiveHour?: Window;
34
- weekly?: Window;
35
- };
24
+ credits: {
25
+ monthlyCredits: number;
26
+ purchasedCredits?: number;
27
+ freeCredits?: number;
28
+ };
29
+ windowLimits?: {
30
+ fiveHour?: Window;
31
+ weekly?: Window;
32
+ };
36
33
  };
37
34
  export type Summary = {
38
- totalCount?: number;
39
- totalCost?: number;
40
- successRate?: number;
41
- totalTokensIn?: number;
42
- totalTokensOut?: number;
35
+ totalCount?: number;
36
+ totalCost?: number;
37
+ successRate?: number;
38
+ totalTokensIn?: number;
39
+ totalTokensOut?: number;
43
40
  };
44
41
  export type ProviderModelsResp = {
45
- data: Array<{
46
- id: string;
47
- name?: string;
48
- context_length?: number;
49
- owned_by?: string;
50
- }>;
42
+ data: Array<{
43
+ id: string;
44
+ name?: string;
45
+ context_length?: number;
46
+ owned_by?: string;
47
+ }>;
51
48
  };
52
49
  export declare function whoami(key: string): Promise<Whoami>;
53
50
  export declare function subscriptions(key: string): Promise<SubData>;
54
51
  export declare function credits(key: string): Promise<Credits>;
55
52
  export declare function usageSummary(key: string): Promise<Summary>;
56
- export declare function providerModels(
57
- key: string,
58
- ): Promise<ProviderModelsResp>;
59
- export declare function getPlanInfo(key: string): Promise<SubData>;
53
+ export declare function providerModels(key: string): Promise<ProviderModelsResp>;
package/dist/gating.d.ts CHANGED
@@ -1,18 +1,17 @@
1
- export declare const OPEN_SOURCE: "opensource";
2
- export declare const PREMIUM: "premium";
3
1
  export type Category = "opensource" | "premium";
4
2
  /** model id -> category (models absent from this table have unknown category) */
5
3
  export declare const MODEL_CATEGORIES: Record<string, Category>;
6
4
  /** planId -> access rules; plan ids absent from this table get everything */
7
- export declare const PLAN_RULES: Record<
8
- string,
9
- {
10
- allowedCategories: Category[];
11
- blockedModels: string[];
12
- }
13
- >;
14
- /** canonical known model ids (lowercase compare) */
15
- export declare const KNOWN_MODELS: string[];
16
- /** deprecated/aliased model id -> canonical id */
17
- export declare const MODEL_ALIASES: Record<string, string>;
5
+ export declare const PLAN_RULES: Record<string, {
6
+ allowedCategories: Category[];
7
+ blockedModels: string[];
8
+ }>;
9
+ /** Models the API hard-blocks (403 MODEL_NOT_IN_PLAN) per plan, beyond the
10
+ * category rules. Empirically probed — the CLI bundle misses these because it
11
+ * tracks category via serving lane, not per-model plan entitlements. */
12
+ export declare const HARD_BLOCKED: Record<string, string[]>;
18
13
  export declare function canonicalizeModelId(model: string): string;
14
+ /** Bare model id with any provider qualifier stripped: everything after the
15
+ * FIRST colon ("anthropic:claude-opus-5" → "claude-opus-5"). Matches
16
+ * cmduse-core's `bare_model`; a model id that itself contains ':' keeps it. */
17
+ export declare function bareModel(blocked: string): string;
package/dist/index.js CHANGED
@@ -48,9 +48,6 @@ async function usageSummary(key) {
48
48
  async function providerModels(key) {
49
49
  return getJson("/provider/v1/models", key, 15000);
50
50
  }
51
- async function getPlanInfo(key) {
52
- return subscriptions(key);
53
- }
54
51
 
55
52
  // src/key.ts
56
53
  import { readFile } from "fs/promises";
@@ -72,198 +69,248 @@ async function resolveKey(getAuth) {
72
69
  } catch {}
73
70
  throw new Error("No Command Code API key found. Run /connect, choose Command Code, and paste your key (or `cmd login` in a terminal, or set CMD_API_KEY).");
74
71
  }
75
-
76
- // src/gating.ts
77
- var MODEL_CATEGORIES = {
78
- "claude-sonnet-5": "premium",
79
- "claude-sonnet-4-6": "premium",
80
- "claude-fable-5": "premium",
81
- "claude-opus-5": "premium",
82
- "claude-opus-4-8": "premium",
83
- "claude-opus-4-7": "premium",
84
- "claude-haiku-4-5-20251001": "premium",
85
- "gpt-5.6-sol": "opensource",
86
- "gpt-5.6-terra": "premium",
87
- "gpt-5.6-luna": "opensource",
88
- "gpt-5.5": "premium",
89
- "gpt-5.4": "premium",
90
- "gpt-5.3-codex": "premium",
91
- "gpt-5.4-mini": "premium",
92
- "google/gemini-3.5-flash": "premium",
93
- "google/gemini-3.1-flash-lite": "premium",
94
- "sakana/fugu-ultra": "premium",
95
- "meta/muse-spark-1.1": "premium",
96
- "meta/muse-spark-1.2": "opensource",
97
- "meta/muse-spark-1.2-contributor": "opensource",
98
- "xai/grok-4.5": "opensource",
99
- "xai/grok-4.6": "opensource",
100
- "google/gemini-3.7-flash": "opensource",
101
- "z-ai/glm-5.3-flash": "opensource",
102
- "tencent/hy4-preview": "opensource",
103
- "tencent/hy3-paid": "opensource",
104
- "tencent/Hy3": "opensource",
105
- "MiniMaxAI/MiniMax-M3-Free": "opensource",
106
- "MiniMaxAI/MiniMax-M3": "opensource",
107
- "MiniMaxAI/MiniMax-M2.7": "opensource",
108
- "minimax/minimax-m3-free": "opensource",
109
- "minimax/minimax-m2.7-free": "opensource",
110
- "MiniMaxAI/MiniMax-M2.5": "opensource",
111
- "deepseek/deepseek-v4-pro": "opensource",
112
- "deepseek/deepseek-v4-flash": "opensource",
113
- "moonshotai/Kimi-K3": "opensource",
114
- "moonshotai/Kimi-K2.7-Code": "opensource",
115
- "moonshotai/Kimi-K2.7-Code-Highspeed": "opensource",
116
- "moonshotai/Kimi-K2.6": "opensource",
117
- "moonshotai/Kimi-K2.5": "opensource",
118
- "zai-org/GLM-5.3": "opensource",
119
- "zai-org/GLM-5.2": "opensource",
120
- "zai-org/GLM-5.2-Fast": "opensource",
121
- "zai-org/GLM-5.1": "opensource",
122
- "zai-org/GLM-5": "opensource",
123
- "xiaomi/mimo-v2.5-pro": "opensource",
124
- "xiaomi/mimo-v2.5": "opensource",
125
- "Qwen/Qwen3.6-Max-Preview": "opensource",
126
- "Qwen/Qwen3.6-Plus": "opensource",
127
- "Qwen/Qwen3.7-Max": "opensource",
128
- "Qwen/Qwen3.7-Plus": "opensource",
129
- "Qwen/Qwen3.8-Max": "opensource",
130
- "Qwen/Qwen3.8-27B": "opensource",
131
- "Qwen/Qwen3.8-Flash": "opensource",
132
- "Qwen/Qwen3.7-Flash": "opensource",
133
- "stepfun/Step-3.7-Flash": "opensource",
134
- "stepfun/Step-3.5-Flash": "opensource",
135
- "nvidia/nemotron-3-ultra-550b-a55b": "opensource",
136
- "thinkingmachines/inkling": "opensource"
137
- };
138
- var PLAN_RULES = {
139
- "individual-go": {
140
- allowedCategories: ["opensource"],
141
- blockedModels: [
142
- "vercel-ai-gateway:meta/muse-spark-1.2",
143
- "vercel-ai-gateway:xai/grok-4.6",
144
- "openrouter:google/gemini-3.7-flash",
145
- "vercel-ai-gateway:gpt-5.6-sol"
146
- ]
72
+ // ../core/gating.json
73
+ var gating_default = {
74
+ categories: {
75
+ "claude-sonnet-5": "premium",
76
+ "claude-sonnet-4-6": "premium",
77
+ "claude-fable-5": "premium",
78
+ "claude-opus-5": "premium",
79
+ "claude-opus-4-8": "premium",
80
+ "claude-opus-4-7": "premium",
81
+ "claude-haiku-4-5-20251001": "premium",
82
+ "gpt-5.6-sol": "opensource",
83
+ "gpt-5.6-terra": "premium",
84
+ "gpt-5.6-luna": "opensource",
85
+ "gpt-5.5": "premium",
86
+ "gpt-5.4": "premium",
87
+ "gpt-5.3-codex": "premium",
88
+ "gpt-5.4-mini": "premium",
89
+ "google/gemini-3.5-flash": "premium",
90
+ "google/gemini-3.1-flash-lite": "premium",
91
+ "sakana/fugu-ultra": "premium",
92
+ "meta/muse-spark-1.1": "premium",
93
+ "meta/muse-spark-1.2": "opensource",
94
+ "meta/muse-spark-1.2-contributor": "opensource",
95
+ "xai/grok-4.5": "opensource",
96
+ "xai/grok-4.6": "opensource",
97
+ "google/gemini-3.7-flash": "opensource",
98
+ "z-ai/glm-5.3-flash": "opensource",
99
+ "tencent/hy4-preview": "opensource",
100
+ "tencent/hy3-paid": "opensource",
101
+ "tencent/Hy3": "opensource",
102
+ "MiniMaxAI/MiniMax-M3-Free": "opensource",
103
+ "MiniMaxAI/MiniMax-M3": "opensource",
104
+ "MiniMaxAI/MiniMax-M2.7": "opensource",
105
+ "minimax/minimax-m3-free": "opensource",
106
+ "minimax/minimax-m2.7-free": "opensource",
107
+ "MiniMaxAI/MiniMax-M2.5": "opensource",
108
+ "deepseek/deepseek-v4-pro": "opensource",
109
+ "deepseek/deepseek-v4-flash": "opensource",
110
+ "moonshotai/Kimi-K3": "opensource",
111
+ "moonshotai/Kimi-K2.7-Code": "opensource",
112
+ "moonshotai/Kimi-K2.7-Code-Highspeed": "opensource",
113
+ "moonshotai/Kimi-K2.6": "opensource",
114
+ "moonshotai/Kimi-K2.5": "opensource",
115
+ "zai-org/GLM-5.3": "opensource",
116
+ "zai-org/GLM-5.2": "opensource",
117
+ "zai-org/GLM-5.2-Fast": "opensource",
118
+ "zai-org/GLM-5.1": "opensource",
119
+ "zai-org/GLM-5": "opensource",
120
+ "xiaomi/mimo-v2.5-pro": "opensource",
121
+ "xiaomi/mimo-v2.5": "opensource",
122
+ "Qwen/Qwen3.6-Max-Preview": "opensource",
123
+ "Qwen/Qwen3.6-Plus": "opensource",
124
+ "Qwen/Qwen3.7-Max": "opensource",
125
+ "Qwen/Qwen3.7-Plus": "opensource",
126
+ "Qwen/Qwen3.8-Max": "opensource",
127
+ "Qwen/Qwen3.8-27B": "opensource",
128
+ "Qwen/Qwen3.8-Flash": "opensource",
129
+ "Qwen/Qwen3.7-Flash": "opensource",
130
+ "stepfun/Step-3.7-Flash": "opensource",
131
+ "stepfun/Step-3.5-Flash": "opensource",
132
+ "nvidia/nemotron-3-ultra-550b-a55b": "opensource",
133
+ "thinkingmachines/inkling": "opensource"
147
134
  },
148
- "individual-goat": {
149
- allowedCategories: ["opensource"],
150
- blockedModels: []
135
+ plans: {
136
+ "individual-go": {
137
+ allowedCategories: [
138
+ "opensource"
139
+ ],
140
+ blockedModels: [
141
+ "vercel-ai-gateway:meta/muse-spark-1.2",
142
+ "vercel-ai-gateway:xai/grok-4.6",
143
+ "openrouter:google/gemini-3.7-flash",
144
+ "vercel-ai-gateway:gpt-5.6-sol"
145
+ ]
146
+ },
147
+ "individual-goat": {
148
+ allowedCategories: [
149
+ "opensource"
150
+ ],
151
+ blockedModels: []
152
+ },
153
+ "individual-pro": {
154
+ allowedCategories: [
155
+ "premium",
156
+ "opensource"
157
+ ],
158
+ blockedModels: [
159
+ "anthropic:claude-fable-5",
160
+ "anthropic:claude-opus-5",
161
+ "anthropic:claude-opus-4-8",
162
+ "anthropic:claude-opus-4-7",
163
+ "anthropic:claude-opus-4-6",
164
+ "anthropic:claude-opus-4-5-20251101",
165
+ "vercel-ai-gateway:sakana/fugu-ultra"
166
+ ]
167
+ },
168
+ "individual-pro-v1": {
169
+ allowedCategories: [
170
+ "premium",
171
+ "opensource"
172
+ ],
173
+ blockedModels: [
174
+ "anthropic:claude-fable-5",
175
+ "anthropic:claude-opus-5",
176
+ "anthropic:claude-opus-4-8",
177
+ "anthropic:claude-opus-4-7",
178
+ "anthropic:claude-opus-4-6",
179
+ "anthropic:claude-opus-4-5-20251101",
180
+ "vercel-ai-gateway:sakana/fugu-ultra"
181
+ ]
182
+ },
183
+ "individual-provider": {
184
+ allowedCategories: [
185
+ "premium",
186
+ "opensource"
187
+ ],
188
+ blockedModels: []
189
+ },
190
+ "individual-max": {
191
+ allowedCategories: [
192
+ "premium",
193
+ "opensource"
194
+ ],
195
+ blockedModels: []
196
+ },
197
+ "individual-ultra": {
198
+ allowedCategories: [
199
+ "premium",
200
+ "opensource"
201
+ ],
202
+ blockedModels: []
203
+ },
204
+ "teams-pro": {
205
+ allowedCategories: [
206
+ "premium",
207
+ "opensource"
208
+ ],
209
+ blockedModels: []
210
+ }
151
211
  },
152
- "individual-pro": {
153
- allowedCategories: ["premium", "opensource"],
154
- blockedModels: [
155
- "anthropic:claude-fable-5",
156
- "anthropic:claude-opus-5",
157
- "anthropic:claude-opus-4-8",
158
- "anthropic:claude-opus-4-7",
159
- "anthropic:claude-opus-4-6",
160
- "anthropic:claude-opus-4-5-20251101",
161
- "vercel-ai-gateway:sakana/fugu-ultra"
162
- ]
212
+ knownModels: [
213
+ "claude-sonnet-4-6",
214
+ "claude-fable-5",
215
+ "claude-opus-5",
216
+ "claude-opus-4-8",
217
+ "claude-opus-4-7",
218
+ "claude-haiku-4-5-20251001",
219
+ "gpt-5.6-sol",
220
+ "gpt-5.6-terra",
221
+ "gpt-5.6-luna",
222
+ "gpt-5.5",
223
+ "gpt-5.4",
224
+ "gpt-5.3-codex",
225
+ "gpt-5.4-mini",
226
+ "moonshotai/Kimi-K3",
227
+ "thinkingmachines/inkling",
228
+ "thinkingmachines/inkling-small",
229
+ "deepseek/deepseek-v4-pro",
230
+ "deepseek/deepseek-v4-flash",
231
+ "deepseek/deepseek-v4-flash-vision-exp",
232
+ "moonshotai/Kimi-K2.7-Code",
233
+ "moonshotai/Kimi-K2.7-Code-Highspeed",
234
+ "moonshotai/Kimi-K2.6",
235
+ "moonshotai/Kimi-K2.5",
236
+ "zai-org/GLM-5.3",
237
+ "z-ai/glm-5.3-flash",
238
+ "zai-org/GLM-5.2",
239
+ "zai-org/GLM-5.2-Fast",
240
+ "zai-org/GLM-5.1",
241
+ "zai-org/GLM-5",
242
+ "xiaomi/mimo-v2.5-pro",
243
+ "xiaomi/mimo-v2.5",
244
+ "stepfun/Step-3.7-Flash",
245
+ "stepfun/Step-3.5-Flash",
246
+ "tencent/hy4-preview",
247
+ "tencent/hy3-paid",
248
+ "tencent/Hy3",
249
+ "google/gemini-3.7-flash",
250
+ "google/gemini-3.6-flash",
251
+ "google/gemini-3.5-flash",
252
+ "google/gemini-3.5-flash-lite",
253
+ "google/gemini-3.1-flash-lite",
254
+ "sakana/fugu-ultra",
255
+ "xai/grok-4.5",
256
+ "xai/grok-4.6",
257
+ "meta/muse-spark-1.1",
258
+ "meta/muse-spark-1.2",
259
+ "meta/muse-spark-1.2-contributor",
260
+ "nvidia/nemotron-3-ultra-550b-a55b",
261
+ "poolside/laguna-s-2.1-free",
262
+ "inclusionai/ling-3.0-flash-free",
263
+ "minimax/minimax-m3-free",
264
+ "minimax/minimax-m2.7-free",
265
+ "claude-sonnet-5",
266
+ "MiniMaxAI/MiniMax-M3-Free",
267
+ "MiniMaxAI/MiniMax-M3",
268
+ "MiniMaxAI/MiniMax-M2.7",
269
+ "MiniMaxAI/MiniMax-M2.5",
270
+ "Qwen/Qwen3.6-Max-Preview",
271
+ "Qwen/Qwen3.6-Plus",
272
+ "Qwen/Qwen3.7-Max",
273
+ "Qwen/Qwen3.7-Plus",
274
+ "Qwen/Qwen3.8-Max",
275
+ "Qwen/Qwen3.8-27B",
276
+ "Qwen/Qwen3.8-Flash",
277
+ "Qwen/Qwen3.7-Flash"
278
+ ],
279
+ aliases: {
280
+ "claude-sonnet-4-20250514": "claude-sonnet-4-6",
281
+ "claude-sonnet-4-5-20250929": "claude-sonnet-4-6",
282
+ "claude-opus-4-5-20251101": "claude-opus-4-7",
283
+ "claude-opus-4-6": "claude-opus-4-7",
284
+ "claude-haiku-4-5": "claude-haiku-4-5-20251001"
163
285
  },
164
- "individual-pro-v1": {
165
- allowedCategories: ["premium", "opensource"],
166
- blockedModels: [
167
- "anthropic:claude-fable-5",
168
- "anthropic:claude-opus-5",
169
- "anthropic:claude-opus-4-8",
170
- "anthropic:claude-opus-4-7",
171
- "anthropic:claude-opus-4-6",
172
- "anthropic:claude-opus-4-5-20251101",
173
- "vercel-ai-gateway:sakana/fugu-ultra"
286
+ hardBlocked: {
287
+ "individual-goat": [
288
+ "meta/muse-spark-1.1",
289
+ "google/gemini-3.5-flash",
290
+ "google/gemini-3.6-flash",
291
+ "google/gemini-3.5-flash-lite",
292
+ "google/gemini-3.1-flash-lite"
293
+ ],
294
+ "individual-go": [
295
+ "meta/muse-spark-1.1",
296
+ "google/gemini-3.5-flash",
297
+ "google/gemini-3.6-flash",
298
+ "google/gemini-3.5-flash-lite",
299
+ "google/gemini-3.1-flash-lite",
300
+ "meta/muse-spark-1.2",
301
+ "meta/muse-spark-1.2-contributor",
302
+ "meta/muse-spark-1.3",
303
+ "meta/muse-spark-1.3-contributor"
174
304
  ]
175
- },
176
- "individual-provider": {
177
- allowedCategories: ["premium", "opensource"],
178
- blockedModels: []
179
- },
180
- "individual-max": {
181
- allowedCategories: ["premium", "opensource"],
182
- blockedModels: []
183
- },
184
- "individual-ultra": {
185
- allowedCategories: ["premium", "opensource"],
186
- blockedModels: []
187
- },
188
- "teams-pro": {
189
- allowedCategories: ["premium", "opensource"],
190
- blockedModels: []
191
305
  }
192
306
  };
193
- var KNOWN_MODELS = [
194
- "claude-sonnet-4-6",
195
- "claude-fable-5",
196
- "claude-opus-5",
197
- "claude-opus-4-8",
198
- "claude-opus-4-7",
199
- "claude-haiku-4-5-20251001",
200
- "gpt-5.6-sol",
201
- "gpt-5.6-terra",
202
- "gpt-5.6-luna",
203
- "gpt-5.5",
204
- "gpt-5.4",
205
- "gpt-5.3-codex",
206
- "gpt-5.4-mini",
207
- "moonshotai/Kimi-K3",
208
- "thinkingmachines/inkling",
209
- "thinkingmachines/inkling-small",
210
- "deepseek/deepseek-v4-pro",
211
- "deepseek/deepseek-v4-flash",
212
- "deepseek/deepseek-v4-flash-vision-exp",
213
- "moonshotai/Kimi-K2.7-Code",
214
- "moonshotai/Kimi-K2.7-Code-Highspeed",
215
- "moonshotai/Kimi-K2.6",
216
- "moonshotai/Kimi-K2.5",
217
- "zai-org/GLM-5.3",
218
- "z-ai/glm-5.3-flash",
219
- "zai-org/GLM-5.2",
220
- "zai-org/GLM-5.2-Fast",
221
- "zai-org/GLM-5.1",
222
- "zai-org/GLM-5",
223
- "xiaomi/mimo-v2.5-pro",
224
- "xiaomi/mimo-v2.5",
225
- "stepfun/Step-3.7-Flash",
226
- "stepfun/Step-3.5-Flash",
227
- "tencent/hy4-preview",
228
- "tencent/hy3-paid",
229
- "tencent/Hy3",
230
- "google/gemini-3.7-flash",
231
- "google/gemini-3.6-flash",
232
- "google/gemini-3.5-flash",
233
- "google/gemini-3.5-flash-lite",
234
- "google/gemini-3.1-flash-lite",
235
- "sakana/fugu-ultra",
236
- "xai/grok-4.5",
237
- "xai/grok-4.6",
238
- "meta/muse-spark-1.1",
239
- "meta/muse-spark-1.2",
240
- "meta/muse-spark-1.2-contributor",
241
- "nvidia/nemotron-3-ultra-550b-a55b",
242
- "poolside/laguna-s-2.1-free",
243
- "inclusionai/ling-3.0-flash-free",
244
- "minimax/minimax-m3-free",
245
- "minimax/minimax-m2.7-free",
246
- "claude-sonnet-5",
247
- "MiniMaxAI/MiniMax-M3-Free",
248
- "MiniMaxAI/MiniMax-M3",
249
- "MiniMaxAI/MiniMax-M2.7",
250
- "MiniMaxAI/MiniMax-M2.5",
251
- "Qwen/Qwen3.6-Max-Preview",
252
- "Qwen/Qwen3.6-Plus",
253
- "Qwen/Qwen3.7-Max",
254
- "Qwen/Qwen3.7-Plus",
255
- "Qwen/Qwen3.8-Max",
256
- "Qwen/Qwen3.8-27B",
257
- "Qwen/Qwen3.8-Flash",
258
- "Qwen/Qwen3.7-Flash"
259
- ];
260
- var MODEL_ALIASES = {
261
- "claude-sonnet-4-20250514": "claude-sonnet-4-6",
262
- "claude-sonnet-4-5-20250929": "claude-sonnet-4-6",
263
- "claude-opus-4-5-20251101": "claude-opus-4-7",
264
- "claude-opus-4-6": "claude-opus-4-7",
265
- "claude-haiku-4-5": "claude-haiku-4-5-20251001"
266
- };
307
+
308
+ // src/gating.ts
309
+ var MODEL_CATEGORIES = gating_default.categories;
310
+ var PLAN_RULES = gating_default.plans;
311
+ var HARD_BLOCKED = gating_default.hardBlocked;
312
+ var KNOWN_MODELS = gating_default.knownModels;
313
+ var MODEL_ALIASES = gating_default.aliases;
267
314
  function findKnown(s) {
268
315
  const k = s.toLowerCase();
269
316
  return KNOWN_MODELS.find((m) => m.toLowerCase() === k);
@@ -278,28 +325,12 @@ function canonicalizeModelId(model) {
278
325
  return findKnown(aliased) ?? model;
279
326
  return findKnown(stripDate(model)) ?? model;
280
327
  }
328
+ function bareModel(blocked) {
329
+ const i = blocked.indexOf(":");
330
+ return i >= 0 ? blocked.slice(i + 1) : blocked;
331
+ }
281
332
 
282
333
  // src/access.ts
283
- var HARD_BLOCKED = {
284
- "individual-goat": [
285
- "meta/muse-spark-1.1",
286
- "google/gemini-3.5-flash",
287
- "google/gemini-3.6-flash",
288
- "google/gemini-3.5-flash-lite",
289
- "google/gemini-3.1-flash-lite"
290
- ],
291
- "individual-go": [
292
- "meta/muse-spark-1.1",
293
- "google/gemini-3.5-flash",
294
- "google/gemini-3.6-flash",
295
- "google/gemini-3.5-flash-lite",
296
- "google/gemini-3.1-flash-lite",
297
- "meta/muse-spark-1.2",
298
- "meta/muse-spark-1.2-contributor",
299
- "meta/muse-spark-1.3",
300
- "meta/muse-spark-1.3-contributor"
301
- ]
302
- };
303
334
  function evaluateModelAccess(model, plan) {
304
335
  if (plan.purchasedCredits > 0 || plan.freeCredits > 0)
305
336
  return { allowed: true };
@@ -315,19 +346,13 @@ function evaluateModelAccess(model, plan) {
315
346
  const category = MODEL_CATEGORIES[canonical] ?? siblingCategory(canonical);
316
347
  if (!category)
317
348
  return { allowed: true };
318
- const blocked = rules.blockedModels.some((b) => {
319
- const bare = b.includes(":") ? b.slice(b.indexOf(":") + 1) : b;
320
- return bare.toLowerCase() === canonical.toLowerCase();
321
- });
349
+ const blocked = rules.blockedModels.some((b) => bareModel(b).toLowerCase() === canonical.toLowerCase());
322
350
  if (blocked)
323
351
  return { allowed: false };
324
352
  if (!rules.allowedCategories.includes(category))
325
353
  return { allowed: false };
326
354
  return { allowed: true };
327
355
  }
328
- function filterByPlan(models, plan) {
329
- return models.filter((m) => evaluateModelAccess(m.id, plan).allowed);
330
- }
331
356
  var KNOWN_KEYS = Object.keys(MODEL_CATEGORIES);
332
357
  function siblingCategory(model) {
333
358
  const lower = model.toLowerCase();
@@ -356,12 +381,10 @@ function splitModels(models) {
356
381
  (isClaude(m.id) ? claude : open).push(m);
357
382
  return { claude, open };
358
383
  }
359
- async function loadModels(key, opts) {
384
+ async function loadModels(key) {
360
385
  let models;
361
- let source;
362
386
  if (cache && Date.now() - cache.at < CACHE_TTL_MS) {
363
387
  models = cache.models;
364
- source = "cache";
365
388
  } else {
366
389
  try {
367
390
  const resp = await providerModels(key);
@@ -371,35 +394,61 @@ async function loadModels(key, opts) {
371
394
  contextLength: m.context_length ?? 0
372
395
  }));
373
396
  cache = { at: Date.now(), models };
374
- source = "live";
375
- } catch {
397
+ } catch (e) {
376
398
  if (cache) {
377
399
  models = cache.models;
378
- source = "stale";
379
400
  } else {
380
- throw new Error("Could not fetch Command Code model list (https://api.commandcode.ai/provider/v1/models). Check network/API key.");
401
+ throw new Error("Could not fetch Command Code model list (https://api.commandcode.ai/provider/v1/models). Check network/API key.", { cause: e });
381
402
  }
382
403
  }
383
404
  }
384
405
  let plan = { planId: "", purchasedCredits: 0, freeCredits: 0 };
385
- let gatedOut = [];
386
- if (!opts?.skipPlan) {
387
- try {
388
- const sub = await getPlanInfo(key);
389
- const cr = await credits(key);
390
- plan = {
391
- planId: sub.planId,
392
- purchasedCredits: cr.credits.purchasedCredits ?? 0,
393
- freeCredits: cr.credits.freeCredits ?? 0
394
- };
395
- } catch {}
396
- }
397
- const allowed = filterByPlan(models, plan);
398
- const allowedIds = new Set(allowed.map((m) => m.id));
399
- gatedOut = models.filter((m) => !allowedIds.has(m.id)).map((m) => m.id);
406
+ try {
407
+ const [sub, cr] = await Promise.all([subscriptions(key), credits(key)]);
408
+ plan = {
409
+ planId: sub.planId,
410
+ purchasedCredits: cr.credits.purchasedCredits ?? 0,
411
+ freeCredits: cr.credits.freeCredits ?? 0
412
+ };
413
+ } catch {}
414
+ const allowed = models.filter((m) => evaluateModelAccess(m.id, plan).allowed);
400
415
  const { claude, open } = splitModels(allowed);
401
- return { claude, open, gatedOut, source };
416
+ return { claude, open };
402
417
  }
418
+ // ../core/plans.json
419
+ var plans_default = {
420
+ nameRules: [
421
+ { needles: ["enterprise"], name: "Enterprise" },
422
+ { needles: ["provider"], name: "Provider" },
423
+ { needles: ["team"], name: "Team Pro" },
424
+ { needles: ["max", "20"], name: "Max 20x" },
425
+ { needles: ["max"], name: "Max 10x" },
426
+ { needles: ["goat"], name: "GOAT" },
427
+ { needles: ["pro"], name: "Pro" },
428
+ { needles: ["go"], name: "Go" }
429
+ ],
430
+ defaultName: "Free",
431
+ caps: {
432
+ Enterprise: null,
433
+ Provider: null,
434
+ "Team Pro": 40,
435
+ "Max 20x": 300,
436
+ "Max 10x": 150,
437
+ GOAT: 70,
438
+ Pro: 80,
439
+ Go: 10,
440
+ Free: null
441
+ },
442
+ plans: [
443
+ { name: "Go", price: "$1", monthly: "$10", fiveHour: "$3", weekly: "$6" },
444
+ { name: "GOAT", price: "$10", monthly: "$70", fiveHour: "$14", weekly: "$35" },
445
+ { name: "Pro", price: "$20", monthly: "$80", fiveHour: "$16", weekly: "$40" },
446
+ { name: "Provider", price: "$15", monthly: "PAYG", fiveHour: "\u2014", weekly: "\u2014" },
447
+ { name: "Max 10x", price: "$100", monthly: "$150", fiveHour: "$45", weekly: "$90" },
448
+ { name: "Max 20x", price: "$200", monthly: "$300", fiveHour: "$90", weekly: "$180" },
449
+ { name: "Team Pro", price: "$40", monthly: "$40", fiveHour: "$12", weekly: "$24" }
450
+ ]
451
+ };
403
452
 
404
453
  // src/usage.ts
405
454
  var BAR_WIDTH = 12;
@@ -440,46 +489,34 @@ function relTime(resetAtMs, nowSecs) {
440
489
  return "<1m";
441
490
  }
442
491
  function parseIsoUtc(s) {
443
- const m = s.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d+)?)Z?/);
492
+ const m = s.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|[+-]\d{2}:?\d{2})?$/);
444
493
  if (!m)
445
494
  return;
446
- const [, y, mo, d, h, mi, sec] = m;
447
- return Date.UTC(+y, +mo - 1, +d, +h, +mi, Math.floor(+sec));
495
+ const [, y, mo, d, h, mi, sec, off] = m;
496
+ let offsetMs = 0;
497
+ if (off && off !== "Z") {
498
+ const sign = off.startsWith("-") ? -1 : 1;
499
+ const digits = off.slice(1).replace(":", "");
500
+ const hh = Number(digits.slice(0, 2));
501
+ const mm = Number(digits.slice(2, 4) || "0");
502
+ offsetMs = sign * (hh * 60 + mm) * 60000;
503
+ }
504
+ return Date.UTC(+y, +mo - 1, +d, +h, +mi, Math.floor(+sec)) - offsetMs;
448
505
  }
449
- var PLAN_CAPS = {
450
- "individual-go": 10,
451
- "individual-goat": 70,
452
- "individual-pro": 80,
453
- "individual-provider": 0,
454
- "individual-max": 150,
455
- "individual-ultra": 0,
456
- "teams-pro": 40
457
- };
506
+ var NAME_RULES = plans_default.nameRules;
507
+ var DEFAULT_NAME = plans_default.defaultName;
508
+ var CAPS = plans_default.caps;
509
+ var PLANS = plans_default.plans;
458
510
  function planMonthlyCap(planId) {
459
- if (planId.includes("max-20"))
460
- return 300;
461
- const cap = PLAN_CAPS[planId];
462
- return cap && cap > 0 ? cap : undefined;
511
+ return CAPS[planName(planId)] ?? undefined;
463
512
  }
464
513
  function planName(planId) {
465
514
  const id = planId.toLowerCase();
466
- if (id.includes("max-20"))
467
- return "Max 20x";
468
- if (id.includes("max"))
469
- return "Max 10x";
470
- if (id.includes("goat"))
471
- return "GOAT";
472
- if (id.includes("provider"))
473
- return "Provider";
474
- if (id.includes("ultra"))
475
- return "Ultra";
476
- if (id.includes("team"))
477
- return "Team Pro";
478
- if (id.includes("pro"))
479
- return "Pro";
480
- if (id.includes("go"))
481
- return "Go";
482
- return "Free";
515
+ for (const rule of NAME_RULES) {
516
+ if (rule.needles.every((n) => id.includes(n)))
517
+ return rule.name;
518
+ }
519
+ return DEFAULT_NAME;
483
520
  }
484
521
  function windowLine(label, w, nowSecs) {
485
522
  const status = w.exceeded ? " \xB7 **LIMIT EXCEEDED**" : "";
@@ -487,22 +524,13 @@ function windowLine(label, w, nowSecs) {
487
524
  `;
488
525
  }
489
526
  function plansTable(current) {
490
- const plans = [
491
- ["go", "Go", "$1", "$10", "$3", "$6"],
492
- ["goat", "GOAT", "$10", "$70", "$14", "$35"],
493
- ["pro", "Pro", "$20", "$80", "$16", "$40"],
494
- ["provider", "Provider", "$15", "PAYG", "\u2014", "\u2014"],
495
- ["max-10", "Max 10x", "$100", "$150", "$45", "$90"],
496
- ["max-20", "Max 20x", "$200", "$300", "$90", "$180"],
497
- ["team-pro", "Team Pro", "$40", "$40", "$12", "$24"]
498
- ];
499
527
  const mine = planName(current);
500
528
  let out = `| Plan | Price | Credits/mo | 5-hour | Weekly |
501
529
  |---|---|---|---|---|
502
530
  `;
503
- for (const [_id, name, price, monthly, h5, wk] of plans) {
531
+ for (const { name, price, monthly, fiveHour, weekly } of PLANS) {
504
532
  const mark = name === mine ? "**" : "";
505
- out += `| ${mark}${name}${mark} | ${price}/mo | ${monthly} | ${h5} | ${wk} |
533
+ out += `| ${mark}${name}${mark} | ${price}/mo | ${monthly} | ${fiveHour} | ${weekly} |
506
534
  `;
507
535
  }
508
536
  out += "\nWindows throttle only included monthly credits; on-demand (`/extra`) credits are never throttled.\n";
@@ -562,8 +590,16 @@ async function renderUsage(key) {
562
590
  }
563
591
 
564
592
  // src/index.ts
565
- var PROVIDER_BASE = "https://api.commandcode.ai/provider/v1";
566
- function toModelDefs(models, providerID, npm) {
593
+ var PROVIDER_BASE = `${API_BASE}/provider/v1`;
594
+ var MODEL_CAPABILITIES = {
595
+ temperature: true,
596
+ reasoning: true,
597
+ attachment: false,
598
+ toolcall: true,
599
+ input: { text: true, audio: false, image: false, video: false, pdf: false },
600
+ output: { text: true, audio: false, image: false, video: false, pdf: false }
601
+ };
602
+ function toModelDefs(models, providerID, npm, interleaved = false) {
567
603
  return Object.fromEntries(models.map((m) => [
568
604
  m.id,
569
605
  {
@@ -571,21 +607,14 @@ function toModelDefs(models, providerID, npm) {
571
607
  providerID,
572
608
  api: { id: m.id, url: PROVIDER_BASE, npm },
573
609
  name: m.name,
574
- capabilities: {
575
- temperature: true,
576
- reasoning: true,
577
- attachment: false,
578
- toolcall: true,
579
- interleaved: false,
580
- input: { text: true, audio: false, image: false, video: false, pdf: false },
581
- output: { text: true, audio: false, image: false, video: false, pdf: false }
582
- },
610
+ capabilities: { ...MODEL_CAPABILITIES, interleaved },
583
611
  cost: { input: 0, output: 0, cache: { read: 0, write: 0 } },
584
612
  limit: { context: m.contextLength || 128000, output: 32000 },
585
613
  status: "active",
586
614
  options: {},
587
615
  headers: {},
588
- release_date: ""
616
+ release_date: "",
617
+ ...interleaved !== false ? { interleaved } : {}
589
618
  }
590
619
  ]));
591
620
  }
@@ -634,10 +663,16 @@ var CommandCodePlugin = async (_input) => {
634
663
  let openKey;
635
664
  try {
636
665
  openKey = await resolveKey();
637
- split = await loadModels(openKey);
638
666
  } catch {}
667
+ if (openKey) {
668
+ try {
669
+ split = await loadModels(openKey);
670
+ } catch (e) {
671
+ console.warn("[command-code] model list unavailable:", e);
672
+ }
673
+ }
639
674
  const claudeDefs = split ? toModelDefs(split.claude, "command-code-anthropic", "@ai-sdk/anthropic") : {};
640
- const openDefs = split ? toModelDefs(split.open, "command-code-openai", "@ai-sdk/openai-compatible") : {};
675
+ const openDefs = split ? toModelDefs(split.open, "command-code-openai", "@ai-sdk/openai-compatible", { field: "reasoning_content" }) : {};
641
676
  const userAnthropic = existing("command-code-anthropic");
642
677
  cfg.provider["command-code-anthropic"] = {
643
678
  npm: userAnthropic.options ? undefined : "@ai-sdk/anthropic",
package/dist/key.d.ts CHANGED
@@ -1,8 +1,3 @@
1
- export declare function resolveKey(
2
- getAuth?: () => Promise<
3
- | {
4
- key: string;
5
- }
6
- | undefined
7
- >,
8
- ): Promise<string>;
1
+ export declare function resolveKey(getAuth?: () => Promise<{
2
+ key: string;
3
+ } | undefined>): Promise<string>;
package/dist/models.d.ts CHANGED
@@ -1,23 +1,16 @@
1
1
  export type CmdModel = {
2
- id: string;
3
- name: string;
4
- contextLength: number;
2
+ id: string;
3
+ name: string;
4
+ contextLength: number;
5
5
  };
6
6
  export type ModelSplit = {
7
- claude: CmdModel[];
8
- open: CmdModel[];
9
- gatedOut: string[];
10
- source: "live" | "cache" | "stale";
7
+ claude: CmdModel[];
8
+ open: CmdModel[];
11
9
  };
12
10
  export declare function isClaude(id: string): boolean;
13
11
  export declare function splitModels(models: CmdModel[]): {
14
- claude: CmdModel[];
15
- open: CmdModel[];
12
+ claude: CmdModel[];
13
+ open: CmdModel[];
16
14
  };
17
15
  /** Fetch live model list, apply plan gating, split by wire protocol. */
18
- export declare function loadModels(
19
- key: string,
20
- opts?: {
21
- skipPlan?: boolean;
22
- },
23
- ): Promise<ModelSplit>;
16
+ export declare function loadModels(key: string): Promise<ModelSplit>;
package/dist/usage.d.ts CHANGED
@@ -3,19 +3,12 @@ export declare function money(v: number): string;
3
3
  export declare function compact(n: number): string;
4
4
  export declare function bar(used: number, cap: number): string;
5
5
  export declare function pctStr(used: number, cap: number): string;
6
- export declare function relTime(
7
- resetAtMs: number | undefined,
8
- nowSecs: number,
9
- ): string;
10
- /** ISO date → epoch ms (UTC, no offset handling — off by hours at most). */
6
+ export declare function relTime(resetAtMs: number | undefined, nowSecs: number): string;
7
+ /** ISO 8601 → epoch ms. Handles trailing Z or a ±HH:MM / ±HHMM offset. */
11
8
  export declare function parseIsoUtc(s: string): number | undefined;
12
9
  export declare function planMonthlyCap(planId: string): number | undefined;
13
10
  export declare function planName(planId: string): string;
14
- export declare function windowLine(
15
- label: string,
16
- w: Window,
17
- nowSecs: number,
18
- ): string;
11
+ export declare function windowLine(label: string, w: Window, nowSecs: number): string;
19
12
  export declare function plansTable(current: string): string;
20
13
  /** Fetch billing data in parallel and render the markdown dashboard. */
21
14
  export declare function renderUsage(key: string): Promise<string>;
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@jeffreyjyz/opencode-command-code",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
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.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "scripts": {
9
- "build": "bun build src/index.ts --outdir dist --target bun --external @opencode-ai/plugin --external @opencode-ai/sdk && tsc --emitDeclarationOnly --declaration --outDir dist",
9
+ "build": "bun build src/index.ts --outdir dist --target bun --external @opencode-ai/plugin --external @opencode-ai/sdk && tsc -p tsconfig.build.json",
10
10
  "test": "bun test",
11
11
  "extract": "bun run scripts/extract-gating.ts",
12
12
  "typecheck": "tsc --noEmit"
@@ -18,7 +18,7 @@
18
18
  "@types/bun": "latest",
19
19
  "typescript": "^5"
20
20
  },
21
- "files": ["dist", "README.md", "LICENSE"],
21
+ "files": ["dist", "LICENSE"],
22
22
  "keywords": ["opencode", "command-code", "plugin", "provider", "ai-sdk"],
23
23
  "license": "MIT",
24
24
  "publishConfig": {