proofscan 0.5.6 → 0.5.7

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.
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,mBAAmB,CAAC,aAAa,EAAE,MAAM,MAAM,GAAG,OAAO,CAiFxE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBpC,wBAAgB,mBAAmB,CAAC,aAAa,EAAE,MAAM,MAAM,GAAG,OAAO,CAkZxE"}
@@ -2,7 +2,10 @@
2
2
  * Config commands
3
3
  */
4
4
  import { Command } from 'commander';
5
+ import { createInterface } from 'readline';
5
6
  import { ConfigManager } from '../config/index.js';
7
+ import { parseConnectorJson, toConnector, findDuplicates, findInternalDuplicates, } from '../config/add.js';
8
+ import { SnapshotManager, formatSnapshotLine, formatConfigDiff, } from '../config/snapshot.js';
6
9
  import { output, outputSuccess, outputError, maskSecretsInObject, getOutputOptions } from '../utils/output.js';
7
10
  export function createConfigCommand(getConfigPath) {
8
11
  const cmd = new Command('config')
@@ -38,17 +41,40 @@ export function createConfigCommand(getConfigPath) {
38
41
  });
39
42
  cmd
40
43
  .command('show')
41
- .description('Show current config (secrets masked)')
42
- .action(async () => {
44
+ .description('Show current config or a snapshot (secrets masked)')
45
+ .argument('[number]', 'Snapshot number to show (from ls)')
46
+ .action(async (num) => {
43
47
  try {
44
48
  const manager = new ConfigManager(getConfigPath());
45
- const config = await manager.load();
46
- const masked = maskSecretsInObject(config);
47
- if (getOutputOptions().json) {
48
- output(masked);
49
+ if (num) {
50
+ // Show snapshot
51
+ const snapshots = new SnapshotManager(manager.getConfigDir());
52
+ const snapshot = await snapshots.getByNumber(parseInt(num, 10));
53
+ if (!snapshot) {
54
+ outputError(`Snapshot #${num} not found`);
55
+ process.exit(1);
56
+ }
57
+ const masked = maskSecretsInObject(snapshot.config);
58
+ if (getOutputOptions().json) {
59
+ output({ snapshot: snapshot.meta, config: masked });
60
+ }
61
+ else {
62
+ console.log(`Snapshot #${num}: ${snapshot.meta.note || '(no note)'}`);
63
+ console.log(`Created: ${snapshot.meta.created_at}`);
64
+ console.log();
65
+ console.log(JSON.stringify(masked, null, 2));
66
+ }
49
67
  }
50
68
  else {
51
- console.log(JSON.stringify(masked, null, 2));
69
+ // Show current config
70
+ const config = await manager.load();
71
+ const masked = maskSecretsInObject(config);
72
+ if (getOutputOptions().json) {
73
+ output(masked);
74
+ }
75
+ else {
76
+ console.log(JSON.stringify(masked, null, 2));
77
+ }
52
78
  }
53
79
  }
54
80
  catch (error) {
@@ -76,6 +102,342 @@ export function createConfigCommand(getConfigPath) {
76
102
  process.exit(1);
77
103
  }
78
104
  });
105
+ // ============================================================
106
+ // config add - add connectors from JSON
107
+ // ============================================================
108
+ cmd
109
+ .command('add')
110
+ .description('Add connectors from MCP server JSON (Claude Desktop, mcp.so, or array)')
111
+ .addHelpText('after', `
112
+ Supported JSON formats:
113
+ Claude Desktop: { "mcpServers": { "<id>": { "command": "...", ... } } }
114
+ Single object: { "id": "...", "command": "...", "args": [...], "env": {...} }
115
+ Array: [ { "id": "...", "command": "...", ... }, ... ]
116
+
117
+ Examples:
118
+ pfscan config add # Paste JSON interactively
119
+ pfscan config add --dry-run # Preview without writing
120
+ pfscan config add --overwrite # Update existing connectors
121
+ cat mcp.json | pfscan config add # Pipe from file
122
+ `)
123
+ .option('--overwrite', 'Overwrite existing connector IDs')
124
+ .option('--dry-run', 'Parse and show what would be added, without writing')
125
+ .action(async (options) => {
126
+ try {
127
+ const manager = new ConfigManager(getConfigPath());
128
+ const jsonInput = await readStdinJson();
129
+ // Parse JSON
130
+ const parseResult = parseConnectorJson(jsonInput);
131
+ if (!parseResult.success || parseResult.connectors.length === 0) {
132
+ if (parseResult.errors.length > 0) {
133
+ outputError('Failed to parse JSON', new Error(parseResult.errors.join('\n')));
134
+ }
135
+ else {
136
+ outputError('No connectors found in JSON');
137
+ }
138
+ process.exit(1);
139
+ }
140
+ // Check for internal duplicates
141
+ const internalDups = findInternalDuplicates(parseResult.connectors);
142
+ if (internalDups.length > 0) {
143
+ outputError(`Duplicate IDs in input: ${internalDups.join(', ')}`);
144
+ process.exit(1);
145
+ }
146
+ // Load existing config
147
+ const config = await manager.loadOrDefault();
148
+ // Check for duplicates with existing connectors
149
+ const duplicates = findDuplicates(parseResult.connectors, config.connectors);
150
+ // Handle duplicates
151
+ if (duplicates.length > 0 && !options.overwrite && !options.dryRun) {
152
+ outputError(`Connector IDs already exist: ${duplicates.join(', ')}\n` +
153
+ 'Use --overwrite to update them, or --dry-run to preview.');
154
+ process.exit(1);
155
+ }
156
+ // Prepare result
157
+ const result = {
158
+ added: [],
159
+ updated: [],
160
+ skipped: [],
161
+ duplicates,
162
+ };
163
+ // Process connectors
164
+ const existingIds = new Set(config.connectors.map(c => c.id));
165
+ for (const parsed of parseResult.connectors) {
166
+ if (existingIds.has(parsed.id)) {
167
+ if (options.overwrite) {
168
+ // Update existing
169
+ const index = config.connectors.findIndex(c => c.id === parsed.id);
170
+ config.connectors[index] = toConnector(parsed);
171
+ result.updated.push(parsed.id);
172
+ }
173
+ else {
174
+ result.skipped.push(parsed.id);
175
+ }
176
+ }
177
+ else {
178
+ // Add new
179
+ config.connectors.push(toConnector(parsed));
180
+ result.added.push(parsed.id);
181
+ }
182
+ }
183
+ // Output summary
184
+ const summary = formatAddSummary(parseResult.connectors, result, options.dryRun);
185
+ if (getOutputOptions().json) {
186
+ output({
187
+ dry_run: options.dryRun || false,
188
+ parsed_count: parseResult.connectors.length,
189
+ added: result.added,
190
+ updated: result.updated,
191
+ skipped: result.skipped,
192
+ });
193
+ }
194
+ else {
195
+ console.log(summary);
196
+ }
197
+ // Save if not dry-run
198
+ if (!options.dryRun && (result.added.length > 0 || result.updated.length > 0)) {
199
+ await manager.save(config);
200
+ outputSuccess('Config updated');
201
+ }
202
+ else if (options.dryRun) {
203
+ console.log('\n(dry-run: no changes written)');
204
+ }
205
+ }
206
+ catch (error) {
207
+ outputError('Failed to add connectors', error instanceof Error ? error : undefined);
208
+ process.exit(1);
209
+ }
210
+ });
211
+ // ============================================================
212
+ // config save - save snapshot
213
+ // ============================================================
214
+ cmd
215
+ .command('save')
216
+ .description('Save a snapshot of the current config')
217
+ .option('--note <text>', 'Add a note to the snapshot')
218
+ .action(async (options) => {
219
+ try {
220
+ const manager = new ConfigManager(getConfigPath());
221
+ const config = await manager.load();
222
+ const snapshots = new SnapshotManager(manager.getConfigDir());
223
+ const meta = await snapshots.save(config, options.note);
224
+ if (getOutputOptions().json) {
225
+ output(meta);
226
+ }
227
+ else {
228
+ outputSuccess(`Snapshot saved: ${meta.id}`);
229
+ if (meta.note) {
230
+ console.log(` Note: "${meta.note}"`);
231
+ }
232
+ console.log(` Connectors: ${meta.connector_count}`);
233
+ }
234
+ }
235
+ catch (error) {
236
+ outputError('Failed to save snapshot', error instanceof Error ? error : undefined);
237
+ process.exit(1);
238
+ }
239
+ });
240
+ // ============================================================
241
+ // config ls - list snapshots
242
+ // ============================================================
243
+ cmd
244
+ .command('ls')
245
+ .description('List saved config snapshots')
246
+ .action(async () => {
247
+ try {
248
+ const manager = new ConfigManager(getConfigPath());
249
+ const snapshots = new SnapshotManager(manager.getConfigDir());
250
+ const list = await snapshots.list();
251
+ if (list.length === 0) {
252
+ console.log('No snapshots saved.');
253
+ console.log('Use `pfscan config save` to create one.');
254
+ return;
255
+ }
256
+ // Find which snapshot matches current config
257
+ let currentMatch = null;
258
+ try {
259
+ const config = await manager.load();
260
+ currentMatch = await snapshots.findMatchingSnapshot(config);
261
+ }
262
+ catch {
263
+ // Config might not exist
264
+ }
265
+ if (getOutputOptions().json) {
266
+ output({
267
+ snapshots: list,
268
+ current_match: currentMatch,
269
+ });
270
+ }
271
+ else {
272
+ console.log('Snapshots (newest first):');
273
+ console.log();
274
+ for (let i = 0; i < list.length; i++) {
275
+ const isCurrent = currentMatch === i + 1;
276
+ console.log(formatSnapshotLine(i + 1, list[i], isCurrent));
277
+ }
278
+ }
279
+ }
280
+ catch (error) {
281
+ outputError('Failed to list snapshots', error instanceof Error ? error : undefined);
282
+ process.exit(1);
283
+ }
284
+ });
285
+ // ============================================================
286
+ // config load - load snapshot
287
+ // ============================================================
288
+ cmd
289
+ .command('load')
290
+ .description('Load a saved snapshot (dry-run by default)')
291
+ .argument('<number>', 'Snapshot number to load (from ls)')
292
+ .option('--force', 'Actually replace current config')
293
+ .action(async (num, options) => {
294
+ try {
295
+ const manager = new ConfigManager(getConfigPath());
296
+ const snapshots = new SnapshotManager(manager.getConfigDir());
297
+ const snapshotNum = parseInt(num, 10);
298
+ const snapshot = await snapshots.getByNumber(snapshotNum);
299
+ if (!snapshot) {
300
+ outputError(`Snapshot #${num} not found`);
301
+ process.exit(1);
302
+ }
303
+ // Load current config for diff
304
+ let currentConfig;
305
+ try {
306
+ currentConfig = await manager.load();
307
+ }
308
+ catch {
309
+ currentConfig = { version: 1, connectors: [] };
310
+ }
311
+ const diff = snapshots.diffConfigs(currentConfig, snapshot.config);
312
+ if (getOutputOptions().json) {
313
+ output({
314
+ dry_run: !options.force,
315
+ snapshot: snapshot.meta,
316
+ diff,
317
+ });
318
+ }
319
+ else {
320
+ console.log(`Snapshot #${num}: ${snapshot.meta.note || '(no note)'}`);
321
+ console.log(`Created: ${snapshot.meta.created_at}`);
322
+ console.log();
323
+ console.log('Changes:');
324
+ console.log(formatConfigDiff(diff));
325
+ }
326
+ if (options.force) {
327
+ await manager.save(snapshot.config);
328
+ outputSuccess('Config replaced with snapshot');
329
+ }
330
+ else {
331
+ console.log();
332
+ console.log('(dry-run: use --force to apply)');
333
+ }
334
+ }
335
+ catch (error) {
336
+ outputError('Failed to load snapshot', error instanceof Error ? error : undefined);
337
+ process.exit(1);
338
+ }
339
+ });
340
+ // ============================================================
341
+ // config delete - delete snapshot
342
+ // ============================================================
343
+ cmd
344
+ .command('delete')
345
+ .description('Delete a saved snapshot (dry-run by default)')
346
+ .argument('<number>', 'Snapshot number to delete (from ls)')
347
+ .option('--force', 'Actually delete the snapshot')
348
+ .action(async (num, options) => {
349
+ try {
350
+ const manager = new ConfigManager(getConfigPath());
351
+ const snapshots = new SnapshotManager(manager.getConfigDir());
352
+ const snapshotNum = parseInt(num, 10);
353
+ const snapshot = await snapshots.getByNumber(snapshotNum);
354
+ if (!snapshot) {
355
+ outputError(`Snapshot #${num} not found`);
356
+ process.exit(1);
357
+ }
358
+ if (getOutputOptions().json) {
359
+ output({
360
+ dry_run: !options.force,
361
+ snapshot: snapshot.meta,
362
+ });
363
+ }
364
+ else {
365
+ console.log(`Snapshot #${num}: ${snapshot.meta.note || '(no note)'}`);
366
+ console.log(`Created: ${snapshot.meta.created_at}`);
367
+ console.log(`Connectors: ${snapshot.meta.connector_count}`);
368
+ }
369
+ if (options.force) {
370
+ await snapshots.delete(snapshotNum);
371
+ outputSuccess('Snapshot deleted');
372
+ }
373
+ else {
374
+ console.log();
375
+ console.log('(dry-run: use --force to delete)');
376
+ }
377
+ }
378
+ catch (error) {
379
+ outputError('Failed to delete snapshot', error instanceof Error ? error : undefined);
380
+ process.exit(1);
381
+ }
382
+ });
79
383
  return cmd;
80
384
  }
385
+ // ============================================================
386
+ // Helper functions
387
+ // ============================================================
388
+ /**
389
+ * Read JSON from stdin interactively
390
+ */
391
+ async function readStdinJson() {
392
+ // Check if stdin is a TTY (interactive)
393
+ if (process.stdin.isTTY) {
394
+ console.log('Paste MCP server configuration (JSON), then press Ctrl+D:');
395
+ }
396
+ return new Promise((resolve, reject) => {
397
+ const chunks = [];
398
+ const rl = createInterface({
399
+ input: process.stdin,
400
+ terminal: false,
401
+ });
402
+ rl.on('line', (line) => {
403
+ chunks.push(line);
404
+ });
405
+ rl.on('close', () => {
406
+ const content = chunks.join('\n').trim();
407
+ if (content.length === 0) {
408
+ reject(new Error('No input received'));
409
+ }
410
+ else {
411
+ resolve(content);
412
+ }
413
+ });
414
+ rl.on('error', reject);
415
+ });
416
+ }
417
+ /**
418
+ * Format summary for add operation
419
+ */
420
+ function formatAddSummary(parsed, result, dryRun) {
421
+ const lines = [];
422
+ const action = dryRun ? 'Would' : 'Will';
423
+ lines.push(`Parsed ${parsed.length} connector(s)`);
424
+ lines.push('');
425
+ // Show connector list with masked env
426
+ for (const p of parsed) {
427
+ const envInfo = p.env ? ` (${Object.keys(p.env).length} env vars)` : '';
428
+ const argsInfo = p.args ? ` [${p.args.length} args]` : '';
429
+ lines.push(` ${p.id}: ${p.command}${argsInfo}${envInfo}`);
430
+ }
431
+ lines.push('');
432
+ if (result.added.length > 0) {
433
+ lines.push(`${action} add: ${result.added.join(', ')}`);
434
+ }
435
+ if (result.updated.length > 0) {
436
+ lines.push(`${action} update: ${result.updated.join(', ')}`);
437
+ }
438
+ if (result.skipped.length > 0) {
439
+ lines.push(`Skipped (already exists): ${result.skipped.join(', ')}`);
440
+ }
441
+ return lines.join('\n');
442
+ }
81
443
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Config add - parse and normalize MCP server JSON from various sources
3
+ *
4
+ * Supports:
5
+ * - Claude Desktop format: { "mcpServers": { "<id>": { "command": "...", ... } } }
6
+ * - Single object: { "id": "...", "command": "...", ... }
7
+ * - Array: [ { "id": "...", "command": "...", ... }, ... ]
8
+ */
9
+ import type { Connector } from '../types/index.js';
10
+ /** Parsed connector from JSON input */
11
+ export interface ParsedConnector {
12
+ id: string;
13
+ command: string;
14
+ args?: string[];
15
+ env?: Record<string, string>;
16
+ }
17
+ /** Result of parsing JSON input */
18
+ export interface ParseResult {
19
+ success: boolean;
20
+ connectors: ParsedConnector[];
21
+ errors: string[];
22
+ }
23
+ /** Result of add operation */
24
+ export interface AddResult {
25
+ added: string[];
26
+ updated: string[];
27
+ skipped: string[];
28
+ duplicates: string[];
29
+ }
30
+ /**
31
+ * Parse and normalize JSON input to connector list
32
+ */
33
+ export declare function parseConnectorJson(jsonString: string): ParseResult;
34
+ /**
35
+ * Convert ParsedConnector to Connector type
36
+ */
37
+ export declare function toConnector(parsed: ParsedConnector): Connector;
38
+ /**
39
+ * Check for duplicates between parsed connectors and existing ones
40
+ */
41
+ export declare function findDuplicates(parsed: ParsedConnector[], existing: Connector[]): string[];
42
+ /**
43
+ * Check for duplicates within parsed connectors
44
+ */
45
+ export declare function findInternalDuplicates(parsed: ParsedConnector[]): string[];
46
+ //# sourceMappingURL=add.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/config/add.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAkB,MAAM,mBAAmB,CAAC;AAMnE,uCAAuC;AACvC,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,mCAAmC;AACnC,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,8BAA8B;AAC9B,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAwHD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,CAsClE;AAMD;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAmB9D;AAMD;;GAEG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,eAAe,EAAE,EACzB,QAAQ,EAAE,SAAS,EAAE,GACpB,MAAM,EAAE,CAGV;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,EAAE,CAe1E"}
@@ -0,0 +1,195 @@
1
+ /**
2
+ * Config add - parse and normalize MCP server JSON from various sources
3
+ *
4
+ * Supports:
5
+ * - Claude Desktop format: { "mcpServers": { "<id>": { "command": "...", ... } } }
6
+ * - Single object: { "id": "...", "command": "...", ... }
7
+ * - Array: [ { "id": "...", "command": "...", ... }, ... ]
8
+ */
9
+ // ============================================================
10
+ // JSON Parsing
11
+ // ============================================================
12
+ /**
13
+ * Check if value is a non-empty string
14
+ */
15
+ function isNonEmptyString(value) {
16
+ return typeof value === 'string' && value.trim().length > 0;
17
+ }
18
+ /**
19
+ * Check if value is a string array
20
+ */
21
+ function isStringArray(value) {
22
+ return Array.isArray(value) && value.every(v => typeof v === 'string');
23
+ }
24
+ /**
25
+ * Check if value is a string-to-string object
26
+ */
27
+ function isStringRecord(value) {
28
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
29
+ return false;
30
+ }
31
+ return Object.entries(value).every(([k, v]) => typeof k === 'string' && typeof v === 'string');
32
+ }
33
+ /**
34
+ * Validate and extract connector from a single object
35
+ */
36
+ function validateConnectorObject(obj, id) {
37
+ if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
38
+ return { connector: null, error: 'Expected an object' };
39
+ }
40
+ const record = obj;
41
+ // Get id from object or provided parameter
42
+ const connectorId = id ?? record.id;
43
+ if (!isNonEmptyString(connectorId)) {
44
+ return { connector: null, error: 'Missing or invalid "id" field' };
45
+ }
46
+ // Validate command
47
+ if (!isNonEmptyString(record.command)) {
48
+ return { connector: null, error: `Connector "${connectorId}": missing or invalid "command"` };
49
+ }
50
+ // Validate args if present
51
+ if (record.args !== undefined && !isStringArray(record.args)) {
52
+ return { connector: null, error: `Connector "${connectorId}": "args" must be an array of strings` };
53
+ }
54
+ // Validate env if present
55
+ if (record.env !== undefined && !isStringRecord(record.env)) {
56
+ return { connector: null, error: `Connector "${connectorId}": "env" must be an object with string values` };
57
+ }
58
+ return {
59
+ connector: {
60
+ id: connectorId,
61
+ command: record.command,
62
+ args: record.args,
63
+ env: record.env,
64
+ },
65
+ error: null,
66
+ };
67
+ }
68
+ /**
69
+ * Parse Claude Desktop format: { "mcpServers": { "<id>": { ... } } }
70
+ */
71
+ function parseClaudeDesktopFormat(obj) {
72
+ const mcpServers = obj.mcpServers;
73
+ if (typeof mcpServers !== 'object' || mcpServers === null || Array.isArray(mcpServers)) {
74
+ return { success: false, connectors: [], errors: ['Invalid mcpServers format'] };
75
+ }
76
+ const connectors = [];
77
+ const errors = [];
78
+ for (const [id, serverConfig] of Object.entries(mcpServers)) {
79
+ const result = validateConnectorObject(serverConfig, id);
80
+ if (result.connector) {
81
+ connectors.push(result.connector);
82
+ }
83
+ else if (result.error) {
84
+ errors.push(result.error);
85
+ }
86
+ }
87
+ return { success: errors.length === 0, connectors, errors };
88
+ }
89
+ /**
90
+ * Parse array format: [ { "id": "...", ... }, ... ]
91
+ */
92
+ function parseArrayFormat(arr) {
93
+ const connectors = [];
94
+ const errors = [];
95
+ for (let i = 0; i < arr.length; i++) {
96
+ const result = validateConnectorObject(arr[i]);
97
+ if (result.connector) {
98
+ connectors.push(result.connector);
99
+ }
100
+ else if (result.error) {
101
+ errors.push(`[${i}]: ${result.error}`);
102
+ }
103
+ }
104
+ return { success: errors.length === 0, connectors, errors };
105
+ }
106
+ /**
107
+ * Parse and normalize JSON input to connector list
108
+ */
109
+ export function parseConnectorJson(jsonString) {
110
+ // Try to parse JSON
111
+ let parsed;
112
+ try {
113
+ parsed = JSON.parse(jsonString);
114
+ }
115
+ catch (e) {
116
+ const message = e instanceof Error ? e.message : 'Unknown error';
117
+ return { success: false, connectors: [], errors: [`Invalid JSON: ${message}`] };
118
+ }
119
+ // Case A: Claude Desktop format with mcpServers
120
+ if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
121
+ const obj = parsed;
122
+ if ('mcpServers' in obj) {
123
+ return parseClaudeDesktopFormat(obj);
124
+ }
125
+ // Case B: Single object with id and command
126
+ if ('command' in obj) {
127
+ const result = validateConnectorObject(obj);
128
+ if (result.connector) {
129
+ return { success: true, connectors: [result.connector], errors: [] };
130
+ }
131
+ return { success: false, connectors: [], errors: [result.error || 'Invalid connector'] };
132
+ }
133
+ return { success: false, connectors: [], errors: ['Unrecognized JSON format'] };
134
+ }
135
+ // Case C: Array format
136
+ if (Array.isArray(parsed)) {
137
+ if (parsed.length === 0) {
138
+ return { success: false, connectors: [], errors: ['Empty array'] };
139
+ }
140
+ return parseArrayFormat(parsed);
141
+ }
142
+ return { success: false, connectors: [], errors: ['Expected object or array'] };
143
+ }
144
+ // ============================================================
145
+ // Connector Conversion
146
+ // ============================================================
147
+ /**
148
+ * Convert ParsedConnector to Connector type
149
+ */
150
+ export function toConnector(parsed) {
151
+ const transport = {
152
+ type: 'stdio',
153
+ command: parsed.command,
154
+ };
155
+ if (parsed.args && parsed.args.length > 0) {
156
+ transport.args = parsed.args;
157
+ }
158
+ if (parsed.env && Object.keys(parsed.env).length > 0) {
159
+ transport.env = parsed.env;
160
+ }
161
+ return {
162
+ id: parsed.id,
163
+ enabled: true,
164
+ transport,
165
+ };
166
+ }
167
+ // ============================================================
168
+ // Duplicate Detection
169
+ // ============================================================
170
+ /**
171
+ * Check for duplicates between parsed connectors and existing ones
172
+ */
173
+ export function findDuplicates(parsed, existing) {
174
+ const existingIds = new Set(existing.map(c => c.id));
175
+ return parsed.filter(p => existingIds.has(p.id)).map(p => p.id);
176
+ }
177
+ /**
178
+ * Check for duplicates within parsed connectors
179
+ */
180
+ export function findInternalDuplicates(parsed) {
181
+ const seen = new Set();
182
+ const duplicates = [];
183
+ for (const p of parsed) {
184
+ if (seen.has(p.id)) {
185
+ if (!duplicates.includes(p.id)) {
186
+ duplicates.push(p.id);
187
+ }
188
+ }
189
+ else {
190
+ seen.add(p.id);
191
+ }
192
+ }
193
+ return duplicates;
194
+ }
195
+ //# sourceMappingURL=add.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/config/add.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,6 @@
1
1
  export * from './schema.js';
