proofscan 0.10.8 → 0.10.10
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/dist/cli.js +8 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/catalog.d.ts +16 -0
- package/dist/commands/catalog.d.ts.map +1 -0
- package/dist/commands/catalog.js +568 -0
- package/dist/commands/catalog.js.map +1 -0
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +2 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/scan.d.ts.map +1 -1
- package/dist/commands/scan.js +1 -17
- package/dist/commands/scan.js.map +1 -1
- package/dist/registry/client.d.ts +97 -0
- package/dist/registry/client.d.ts.map +1 -0
- package/dist/registry/client.js +227 -0
- package/dist/registry/client.js.map +1 -0
- package/dist/registry/index.d.ts +6 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +6 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/registry/sources.d.ts +60 -0
- package/dist/registry/sources.d.ts.map +1 -0
- package/dist/registry/sources.js +81 -0
- package/dist/registry/sources.js.map +1 -0
- package/dist/shell/popl-commands.d.ts.map +1 -1
- package/dist/shell/popl-commands.js +20 -3
- package/dist/shell/popl-commands.js.map +1 -1
- package/dist/shell/ref-commands.d.ts.map +1 -1
- package/dist/shell/ref-commands.js +28 -0
- package/dist/shell/ref-commands.js.map +1 -1
- package/dist/shell/tool-commands.d.ts.map +1 -1
- package/dist/shell/tool-commands.js +12 -0
- package/dist/shell/tool-commands.js.map +1 -1
- package/dist/shell/types.d.ts.map +1 -1
- package/dist/shell/types.js +12 -0
- package/dist/shell/types.js.map +1 -1
- package/dist/types/config.d.ts +9 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js.map +1 -1
- package/package.json +4 -1
package/dist/cli.js
CHANGED
|
@@ -25,7 +25,7 @@ import { setOutputOptions } from './utils/output.js';
|
|
|
25
25
|
const require = createRequire(import.meta.url);
|
|
26
26
|
const packageJson = require('../package.json');
|
|
27
27
|
const VERSION = packageJson.version;
|
|
28
|
-
import { createConfigCommand, createConnectorsCommand, createScanCommand, createMonitorCommand, createSessionsCommand, createArchiveCommand, createViewCommand, createTreeCommand, createExploreCommand, createStatusCommand, createEventsCommand, createRpcCommand, createSummaryCommand, createPermissionsCommand, createRecordCommand, createDoctorCommand, createShellCommand, createSecretsCommand, createToolCommand, createProxyCommand, createLogCommand, createPoplCommand, } from './commands/index.js';
|
|
28
|
+
import { createConfigCommand, createConnectorsCommand, createScanCommand, createMonitorCommand, createSessionsCommand, createArchiveCommand, createViewCommand, createTreeCommand, createExploreCommand, createStatusCommand, createEventsCommand, createRpcCommand, createSummaryCommand, createPermissionsCommand, createRecordCommand, createDoctorCommand, createShellCommand, createSecretsCommand, createToolCommand, createProxyCommand, createLogCommand, createPoplCommand, createCatalogCommand, } from './commands/index.js';
|
|
29
29
|
const program = new Command();
|
|
30
30
|
// Global state for config path
|
|
31
31
|
let globalConfigPath;
|
|
@@ -178,6 +178,12 @@ program.addCommand(createProxyCommand(getConfigPath));
|
|
|
178
178
|
program.addCommand(createLogCommand(getConfigPath));
|
|
179
179
|
// popl (Phase 6.0: Public Observable Proof Ledger)
|
|
180
180
|
program.addCommand(createPoplCommand(getConfigPath));
|
|
181
|
+
// catalog (Phase 7.0: MCP Registry)
|
|
182
|
+
program.addCommand(createCatalogCommand(getConfigPath));
|
|
183
|
+
// Alias: cat = catalog
|
|
184
|
+
const catCmd = createCatalogCommand(getConfigPath);
|
|
185
|
+
catCmd.name('cat').description('Alias for catalog');
|
|
186
|
+
program.addCommand(catCmd);
|
|
181
187
|
// ============================================================
|
|
182
188
|
// Default action: pfscan → pfscan view
|
|
183
189
|
// ============================================================
|
|
@@ -189,7 +195,7 @@ function hasHelpFlag() {
|
|
|
189
195
|
const KNOWN_COMMANDS = new Set([
|
|
190
196
|
'view', 'v', 'tree', 't', 'explore', 'e', 'status', 'st',
|
|
191
197
|
'scan', 's', 'archive', 'a', 'config', 'c',
|
|
192
|
-
'connectors', 'connector', 'sessions', 'monitor', 'events', 'rpc', 'summary', 'permissions', 'record', 'doctor', 'shell', 'secrets', 'secret', 'tool', 'proxy', 'log', 'popl', 'help'
|
|
198
|
+
'connectors', 'connector', 'sessions', 'monitor', 'events', 'rpc', 'summary', 'permissions', 'record', 'doctor', 'shell', 'secrets', 'secret', 'tool', 'proxy', 'log', 'popl', 'catalog', 'cat', 'help'
|
|
193
199
|
]);
|
|
194
200
|
// Shell-only commands (not available as CLI commands)
|
|
195
201
|
const SHELL_ONLY_COMMANDS = new Set(['send']);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,iCAAiC;AACjC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAC/C,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;AACpC,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog command - MCP Registry operations
|
|
3
|
+
*
|
|
4
|
+
* pfscan catalog search <query> # Search servers by name/description
|
|
5
|
+
* pfscan catalog search <query> --all # Cross-source search
|
|
6
|
+
* pfscan catalog view <server> [field] # View server details or specific field
|
|
7
|
+
* pfscan catalog sources # Show available catalog sources
|
|
8
|
+
* pfscan catalog sources list # Same as sources
|
|
9
|
+
* pfscan catalog sources set <name> # Set default catalog source
|
|
10
|
+
*
|
|
11
|
+
* Provides access to the MCP server registry for discovering and inspecting
|
|
12
|
+
* available MCP servers.
|
|
13
|
+
*/
|
|
14
|
+
import { Command } from 'commander';
|
|
15
|
+
export declare function createCatalogCommand(getConfigPath: () => string): Command;
|
|
16
|
+
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/commands/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuZpC,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,MAAM,MAAM,GAAG,OAAO,CAwQzE"}
|
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog command - MCP Registry operations
|
|
3
|
+
*
|
|
4
|
+
* pfscan catalog search <query> # Search servers by name/description
|
|
5
|
+
* pfscan catalog search <query> --all # Cross-source search
|
|
6
|
+
* pfscan catalog view <server> [field] # View server details or specific field
|
|
7
|
+
* pfscan catalog sources # Show available catalog sources
|
|
8
|
+
* pfscan catalog sources list # Same as sources
|
|
9
|
+
* pfscan catalog sources set <name> # Set default catalog source
|
|
10
|
+
*
|
|
11
|
+
* Provides access to the MCP server registry for discovering and inspecting
|
|
12
|
+
* available MCP servers.
|
|
13
|
+
*/
|
|
14
|
+
import { Command } from 'commander';
|
|
15
|
+
import ora from 'ora';
|
|
16
|
+
import { RegistryClient, RegistryError, SUPPORTED_FIELDS, isSupportedField, getFieldValue, formatFieldValue, CATALOG_SOURCES, DEFAULT_CATALOG_SOURCE, getSource, isValidSource, getSourceNames, isSourceReady, getAuthErrorMessage, formatSourceLine, } from '../registry/index.js';
|
|
17
|
+
import { ConfigManager } from '../config/index.js';
|
|
18
|
+
import { output, getOutputOptions, outputSuccess, outputError } from '../utils/output.js';
|
|
19
|
+
/** Braille spinner frames */
|
|
20
|
+
const BRAILLE_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
21
|
+
/** Terminal width for formatting (fallback to 80) */
|
|
22
|
+
const TERM_WIDTH = process.stdout.columns || 80;
|
|
23
|
+
/**
|
|
24
|
+
* Check if we should show spinner
|
|
25
|
+
* - Only in TTY
|
|
26
|
+
* - Not in --json mode
|
|
27
|
+
* - Not in --verbose mode
|
|
28
|
+
*/
|
|
29
|
+
function shouldShowSpinner() {
|
|
30
|
+
const opts = getOutputOptions();
|
|
31
|
+
return process.stdout.isTTY === true && !opts.json && !opts.verbose;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Create a braille spinner with SIGINT handling
|
|
35
|
+
*/
|
|
36
|
+
function createSpinner(text) {
|
|
37
|
+
if (!shouldShowSpinner()) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const spinner = ora({
|
|
41
|
+
text,
|
|
42
|
+
spinner: {
|
|
43
|
+
frames: BRAILLE_FRAMES,
|
|
44
|
+
interval: 80,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
// Handle SIGINT to stop spinner gracefully
|
|
48
|
+
const sigintHandler = () => {
|
|
49
|
+
spinner.stop();
|
|
50
|
+
process.exit(130);
|
|
51
|
+
};
|
|
52
|
+
process.once('SIGINT', sigintHandler);
|
|
53
|
+
// Store handler for cleanup
|
|
54
|
+
spinner._sigintHandler = sigintHandler;
|
|
55
|
+
return spinner;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Stop spinner and clean up SIGINT handler
|
|
59
|
+
*/
|
|
60
|
+
function stopSpinner(spinner) {
|
|
61
|
+
if (spinner) {
|
|
62
|
+
const handler = spinner._sigintHandler;
|
|
63
|
+
if (handler) {
|
|
64
|
+
process.removeListener('SIGINT', handler);
|
|
65
|
+
}
|
|
66
|
+
spinner.stop();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get the effective catalog source from config or default
|
|
71
|
+
* Priority: 1) config.catalog.defaultSource, 2) DEFAULT_CATALOG_SOURCE
|
|
72
|
+
*/
|
|
73
|
+
async function getEffectiveSource(getConfigPath) {
|
|
74
|
+
try {
|
|
75
|
+
const manager = new ConfigManager(getConfigPath());
|
|
76
|
+
const config = await manager.loadOrDefault();
|
|
77
|
+
return config.catalog?.defaultSource || DEFAULT_CATALOG_SOURCE;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return DEFAULT_CATALOG_SOURCE;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Create a RegistryClient for the effective source
|
|
85
|
+
* Validates source and checks authentication
|
|
86
|
+
*/
|
|
87
|
+
async function createClientForSource(getConfigPath, sourceOverride) {
|
|
88
|
+
const sourceName = sourceOverride || (await getEffectiveSource(getConfigPath));
|
|
89
|
+
const source = getSource(sourceName);
|
|
90
|
+
if (!source) {
|
|
91
|
+
throw new Error(`Unknown catalog source: ${sourceName}`);
|
|
92
|
+
}
|
|
93
|
+
if (!isSourceReady(source)) {
|
|
94
|
+
throw new Error(getAuthErrorMessage(source));
|
|
95
|
+
}
|
|
96
|
+
return new RegistryClient({ baseUrl: source.baseUrl });
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Cross-source search: search all available sources in parallel and merge results
|
|
100
|
+
*/
|
|
101
|
+
async function searchAllSources(query, spinner) {
|
|
102
|
+
const allServers = [];
|
|
103
|
+
const skipped = [];
|
|
104
|
+
const warnings = [];
|
|
105
|
+
const seenNames = new Set();
|
|
106
|
+
// Separate ready and not-ready sources
|
|
107
|
+
const readySources = CATALOG_SOURCES.filter((source) => {
|
|
108
|
+
if (!isSourceReady(source)) {
|
|
109
|
+
skipped.push(source.name);
|
|
110
|
+
warnings.push(`(${source.name} skipped: ${source.authEnvVar} not set)`);
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
return true;
|
|
114
|
+
});
|
|
115
|
+
// Update spinner text for parallel search
|
|
116
|
+
if (spinner) {
|
|
117
|
+
spinner.text = `Searching ${readySources.length} source(s)...`;
|
|
118
|
+
}
|
|
119
|
+
// Search all ready sources in parallel
|
|
120
|
+
const searchPromises = readySources.map(async (source) => {
|
|
121
|
+
try {
|
|
122
|
+
const client = new RegistryClient({ baseUrl: source.baseUrl });
|
|
123
|
+
const servers = await client.searchServers(query);
|
|
124
|
+
return { source: source.name, servers, error: null };
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
const msg = error instanceof Error ? error.message : 'Unknown error';
|
|
128
|
+
return { source: source.name, servers: [], error: msg };
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
const results = await Promise.all(searchPromises);
|
|
132
|
+
// Merge results and collect warnings
|
|
133
|
+
for (const result of results) {
|
|
134
|
+
if (result.error) {
|
|
135
|
+
warnings.push(`(${result.source} error: ${result.error})`);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
// Add source info and deduplicate by name
|
|
139
|
+
for (const server of result.servers) {
|
|
140
|
+
const key = server.name || server.repository || JSON.stringify(server);
|
|
141
|
+
if (!seenNames.has(key)) {
|
|
142
|
+
seenNames.add(key);
|
|
143
|
+
allServers.push({ ...server, _source: result.source });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return { servers: allServers, skipped, warnings };
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Format search results with two-line format
|
|
151
|
+
* Line 1: NAME (full)
|
|
152
|
+
* Line 2: VERSION + truncated DESC
|
|
153
|
+
* Optional: source info for cross-source search
|
|
154
|
+
*/
|
|
155
|
+
function formatSearchResults(servers, showSource = false) {
|
|
156
|
+
console.log();
|
|
157
|
+
for (const server of servers) {
|
|
158
|
+
const name = server.name || '(unknown)';
|
|
159
|
+
const version = server.version || '-';
|
|
160
|
+
const desc = server.description || '';
|
|
161
|
+
// Line 1: Full name
|
|
162
|
+
console.log(` ${name}`);
|
|
163
|
+
// Line 2: version + description (truncated to fit)
|
|
164
|
+
const versionPart = ` v${version}`;
|
|
165
|
+
const sourceInfo = showSource && server._source ? ` [${server._source}]` : '';
|
|
166
|
+
const maxDescLen = TERM_WIDTH - versionPart.length - sourceInfo.length - 4;
|
|
167
|
+
const truncatedDesc = desc.length > maxDescLen ? desc.slice(0, maxDescLen - 1) + '…' : desc;
|
|
168
|
+
console.log(`${versionPart} ${truncatedDesc}${sourceInfo}`);
|
|
169
|
+
console.log(); // blank line between entries
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Find similar servers for did-you-mean suggestions
|
|
174
|
+
* Uses already-fetched server list to avoid extra network calls
|
|
175
|
+
*/
|
|
176
|
+
function findSimilarServers(query, servers, maxResults = 5) {
|
|
177
|
+
const lowerQuery = query.toLowerCase();
|
|
178
|
+
// Score servers by similarity
|
|
179
|
+
const scored = servers.map((server) => {
|
|
180
|
+
const name = server.name?.toLowerCase() || '';
|
|
181
|
+
const desc = server.description?.toLowerCase() || '';
|
|
182
|
+
let score = 0;
|
|
183
|
+
// Exact substring match in name (highest)
|
|
184
|
+
if (name.includes(lowerQuery)) {
|
|
185
|
+
score += 100;
|
|
186
|
+
}
|
|
187
|
+
// Substring match in description
|
|
188
|
+
if (desc.includes(lowerQuery)) {
|
|
189
|
+
score += 50;
|
|
190
|
+
}
|
|
191
|
+
// Prefix match on short name (e.g., query "ex" matches "ai.exa/exa")
|
|
192
|
+
const shortName = name.split('/').pop() || name;
|
|
193
|
+
if (shortName.startsWith(lowerQuery)) {
|
|
194
|
+
score += 80;
|
|
195
|
+
}
|
|
196
|
+
// Contains any query word
|
|
197
|
+
const queryWords = lowerQuery.split(/\s+/);
|
|
198
|
+
for (const word of queryWords) {
|
|
199
|
+
if (word.length >= 2 && (name.includes(word) || desc.includes(word))) {
|
|
200
|
+
score += 20;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return { server, score };
|
|
204
|
+
});
|
|
205
|
+
// Return top matches with score > 0
|
|
206
|
+
return scored
|
|
207
|
+
.filter((s) => s.score > 0)
|
|
208
|
+
.sort((a, b) => b.score - a.score)
|
|
209
|
+
.slice(0, maxResults)
|
|
210
|
+
.map((s) => s.server);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Format candidate servers for selection prompt
|
|
214
|
+
*/
|
|
215
|
+
function formatCandidates(servers) {
|
|
216
|
+
const lines = [];
|
|
217
|
+
for (let i = 0; i < servers.length; i++) {
|
|
218
|
+
const s = servers[i];
|
|
219
|
+
const shortDesc = s.description
|
|
220
|
+
? s.description.slice(0, 50) + (s.description.length > 50 ? '…' : '')
|
|
221
|
+
: '';
|
|
222
|
+
lines.push(` ${i + 1}. ${s.name}${shortDesc ? ` - ${shortDesc}` : ''}`);
|
|
223
|
+
}
|
|
224
|
+
return lines.join('\n');
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Format server info for detailed view
|
|
228
|
+
*/
|
|
229
|
+
function formatServerDetails(server) {
|
|
230
|
+
const lines = [];
|
|
231
|
+
lines.push(`Name: ${server.name || '(unknown)'}`);
|
|
232
|
+
lines.push(`Description: ${server.description || '(none)'}`);
|
|
233
|
+
lines.push(`Version: ${server.version || '(unknown)'}`);
|
|
234
|
+
if (server.versions && server.versions.length > 0) {
|
|
235
|
+
lines.push(`Versions: ${server.versions.join(', ')}`);
|
|
236
|
+
}
|
|
237
|
+
if (server.repository) {
|
|
238
|
+
lines.push(`Repository: ${server.repository}`);
|
|
239
|
+
}
|
|
240
|
+
if (server.homepage) {
|
|
241
|
+
lines.push(`Homepage: ${server.homepage}`);
|
|
242
|
+
}
|
|
243
|
+
if (server.transport) {
|
|
244
|
+
lines.push(`Transport: ${JSON.stringify(server.transport)}`);
|
|
245
|
+
}
|
|
246
|
+
return lines.join('\n');
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Show not-found guidance with source info
|
|
250
|
+
*/
|
|
251
|
+
function showNotFoundGuidance(query, currentSource, useAll, sourceOverride) {
|
|
252
|
+
const effectiveSource = sourceOverride || currentSource;
|
|
253
|
+
console.error(`Server not found: ${query} (source: ${effectiveSource})`);
|
|
254
|
+
console.error();
|
|
255
|
+
console.error('Try one of the following:');
|
|
256
|
+
// Show --all first if not already using it
|
|
257
|
+
if (!useAll) {
|
|
258
|
+
console.error(` pfscan cat search ${query} --all`);
|
|
259
|
+
}
|
|
260
|
+
// Show alternative sources
|
|
261
|
+
for (const source of CATALOG_SOURCES) {
|
|
262
|
+
if (source.name !== effectiveSource) {
|
|
263
|
+
console.error(` pfscan cat search ${query} --source ${source.name}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// Show source switch command
|
|
267
|
+
if (!sourceOverride && currentSource !== 'smithery') {
|
|
268
|
+
console.error(` pfscan cat sources set smithery`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Handle registry errors with user-friendly messages
|
|
273
|
+
*/
|
|
274
|
+
function handleRegistryError(error) {
|
|
275
|
+
if (error instanceof RegistryError) {
|
|
276
|
+
switch (error.code) {
|
|
277
|
+
case 'NETWORK':
|
|
278
|
+
console.error(`Network error: ${error.message}`);
|
|
279
|
+
console.error('Check your internet connection or try again later.');
|
|
280
|
+
break;
|
|
281
|
+
case 'NOT_FOUND':
|
|
282
|
+
console.error(`Server not found.`);
|
|
283
|
+
console.error('Use "pfscan catalog search <query>" to find available servers.');
|
|
284
|
+
break;
|
|
285
|
+
case 'TIMEOUT':
|
|
286
|
+
console.error('Request timed out.');
|
|
287
|
+
console.error('The registry may be slow or unavailable. Try again later.');
|
|
288
|
+
break;
|
|
289
|
+
case 'PARSE':
|
|
290
|
+
console.error('Failed to parse registry response.');
|
|
291
|
+
console.error('The registry API may have changed.');
|
|
292
|
+
break;
|
|
293
|
+
default:
|
|
294
|
+
console.error(`Registry error: ${error.message}`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
else if (error instanceof Error) {
|
|
298
|
+
console.error(`Error: ${error.message}`);
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
console.error('An unknown error occurred.');
|
|
302
|
+
}
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Show sources list (shared by 'sources' and 'sources list')
|
|
307
|
+
*/
|
|
308
|
+
async function showSourcesList(getConfigPath) {
|
|
309
|
+
const opts = getOutputOptions();
|
|
310
|
+
const defaultSource = await getEffectiveSource(getConfigPath);
|
|
311
|
+
if (opts.json) {
|
|
312
|
+
output({
|
|
313
|
+
defaultSource,
|
|
314
|
+
sources: CATALOG_SOURCES.map((s) => ({
|
|
315
|
+
name: s.name,
|
|
316
|
+
baseUrl: s.baseUrl,
|
|
317
|
+
authRequired: s.authRequired,
|
|
318
|
+
authEnvVar: s.authEnvVar,
|
|
319
|
+
ready: isSourceReady(s),
|
|
320
|
+
})),
|
|
321
|
+
});
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
console.log(`Default catalog source: ${defaultSource}`);
|
|
325
|
+
console.log();
|
|
326
|
+
console.log('Sources:');
|
|
327
|
+
for (const source of CATALOG_SOURCES) {
|
|
328
|
+
const isDefault = source.name === defaultSource;
|
|
329
|
+
console.log(formatSourceLine(source, isDefault));
|
|
330
|
+
}
|
|
331
|
+
console.log();
|
|
332
|
+
console.log('Tip: pfscan cat sources set <name>');
|
|
333
|
+
}
|
|
334
|
+
export function createCatalogCommand(getConfigPath) {
|
|
335
|
+
const cmd = new Command('catalog').description('Search and view MCP servers from registry');
|
|
336
|
+
// catalog search <query>
|
|
337
|
+
cmd
|
|
338
|
+
.command('search')
|
|
339
|
+
.description('Search for MCP servers by name or description')
|
|
340
|
+
.argument('<query>', 'Search query')
|
|
341
|
+
.option('--source <name>', 'Use specific catalog source')
|
|
342
|
+
.option('--all', 'Search all available catalog sources')
|
|
343
|
+
.action(async (query, options) => {
|
|
344
|
+
const opts = getOutputOptions();
|
|
345
|
+
const currentSource = await getEffectiveSource(getConfigPath);
|
|
346
|
+
// Cross-source search with --all
|
|
347
|
+
if (options.all) {
|
|
348
|
+
const spinner = createSpinner(`Searching all sources for "${query}"...`);
|
|
349
|
+
try {
|
|
350
|
+
spinner?.start();
|
|
351
|
+
const { servers, warnings } = await searchAllSources(query, spinner);
|
|
352
|
+
stopSpinner(spinner);
|
|
353
|
+
if (opts.json) {
|
|
354
|
+
output(servers.map((s) => ({ ...s, source: s._source })));
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
// Show warnings for skipped sources
|
|
358
|
+
for (const warning of warnings) {
|
|
359
|
+
console.log(warning);
|
|
360
|
+
}
|
|
361
|
+
if (servers.length === 0) {
|
|
362
|
+
console.log(`No servers found matching "${query}" across all sources.`);
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
// Two-line format with source info
|
|
366
|
+
formatSearchResults(servers, true);
|
|
367
|
+
console.log(`${servers.length} server(s) found across sources.`);
|
|
368
|
+
console.log();
|
|
369
|
+
// Improved Tip: embed full ID if single result
|
|
370
|
+
if (servers.length === 1 && servers[0].name) {
|
|
371
|
+
console.log(`Tip: pfscan cat view "${servers[0].name}"`);
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
console.log('Tip: pfscan cat view <name>');
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
catch (error) {
|
|
378
|
+
stopSpinner(spinner);
|
|
379
|
+
handleRegistryError(error);
|
|
380
|
+
}
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
// Single source search
|
|
384
|
+
const spinner = createSpinner(`Searching for "${query}"...`);
|
|
385
|
+
try {
|
|
386
|
+
const client = await createClientForSource(getConfigPath, options.source);
|
|
387
|
+
spinner?.start();
|
|
388
|
+
const servers = await client.searchServers(query);
|
|
389
|
+
stopSpinner(spinner);
|
|
390
|
+
if (opts.json) {
|
|
391
|
+
output(servers);
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
if (servers.length === 0) {
|
|
395
|
+
console.log(`No servers found matching "${query}" (source: ${options.source || currentSource}).`);
|
|
396
|
+
console.log();
|
|
397
|
+
console.log('Try searching all sources:');
|
|
398
|
+
console.log(` pfscan cat search ${query} --all`);
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
// Two-line format with full NAME
|
|
402
|
+
formatSearchResults(servers);
|
|
403
|
+
console.log(`${servers.length} server(s) found.`);
|
|
404
|
+
console.log();
|
|
405
|
+
// Improved Tip: embed full ID if single result
|
|
406
|
+
if (servers.length === 1 && servers[0].name) {
|
|
407
|
+
console.log(`Tip: pfscan cat view "${servers[0].name}"`);
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
console.log('Tip: pfscan cat view <name>');
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
catch (error) {
|
|
414
|
+
stopSpinner(spinner);
|
|
415
|
+
handleRegistryError(error);
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
// catalog view <server> [field]
|
|
419
|
+
cmd
|
|
420
|
+
.command('view')
|
|
421
|
+
.description('View server details or a specific field')
|
|
422
|
+
.argument('<server>', 'Server name')
|
|
423
|
+
.argument('[field]', 'Specific field to display')
|
|
424
|
+
.option('--source <name>', 'Use specific catalog source')
|
|
425
|
+
.action(async (serverName, field, options) => {
|
|
426
|
+
const opts = getOutputOptions();
|
|
427
|
+
const currentSource = await getEffectiveSource(getConfigPath);
|
|
428
|
+
const spinner = createSpinner(`Fetching "${serverName}"...`);
|
|
429
|
+
try {
|
|
430
|
+
const client = await createClientForSource(getConfigPath, options.source);
|
|
431
|
+
spinner?.start();
|
|
432
|
+
let server = await client.getServer(serverName);
|
|
433
|
+
// Fallback: if not found, search and try to resolve
|
|
434
|
+
if (!server) {
|
|
435
|
+
// Get all servers for similarity search
|
|
436
|
+
const allServers = await client.listServers();
|
|
437
|
+
const similar = findSimilarServers(serverName, allServers);
|
|
438
|
+
stopSpinner(spinner);
|
|
439
|
+
if (similar.length === 0) {
|
|
440
|
+
// No suggestions available - show enhanced guidance
|
|
441
|
+
if (opts.json) {
|
|
442
|
+
output({
|
|
443
|
+
error: 'Server not found',
|
|
444
|
+
query: serverName,
|
|
445
|
+
source: options.source || currentSource,
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
showNotFoundGuidance(serverName, currentSource, false, options.source);
|
|
450
|
+
}
|
|
451
|
+
process.exit(1);
|
|
452
|
+
}
|
|
453
|
+
if (similar.length === 1) {
|
|
454
|
+
// Single match - auto-resolve
|
|
455
|
+
server = similar[0];
|
|
456
|
+
console.log(`Resolved "${serverName}" → ${server.name}`);
|
|
457
|
+
console.log();
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
// Multiple candidates - show did-you-mean
|
|
461
|
+
console.error(`Server not found: ${serverName} (source: ${options.source || currentSource})`);
|
|
462
|
+
console.error();
|
|
463
|
+
console.error('Did you mean:');
|
|
464
|
+
console.error(formatCandidates(similar));
|
|
465
|
+
console.error();
|
|
466
|
+
console.error('Tip: pfscan cat view <full-name>');
|
|
467
|
+
process.exit(1);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
stopSpinner(spinner);
|
|
472
|
+
}
|
|
473
|
+
// If field specified, show only that field
|
|
474
|
+
if (field) {
|
|
475
|
+
if (!isSupportedField(field)) {
|
|
476
|
+
console.error(`Unknown field: ${field}`);
|
|
477
|
+
console.error(`Supported fields: ${SUPPORTED_FIELDS.join(', ')}`);
|
|
478
|
+
process.exit(1);
|
|
479
|
+
}
|
|
480
|
+
const value = getFieldValue(server, field);
|
|
481
|
+
if (opts.json) {
|
|
482
|
+
output({ [field]: value });
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
console.log(formatFieldValue(value));
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
// Show all details
|
|
489
|
+
if (opts.json) {
|
|
490
|
+
output(server);
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
console.log();
|
|
494
|
+
console.log(formatServerDetails(server));
|
|
495
|
+
console.log();
|
|
496
|
+
}
|
|
497
|
+
catch (error) {
|
|
498
|
+
stopSpinner(spinner);
|
|
499
|
+
handleRegistryError(error);
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
// catalog sources - show available sources
|
|
503
|
+
const sourcesCmd = cmd
|
|
504
|
+
.command('sources')
|
|
505
|
+
.description('Manage catalog sources');
|
|
506
|
+
// Default action for 'sources' (no subcommand)
|
|
507
|
+
sourcesCmd.action(async () => {
|
|
508
|
+
await showSourcesList(getConfigPath);
|
|
509
|
+
});
|
|
510
|
+
// catalog sources list - explicit list subcommand
|
|
511
|
+
sourcesCmd
|
|
512
|
+
.command('list')
|
|
513
|
+
.description('List available catalog sources')
|
|
514
|
+
.action(async () => {
|
|
515
|
+
await showSourcesList(getConfigPath);
|
|
516
|
+
});
|
|
517
|
+
// catalog sources set <name> - set default source
|
|
518
|
+
sourcesCmd
|
|
519
|
+
.command('set')
|
|
520
|
+
.description('Set default catalog source')
|
|
521
|
+
.argument('<name>', 'Source name')
|
|
522
|
+
.action(async (name) => {
|
|
523
|
+
const opts = getOutputOptions();
|
|
524
|
+
// Validate source name
|
|
525
|
+
if (!isValidSource(name)) {
|
|
526
|
+
if (opts.json) {
|
|
527
|
+
output({ success: false, error: `Unknown catalog source: ${name}` });
|
|
528
|
+
}
|
|
529
|
+
else {
|
|
530
|
+
outputError(`Unknown catalog source: ${name}`);
|
|
531
|
+
console.error();
|
|
532
|
+
console.error('Available sources:');
|
|
533
|
+
for (const sourceName of getSourceNames()) {
|
|
534
|
+
console.error(` ${sourceName}`);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
process.exit(1);
|
|
538
|
+
}
|
|
539
|
+
try {
|
|
540
|
+
const manager = new ConfigManager(getConfigPath());
|
|
541
|
+
const config = await manager.loadOrDefault();
|
|
542
|
+
// Update catalog config
|
|
543
|
+
config.catalog = config.catalog || {};
|
|
544
|
+
config.catalog.defaultSource = name;
|
|
545
|
+
await manager.save(config);
|
|
546
|
+
if (opts.json) {
|
|
547
|
+
output({ success: true, defaultSource: name });
|
|
548
|
+
}
|
|
549
|
+
else {
|
|
550
|
+
outputSuccess(`Default catalog source set to: ${name}`);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
catch (error) {
|
|
554
|
+
if (opts.json) {
|
|
555
|
+
output({
|
|
556
|
+
success: false,
|
|
557
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
outputError('Failed to save config', error instanceof Error ? error : undefined);
|
|
562
|
+
}
|
|
563
|
+
process.exit(1);
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
return cmd;
|
|
567
|
+
}
|
|
568
|
+
//# sourceMappingURL=catalog.js.map
|