opencommand-plugin 0.0.1
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 +80 -0
- package/dist/index.d.ts +86 -0
- package/dist/index.js +326 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# OpenCommand Plugin - OpenCode Integration
|
|
2
|
+
|
|
3
|
+
Plugin for OpenCode that manages the CommandCode proxy lifecycle.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✅ Automatic proxy startup on editor launch
|
|
8
|
+
- ✅ Dynamic port allocation (no conflicts)
|
|
9
|
+
- ✅ Secure session token storage via SecretStorage
|
|
10
|
+
- ✅ Health checks (proxy readiness verification)
|
|
11
|
+
- ✅ Graceful shutdown on editor close
|
|
12
|
+
- ✅ Configuration export to OpenCode
|
|
13
|
+
|
|
14
|
+
## Architecture
|
|
15
|
+
|
|
16
|
+
### ProxyManager
|
|
17
|
+
Handles proxy process lifecycle:
|
|
18
|
+
- Start/stop proxy on dynamic port
|
|
19
|
+
- Health check polling
|
|
20
|
+
- Process signal handling
|
|
21
|
+
|
|
22
|
+
### SecretStorage
|
|
23
|
+
Secure credential management:
|
|
24
|
+
- Store CC_SESSION_COOKIE securely
|
|
25
|
+
- Retrieve only when needed
|
|
26
|
+
- Mock implementation (real version uses OpenCode API)
|
|
27
|
+
|
|
28
|
+
### OpenCommandPlugin
|
|
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
|
|
34
|
+
|
|
35
|
+
## Building
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install
|
|
39
|
+
npm run build
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Testing
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm test
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Usage
|
|
49
|
+
|
|
50
|
+
1. User installs plugin in OpenCode
|
|
51
|
+
2. Plugin prompts for CC_SESSION_COOKIE
|
|
52
|
+
3. On startup:
|
|
53
|
+
- Token retrieved from SecretStorage
|
|
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
|
|
62
|
+
|
|
63
|
+
The plugin exports this configuration to OpenCode:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"opencommand": {
|
|
68
|
+
"proxyUrl": "http://localhost:3001",
|
|
69
|
+
"apiBaseUrl": "http://localhost:3001/v1"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
OpenCode and other clients use this to route requests to the proxy.
|
|
75
|
+
|
|
76
|
+
## Related Issues
|
|
77
|
+
|
|
78
|
+
- Fase 2 Implementation (#2)
|
|
79
|
+
- Depends on: Proxy Core (Fase 1)
|
|
80
|
+
- Prepares for: Cookie Scraper (Fase 3)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export interface ProxyConfig {
|
|
2
|
+
port: number;
|
|
3
|
+
sessionToken: string;
|
|
4
|
+
}
|
|
5
|
+
export declare class ProxyManager {
|
|
6
|
+
private proxyProcess;
|
|
7
|
+
private config;
|
|
8
|
+
private proxyBinaryPath;
|
|
9
|
+
constructor(binaryPath: string);
|
|
10
|
+
/**
|
|
11
|
+
* Find an available port (dynamic allocation)
|
|
12
|
+
*/
|
|
13
|
+
findAvailablePort(): Promise<number>;
|
|
14
|
+
/**
|
|
15
|
+
* Start the proxy server
|
|
16
|
+
*/
|
|
17
|
+
start(sessionToken: string): Promise<ProxyConfig>;
|
|
18
|
+
/**
|
|
19
|
+
* Stop the proxy server
|
|
20
|
+
*/
|
|
21
|
+
stop(): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Wait for proxy to be healthy
|
|
24
|
+
*/
|
|
25
|
+
private waitForHealthz;
|
|
26
|
+
/**
|
|
27
|
+
* Get current proxy configuration
|
|
28
|
+
*/
|
|
29
|
+
getConfig(): ProxyConfig | null;
|
|
30
|
+
/**
|
|
31
|
+
* Get proxy base URL
|
|
32
|
+
*/
|
|
33
|
+
getBaseUrl(): string | null;
|
|
34
|
+
/**
|
|
35
|
+
* Check if proxy is running
|
|
36
|
+
*/
|
|
37
|
+
isRunning(): boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* File-based persistent secret storage.
|
|
41
|
+
* Fix: Persists session token across plugin restarts (not instance-local Map).
|
|
42
|
+
*/
|
|
43
|
+
export declare class SecretStorage {
|
|
44
|
+
private filePath;
|
|
45
|
+
constructor(storageDir?: string);
|
|
46
|
+
private readStore;
|
|
47
|
+
private writeStore;
|
|
48
|
+
set(key: string, value: string): Promise<void>;
|
|
49
|
+
get(key: string): Promise<string | undefined>;
|
|
50
|
+
delete(key: string): Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* OpenCommand Plugin Main Class
|
|
54
|
+
*/
|
|
55
|
+
export declare class OpenCommandPlugin {
|
|
56
|
+
private proxyManager;
|
|
57
|
+
private secretStorage;
|
|
58
|
+
private SESSION_TOKEN_KEY;
|
|
59
|
+
constructor(proxyBinaryPath: string, storageDir?: string);
|
|
60
|
+
/**
|
|
61
|
+
* Initialize plugin on editor startup
|
|
62
|
+
*/
|
|
63
|
+
activate(): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Clean up on editor shutdown
|
|
66
|
+
*/
|
|
67
|
+
deactivate(): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Save proxy config to OpenCode configuration.
|
|
70
|
+
* Fix: Persist to file so OpenCodeBar can discover the dynamic port.
|
|
71
|
+
*/
|
|
72
|
+
private saveOpenCodeConfig;
|
|
73
|
+
/**
|
|
74
|
+
* Persist proxy URL and port to a config file (Issue #5).
|
|
75
|
+
* OpenCodeBar reads this to discover the dynamically allocated port.
|
|
76
|
+
*/
|
|
77
|
+
private persistProxyConfig;
|
|
78
|
+
/**
|
|
79
|
+
* Set session token via command
|
|
80
|
+
*/
|
|
81
|
+
setSessionToken(token: string): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* Get proxy configuration
|
|
84
|
+
*/
|
|
85
|
+
getProxyConfig(): string;
|
|
86
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
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.OpenCommandPlugin = exports.SecretStorage = exports.ProxyManager = void 0;
|
|
37
|
+
const cp = __importStar(require("child_process"));
|
|
38
|
+
const net = __importStar(require("net"));
|
|
39
|
+
class ProxyManager {
|
|
40
|
+
constructor(binaryPath) {
|
|
41
|
+
this.proxyProcess = null;
|
|
42
|
+
this.config = null;
|
|
43
|
+
this.proxyBinaryPath = binaryPath;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Find an available port (dynamic allocation)
|
|
47
|
+
*/
|
|
48
|
+
async findAvailablePort() {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
const server = net.createServer();
|
|
51
|
+
server.listen(0, () => {
|
|
52
|
+
const address = server.address();
|
|
53
|
+
if (address && typeof address === "object" && address.port) {
|
|
54
|
+
server.close(() => resolve(address.port));
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
reject(new Error("Failed to find available port"));
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
server.on("error", reject);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Start the proxy server
|
|
65
|
+
*/
|
|
66
|
+
async start(sessionToken) {
|
|
67
|
+
// Find available port
|
|
68
|
+
const port = await this.findAvailablePort();
|
|
69
|
+
this.config = { port, sessionToken };
|
|
70
|
+
// Prepare environment
|
|
71
|
+
const env = {
|
|
72
|
+
...process.env,
|
|
73
|
+
PORT: String(port),
|
|
74
|
+
CC_SESSION_COOKIE: sessionToken,
|
|
75
|
+
PRODUCTION: "true",
|
|
76
|
+
};
|
|
77
|
+
// Start proxy process
|
|
78
|
+
this.proxyProcess = cp.spawn(this.proxyBinaryPath, [], {
|
|
79
|
+
env,
|
|
80
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
81
|
+
});
|
|
82
|
+
// Log output
|
|
83
|
+
this.proxyProcess.stdout?.on("data", (data) => {
|
|
84
|
+
console.log(`[Proxy stdout] ${data}`);
|
|
85
|
+
});
|
|
86
|
+
this.proxyProcess.stderr?.on("data", (data) => {
|
|
87
|
+
console.error(`[Proxy stderr] ${data}`);
|
|
88
|
+
});
|
|
89
|
+
// Wait for proxy to be ready
|
|
90
|
+
await this.waitForHealthz(port, 30000);
|
|
91
|
+
console.log(`✓ Proxy started on port ${port}`);
|
|
92
|
+
return this.config;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Stop the proxy server
|
|
96
|
+
*/
|
|
97
|
+
async stop() {
|
|
98
|
+
const proc = this.proxyProcess;
|
|
99
|
+
if (!proc) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
return new Promise((resolve) => {
|
|
103
|
+
let resolved = false;
|
|
104
|
+
const finish = () => {
|
|
105
|
+
if (!resolved) {
|
|
106
|
+
resolved = true;
|
|
107
|
+
this.proxyProcess = null;
|
|
108
|
+
resolve();
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
proc.once("exit", finish);
|
|
112
|
+
proc.once("error", (error) => {
|
|
113
|
+
console.error("Proxy process error while stopping:", error);
|
|
114
|
+
finish();
|
|
115
|
+
});
|
|
116
|
+
try {
|
|
117
|
+
if (!proc.killed) {
|
|
118
|
+
proc.kill("SIGTERM");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
console.error("Failed to send SIGTERM to proxy process:", error);
|
|
123
|
+
finish();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
setTimeout(() => {
|
|
127
|
+
if (!resolved && !proc.killed) {
|
|
128
|
+
try {
|
|
129
|
+
proc.kill("SIGKILL");
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
console.error("Failed to send SIGKILL to proxy process:", error);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
finish();
|
|
136
|
+
}, 5000);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Wait for proxy to be healthy
|
|
141
|
+
*/
|
|
142
|
+
async waitForHealthz(port, timeoutMs) {
|
|
143
|
+
const startTime = Date.now();
|
|
144
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
145
|
+
try {
|
|
146
|
+
const controller = new AbortController();
|
|
147
|
+
const timeoutId = setTimeout(() => controller.abort(), 2000);
|
|
148
|
+
const response = await fetch(`http://localhost:${port}/healthz`, {
|
|
149
|
+
signal: controller.signal,
|
|
150
|
+
});
|
|
151
|
+
clearTimeout(timeoutId);
|
|
152
|
+
if (response.ok) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
console.debug(`Health check attempt failed for port ${port}:`, err);
|
|
158
|
+
}
|
|
159
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
160
|
+
}
|
|
161
|
+
throw new Error(`Proxy failed to become healthy after ${timeoutMs}ms on port ${port}`);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get current proxy configuration
|
|
165
|
+
*/
|
|
166
|
+
getConfig() {
|
|
167
|
+
return this.config;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Get proxy base URL
|
|
171
|
+
*/
|
|
172
|
+
getBaseUrl() {
|
|
173
|
+
return this.config ? `http://localhost:${this.config.port}` : null;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Check if proxy is running
|
|
177
|
+
*/
|
|
178
|
+
isRunning() {
|
|
179
|
+
return this.proxyProcess !== null && !this.proxyProcess.killed;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
exports.ProxyManager = ProxyManager;
|
|
183
|
+
/**
|
|
184
|
+
* File-based persistent secret storage.
|
|
185
|
+
* Fix: Persists session token across plugin restarts (not instance-local Map).
|
|
186
|
+
*/
|
|
187
|
+
class SecretStorage {
|
|
188
|
+
constructor(storageDir = `${process.env.HOME || "/tmp"}/.opencommand`) {
|
|
189
|
+
this.filePath = `${storageDir}/opencommand-secrets.json`;
|
|
190
|
+
}
|
|
191
|
+
async readStore() {
|
|
192
|
+
const fs = await Promise.resolve().then(() => __importStar(require("fs/promises")));
|
|
193
|
+
try {
|
|
194
|
+
const data = await fs.readFile(this.filePath, "utf-8");
|
|
195
|
+
return JSON.parse(data);
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
if (error.code !== "ENOENT") {
|
|
199
|
+
console.debug("Could not read OpenCommand secret store:", error);
|
|
200
|
+
}
|
|
201
|
+
return {};
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
async writeStore(store) {
|
|
205
|
+
const fs = await Promise.resolve().then(() => __importStar(require("fs/promises")));
|
|
206
|
+
const path = await Promise.resolve().then(() => __importStar(require("path")));
|
|
207
|
+
const dir = path.dirname(this.filePath);
|
|
208
|
+
await fs.mkdir(dir, { recursive: true });
|
|
209
|
+
await fs.writeFile(this.filePath, JSON.stringify(store, null, 2), {
|
|
210
|
+
mode: 0o600,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
async set(key, value) {
|
|
214
|
+
const store = await this.readStore();
|
|
215
|
+
store[key] = value;
|
|
216
|
+
await this.writeStore(store);
|
|
217
|
+
}
|
|
218
|
+
async get(key) {
|
|
219
|
+
const store = await this.readStore();
|
|
220
|
+
return store[key];
|
|
221
|
+
}
|
|
222
|
+
async delete(key) {
|
|
223
|
+
const store = await this.readStore();
|
|
224
|
+
delete store[key];
|
|
225
|
+
await this.writeStore(store);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
exports.SecretStorage = SecretStorage;
|
|
229
|
+
/**
|
|
230
|
+
* OpenCommand Plugin Main Class
|
|
231
|
+
*/
|
|
232
|
+
class OpenCommandPlugin {
|
|
233
|
+
constructor(proxyBinaryPath, storageDir) {
|
|
234
|
+
this.SESSION_TOKEN_KEY = "opencommand.cc_session_token";
|
|
235
|
+
this.proxyManager = new ProxyManager(proxyBinaryPath);
|
|
236
|
+
const dir = storageDir || `${process.env.HOME || "/tmp"}/.opencommand`;
|
|
237
|
+
this.secretStorage = new SecretStorage(dir);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Initialize plugin on editor startup
|
|
241
|
+
*/
|
|
242
|
+
async activate() {
|
|
243
|
+
console.log("OpenCommand Plugin activating...");
|
|
244
|
+
// Try to retrieve stored session token
|
|
245
|
+
const storedToken = await this.secretStorage.get(this.SESSION_TOKEN_KEY);
|
|
246
|
+
if (!storedToken) {
|
|
247
|
+
console.warn("No CC_SESSION_COOKIE found. Please configure token.");
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
// Start proxy
|
|
251
|
+
try {
|
|
252
|
+
const config = await this.proxyManager.start(storedToken);
|
|
253
|
+
console.log(`✓ OpenCommand proxy ready at ${config.port}`);
|
|
254
|
+
// Store config for use by OpenCode
|
|
255
|
+
this.saveOpenCodeConfig(config);
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
console.error("Failed to start proxy:", error);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Clean up on editor shutdown
|
|
263
|
+
*/
|
|
264
|
+
async deactivate() {
|
|
265
|
+
console.log("OpenCommand Plugin deactivating...");
|
|
266
|
+
await this.proxyManager.stop();
|
|
267
|
+
console.log("✓ Proxy stopped");
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Save proxy config to OpenCode configuration.
|
|
271
|
+
* Fix: Persist to file so OpenCodeBar can discover the dynamic port.
|
|
272
|
+
*/
|
|
273
|
+
saveOpenCodeConfig(config) {
|
|
274
|
+
const proxyUrl = `http://localhost:${config.port}`;
|
|
275
|
+
const openCodeConfig = {
|
|
276
|
+
opencommand: {
|
|
277
|
+
proxyUrl,
|
|
278
|
+
apiBaseUrl: `${proxyUrl}/v1`,
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
// Log for debugging
|
|
282
|
+
console.log("Proxy configuration saved:", openCodeConfig);
|
|
283
|
+
// Persist to config file (readable by OpenCodeBar)
|
|
284
|
+
this.persistProxyConfig(proxyUrl, config.port);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Persist proxy URL and port to a config file (Issue #5).
|
|
288
|
+
* OpenCodeBar reads this to discover the dynamically allocated port.
|
|
289
|
+
*/
|
|
290
|
+
persistProxyConfig(url, port) {
|
|
291
|
+
const fs = require("fs");
|
|
292
|
+
const path = require("path");
|
|
293
|
+
const configDir = `${process.env.HOME || "/tmp"}/.opencommand`;
|
|
294
|
+
const configPath = path.join(configDir, "proxy-config.json");
|
|
295
|
+
try {
|
|
296
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
297
|
+
fs.writeFileSync(configPath, JSON.stringify({ url, port, updatedAt: new Date().toISOString() }, null, 2), { mode: 0o644 });
|
|
298
|
+
console.log(`✓ Proxy config persisted to ${configPath}`);
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
console.error("Failed to persist proxy config:", err);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Set session token via command
|
|
306
|
+
*/
|
|
307
|
+
async setSessionToken(token) {
|
|
308
|
+
await this.secretStorage.set(this.SESSION_TOKEN_KEY, token);
|
|
309
|
+
console.log("✓ Session token saved securely");
|
|
310
|
+
// Restart proxy with new token
|
|
311
|
+
await this.proxyManager.stop();
|
|
312
|
+
const config = await this.proxyManager.start(token);
|
|
313
|
+
this.saveOpenCodeConfig(config);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Get proxy configuration
|
|
317
|
+
*/
|
|
318
|
+
getProxyConfig() {
|
|
319
|
+
const config = this.proxyManager.getConfig();
|
|
320
|
+
if (!config) {
|
|
321
|
+
return "Proxy not running";
|
|
322
|
+
}
|
|
323
|
+
return JSON.stringify(config, null, 2);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
exports.OpenCommandPlugin = OpenCommandPlugin;
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencommand-plugin",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "OpenCommand - CommandCode API Plugin for OpenCode",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc",
|
|
8
|
+
"test": "jest",
|
|
9
|
+
"dev": "tsc --watch",
|
|
10
|
+
"clean": "rm -rf dist",
|
|
11
|
+
"prepack": "npm run build"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"opencode",
|
|
15
|
+
"commandcode",
|
|
16
|
+
"api",
|
|
17
|
+
"proxy"
|
|
18
|
+
],
|
|
19
|
+
"author": "OpenCommand",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^20.0.0",
|
|
23
|
+
"@types/jest": "^29.0.0",
|
|
24
|
+
"typescript": "^5.0.0",
|
|
25
|
+
"jest": "^29.0.0",
|
|
26
|
+
"ts-jest": "^29.0.0"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"node-fetch": "^3.0.0"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist/**",
|
|
33
|
+
"README.md",
|
|
34
|
+
"package.json"
|
|
35
|
+
]
|
|
36
|
+
}
|