2
2
  export * from './manager.js';
3
3
  export * from './import.js';
4
+ export * from './add.js';
5
+ export * from './snapshot.js';
4
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC"}
@@ -1,4 +1,6 @@
1
1
  export * from './schema.js';
2
2
  export * from './manager.js';
3
3
  export * from './import.js';
4
+ export * from './add.js';
5
+ export * from './snapshot.js';
4
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Config snapshot management
3
+ *
4
+ * Stores snapshots of config in state/config-snapshots/
5
+ * Maintains an index file with metadata for each snapshot.
6
+ */
7
+ import type { Config } from '../types/index.js';
8
+ /** Snapshot metadata */
9
+ export interface SnapshotMeta {
10
+ id: string;
11
+ created_at: string;
12
+ note: string | null;
13
+ file_name: string;
14
+ connector_count: number;
15
+ hash: string;
16
+ }
17
+ /** Snapshot index */
18
+ export interface SnapshotIndex {
19
+ version: 1;
20
+ snapshots: SnapshotMeta[];
21
+ }
22
+ /** Snapshot with full config */
23
+ export interface Snapshot {
24
+ meta: SnapshotMeta;
25
+ config: Config;
26
+ }
27
+ /** Diff between two configs */
28
+ export interface ConfigDiff {
29
+ added: string[];
30
+ removed: string[];
31
+ changed: string[];
32
+ unchanged: string[];
33
+ }
34
+ export declare class SnapshotManager {
35
+ private snapshotDir;
36
+ private indexPath;
37
+ constructor(configDir: string);
38
+ /**
39
+ * Ensure snapshot directory exists
40
+ */
41
+ private ensureDir;
42
+ /**
43
+ * Load snapshot index
44
+ */
45
+ loadIndex(): Promise<SnapshotIndex>;
46
+ /**
47
+ * Save snapshot index
48
+ */
49
+ private saveIndex;
50
+ /**
51
+ * Compute hash of config for comparison
52
+ */
53
+ computeHash(config: Config): string;
54
+ /**
55
+ * Generate snapshot ID from timestamp
56
+ */
57
+ private generateId;
58
+ /**
59
+ * Save a snapshot of current config
60
+ */
61
+ save(config: Config, note?: string): Promise<SnapshotMeta>;
62
+ /**
63
+ * List all snapshots (newest first)
64
+ */
65
+ list(): Promise<SnapshotMeta[]>;
66
+ /**
67
+ * Get snapshot by display number (1-indexed, newest first)
68
+ */
69
+ getByNumber(num: number): Promise<Snapshot | null>;
70
+ /**
71
+ * Delete snapshot by display number
72
+ */
73
+ delete(num: number): Promise<SnapshotMeta | null>;
74
+ /**
75
+ * Find snapshot matching current config by hash
76
+ */
77
+ findMatchingSnapshot(config: Config): Promise<number | null>;
78
+ /**
79
+ * Compare two configs and return diff
80
+ */
81
+ diffConfigs(current: Config, target: Config): ConfigDiff;
82
+ }
83
+ /**
84
+ * Format snapshot for display
85
+ */
86
+ export declare function formatSnapshotLine(num: number, meta: SnapshotMeta, isCurrent?: boolean): string;
87
+ /**
88
+ * Format config diff for display
89
+ */
90
+ export declare function formatConfigDiff(diff: ConfigDiff): string;
91
+ //# sourceMappingURL=snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../src/config/snapshot.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAOhD,wBAAwB;AACxB,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAAqB;AACrB,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,gCAAgC;AAChC,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,+BAA+B;AAC/B,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAMD,qBAAa,eAAe;IAC1B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAS;gBAEd,SAAS,EAAE,MAAM;IAK7B;;OAEG;YACW,SAAS;IAIvB;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,aAAa,CAAC;IAazC;;OAEG;YACW,SAAS;IAKvB;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAKnC;;OAEG;IACH,OAAO,CAAC,UAAU;IAIlB;;OAEG;IACG,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IA6BhE;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAKrC;;OAEG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAsBxD;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAqBvD;;OAEG;IACG,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAalE;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU;CAiCzD;AAMD;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,YAAY,EAClB,SAAS,GAAE,OAAe,GACzB,MAAM,CAeR;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAqBzD"}
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Config snapshot management
3
+ *
4
+ * Stores snapshots of config in state/config-snapshots/
5
+ * Maintains an index file with metadata for each snapshot.
6
+ */
7
+ import { createHash } from 'crypto';
8
+ import { join } from 'path';
9
+ import { mkdir, unlink } from 'fs/promises';
10
+ import { atomicWriteFile, readFileSafe, fileExists } from '../utils/fs.js';
11
+ // ============================================================
12
+ // Snapshot Manager
13
+ // ============================================================
14
+ export class SnapshotManager {
15
+ snapshotDir;
16
+ indexPath;
17
+ constructor(configDir) {
18
+ this.snapshotDir = join(configDir, 'config-snapshots');
19
+ this.indexPath = join(this.snapshotDir, 'index.json');
20
+ }
21
+ /**
22
+ * Ensure snapshot directory exists
23
+ */
24
+ async ensureDir() {
25
+ await mkdir(this.snapshotDir, { recursive: true });
26
+ }
27
+ /**
28
+ * Load snapshot index
29
+ */
30
+ async loadIndex() {
31
+ const content = await readFileSafe(this.indexPath);
32
+ if (!content) {
33
+ return { version: 1, snapshots: [] };
34
+ }
35
+ try {
36
+ return JSON.parse(content);
37
+ }
38
+ catch {
39
+ return { version: 1, snapshots: [] };
40
+ }
41
+ }
42
+ /**
43
+ * Save snapshot index
44
+ */
45
+ async saveIndex(index) {
46
+ await this.ensureDir();
47
+ await atomicWriteFile(this.indexPath, JSON.stringify(index, null, 2) + '\n');
48
+ }
49
+ /**
50
+ * Compute hash of config for comparison
51
+ */
52
+ computeHash(config) {
53
+ const canonical = JSON.stringify(config);
54
+ return createHash('sha256').update(canonical).digest('hex').slice(0, 16);
55
+ }
56
+ /**
57
+ * Generate snapshot ID from timestamp
58
+ */
59
+ generateId() {
60
+ return new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
61
+ }
62
+ /**
63
+ * Save a snapshot of current config
64
+ */
65
+ async save(config, note) {
66
+ await this.ensureDir();
67
+ const id = this.generateId();
68
+ const hash = this.computeHash(config);
69
+ const noteSuffix = note ? `_${note.replace(/[^a-zA-Z0-9-]/g, '_').slice(0, 30)}` : '';
70
+ const fileName = `${id}${noteSuffix}.json`;
71
+ const filePath = join(this.snapshotDir, fileName);
72
+ // Save snapshot file
73
+ await atomicWriteFile(filePath, JSON.stringify(config, null, 2) + '\n');
74
+ // Update index
75
+ const index = await this.loadIndex();
76
+ const meta = {
77
+ id,
78
+ created_at: new Date().toISOString(),
79
+ note: note || null,
80
+ file_name: fileName,
81
+ connector_count: config.connectors.length,
82
+ hash,
83
+ };
84
+ index.snapshots.unshift(meta); // newest first
85
+ await this.saveIndex(index);
86
+ return meta;
87
+ }
88
+ /**
89
+ * List all snapshots (newest first)
90
+ */
91
+ async list() {
92
+ const index = await this.loadIndex();
93
+ return index.snapshots;
94
+ }
95
+ /**
96
+ * Get snapshot by display number (1-indexed, newest first)
97
+ */
98
+ async getByNumber(num) {
99
+ const index = await this.loadIndex();
100
+ if (num < 1 || num > index.snapshots.length) {
101
+ return null;
102
+ }
103
+ const meta = index.snapshots[num - 1];
104
+ const filePath = join(this.snapshotDir, meta.file_name);
105
+ const content = await readFileSafe(filePath);
106
+ if (!content) {
107
+ return null;
108
+ }
109
+ try {
110
+ const config = JSON.parse(content);
111
+ return { meta, config };
112
+ }
113
+ catch {
114
+ return null;
115
+ }
116
+ }
117
+ /**
118
+ * Delete snapshot by display number
119
+ */
120
+ async delete(num) {
121
+ const index = await this.loadIndex();
122
+ if (num < 1 || num > index.snapshots.length) {
123
+ return null;
124
+ }
125
+ const meta = index.snapshots[num - 1];
126
+ const filePath = join(this.snapshotDir, meta.file_name);
127
+ // Remove file if exists
128
+ if (await fileExists(filePath)) {
129
+ await unlink(filePath);
130
+ }
131
+ // Remove from index
132
+ index.snapshots.splice(num - 1, 1);
133
+ await this.saveIndex(index);
134
+ return meta;
135
+ }
136
+ /**
137
+ * Find snapshot matching current config by hash
138
+ */
139
+ async findMatchingSnapshot(config) {
140
+ const hash = this.computeHash(config);
141
+ const index = await this.loadIndex();
142
+ for (let i = 0; i < index.snapshots.length; i++) {
143
+ if (index.snapshots[i].hash === hash) {
144
+ return i + 1; // 1-indexed
145
+ }
146
+ }
147
+ return null;
148
+ }
149
+ /**
150
+ * Compare two configs and return diff
151
+ */
152
+ diffConfigs(current, target) {
153
+ const currentIds = new Set(current.connectors.map(c => c.id));
154
+ const targetIds = new Set(target.connectors.map(c => c.id));
155
+ const added = [];
156
+ const removed = [];
157
+ const changed = [];
158
+ const unchanged = [];
159
+ // Find removed (in current but not in target)
160
+ for (const id of currentIds) {
161
+ if (!targetIds.has(id)) {
162
+ removed.push(id);
163
+ }
164
+ }
165
+ // Find added and changed
166
+ for (const targetConn of target.connectors) {
167
+ if (!currentIds.has(targetConn.id)) {
168
+ added.push(targetConn.id);
169
+ }
170
+ else {
171
+ // Check if changed
172
+ const currentConn = current.connectors.find(c => c.id === targetConn.id);
173
+ if (JSON.stringify(currentConn) !== JSON.stringify(targetConn)) {
174
+ changed.push(targetConn.id);
175
+ }
176
+ else {
177
+ unchanged.push(targetConn.id);
178
+ }
179
+ }
180
+ }
181
+ return { added, removed, changed, unchanged };
182
+ }
183
+ }
184
+ // ============================================================
185
+ // Formatting helpers
186
+ // ============================================================
187
+ /**
188
+ * Format snapshot for display
189
+ */
190
+ export function formatSnapshotLine(num, meta, isCurrent = false) {
191
+ const date = new Date(meta.created_at);
192
+ const dateStr = date.toLocaleString('ja-JP', {
193
+ year: 'numeric',
194
+ month: '2-digit',
195
+ day: '2-digit',
196
+ hour: '2-digit',
197
+ minute: '2-digit',
198
+ });
199
+ const note = meta.note ? ` "${meta.note}"` : '';
200
+ const current = isCurrent ? ' [current]' : '';
201
+ const connectors = `${meta.connector_count} connectors`;
202
+ return ` ${num}. ${dateStr} - ${connectors}${note}${current}`;
203
+ }
204
+ /**
205
+ * Format config diff for display
206
+ */
207
+ export function formatConfigDiff(diff) {
208
+ const lines = [];
209
+ if (diff.added.length > 0) {
210
+ lines.push(` + Added: ${diff.added.join(', ')}`);
211
+ }
212
+ if (diff.removed.length > 0) {
213
+ lines.push(` - Removed: ${diff.removed.join(', ')}`);
214
+ }
215
+ if (diff.changed.length > 0) {
216
+ lines.push(` ~ Changed: ${diff.changed.join(', ')}`);
217
+ }
218
+ if (diff.unchanged.length > 0) {
219
+ lines.push(` = Unchanged: ${diff.unchanged.join(', ')}`);
220
+ }
221
+ if (lines.length === 0) {
222
+ lines.push(' No changes');
223
+ }
224
+ return lines.join('\n');
225
+ }
226
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/config/snapshot.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "proofscan",
3
- "version": "0.5.6",
3
+ "version": "0.5.7",
4
4
  "description": "MCP Server scanner - eliminate black boxes by capturing JSON-RPC from connection to tools/list",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",