@jeffreyjyz/opencode-command-code 0.1.1 → 0.1.2

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,13 @@
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;
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);
@@ -280,26 +327,6 @@ function canonicalizeModelId(model) {
280
327
  }
281
328
 
282
329
  // 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
330
  function evaluateModelAccess(model, plan) {
304
331
  if (plan.purchasedCredits > 0 || plan.freeCredits > 0)
305
332
  return { allowed: true };
@@ -325,9 +352,6 @@ function evaluateModelAccess(model, plan) {
325
352
  return { allowed: false };
326
353
  return { allowed: true };
327
354
  }
328
- function filterByPlan(models, plan) {
329
- return models.filter((m) => evaluateModelAccess(m.id, plan).allowed);
330
- }
331
355
  var KNOWN_KEYS = Object.keys(MODEL_CATEGORIES);
332
356
  function siblingCategory(model) {
333
357
  const lower = model.toLowerCase();
@@ -356,12 +380,10 @@ function splitModels(models) {
356
380
  (isClaude(m.id) ? claude : open).push(m);
357
381
  return { claude, open };
358
382
  }
359
- async function loadModels(key, opts) {
383
+ async function loadModels(key) {
360
384
  let models;
361
- let source;
362
385
  if (cache && Date.now() - cache.at < CACHE_TTL_MS) {
363
386
  models = cache.models;
364
- source = "cache";
365
387
  } else {
366
388
  try {
367
389
  const resp = await providerModels(key);
@@ -371,35 +393,61 @@ async function loadModels(key, opts) {
371
393
  contextLength: m.context_length ?? 0
372
394
  }));
373
395
  cache = { at: Date.now(), models };
374
- source = "live";
375
396
  } catch {
376
397
  if (cache) {
377
398
  models = cache.models;
378
- source = "stale";
379
399
  } else {
380
400
  throw new Error("Could not fetch Command Code model list (https://api.commandcode.ai/provider/v1/models). Check network/API key.");
381
401
  }
382
402
  }
383
403
  }
384
404
  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);
405
+ try {
406
+ const [sub, cr] = await Promise.all([subscriptions(key), credits(key)]);
407
+ plan = {
408
+ planId: sub.planId,
409
+ purchasedCredits: cr.credits.purchasedCredits ?? 0,
410
+ freeCredits: cr.credits.freeCredits ?? 0
411
+ };
412
+ } catch {}
413
+ const allowed = models.filter((m) => evaluateModelAccess(m.id, plan).allowed);
400
414
  const { claude, open } = splitModels(allowed);
401
- return { claude, open, gatedOut, source };
415
+ return { claude, open };
402
416
  }
417
+ // ../core/plans.json
418
+ var plans_default = {
419
+ nameRules: [
420
+ { needles: ["enterprise"], name: "Enterprise" },
421
+ { needles: ["provider"], name: "Provider" },
422
+ { needles: ["team"], name: "Team Pro" },
423
+ { needles: ["max", "20"], name: "Max 20x" },
424
+ { needles: ["max"], name: "Max 10x" },
425
+ { needles: ["goat"], name: "GOAT" },
426
+ { needles: ["pro"], name: "Pro" },
427
+ { needles: ["go"], name: "Go" }
428
+ ],
429
+ defaultName: "Free",
430
+ caps: {
431
+ Enterprise: null,
432
+ Provider: null,
433
+ "Team Pro": 40,
434
+ "Max 20x": 300,
435
+ "Max 10x": 150,
436
+ GOAT: 70,
437
+ Pro: 80,
438
+ Go: 10,
439
+ Free: null
440
+ },
441
+ plans: [
442
+ { name: "Go", price: "$1", monthly: "$10", fiveHour: "$3", weekly: "$6" },
443
+ { name: "GOAT", price: "$10", monthly: "$70", fiveHour: "$14", weekly: "$35" },
444
+ { name: "Pro", price: "$20", monthly: "$80", fiveHour: "$16", weekly: "$40" },
445
+ { name: "Provider", price: "$15", monthly: "PAYG", fiveHour: "\u2014", weekly: "\u2014" },
446
+ { name: "Max 10x", price: "$100", monthly: "$150", fiveHour: "$45", weekly: "$90" },
447
+ { name: "Max 20x", price: "$200", monthly: "$300", fiveHour: "$90", weekly: "$180" },
448
+ { name: "Team Pro", price: "$40", monthly: "$40", fiveHour: "$12", weekly: "$24" }
449
+ ]
450
+ };
403
451
 
404
452
  // src/usage.ts
405
453
  var BAR_WIDTH = 12;
@@ -440,46 +488,34 @@ function relTime(resetAtMs, nowSecs) {
440
488
  return "<1m";
441
489
  }
