opencommand-plugin 0.0.3 → 0.0.5
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/README.md +33 -60
- package/bin/opencode-plugin.js +3 -0
- package/dist/index.d.ts +20 -1
- package/dist/index.js +213 -60
- package/package.json +17 -3
package/README.md
CHANGED
|
@@ -1,80 +1,53 @@
|
|
|
1
|
-
# OpenCommand Plugin
|
|
1
|
+
# OpenCommand Plugin
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
OpenCode plugin for CommandCode. It starts the local OpenCommand proxy, stores CommandCode auth locally, registers the `opencommand` provider, and loads the right model list for the active CommandCode plan.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
7
|
+
- Starts/stops the Go proxy automatically.
|
|
8
|
+
- Uses a dynamic local port and exposes `http://localhost:<port>/v1` to OpenCode.
|
|
9
|
+
- Stores the CommandCode API token locally in `~/.opencommand/opencommand-secrets.json`.
|
|
10
|
+
- Supports `COMMAND_CODE_TOKEN` and `COMMANDCODE_API_KEY` environment overrides.
|
|
11
|
+
- Attempts local browser cookie discovery for CommandCode Studio usage scraping.
|
|
12
|
+
- Registers OpenCode provider `opencommand` using `@ai-sdk/openai-compatible`.
|
|
13
|
+
- Detects the active CommandCode plan and registers the matching OpenCode model list.
|
|
13
14
|
|
|
14
|
-
##
|
|
15
|
+
## Auth
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
Handles proxy process lifecycle:
|
|
18
|
-
- Start/stop proxy on dynamic port
|
|
19
|
-
- Health check polling
|
|
20
|
-
- Process signal handling
|
|
17
|
+
Primary token key:
|
|
21
18
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"opencommand.command_code_token": "user_xxx..."
|
|
22
|
+
}
|
|
23
|
+
```
|
|
27
24
|
|
|
28
|
-
|
|
29
|
-
Main plugin interface:
|
|
30
|
-
- activate() - Initialize on editor startup
|
|
31
|
-
- deactivate() - Clean up on shutdown
|
|
32
|
-
- setSessionToken() - Configure CommandCode credentials
|
|
33
|
-
- getProxyConfig() - Get current config
|
|
25
|
+
Do not put this token in synced `opencode.jsonc`.
|
|
34
26
|
|
|
35
|
-
##
|
|
27
|
+
## Models in v0.0.4
|
|
36
28
|
|
|
37
|
-
|
|
38
|
-
npm install
|
|
39
|
-
npm run build
|
|
40
|
-
```
|
|
29
|
+
The proxy detects the active CommandCode subscription through `/alpha/billing/subscriptions` and filters models:
|
|
41
30
|
|
|
42
|
-
|
|
31
|
+
- Go: open-source models only.
|
|
32
|
+
- Pro: open-source + premium, excluding Opus.
|
|
33
|
+
- Max / Ultra / Teams Pro: open-source + premium including Opus.
|
|
43
34
|
|
|
44
|
-
|
|
45
|
-
npm test
|
|
46
|
-
```
|
|
35
|
+
If detection fails, the plugin falls back to the local proxy model endpoint and then to the Go/open-source model list.
|
|
47
36
|
|
|
48
|
-
##
|
|
37
|
+
## Build
|
|
49
38
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
- Proxy started on random available port
|
|
55
|
-
- Configuration saved to OpenCode
|
|
56
|
-
- Clients use http://localhost:PORT/v1 for API calls
|
|
57
|
-
4. On shutdown:
|
|
58
|
-
- Proxy process terminated gracefully
|
|
59
|
-
- SIGTERM → wait 5s → SIGKILL
|
|
60
|
-
|
|
61
|
-
## Configuration
|
|
39
|
+
```bash
|
|
40
|
+
npm ci
|
|
41
|
+
npm run build
|
|
42
|
+
```
|
|
62
43
|
|
|
63
|
-
|
|
44
|
+
## Test
|
|
64
45
|
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
"opencommand": {
|
|
68
|
-
"proxyUrl": "http://localhost:3001",
|
|
69
|
-
"apiBaseUrl": "http://localhost:3001/v1"
|
|
70
|
-
}
|
|
71
|
-
}
|
|
46
|
+
```bash
|
|
47
|
+
npm test -- --runInBand
|
|
72
48
|
```
|
|
73
49
|
|
|
74
|
-
|
|
50
|
+
## v0.0.5 OpenCode loading fix
|
|
75
51
|
|
|
76
|
-
|
|
52
|
+
`opencommand-plugin@0.0.5` publishes an explicit ESM wrapper at `bin/opencode-plugin.js` and should be pinned in `opencode.jsonc` as `opencommand-plugin@0.0.5` (or newer). This avoids stale `@latest` cache entries and ensures OpenCode sees the plugin default export as a function.
|
|
77
53
|
|
|
78
|
-
- Fase 2 Implementation (#2)
|
|
79
|
-
- Depends on: Proxy Core (Fase 1)
|
|
80
|
-
- Prepares for: Cookie Scraper (Fase 3)
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ interface CommandCodeModelDefinition {
|
|
|
11
11
|
id: string;
|
|
12
12
|
name: string;
|
|
13
13
|
description: string;
|
|
14
|
+
category?: string;
|
|
14
15
|
reasoning?: boolean;
|
|
15
16
|
context: number;
|
|
16
17
|
output: number;
|
|
@@ -93,8 +94,25 @@ export declare class OpenCommandPlugin {
|
|
|
93
94
|
private restartIfPossible;
|
|
94
95
|
getProxyConfig(): string;
|
|
95
96
|
}
|
|
96
|
-
export declare function
|
|
97
|
+
export declare function fetchOpenCommandModels(baseURL: string): Promise<CommandCodeModelDefinition[] | undefined>;
|
|
98
|
+
export declare function commandCodeModelsForPlan(planID: string): CommandCodeModelDefinition[];
|
|
99
|
+
export declare function fetchCommandCodePlanModels(commandCodeToken: string, apiBaseURL?: string): Promise<CommandCodeModelDefinition[] | undefined>;
|
|
100
|
+
export declare function parseCommandCodePlanID(body: unknown): string | undefined;
|
|
101
|
+
export declare function registerOpenCommandProvider(config: OpenCodeConfig, baseURL?: string, modelDefinitions?: CommandCodeModelDefinition[]): void;
|
|
97
102
|
export declare const OpenCommandOpenCodePlugin: () => Promise<{
|
|
103
|
+
provider: {
|
|
104
|
+
opencommand: {
|
|
105
|
+
npm: string;
|
|
106
|
+
name: string;
|
|
107
|
+
options: {
|
|
108
|
+
apiKey: string;
|
|
109
|
+
baseURL: string;
|
|
110
|
+
};
|
|
111
|
+
models: {
|
|
112
|
+
[k: string]: Record<string, unknown>;
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
};
|
|
98
116
|
auth: {
|
|
99
117
|
provider: string;
|
|
100
118
|
loader: () => Promise<{
|
|
@@ -106,3 +124,4 @@ export declare const OpenCommandOpenCodePlugin: () => Promise<{
|
|
|
106
124
|
config: (config: OpenCodeConfig) => Promise<void>;
|
|
107
125
|
}>;
|
|
108
126
|
export default OpenCommandOpenCodePlugin;
|
|
127
|
+
export { OpenCommandOpenCodePlugin as opencommandPlugin };
|
package/dist/index.js
CHANGED
|
@@ -1,52 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.OpenCommandOpenCodePlugin = exports.OpenCommandPlugin = exports.BrowserCookieExtractor = exports.SecretStorage = exports.ProxyManager = exports.COMMAND_CODE_GO_PLAN_MODELS = void 0;
|
|
37
|
-
exports.registerOpenCommandProvider = registerOpenCommandProvider;
|
|
38
|
-
const cp = __importStar(require("child_process"));
|
|
39
|
-
const crypto = __importStar(require("crypto"));
|
|
40
|
-
const fs = __importStar(require("fs"));
|
|
41
|
-
const fsp = __importStar(require("fs/promises"));
|
|
42
|
-
const net = __importStar(require("net"));
|
|
43
|
-
const os = __importStar(require("os"));
|
|
44
|
-
const path = __importStar(require("path"));
|
|
1
|
+
import * as cp from "child_process";
|
|
2
|
+
import * as crypto from "crypto";
|
|
3
|
+
import * as fs from "fs";
|
|
4
|
+
import * as fsp from "fs/promises";
|
|
5
|
+
import * as net from "net";
|
|
6
|
+
import * as os from "os";
|
|
7
|
+
import * as path from "path";
|
|
45
8
|
const PROVIDER_ID = "opencommand";
|
|
46
9
|
const PROVIDER_NAME = "CommandCode";
|
|
47
10
|
const PROVIDER_API_KEY_PLACEHOLDER = "opencommand";
|
|
48
11
|
const DEFAULT_PROXY_BASE_URL = "http://localhost:3000/v1";
|
|
49
|
-
|
|
12
|
+
const COMMAND_CODE_API_BASE_URL = "https://api.commandcode.ai";
|
|
13
|
+
export const COMMAND_CODE_GO_PLAN_MODELS = [
|
|
50
14
|
{
|
|
51
15
|
id: "deepseek/deepseek-v4-pro",
|
|
52
16
|
name: "DeepSeek V4 Pro",
|
|
@@ -141,7 +105,87 @@ exports.COMMAND_CODE_GO_PLAN_MODELS = [
|
|
|
141
105
|
cost: { input: 0.1, output: 0.3, cache_read: 0.02 },
|
|
142
106
|
},
|
|
143
107
|
];
|
|
144
|
-
|
|
108
|
+
const COMMAND_CODE_PREMIUM_MODELS = [
|
|
109
|
+
{
|
|
110
|
+
id: "anthropic:claude-opus-4-7",
|
|
111
|
+
name: "Claude Opus 4.7",
|
|
112
|
+
description: "Premium Claude Opus coding and reasoning",
|
|
113
|
+
category: "premium",
|
|
114
|
+
reasoning: true,
|
|
115
|
+
context: 200000,
|
|
116
|
+
output: 8192,
|
|
117
|
+
cost: { input: 0, output: 0 },
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: "anthropic:claude-opus-4-6",
|
|
121
|
+
name: "Claude Opus 4.6",
|
|
122
|
+
description: "Premium Claude Opus coding and reasoning",
|
|
123
|
+
category: "premium",
|
|
124
|
+
reasoning: true,
|
|
125
|
+
context: 200000,
|
|
126
|
+
output: 8192,
|
|
127
|
+
cost: { input: 0, output: 0 },
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
id: "anthropic:claude-sonnet-4-6",
|
|
131
|
+
name: "Claude Sonnet 4.6",
|
|
132
|
+
description: "Premium Claude Sonnet coding",
|
|
133
|
+
category: "premium",
|
|
134
|
+
reasoning: true,
|
|
135
|
+
context: 200000,
|
|
136
|
+
output: 8192,
|
|
137
|
+
cost: { input: 0, output: 0 },
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: "anthropic:claude-haiku-4-5-20251001",
|
|
141
|
+
name: "Claude Haiku 4.5",
|
|
142
|
+
description: "Fast premium Claude model",
|
|
143
|
+
category: "premium",
|
|
144
|
+
context: 200000,
|
|
145
|
+
output: 8192,
|
|
146
|
+
cost: { input: 0, output: 0 },
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
id: "openai:gpt-5.5",
|
|
150
|
+
name: "GPT-5.5",
|
|
151
|
+
description: "Premium OpenAI reasoning model",
|
|
152
|
+
category: "premium",
|
|
153
|
+
reasoning: true,
|
|
154
|
+
context: 200000,
|
|
155
|
+
output: 8192,
|
|
156
|
+
cost: { input: 0, output: 0 },
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: "openai:gpt-5.4",
|
|
160
|
+
name: "GPT-5.4",
|
|
161
|
+
description: "Premium OpenAI coding model",
|
|
162
|
+
category: "premium",
|
|
163
|
+
reasoning: true,
|
|
164
|
+
context: 200000,
|
|
165
|
+
output: 8192,
|
|
166
|
+
cost: { input: 0, output: 0 },
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: "openai:gpt-5.4-mini",
|
|
170
|
+
name: "GPT-5.4 Mini",
|
|
171
|
+
description: "Efficient premium OpenAI coding model",
|
|
172
|
+
category: "premium",
|
|
173
|
+
context: 200000,
|
|
174
|
+
output: 8192,
|
|
175
|
+
cost: { input: 0, output: 0 },
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
id: "openai:gpt-5.3-codex",
|
|
179
|
+
name: "GPT-5.3 Codex",
|
|
180
|
+
description: "Premium OpenAI Codex coding model",
|
|
181
|
+
category: "premium",
|
|
182
|
+
reasoning: true,
|
|
183
|
+
context: 200000,
|
|
184
|
+
output: 8192,
|
|
185
|
+
cost: { input: 0, output: 0 },
|
|
186
|
+
},
|
|
187
|
+
];
|
|
188
|
+
export class ProxyManager {
|
|
145
189
|
constructor(binaryPath = resolveProxyBinaryPath()) {
|
|
146
190
|
this.proxyProcess = null;
|
|
147
191
|
this.config = null;
|
|
@@ -262,8 +306,7 @@ class ProxyManager {
|
|
|
262
306
|
return this.proxyProcess !== null && !this.proxyProcess.killed;
|
|
263
307
|
}
|
|
264
308
|
}
|
|
265
|
-
|
|
266
|
-
class SecretStorage {
|
|
309
|
+
export class SecretStorage {
|
|
267
310
|
constructor(storageDir = `${process.env.HOME || "/tmp"}/.opencommand`) {
|
|
268
311
|
this.filePath = `${storageDir}/opencommand-secrets.json`;
|
|
269
312
|
}
|
|
@@ -301,8 +344,7 @@ class SecretStorage {
|
|
|
301
344
|
await this.writeStore(store);
|
|
302
345
|
}
|
|
303
346
|
}
|
|
304
|
-
|
|
305
|
-
class BrowserCookieExtractor {
|
|
347
|
+
export class BrowserCookieExtractor {
|
|
306
348
|
constructor(homeDir = os.homedir()) {
|
|
307
349
|
this.homeDir = homeDir;
|
|
308
350
|
}
|
|
@@ -396,7 +438,8 @@ class BrowserCookieExtractor {
|
|
|
396
438
|
try {
|
|
397
439
|
fs.copyFileSync(profile.cookieDatabase, tmpDb);
|
|
398
440
|
const query = profile.browser === "Firefox" ? firefoxCookieQuery : chromiumCookieQuery;
|
|
399
|
-
const output = cp.execFileSync("/usr/bin/sqlite3", [tmpDb
|
|
441
|
+
const output = cp.execFileSync("/usr/bin/sqlite3", [tmpDb], {
|
|
442
|
+
input: query,
|
|
400
443
|
encoding: "utf8",
|
|
401
444
|
timeout: 5000,
|
|
402
445
|
});
|
|
@@ -463,7 +506,6 @@ class BrowserCookieExtractor {
|
|
|
463
506
|
}
|
|
464
507
|
}
|
|
465
508
|
}
|
|
466
|
-
exports.BrowserCookieExtractor = BrowserCookieExtractor;
|
|
467
509
|
function decryptMacChromiumCookie(encryptedValue, safeStoragePassword) {
|
|
468
510
|
try {
|
|
469
511
|
const payload = encryptedValue.subarray(0, 3).toString() === "v10"
|
|
@@ -485,7 +527,7 @@ const firefoxCookieQuery = [
|
|
|
485
527
|
".mode tabs",
|
|
486
528
|
"SELECT host, name, value, '' FROM moz_cookies WHERE host LIKE '%commandcode.ai%';",
|
|
487
529
|
].join("\n");
|
|
488
|
-
class OpenCommandPlugin {
|
|
530
|
+
export class OpenCommandPlugin {
|
|
489
531
|
constructor(proxyBinaryPath = resolveProxyBinaryPath(), storageDir) {
|
|
490
532
|
this.commandCodeTokenKey = "opencommand.command_code_token";
|
|
491
533
|
this.legacyTokenKey = "opencommand.cc_session_token";
|
|
@@ -599,7 +641,6 @@ class OpenCommandPlugin {
|
|
|
599
641
|
return JSON.stringify(config, null, 2);
|
|
600
642
|
}
|
|
601
643
|
}
|
|
602
|
-
exports.OpenCommandPlugin = OpenCommandPlugin;
|
|
603
644
|
function firstDefined(...values) {
|
|
604
645
|
for (const value of values) {
|
|
605
646
|
const trimmed = value?.trim();
|
|
@@ -622,6 +663,7 @@ function openCodeModelConfig(model) {
|
|
|
622
663
|
id: model.id,
|
|
623
664
|
name: model.name,
|
|
624
665
|
description: model.description,
|
|
666
|
+
category: model.category ?? "opensource",
|
|
625
667
|
reasoning: model.reasoning ?? false,
|
|
626
668
|
tool_call: true,
|
|
627
669
|
attachment: false,
|
|
@@ -636,9 +678,100 @@ function openCodeModelConfig(model) {
|
|
|
636
678
|
},
|
|
637
679
|
};
|
|
638
680
|
}
|
|
639
|
-
function
|
|
681
|
+
function modelFromProxy(model) {
|
|
682
|
+
if (!model.id)
|
|
683
|
+
return undefined;
|
|
684
|
+
return {
|
|
685
|
+
id: model.id,
|
|
686
|
+
name: model.name ?? model.id,
|
|
687
|
+
description: model.description ?? "CommandCode model",
|
|
688
|
+
category: model.category,
|
|
689
|
+
reasoning: model.reasoning ?? false,
|
|
690
|
+
context: model.limit?.context ?? 200000,
|
|
691
|
+
output: model.limit?.output ?? 8192,
|
|
692
|
+
cost: model.cost ?? { input: 0, output: 0 },
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
export async function fetchOpenCommandModels(baseURL) {
|
|
696
|
+
try {
|
|
697
|
+
const response = await fetch(`${baseURL.replace(/\/$/, "")}/models`, {
|
|
698
|
+
headers: { Authorization: `Bearer ${PROVIDER_API_KEY_PLACEHOLDER}` },
|
|
699
|
+
});
|
|
700
|
+
if (!response.ok)
|
|
701
|
+
return undefined;
|
|
702
|
+
const body = (await response.json());
|
|
703
|
+
const models = (body.data ?? [])
|
|
704
|
+
.map(modelFromProxy)
|
|
705
|
+
.filter((model) => Boolean(model));
|
|
706
|
+
return models.length > 0 ? models : undefined;
|
|
707
|
+
}
|
|
708
|
+
catch (error) {
|
|
709
|
+
console.debug("Could not fetch OpenCommand models from local proxy:", error);
|
|
710
|
+
return undefined;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
export function commandCodeModelsForPlan(planID) {
|
|
714
|
+
const models = [...COMMAND_CODE_GO_PLAN_MODELS];
|
|
715
|
+
if (!planCanUsePremium(planID))
|
|
716
|
+
return models;
|
|
717
|
+
for (const model of COMMAND_CODE_PREMIUM_MODELS) {
|
|
718
|
+
if (isOpusModel(model.id) && !planCanUseOpus(planID))
|
|
719
|
+
continue;
|
|
720
|
+
models.push(model);
|
|
721
|
+
}
|
|
722
|
+
return models;
|
|
723
|
+
}
|
|
724
|
+
export async function fetchCommandCodePlanModels(commandCodeToken, apiBaseURL = COMMAND_CODE_API_BASE_URL) {
|
|
725
|
+
try {
|
|
726
|
+
const response = await fetch(`${apiBaseURL.replace(/\/$/, "")}/alpha/billing/subscriptions`, {
|
|
727
|
+
headers: {
|
|
728
|
+
Accept: "application/json",
|
|
729
|
+
Authorization: `Bearer ${commandCodeToken}`,
|
|
730
|
+
},
|
|
731
|
+
});
|
|
732
|
+
if (!response.ok)
|
|
733
|
+
return undefined;
|
|
734
|
+
const body = await response.json();
|
|
735
|
+
const planID = parseCommandCodePlanID(body);
|
|
736
|
+
return planID ? commandCodeModelsForPlan(planID) : undefined;
|
|
737
|
+
}
|
|
738
|
+
catch (error) {
|
|
739
|
+
console.debug("Could not detect CommandCode plan for model registration:", error);
|
|
740
|
+
return undefined;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
export function parseCommandCodePlanID(body) {
|
|
744
|
+
const root = body;
|
|
745
|
+
if (typeof root?.planId === "string" && root.planId.trim())
|
|
746
|
+
return root.planId.trim();
|
|
747
|
+
const data = root?.data;
|
|
748
|
+
if (Array.isArray(data)) {
|
|
749
|
+
const active = data.find((item) => {
|
|
750
|
+
const entry = item;
|
|
751
|
+
return typeof entry.planId === "string" && entry.status === "active";
|
|
752
|
+
});
|
|
753
|
+
const first = active ?? data[0];
|
|
754
|
+
return typeof first?.planId === "string" && first.planId.trim()
|
|
755
|
+
? first.planId.trim()
|
|
756
|
+
: undefined;
|
|
757
|
+
}
|
|
758
|
+
const single = data;
|
|
759
|
+
return typeof single?.planId === "string" && single.planId.trim()
|
|
760
|
+
? single.planId.trim()
|
|
761
|
+
: undefined;
|
|
762
|
+
}
|
|
763
|
+
function planCanUsePremium(planID) {
|
|
764
|
+
return ["individual-pro", "individual-max", "individual-ultra", "teams-pro"].includes(planID.toLowerCase());
|
|
765
|
+
}
|
|
766
|
+
function planCanUseOpus(planID) {
|
|
767
|
+
return ["individual-max", "individual-ultra", "teams-pro"].includes(planID.toLowerCase());
|
|
768
|
+
}
|
|
769
|
+
function isOpusModel(modelID) {
|
|
770
|
+
return modelID.toLowerCase().includes("opus");
|
|
771
|
+
}
|
|
772
|
+
export function registerOpenCommandProvider(config, baseURL = DEFAULT_PROXY_BASE_URL, modelDefinitions = COMMAND_CODE_GO_PLAN_MODELS) {
|
|
640
773
|
const models = {};
|
|
641
|
-
for (const model of
|
|
774
|
+
for (const model of modelDefinitions) {
|
|
642
775
|
models[model.id] = openCodeModelConfig(model);
|
|
643
776
|
}
|
|
644
777
|
config.provider = {
|
|
@@ -659,7 +792,18 @@ function getRuntimePlugin() {
|
|
|
659
792
|
runtimePlugin ?? (runtimePlugin = new OpenCommandPlugin());
|
|
660
793
|
return runtimePlugin;
|
|
661
794
|
}
|
|
662
|
-
const OpenCommandOpenCodePlugin = async () => ({
|
|
795
|
+
export const OpenCommandOpenCodePlugin = async () => ({
|
|
796
|
+
provider: {
|
|
797
|
+
[PROVIDER_ID]: {
|
|
798
|
+
npm: "@ai-sdk/openai-compatible",
|
|
799
|
+
name: PROVIDER_NAME,
|
|
800
|
+
options: {
|
|
801
|
+
apiKey: PROVIDER_API_KEY_PLACEHOLDER,
|
|
802
|
+
baseURL: DEFAULT_PROXY_BASE_URL,
|
|
803
|
+
},
|
|
804
|
+
models: Object.fromEntries(COMMAND_CODE_GO_PLAN_MODELS.map((model) => [model.id, openCodeModelConfig(model)])),
|
|
805
|
+
},
|
|
806
|
+
},
|
|
663
807
|
auth: {
|
|
664
808
|
provider: PROVIDER_ID,
|
|
665
809
|
loader: async () => {
|
|
@@ -674,8 +818,17 @@ const OpenCommandOpenCodePlugin = async () => ({
|
|
|
674
818
|
methods: [],
|
|
675
819
|
},
|
|
676
820
|
config: async (config) => {
|
|
677
|
-
|
|
821
|
+
let baseURL = DEFAULT_PROXY_BASE_URL;
|
|
822
|
+
let models;
|
|
823
|
+
const proxyConfig = await getRuntimePlugin().ensureStarted();
|
|
824
|
+
if (proxyConfig) {
|
|
825
|
+
baseURL = `http://localhost:${proxyConfig.port}/v1`;
|
|
826
|
+
models =
|
|
827
|
+
(await fetchCommandCodePlanModels(proxyConfig.commandCodeToken)) ??
|
|
828
|
+
(await fetchOpenCommandModels(baseURL));
|
|
829
|
+
}
|
|
830
|
+
registerOpenCommandProvider(config, baseURL, models ?? COMMAND_CODE_GO_PLAN_MODELS);
|
|
678
831
|
},
|
|
679
832
|
});
|
|
680
|
-
|
|
681
|
-
|
|
833
|
+
export default OpenCommandOpenCodePlugin;
|
|
834
|
+
export { OpenCommandOpenCodePlugin as opencommandPlugin };
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencommand-plugin",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "OpenCommand - CommandCode API Plugin for OpenCode",
|
|
5
|
-
"main": "
|
|
5
|
+
"main": "./bin/opencode-plugin.js",
|
|
6
|
+
"module": "./bin/opencode-plugin.js",
|
|
6
7
|
"scripts": {
|
|
7
8
|
"build": "tsc",
|
|
8
9
|
"test": "jest",
|
|
@@ -30,7 +31,20 @@
|
|
|
30
31
|
},
|
|
31
32
|
"files": [
|
|
32
33
|
"dist/**",
|
|
34
|
+
"bin/**",
|
|
33
35
|
"README.md",
|
|
34
36
|
"package.json"
|
|
35
|
-
]
|
|
37
|
+
],
|
|
38
|
+
"type": "module",
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"exports": {
|
|
41
|
+
".": {
|
|
42
|
+
"types": "./dist/index.d.ts",
|
|
43
|
+
"import": "./bin/opencode-plugin.js"
|
|
44
|
+
},
|
|
45
|
+
"./dist/index.js": {
|
|
46
|
+
"types": "./dist/index.d.ts",
|
|
47
|
+
"import": "./dist/index.js"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
36
50
|
}
|