@fentz26/envcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +27 -0
- package/LICENSE +21 -0
- package/README.md +381 -0
- package/dist/adapters/base.d.ts +79 -0
- package/dist/adapters/base.d.ts.map +1 -0
- package/dist/adapters/base.js +317 -0
- package/dist/adapters/base.js.map +1 -0
- package/dist/adapters/gemini.d.ts +12 -0
- package/dist/adapters/gemini.d.ts.map +1 -0
- package/dist/adapters/gemini.js +284 -0
- package/dist/adapters/gemini.js.map +1 -0
- package/dist/adapters/index.d.ts +5 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +5 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/openai.d.ts +12 -0
- package/dist/adapters/openai.d.ts.map +1 -0
- package/dist/adapters/openai.js +294 -0
- package/dist/adapters/openai.js.map +1 -0
- package/dist/adapters/rest.d.ts +12 -0
- package/dist/adapters/rest.d.ts.map +1 -0
- package/dist/adapters/rest.js +265 -0
- package/dist/adapters/rest.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +472 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +3 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/manager.d.ts +11 -0
- package/dist/config/manager.d.ts.map +1 -0
- package/dist/config/manager.js +117 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/index.d.ts +2 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +2 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +24 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +539 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +2 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/unified.d.ts +21 -0
- package/dist/server/unified.d.ts.map +1 -0
- package/dist/server/unified.js +397 -0
- package/dist/server/unified.js.map +1 -0
- package/dist/storage/index.d.ts +23 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +92 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/types.d.ts +404 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +92 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/crypto.d.ts +17 -0
- package/dist/utils/crypto.d.ts.map +1 -0
- package/dist/utils/crypto.js +73 -0
- package/dist/utils/crypto.js.map +1 -0
- package/dist/utils/http.d.ts +6 -0
- package/dist/utils/http.d.ts.map +1 -0
- package/dist/utils/http.js +43 -0
- package/dist/utils/http.js.map +1 -0
- package/dist/utils/session.d.ts +19 -0
- package/dist/utils/session.d.ts.map +1 -0
- package/dist/utils/session.js +112 -0
- package/dist/utils/session.js.map +1 -0
- package/package.json +50 -0
- package/src/adapters/base.ts +411 -0
- package/src/adapters/gemini.ts +314 -0
- package/src/adapters/index.ts +4 -0
- package/src/adapters/openai.ts +324 -0
- package/src/adapters/rest.ts +294 -0
- package/src/cli/index.ts +640 -0
- package/src/cli.ts +2 -0
- package/src/config/manager.ts +134 -0
- package/src/index.ts +4 -0
- package/src/mcp/index.ts +1 -0
- package/src/mcp/server.ts +623 -0
- package/src/server/index.ts +1 -0
- package/src/server/unified.ts +460 -0
- package/src/storage/index.ts +112 -0
- package/src/types.ts +181 -0
- package/src/utils/crypto.ts +100 -0
- package/src/utils/http.ts +45 -0
- package/src/utils/session.ts +141 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { BaseAdapter } from './base.js';
|
|
2
|
+
import { EnvCPConfig, RESTResponse, ToolDefinition } from '../types.js';
|
|
3
|
+
import { setCorsHeaders, sendJson, parseBody, validateApiKey } from '../utils/http.js';
|
|
4
|
+
import * as http from 'http';
|
|
5
|
+
import * as url from 'url';
|
|
6
|
+
|
|
7
|
+
export class RESTAdapter extends BaseAdapter {
|
|
8
|
+
private server: http.Server | null = null;
|
|
9
|
+
|
|
10
|
+
constructor(config: EnvCPConfig, projectPath: string, password?: string) {
|
|
11
|
+
super(config, projectPath, password);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
protected registerTools(): void {
|
|
15
|
+
const tools: ToolDefinition[] = [
|
|
16
|
+
{
|
|
17
|
+
name: 'envcp_list',
|
|
18
|
+
description: 'List all available environment variable names',
|
|
19
|
+
parameters: {
|
|
20
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Filter by tags' },
|
|
21
|
+
},
|
|
22
|
+
handler: async (params) => this.listVariables(params as { tags?: string[] }),
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'envcp_get',
|
|
26
|
+
description: 'Get an environment variable',
|
|
27
|
+
parameters: {
|
|
28
|
+
name: { type: 'string', required: true, description: 'Variable name' },
|
|
29
|
+
show_value: { type: 'boolean', description: 'Show actual value' },
|
|
30
|
+
},
|
|
31
|
+
handler: async (params) => this.getVariable(params as { name: string; show_value?: boolean }),
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'envcp_set',
|
|
35
|
+
description: 'Create or update an environment variable',
|
|
36
|
+
parameters: {
|
|
37
|
+
name: { type: 'string', required: true, description: 'Variable name' },
|
|
38
|
+
value: { type: 'string', required: true, description: 'Variable value' },
|
|
39
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Tags' },
|
|
40
|
+
description: { type: 'string', description: 'Description' },
|
|
41
|
+
},
|
|
42
|
+
handler: async (params) => this.setVariable(params as any),
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'envcp_delete',
|
|
46
|
+
description: 'Delete an environment variable',
|
|
47
|
+
parameters: {
|
|
48
|
+
name: { type: 'string', required: true, description: 'Variable name' },
|
|
49
|
+
},
|
|
50
|
+
handler: async (params) => this.deleteVariable(params as { name: string }),
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'envcp_sync',
|
|
54
|
+
description: 'Sync variables to .env file',
|
|
55
|
+
parameters: {},
|
|
56
|
+
handler: async () => this.syncToEnv(),
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'envcp_add_to_env',
|
|
60
|
+
description: 'Add variable to .env file',
|
|
61
|
+
parameters: {
|
|
62
|
+
name: { type: 'string', required: true, description: 'Variable name' },
|
|
63
|
+
env_file: { type: 'string', description: 'Path to .env file' },
|
|
64
|
+
},
|
|
65
|
+
handler: async (params) => this.addToEnv(params as { name: string; env_file?: string }),
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'envcp_check_access',
|
|
69
|
+
description: 'Check if a variable can be accessed',
|
|
70
|
+
parameters: {
|
|
71
|
+
name: { type: 'string', required: true, description: 'Variable name' },
|
|
72
|
+
},
|
|
73
|
+
handler: async (params) => this.checkAccess(params as { name: string }),
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'envcp_run',
|
|
77
|
+
description: 'Execute a command with environment variables',
|
|
78
|
+
parameters: {
|
|
79
|
+
command: { type: 'string', required: true, description: 'Command to execute' },
|
|
80
|
+
variables: { type: 'array', items: { type: 'string' }, required: true, description: 'Variables to inject' },
|
|
81
|
+
},
|
|
82
|
+
handler: async (params) => this.runCommand(params as { command: string; variables: string[] }),
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
tools.forEach(tool => this.tools.set(tool.name, tool));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private createResponse<T>(success: boolean, data?: T, error?: string): RESTResponse<T> {
|
|
90
|
+
return {
|
|
91
|
+
success,
|
|
92
|
+
data,
|
|
93
|
+
error,
|
|
94
|
+
timestamp: new Date().toISOString(),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
async startServer(port: number, host: string, apiKey?: string): Promise<void> {
|
|
100
|
+
await this.init();
|
|
101
|
+
|
|
102
|
+
this.server = http.createServer(async (req, res) => {
|
|
103
|
+
setCorsHeaders(res);
|
|
104
|
+
|
|
105
|
+
if (req.method === 'OPTIONS') {
|
|
106
|
+
res.writeHead(204);
|
|
107
|
+
res.end();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// API key validation
|
|
112
|
+
if (apiKey) {
|
|
113
|
+
const providedKey = (req.headers['x-api-key'] || req.headers['authorization']?.replace('Bearer ', '')) as string | undefined;
|
|
114
|
+
if (!validateApiKey(providedKey, apiKey)) {
|
|
115
|
+
sendJson(res, 401, this.createResponse(false, undefined, 'Invalid API key'));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const parsedUrl = url.parse(req.url || '/', true);
|
|
121
|
+
const pathname = parsedUrl.pathname || '/';
|
|
122
|
+
const segments = pathname.split('/').filter(Boolean);
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
// Routes:
|
|
126
|
+
// GET /api/variables - List variables
|
|
127
|
+
// GET /api/variables/:name - Get variable
|
|
128
|
+
// POST /api/variables - Create variable
|
|
129
|
+
// PUT /api/variables/:name - Update variable
|
|
130
|
+
// DELETE /api/variables/:name - Delete variable
|
|
131
|
+
// POST /api/sync - Sync to .env
|
|
132
|
+
// POST /api/run - Run command
|
|
133
|
+
// GET /api/tools - List available tools
|
|
134
|
+
// POST /api/tools/:name - Call a tool
|
|
135
|
+
|
|
136
|
+
if (segments[0] === 'api') {
|
|
137
|
+
const resource = segments[1];
|
|
138
|
+
|
|
139
|
+
// Health check
|
|
140
|
+
if (pathname === '/api/health' || pathname === '/api') {
|
|
141
|
+
sendJson(res, 200, this.createResponse(true, {
|
|
142
|
+
status: 'ok',
|
|
143
|
+
version: '1.0.0',
|
|
144
|
+
mode: 'rest',
|
|
145
|
+
}));
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// List tools
|
|
150
|
+
if (resource === 'tools' && !segments[2] && req.method === 'GET') {
|
|
151
|
+
const tools = this.getToolDefinitions().map(t => ({
|
|
152
|
+
name: t.name,
|
|
153
|
+
description: t.description,
|
|
154
|
+
parameters: t.parameters,
|
|
155
|
+
}));
|
|
156
|
+
sendJson(res, 200, this.createResponse(true, { tools }));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Call tool
|
|
161
|
+
if (resource === 'tools' && segments[2] && req.method === 'POST') {
|
|
162
|
+
const toolName = segments[2];
|
|
163
|
+
const body = await parseBody(req);
|
|
164
|
+
const result = await this.callTool(toolName, body);
|
|
165
|
+
sendJson(res, 200, this.createResponse(true, result));
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Variables
|
|
170
|
+
if (resource === 'variables') {
|
|
171
|
+
const varName = segments[2];
|
|
172
|
+
|
|
173
|
+
if (!varName && req.method === 'GET') {
|
|
174
|
+
const tags = parsedUrl.query.tags
|
|
175
|
+
? (Array.isArray(parsedUrl.query.tags) ? parsedUrl.query.tags : [parsedUrl.query.tags])
|
|
176
|
+
: undefined;
|
|
177
|
+
const result = await this.callTool('envcp_list', { tags });
|
|
178
|
+
sendJson(res, 200, this.createResponse(true, result));
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (!varName && req.method === 'POST') {
|
|
183
|
+
const body = await parseBody(req);
|
|
184
|
+
const result = await this.callTool('envcp_set', body);
|
|
185
|
+
sendJson(res, 201, this.createResponse(true, result));
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (varName && req.method === 'GET') {
|
|
190
|
+
const showValue = parsedUrl.query.show_value === 'true';
|
|
191
|
+
const result = await this.callTool('envcp_get', { name: varName, show_value: showValue });
|
|
192
|
+
sendJson(res, 200, this.createResponse(true, result));
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (varName && req.method === 'PUT') {
|
|
197
|
+
const body = await parseBody(req);
|
|
198
|
+
const result = await this.callTool('envcp_set', { ...body, name: varName });
|
|
199
|
+
sendJson(res, 200, this.createResponse(true, result));
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (varName && req.method === 'DELETE') {
|
|
204
|
+
const result = await this.callTool('envcp_delete', { name: varName });
|
|
205
|
+
sendJson(res, 200, this.createResponse(true, result));
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Sync
|
|
211
|
+
if (resource === 'sync' && req.method === 'POST') {
|
|
212
|
+
const result = await this.callTool('envcp_sync', {});
|
|
213
|
+
sendJson(res, 200, this.createResponse(true, result));
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Run
|
|
218
|
+
if (resource === 'run' && req.method === 'POST') {
|
|
219
|
+
const body = await parseBody(req);
|
|
220
|
+
const result = await this.callTool('envcp_run', body);
|
|
221
|
+
sendJson(res, 200, this.createResponse(true, result));
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Check access
|
|
226
|
+
if (resource === 'access' && segments[2] && req.method === 'GET') {
|
|
227
|
+
const result = await this.callTool('envcp_check_access', { name: segments[2] });
|
|
228
|
+
sendJson(res, 200, this.createResponse(true, result));
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// 404
|
|
234
|
+
sendJson(res, 404, this.createResponse(false, undefined, 'Not found'));
|
|
235
|
+
|
|
236
|
+
} catch (error: any) {
|
|
237
|
+
const status = error.message.includes('locked') ? 401 :
|
|
238
|
+
error.message.includes('not found') ? 404 :
|
|
239
|
+
error.message.includes('disabled') ? 403 : 500;
|
|
240
|
+
sendJson(res, status, this.createResponse(false, undefined, error.message));
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
return new Promise((resolve) => {
|
|
245
|
+
this.server!.listen(port, host, () => {
|
|
246
|
+
resolve();
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
stopServer(): void {
|
|
252
|
+
if (this.server) {
|
|
253
|
+
this.server.close();
|
|
254
|
+
this.server = null;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
getApiDocs(): string {
|
|
259
|
+
return `
|
|
260
|
+
EnvCP REST API
|
|
261
|
+
==============
|
|
262
|
+
|
|
263
|
+
Base URL: http://localhost:{port}/api
|
|
264
|
+
|
|
265
|
+
Authentication:
|
|
266
|
+
Header: X-API-Key: {your-api-key}
|
|
267
|
+
Or: Authorization: Bearer {your-api-key}
|
|
268
|
+
|
|
269
|
+
Endpoints:
|
|
270
|
+
|
|
271
|
+
GET /api/health - Health check
|
|
272
|
+
GET /api/tools - List available tools
|
|
273
|
+
POST /api/tools/:name - Call a tool by name
|
|
274
|
+
|
|
275
|
+
GET /api/variables - List all variables
|
|
276
|
+
GET /api/variables/:name - Get a variable
|
|
277
|
+
POST /api/variables - Create a variable
|
|
278
|
+
PUT /api/variables/:name - Update a variable
|
|
279
|
+
DELETE /api/variables/:name - Delete a variable
|
|
280
|
+
|
|
281
|
+
POST /api/sync - Sync to .env file
|
|
282
|
+
POST /api/run - Run command with variables
|
|
283
|
+
GET /api/access/:name - Check variable access
|
|
284
|
+
|
|
285
|
+
Response format:
|
|
286
|
+
{
|
|
287
|
+
"success": true/false,
|
|
288
|
+
"data": { ... },
|
|
289
|
+
"error": "Error message (if any)",
|
|
290
|
+
"timestamp": "ISO timestamp"
|
|
291
|
+
}
|
|
292
|
+
`.trim();
|
|
293
|
+
}
|
|
294
|
+
}
|