442
490
  function parseIsoUtc(s) {
443
- const m = s.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d+)?)Z?/);
491
+ const m = s.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|[+-]\d{2}:?\d{2})?$/);
444
492
  if (!m)
445
493
  return;
446
- const [, y, mo, d, h, mi, sec] = m;
447
- return Date.UTC(+y, +mo - 1, +d, +h, +mi, Math.floor(+sec));
494
+ const [, y, mo, d, h, mi, sec, off] = m;
495
+ let offsetMs = 0;
496
+ if (off && off !== "Z") {
497
+ const sign = off.startsWith("-") ? -1 : 1;
498
+ const digits = off.slice(1).replace(":", "");
499
+ const hh = Number(digits.slice(0, 2));
500
+ const mm = Number(digits.slice(2, 4) || "0");
501
+ offsetMs = sign * (hh * 60 + mm) * 60000;
502
+ }
503
+ return Date.UTC(+y, +mo - 1, +d, +h, +mi, Math.floor(+sec)) - offsetMs;
448
504
  }
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
- };
505
+ var NAME_RULES = plans_default.nameRules;
506
+ var DEFAULT_NAME = plans_default.defaultName;
507
+ var CAPS = plans_default.caps;
508
+ var PLANS = plans_default.plans;
458
509
  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;
510
+ return CAPS[planName(planId)] ?? undefined;
463
511
  }
464
512
  function planName(planId) {
465
513
  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";
514
+ for (const rule of NAME_RULES) {
515
+ if (rule.needles.every((n) => id.includes(n)))
516
+ return rule.name;
517
+ }
518
+ return DEFAULT_NAME;
483
519
  }
484
520
  function windowLine(label, w, nowSecs) {
485
521
  const status = w.exceeded ? " \xB7 **LIMIT EXCEEDED**" : "";
@@ -487,22 +523,13 @@ function windowLine(label, w, nowSecs) {
487
523
  `;
488
524
  }
489
525
  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
526
  const mine = planName(current);
500
527
  let out = `| Plan | Price | Credits/mo | 5-hour | Weekly |
501
528
  |---|---|---|---|---|
502
529
  `;
503
- for (const [_id, name, price, monthly, h5, wk] of plans) {
530
+ for (const { name, price, monthly, fiveHour, weekly } of PLANS) {
504
531
  const mark = name === mine ? "**" : "";
505
- out += `| ${mark}${name}${mark} | ${price}/mo | ${monthly} | ${h5} | ${wk} |
532
+ out += `| ${mark}${name}${mark} | ${price}/mo | ${monthly} | ${fiveHour} | ${weekly} |
506
533
  `;
507
534
  }
508
535
  out += "\nWindows throttle only included monthly credits; on-demand (`/extra`) credits are never throttled.\n";
@@ -562,8 +589,16 @@ async function renderUsage(key) {
562
589
  }
563
590
 
564
591
  // src/index.ts
565
- var PROVIDER_BASE = "https://api.commandcode.ai/provider/v1";
566
- function toModelDefs(models, providerID, npm) {
592
+ var PROVIDER_BASE = `${API_BASE}/provider/v1`;
593
+ var MODEL_CAPABILITIES = {
594
+ temperature: true,
595
+ reasoning: true,
596
+ attachment: false,
597
+ toolcall: true,
598
+ input: { text: true, audio: false, image: false, video: false, pdf: false },
599
+ output: { text: true, audio: false, image: false, video: false, pdf: false }
600
+ };
601
+ function toModelDefs(models, providerID, npm, interleaved = false) {
567
602
  return Object.fromEntries(models.map((m) => [
568
603
  m.id,
569
604
  {
@@ -571,21 +606,14 @@ function toModelDefs(models, providerID, npm) {
571
606
  providerID,
572
607
  api: { id: m.id, url: PROVIDER_BASE, npm },
573
608
  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
- },
609
+ capabilities: { ...MODEL_CAPABILITIES, interleaved },
583
610
  cost: { input: 0, output: 0, cache: { read: 0, write: 0 } },
584
611
  limit: { context: m.contextLength || 128000, output: 32000 },
585
612
  status: "active",
586
613
  options: {},
587
614
  headers: {},
588
- release_date: ""
615
+ release_date: "",
616
+ ...interleaved !== false ? { interleaved } : {}
589
617
  }
590
618
  ]));
591
619
  }
@@ -637,7 +665,7 @@ var CommandCodePlugin = async (_input) => {
637
665
  split = await loadModels(openKey);
638
666
  } catch {}
639
667
  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") : {};
668
+ const openDefs = split ? toModelDefs(split.open, "command-code-openai", "@ai-sdk/openai-compatible", { field: "reasoning_content" }) : {};
641
669
  const userAnthropic = existing("command-code-anthropic");
642
670
  cfg.provider["command-code-anthropic"] = {
643
671
  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.2",
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": {