@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.
Files changed (95) hide show
  1. package/.github/workflows/publish.yml +27 -0
  2. package/LICENSE +21 -0
  3. package/README.md +381 -0
  4. package/dist/adapters/base.d.ts +79 -0
  5. package/dist/adapters/base.d.ts.map +1 -0
  6. package/dist/adapters/base.js +317 -0
  7. package/dist/adapters/base.js.map +1 -0
  8. package/dist/adapters/gemini.d.ts +12 -0
  9. package/dist/adapters/gemini.d.ts.map +1 -0
  10. package/dist/adapters/gemini.js +284 -0
  11. package/dist/adapters/gemini.js.map +1 -0
  12. package/dist/adapters/index.d.ts +5 -0
  13. package/dist/adapters/index.d.ts.map +1 -0
  14. package/dist/adapters/index.js +5 -0
  15. package/dist/adapters/index.js.map +1 -0
  16. package/dist/adapters/openai.d.ts +12 -0
  17. package/dist/adapters/openai.d.ts.map +1 -0
  18. package/dist/adapters/openai.js +294 -0
  19. package/dist/adapters/openai.js.map +1 -0
  20. package/dist/adapters/rest.d.ts +12 -0
  21. package/dist/adapters/rest.d.ts.map +1 -0
  22. package/dist/adapters/rest.js +265 -0
  23. package/dist/adapters/rest.js.map +1 -0
  24. package/dist/cli/index.d.ts +2 -0
  25. package/dist/cli/index.d.ts.map +1 -0
  26. package/dist/cli/index.js +472 -0
  27. package/dist/cli/index.js.map +1 -0
  28. package/dist/cli.d.ts +3 -0
  29. package/dist/cli.d.ts.map +1 -0
  30. package/dist/cli.js +3 -0
  31. package/dist/cli.js.map +1 -0
  32. package/dist/config/manager.d.ts +11 -0
  33. package/dist/config/manager.d.ts.map +1 -0
  34. package/dist/config/manager.js +117 -0
  35. package/dist/config/manager.js.map +1 -0
  36. package/dist/index.d.ts +5 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +5 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/mcp/index.d.ts +2 -0
  41. package/dist/mcp/index.d.ts.map +1 -0
  42. package/dist/mcp/index.js +2 -0
  43. package/dist/mcp/index.js.map +1 -0
  44. package/dist/mcp/server.d.ts +24 -0
  45. package/dist/mcp/server.d.ts.map +1 -0
  46. package/dist/mcp/server.js +539 -0
  47. package/dist/mcp/server.js.map +1 -0
  48. package/dist/server/index.d.ts +2 -0
  49. package/dist/server/index.d.ts.map +1 -0
  50. package/dist/server/index.js +2 -0
  51. package/dist/server/index.js.map +1 -0
  52. package/dist/server/unified.d.ts +21 -0
  53. package/dist/server/unified.d.ts.map +1 -0
  54. package/dist/server/unified.js +397 -0
  55. package/dist/server/unified.js.map +1 -0
  56. package/dist/storage/index.d.ts +23 -0
  57. package/dist/storage/index.d.ts.map +1 -0
  58. package/dist/storage/index.js +92 -0
  59. package/dist/storage/index.js.map +1 -0
  60. package/dist/types.d.ts +404 -0
  61. package/dist/types.d.ts.map +1 -0
  62. package/dist/types.js +92 -0
  63. package/dist/types.js.map +1 -0
  64. package/dist/utils/crypto.d.ts +17 -0
  65. package/dist/utils/crypto.d.ts.map +1 -0
  66. package/dist/utils/crypto.js +73 -0
  67. package/dist/utils/crypto.js.map +1 -0
  68. package/dist/utils/http.d.ts +6 -0
  69. package/dist/utils/http.d.ts.map +1 -0
  70. package/dist/utils/http.js +43 -0
  71. package/dist/utils/http.js.map +1 -0
  72. package/dist/utils/session.d.ts +19 -0
  73. package/dist/utils/session.d.ts.map +1 -0
  74. package/dist/utils/session.js +112 -0
  75. package/dist/utils/session.js.map +1 -0
  76. package/package.json +50 -0
  77. package/src/adapters/base.ts +411 -0
  78. package/src/adapters/gemini.ts +314 -0
  79. package/src/adapters/index.ts +4 -0
  80. package/src/adapters/openai.ts +324 -0
  81. package/src/adapters/rest.ts +294 -0
  82. package/src/cli/index.ts +640 -0
  83. package/src/cli.ts +2 -0
  84. package/src/config/manager.ts +134 -0
  85. package/src/index.ts +4 -0
  86. package/src/mcp/index.ts +1 -0
  87. package/src/mcp/server.ts +623 -0
  88. package/src/server/index.ts +1 -0
  89. package/src/server/unified.ts +460 -0
  90. package/src/storage/index.ts +112 -0
  91. package/src/types.ts +181 -0
  92. package/src/utils/crypto.ts +100 -0
  93. package/src/utils/http.ts +45 -0
  94. package/src/utils/session.ts +141 -0
  95. 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
+ }