@fentz26/envcp 1.0.1 → 1.0.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/README.md +79 -130
- package/__tests__/config.test.ts +65 -0
- package/__tests__/crypto.test.ts +76 -0
- package/__tests__/http.test.ts +49 -0
- package/__tests__/storage.test.ts +94 -0
- package/dist/adapters/base.d.ts +1 -2
- package/dist/adapters/base.d.ts.map +1 -1
- package/dist/adapters/base.js +139 -14
- package/dist/adapters/base.js.map +1 -1
- package/dist/adapters/gemini.d.ts +1 -0
- package/dist/adapters/gemini.d.ts.map +1 -1
- package/dist/adapters/gemini.js +13 -99
- package/dist/adapters/gemini.js.map +1 -1
- package/dist/adapters/openai.d.ts +1 -0
- package/dist/adapters/openai.d.ts.map +1 -1
- package/dist/adapters/openai.js +13 -99
- package/dist/adapters/openai.js.map +1 -1
- package/dist/adapters/rest.d.ts +1 -0
- package/dist/adapters/rest.d.ts.map +1 -1
- package/dist/adapters/rest.js +16 -13
- package/dist/adapters/rest.js.map +1 -1
- package/dist/cli/index.js +132 -196
- package/dist/cli/index.js.map +1 -1
- package/dist/config/manager.d.ts.map +1 -1
- package/dist/config/manager.js +4 -1
- package/dist/config/manager.js.map +1 -1
- package/dist/mcp/server.d.ts +1 -16
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +23 -511
- package/dist/mcp/server.js.map +1 -1
- package/dist/server/unified.d.ts +1 -0
- package/dist/server/unified.d.ts.map +1 -1
- package/dist/server/unified.js +31 -19
- package/dist/server/unified.js.map +1 -1
- package/dist/storage/index.d.ts +2 -0
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +18 -4
- package/dist/storage/index.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/http.d.ts +13 -1
- package/dist/utils/http.d.ts.map +1 -1
- package/dist/utils/http.js +65 -2
- package/dist/utils/http.js.map +1 -1
- package/dist/utils/session.d.ts.map +1 -1
- package/dist/utils/session.js +8 -3
- package/dist/utils/session.js.map +1 -1
- package/jest.config.js +11 -0
- package/package.json +4 -3
- package/src/adapters/base.ts +147 -16
- package/src/adapters/gemini.ts +19 -105
- package/src/adapters/openai.ts +19 -105
- package/src/adapters/rest.ts +19 -15
- package/src/cli/index.ts +135 -259
- package/src/config/manager.ts +4 -1
- package/src/mcp/server.ts +26 -582
- package/src/server/unified.ts +37 -23
- package/src/storage/index.ts +22 -6
- package/src/types.ts +2 -0
- package/src/utils/http.ts +76 -2
- package/src/utils/session.ts +13 -8
package/src/cli/index.ts
CHANGED
|
@@ -3,11 +3,51 @@ import inquirer from 'inquirer';
|
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import * as path from 'path';
|
|
5
5
|
import * as fs from 'fs-extra';
|
|
6
|
-
import { loadConfig,
|
|
7
|
-
import { StorageManager
|
|
6
|
+
import { loadConfig, initConfig } from '../config/manager.js';
|
|
7
|
+
import { StorageManager } from '../storage/index.js';
|
|
8
8
|
import { SessionManager } from '../utils/session.js';
|
|
9
9
|
import { maskValue, validatePassword } from '../utils/crypto.js';
|
|
10
|
-
import { Variable } from '../types.js';
|
|
10
|
+
import { Variable, EnvCPConfig } from '../types.js';
|
|
11
|
+
|
|
12
|
+
async function withSession(fn: (storage: StorageManager, password: string, config: EnvCPConfig, projectPath: string) => Promise<void>): Promise<void> {
|
|
13
|
+
const projectPath = process.cwd();
|
|
14
|
+
const config = await loadConfig(projectPath);
|
|
15
|
+
|
|
16
|
+
const sessionManager = new SessionManager(
|
|
17
|
+
path.join(projectPath, config.session?.path || '.envcp/.session'),
|
|
18
|
+
config.session?.timeout_minutes || 30,
|
|
19
|
+
config.session?.max_extensions || 5
|
|
20
|
+
);
|
|
21
|
+
await sessionManager.init();
|
|
22
|
+
|
|
23
|
+
let session = await sessionManager.load();
|
|
24
|
+
let password = '';
|
|
25
|
+
|
|
26
|
+
if (!session) {
|
|
27
|
+
const answer = await inquirer.prompt([
|
|
28
|
+
{ type: 'password', name: 'password', message: 'Enter password:', mask: '*' }
|
|
29
|
+
]);
|
|
30
|
+
password = answer.password;
|
|
31
|
+
|
|
32
|
+
const validation = validatePassword(password, config.password || {});
|
|
33
|
+
if (!validation.valid) {
|
|
34
|
+
console.log(chalk.red(validation.error));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
session = await sessionManager.create(password);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
password = sessionManager.getPassword() || password;
|
|
42
|
+
|
|
43
|
+
const storage = new StorageManager(
|
|
44
|
+
path.join(projectPath, config.storage.path),
|
|
45
|
+
config.storage.encrypted
|
|
46
|
+
);
|
|
47
|
+
if (password) storage.setPassword(password);
|
|
48
|
+
|
|
49
|
+
await fn(storage, password, config, projectPath);
|
|
50
|
+
}
|
|
11
51
|
|
|
12
52
|
const program = new Command();
|
|
13
53
|
|
|
@@ -207,74 +247,39 @@ program
|
|
|
207
247
|
.option('-t, --tags <tags>', 'Tags (comma-separated)')
|
|
208
248
|
.option('-d, --description <desc>', 'Description')
|
|
209
249
|
.action(async (name, options) => {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
]);
|
|
227
|
-
password = answer.password;
|
|
228
|
-
|
|
229
|
-
const validation = validatePassword(password, config.password || {});
|
|
230
|
-
if (!validation.valid) {
|
|
231
|
-
console.log(chalk.red(validation.error));
|
|
232
|
-
return;
|
|
250
|
+
await withSession(async (storage, _password, config) => {
|
|
251
|
+
let value = options.value;
|
|
252
|
+
let tags: string[] = [];
|
|
253
|
+
let description = options.description;
|
|
254
|
+
|
|
255
|
+
if (!value) {
|
|
256
|
+
const answers = await inquirer.prompt([
|
|
257
|
+
{ type: 'password', name: 'value', message: 'Enter value:', mask: '*' },
|
|
258
|
+
{ type: 'input', name: 'tags', message: 'Tags (comma-separated):' },
|
|
259
|
+
{ type: 'input', name: 'description', message: 'Description:' },
|
|
260
|
+
]);
|
|
261
|
+
value = answers.value;
|
|
262
|
+
tags = answers.tags.split(',').map((t: string) => t.trim()).filter(Boolean);
|
|
263
|
+
description = answers.description;
|
|
264
|
+
} else if (options.tags) {
|
|
265
|
+
tags = options.tags.split(',').map((t: string) => t.trim()).filter(Boolean);
|
|
233
266
|
}
|
|
234
|
-
|
|
235
|
-
session = await sessionManager.create(password);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
password = sessionManager.getPassword() || password;
|
|
239
|
-
|
|
240
|
-
let value = options.value;
|
|
241
|
-
let tags: string[] = [];
|
|
242
|
-
let description = options.description;
|
|
243
|
-
|
|
244
|
-
if (!value) {
|
|
245
|
-
const answers = await inquirer.prompt([
|
|
246
|
-
{ type: 'password', name: 'value', message: 'Enter value:', mask: '*' },
|
|
247
|
-
{ type: 'input', name: 'tags', message: 'Tags (comma-separated):' },
|
|
248
|
-
{ type: 'input', name: 'description', message: 'Description:' },
|
|
249
|
-
]);
|
|
250
|
-
value = answers.value;
|
|
251
|
-
tags = answers.tags.split(',').map((t: string) => t.trim()).filter(Boolean);
|
|
252
|
-
description = answers.description;
|
|
253
|
-
} else if (options.tags) {
|
|
254
|
-
tags = options.tags.split(',').map((t: string) => t.trim()).filter(Boolean);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
const storage = new StorageManager(
|
|
258
|
-
path.join(projectPath, config.storage.path),
|
|
259
|
-
config.storage.encrypted
|
|
260
|
-
);
|
|
261
|
-
if (password) storage.setPassword(password);
|
|
262
|
-
|
|
263
|
-
const now = new Date().toISOString();
|
|
264
|
-
const variable: Variable = {
|
|
265
|
-
name,
|
|
266
|
-
value,
|
|
267
|
-
encrypted: config.storage.encrypted,
|
|
268
|
-
tags: tags.length > 0 ? tags : undefined,
|
|
269
|
-
description,
|
|
270
|
-
created: now,
|
|
271
|
-
updated: now,
|
|
272
|
-
sync_to_env: true,
|
|
273
|
-
};
|
|
274
267
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
268
|
+
const now = new Date().toISOString();
|
|
269
|
+
const variable: Variable = {
|
|
270
|
+
name,
|
|
271
|
+
value,
|
|
272
|
+
encrypted: config.storage.encrypted,
|
|
273
|
+
tags: tags.length > 0 ? tags : undefined,
|
|
274
|
+
description,
|
|
275
|
+
created: now,
|
|
276
|
+
updated: now,
|
|
277
|
+
sync_to_env: true,
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
await storage.set(name, variable);
|
|
281
|
+
console.log(chalk.green(`Variable '${name}' added successfully`));
|
|
282
|
+
});
|
|
278
283
|
});
|
|
279
284
|
|
|
280
285
|
program
|
|
@@ -282,194 +287,88 @@ program
|
|
|
282
287
|
.description('List all variables (names only, values hidden)')
|
|
283
288
|
.option('-v, --show-values', 'Show actual values')
|
|
284
289
|
.action(async (options) => {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
const sessionManager = new SessionManager(
|
|
289
|
-
path.join(projectPath, config.session?.path || '.envcp/.session'),
|
|
290
|
-
config.session?.timeout_minutes || 30,
|
|
291
|
-
config.session?.max_extensions || 5
|
|
292
|
-
);
|
|
293
|
-
await sessionManager.init();
|
|
294
|
-
|
|
295
|
-
let session = await sessionManager.load();
|
|
296
|
-
let password = '';
|
|
297
|
-
|
|
298
|
-
if (!session) {
|
|
299
|
-
const answer = await inquirer.prompt([
|
|
300
|
-
{ type: 'password', name: 'password', message: 'Enter password:', mask: '*' }
|
|
301
|
-
]);
|
|
302
|
-
password = answer.password;
|
|
303
|
-
session = await sessionManager.create(password);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
password = sessionManager.getPassword() || password;
|
|
290
|
+
await withSession(async (storage) => {
|
|
291
|
+
const variables = await storage.load();
|
|
292
|
+
const names = Object.keys(variables);
|
|
307
293
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
if (password) storage.setPassword(password);
|
|
294
|
+
if (names.length === 0) {
|
|
295
|
+
console.log(chalk.yellow('No variables found'));
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
313
298
|
|
|
314
|
-
|
|
315
|
-
const names = Object.keys(variables);
|
|
299
|
+
console.log(chalk.blue(`\nVariables (${names.length}):\n`));
|
|
316
300
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
301
|
+
for (const name of names) {
|
|
302
|
+
const v = variables[name];
|
|
303
|
+
const value = options.showValues ? v.value : maskValue(v.value);
|
|
304
|
+
const tags = v.tags ? chalk.gray(` [${v.tags.join(', ')}]`) : '';
|
|
305
|
+
console.log(` ${chalk.cyan(name)} = ${value}${tags}`);
|
|
306
|
+
}
|
|
321
307
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
for (const name of names) {
|
|
325
|
-
const v = variables[name];
|
|
326
|
-
const value = options.showValues ? v.value : maskValue(v.value);
|
|
327
|
-
const tags = v.tags ? chalk.gray(` [${v.tags.join(', ')}]`) : '';
|
|
328
|
-
console.log(` ${chalk.cyan(name)} = ${value}${tags}`);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
console.log('');
|
|
308
|
+
console.log('');
|
|
309
|
+
});
|
|
332
310
|
});
|
|
333
311
|
|
|
334
312
|
program
|
|
335
313
|
.command('get <name>')
|
|
336
314
|
.description('Get a variable value')
|
|
337
315
|
.action(async (name) => {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
const sessionManager = new SessionManager(
|
|
342
|
-
path.join(projectPath, config.session?.path || '.envcp/.session'),
|
|
343
|
-
config.session?.timeout_minutes || 30,
|
|
344
|
-
config.session?.max_extensions || 5
|
|
345
|
-
);
|
|
346
|
-
await sessionManager.init();
|
|
347
|
-
|
|
348
|
-
let session = await sessionManager.load();
|
|
349
|
-
let password = '';
|
|
350
|
-
|
|
351
|
-
if (!session) {
|
|
352
|
-
const answer = await inquirer.prompt([
|
|
353
|
-
{ type: 'password', name: 'password', message: 'Enter password:', mask: '*' }
|
|
354
|
-
]);
|
|
355
|
-
password = answer.password;
|
|
356
|
-
session = await sessionManager.create(password);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
password = sessionManager.getPassword() || password;
|
|
360
|
-
|
|
361
|
-
const storage = new StorageManager(
|
|
362
|
-
path.join(projectPath, config.storage.path),
|
|
363
|
-
config.storage.encrypted
|
|
364
|
-
);
|
|
365
|
-
if (password) storage.setPassword(password);
|
|
316
|
+
await withSession(async (storage) => {
|
|
317
|
+
const variable = await storage.get(name);
|
|
366
318
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
319
|
+
if (!variable) {
|
|
320
|
+
console.log(chalk.red(`Variable '${name}' not found`));
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
373
323
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
324
|
+
console.log(chalk.cyan(name));
|
|
325
|
+
console.log(` Value: ${variable.value}`);
|
|
326
|
+
if (variable.tags) console.log(` Tags: ${variable.tags.join(', ')}`);
|
|
327
|
+
if (variable.description) console.log(` Description: ${variable.description}`);
|
|
328
|
+
});
|
|
378
329
|
});
|
|
379
330
|
|
|
380
331
|
program
|
|
381
332
|
.command('remove <name>')
|
|
382
333
|
.description('Remove a variable')
|
|
383
334
|
.action(async (name) => {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
const sessionManager = new SessionManager(
|
|
388
|
-
path.join(projectPath, config.session?.path || '.envcp/.session'),
|
|
389
|
-
config.session?.timeout_minutes || 30,
|
|
390
|
-
config.session?.max_extensions || 5
|
|
391
|
-
);
|
|
392
|
-
await sessionManager.init();
|
|
393
|
-
|
|
394
|
-
let session = await sessionManager.load();
|
|
395
|
-
let password = '';
|
|
396
|
-
|
|
397
|
-
if (!session) {
|
|
398
|
-
const answer = await inquirer.prompt([
|
|
399
|
-
{ type: 'password', name: 'password', message: 'Enter password:', mask: '*' }
|
|
400
|
-
]);
|
|
401
|
-
password = answer.password;
|
|
402
|
-
session = await sessionManager.create(password);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
password = sessionManager.getPassword() || password;
|
|
406
|
-
|
|
407
|
-
const storage = new StorageManager(
|
|
408
|
-
path.join(projectPath, config.storage.path),
|
|
409
|
-
config.storage.encrypted
|
|
410
|
-
);
|
|
411
|
-
if (password) storage.setPassword(password);
|
|
335
|
+
await withSession(async (storage) => {
|
|
336
|
+
const deleted = await storage.delete(name);
|
|
412
337
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
}
|
|
338
|
+
if (deleted) {
|
|
339
|
+
console.log(chalk.green(`Variable '${name}' removed`));
|
|
340
|
+
} else {
|
|
341
|
+
console.log(chalk.red(`Variable '${name}' not found`));
|
|
342
|
+
}
|
|
343
|
+
});
|
|
420
344
|
});
|
|
421
345
|
|
|
422
346
|
program
|
|
423
347
|
.command('sync')
|
|
424
348
|
.description('Sync variables to .env file')
|
|
425
349
|
.action(async () => {
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
return;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
const sessionManager = new SessionManager(
|
|
435
|
-
path.join(projectPath, config.session?.path || '.envcp/.session'),
|
|
436
|
-
config.session?.timeout_minutes || 30,
|
|
437
|
-
config.session?.max_extensions || 5
|
|
438
|
-
);
|
|
439
|
-
await sessionManager.init();
|
|
440
|
-
|
|
441
|
-
let session = await sessionManager.load();
|
|
442
|
-
let password = '';
|
|
443
|
-
|
|
444
|
-
if (!session) {
|
|
445
|
-
const answer = await inquirer.prompt([
|
|
446
|
-
{ type: 'password', name: 'password', message: 'Enter password:', mask: '*' }
|
|
447
|
-
]);
|
|
448
|
-
password = answer.password;
|
|
449
|
-
session = await sessionManager.create(password);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
password = sessionManager.getPassword() || password;
|
|
350
|
+
await withSession(async (storage, _password, config, projectPath) => {
|
|
351
|
+
if (!config.sync.enabled) {
|
|
352
|
+
console.log(chalk.yellow('Sync is disabled in configuration'));
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
453
355
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
config.storage.encrypted
|
|
457
|
-
);
|
|
458
|
-
if (password) storage.setPassword(password);
|
|
356
|
+
const variables = await storage.load();
|
|
357
|
+
const lines: string[] = [];
|
|
459
358
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
if (config.sync.header) {
|
|
464
|
-
lines.push(config.sync.header);
|
|
465
|
-
}
|
|
359
|
+
if (config.sync.header) {
|
|
360
|
+
lines.push(config.sync.header);
|
|
361
|
+
}
|
|
466
362
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
363
|
+
for (const [name, variable] of Object.entries(variables)) {
|
|
364
|
+
const needsQuoting = /[\s#"'\\]/.test(variable.value);
|
|
365
|
+
const val = needsQuoting ? `"${variable.value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"` : variable.value;
|
|
366
|
+
lines.push(`${name}=${val}`);
|
|
367
|
+
}
|
|
470
368
|
|
|
471
|
-
|
|
472
|
-
|
|
369
|
+
await fs.writeFile(path.join(projectPath, config.sync.target), lines.join('\n'), 'utf8');
|
|
370
|
+
console.log(chalk.green(`Synced ${lines.length} variables to ${config.sync.target}`));
|
|
371
|
+
});
|
|
473
372
|
});
|
|
474
373
|
|
|
475
374
|
program
|
|
@@ -528,7 +427,7 @@ program
|
|
|
528
427
|
const { UnifiedServer } = await import('../server/unified.js');
|
|
529
428
|
|
|
530
429
|
const serverConfig = {
|
|
531
|
-
mode: mode as
|
|
430
|
+
mode: mode as 'mcp' | 'rest' | 'openai' | 'gemini' | 'all' | 'auto',
|
|
532
431
|
port,
|
|
533
432
|
host,
|
|
534
433
|
api_key: apiKey,
|
|
@@ -588,35 +487,7 @@ program
|
|
|
588
487
|
.description('Export variables')
|
|
589
488
|
.option('-f, --format <format>', 'Output format: env, json, yaml', 'env')
|
|
590
489
|
.action(async (options) => {
|
|
591
|
-
|
|
592
|
-
const config = await loadConfig(projectPath);
|
|
593
|
-
|
|
594
|
-
const sessionManager = new SessionManager(
|
|
595
|
-
path.join(projectPath, config.session?.path || '.envcp/.session'),
|
|
596
|
-
config.session?.timeout_minutes || 30,
|
|
597
|
-
config.session?.max_extensions || 5
|
|
598
|
-
);
|
|
599
|
-
await sessionManager.init();
|
|
600
|
-
|
|
601
|
-
let session = await sessionManager.load();
|
|
602
|
-
let password = '';
|
|
603
|
-
|
|
604
|
-
if (!session) {
|
|
605
|
-
const answer = await inquirer.prompt([
|
|
606
|
-
{ type: 'password', name: 'password', message: 'Enter password:', mask: '*' }
|
|
607
|
-
]);
|
|
608
|
-
password = answer.password;
|
|
609
|
-
session = await sessionManager.create(password);
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
password = sessionManager.getPassword() || password;
|
|
613
|
-
|
|
614
|
-
const storage = new StorageManager(
|
|
615
|
-
path.join(projectPath, config.storage.path),
|
|
616
|
-
config.storage.encrypted
|
|
617
|
-
);
|
|
618
|
-
if (password) storage.setPassword(password);
|
|
619
|
-
|
|
490
|
+
await withSession(async (storage) => {
|
|
620
491
|
const variables = await storage.load();
|
|
621
492
|
|
|
622
493
|
let output: string;
|
|
@@ -630,11 +501,16 @@ program
|
|
|
630
501
|
output = yaml.dump(variables);
|
|
631
502
|
break;
|
|
632
503
|
default:
|
|
633
|
-
const lines = Object.entries(variables).map(([k, v]) =>
|
|
504
|
+
const lines = Object.entries(variables).map(([k, v]) => {
|
|
505
|
+
const needsQuoting = /[\s#"'\\]/.test(v.value);
|
|
506
|
+
const val = needsQuoting ? `"${v.value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"` : v.value;
|
|
507
|
+
return `${k}=${val}`;
|
|
508
|
+
});
|
|
634
509
|
output = lines.join('\n');
|
|
635
510
|
}
|
|
636
511
|
|
|
637
512
|
console.log(output);
|
|
513
|
+
});
|
|
638
514
|
});
|
|
639
515
|
|
|
640
516
|
program.parse();
|
package/src/config/manager.ts
CHANGED
|
@@ -16,8 +16,10 @@ const DEFAULT_CONFIG: Partial<EnvCPConfig> = {
|
|
|
16
16
|
allow_ai_write: false,
|
|
17
17
|
allow_ai_delete: false,
|
|
18
18
|
allow_ai_export: false,
|
|
19
|
+
allow_ai_execute: false,
|
|
19
20
|
allow_ai_active_check: false,
|
|
20
21
|
require_user_reference: true,
|
|
22
|
+
allowed_commands: undefined,
|
|
21
23
|
require_confirmation: true,
|
|
22
24
|
mask_values: true,
|
|
23
25
|
audit_log: true,
|
|
@@ -92,7 +94,8 @@ export function validateVariableName(name: string): boolean {
|
|
|
92
94
|
}
|
|
93
95
|
|
|
94
96
|
export function matchesPattern(name: string, pattern: string): boolean {
|
|
95
|
-
const
|
|
97
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
|
|
98
|
+
const regex = new RegExp('^' + escaped.replace(/\*/g, '.*') + '$');
|
|
96
99
|
return regex.test(name);
|
|
97
100
|
}
|
|
98
101
|
|