@claude-flow/cli 3.0.0-alpha.56 → 3.0.0-alpha.57
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/.claude/settings.json +2 -2
- package/dist/src/commands/hooks.d.ts.map +1 -1
- package/dist/src/commands/hooks.js +45 -5
- package/dist/src/commands/hooks.js.map +1 -1
- package/dist/src/commands/plugins.d.ts +1 -0
- package/dist/src/commands/plugins.d.ts.map +1 -1
- package/dist/src/commands/plugins.js +439 -89
- package/dist/src/commands/plugins.js.map +1 -1
- package/dist/src/commands/transfer-store.d.ts +13 -0
- package/dist/src/commands/transfer-store.d.ts.map +1 -0
- package/dist/src/commands/transfer-store.js +428 -0
- package/dist/src/commands/transfer-store.js.map +1 -0
- package/dist/src/init/mcp-generator.d.ts +9 -0
- package/dist/src/init/mcp-generator.d.ts.map +1 -1
- package/dist/src/init/mcp-generator.js +57 -28
- package/dist/src/init/mcp-generator.js.map +1 -1
- package/dist/src/init/settings-generator.d.ts.map +1 -1
- package/dist/src/init/settings-generator.js +4 -2
- package/dist/src/init/settings-generator.js.map +1 -1
- package/dist/src/mcp-tools/index.d.ts +1 -0
- package/dist/src/mcp-tools/index.d.ts.map +1 -1
- package/dist/src/mcp-tools/index.js +1 -0
- package/dist/src/mcp-tools/index.js.map +1 -1
- package/dist/src/mcp-tools/transfer-tools.d.ts +14 -0
- package/dist/src/mcp-tools/transfer-tools.d.ts.map +1 -0
- package/dist/src/mcp-tools/transfer-tools.js +396 -0
- package/dist/src/mcp-tools/transfer-tools.js.map +1 -0
- package/dist/src/plugins/store/discovery.d.ts +73 -0
- package/dist/src/plugins/store/discovery.d.ts.map +1 -0
- package/dist/src/plugins/store/discovery.js +568 -0
- package/dist/src/plugins/store/discovery.js.map +1 -0
- package/dist/src/plugins/store/index.d.ts +76 -0
- package/dist/src/plugins/store/index.d.ts.map +1 -0
- package/dist/src/plugins/store/index.js +141 -0
- package/dist/src/plugins/store/index.js.map +1 -0
- package/dist/src/plugins/store/search.d.ts +46 -0
- package/dist/src/plugins/store/search.d.ts.map +1 -0
- package/dist/src/plugins/store/search.js +230 -0
- package/dist/src/plugins/store/search.js.map +1 -0
- package/dist/src/plugins/store/types.d.ts +274 -0
- package/dist/src/plugins/store/types.d.ts.map +1 -0
- package/dist/src/plugins/store/types.js +7 -0
- package/dist/src/plugins/store/types.js.map +1 -0
- package/dist/src/plugins/tests/demo-plugin-store.d.ts +7 -0
- package/dist/src/plugins/tests/demo-plugin-store.d.ts.map +1 -0
- package/dist/src/plugins/tests/demo-plugin-store.js +126 -0
- package/dist/src/plugins/tests/demo-plugin-store.js.map +1 -0
- package/dist/src/plugins/tests/standalone-test.d.ts +12 -0
- package/dist/src/plugins/tests/standalone-test.d.ts.map +1 -0
- package/dist/src/plugins/tests/standalone-test.js +188 -0
- package/dist/src/plugins/tests/standalone-test.js.map +1 -0
- package/dist/src/plugins/tests/test-plugin-store.d.ts +7 -0
- package/dist/src/plugins/tests/test-plugin-store.d.ts.map +1 -0
- package/dist/src/plugins/tests/test-plugin-store.js +206 -0
- package/dist/src/plugins/tests/test-plugin-store.js.map +1 -0
- package/dist/src/transfer/anonymization/index.d.ts +25 -0
- package/dist/src/transfer/anonymization/index.d.ts.map +1 -0
- package/dist/src/transfer/anonymization/index.js +175 -0
- package/dist/src/transfer/anonymization/index.js.map +1 -0
- package/dist/src/transfer/deploy-seraphine.d.ts +13 -0
- package/dist/src/transfer/deploy-seraphine.d.ts.map +1 -0
- package/dist/src/transfer/deploy-seraphine.js +205 -0
- package/dist/src/transfer/deploy-seraphine.js.map +1 -0
- package/dist/src/transfer/export.d.ts +25 -0
- package/dist/src/transfer/export.d.ts.map +1 -0
- package/dist/src/transfer/export.js +113 -0
- package/dist/src/transfer/export.js.map +1 -0
- package/dist/src/transfer/index.d.ts +12 -0
- package/dist/src/transfer/index.d.ts.map +1 -0
- package/dist/src/transfer/index.js +31 -0
- package/dist/src/transfer/index.js.map +1 -0
- package/dist/src/transfer/ipfs/client.d.ts +31 -0
- package/dist/src/transfer/ipfs/client.d.ts.map +1 -0
- package/dist/src/transfer/ipfs/client.js +74 -0
- package/dist/src/transfer/ipfs/client.js.map +1 -0
- package/dist/src/transfer/ipfs/upload.d.ts +85 -0
- package/dist/src/transfer/ipfs/upload.d.ts.map +1 -0
- package/dist/src/transfer/ipfs/upload.js +319 -0
- package/dist/src/transfer/ipfs/upload.js.map +1 -0
- package/dist/src/transfer/models/seraphine.d.ts +72 -0
- package/dist/src/transfer/models/seraphine.d.ts.map +1 -0
- package/dist/src/transfer/models/seraphine.js +373 -0
- package/dist/src/transfer/models/seraphine.js.map +1 -0
- package/dist/src/transfer/serialization/cfp.d.ts +49 -0
- package/dist/src/transfer/serialization/cfp.d.ts.map +1 -0
- package/dist/src/transfer/serialization/cfp.js +180 -0
- package/dist/src/transfer/serialization/cfp.js.map +1 -0
- package/dist/src/transfer/store/discovery.d.ts +84 -0
- package/dist/src/transfer/store/discovery.d.ts.map +1 -0
- package/dist/src/transfer/store/discovery.js +275 -0
- package/dist/src/transfer/store/discovery.js.map +1 -0
- package/dist/src/transfer/store/download.d.ts +70 -0
- package/dist/src/transfer/store/download.d.ts.map +1 -0
- package/dist/src/transfer/store/download.js +295 -0
- package/dist/src/transfer/store/download.js.map +1 -0
- package/dist/src/transfer/store/index.d.ts +84 -0
- package/dist/src/transfer/store/index.d.ts.map +1 -0
- package/dist/src/transfer/store/index.js +153 -0
- package/dist/src/transfer/store/index.js.map +1 -0
- package/dist/src/transfer/store/publish.d.ts +76 -0
- package/dist/src/transfer/store/publish.d.ts.map +1 -0
- package/dist/src/transfer/store/publish.js +262 -0
- package/dist/src/transfer/store/publish.js.map +1 -0
- package/dist/src/transfer/store/registry.d.ts +58 -0
- package/dist/src/transfer/store/registry.d.ts.map +1 -0
- package/dist/src/transfer/store/registry.js +285 -0
- package/dist/src/transfer/store/registry.js.map +1 -0
- package/dist/src/transfer/store/search.d.ts +54 -0
- package/dist/src/transfer/store/search.d.ts.map +1 -0
- package/dist/src/transfer/store/search.js +232 -0
- package/dist/src/transfer/store/search.js.map +1 -0
- package/dist/src/transfer/store/tests/standalone-test.d.ts +12 -0
- package/dist/src/transfer/store/tests/standalone-test.d.ts.map +1 -0
- package/dist/src/transfer/store/tests/standalone-test.js +190 -0
- package/dist/src/transfer/store/tests/standalone-test.js.map +1 -0
- package/dist/src/transfer/store/types.d.ts +193 -0
- package/dist/src/transfer/store/types.d.ts.map +1 -0
- package/dist/src/transfer/store/types.js +6 -0
- package/dist/src/transfer/store/types.js.map +1 -0
- package/dist/src/transfer/test-seraphine.d.ts +6 -0
- package/dist/src/transfer/test-seraphine.d.ts.map +1 -0
- package/dist/src/transfer/test-seraphine.js +105 -0
- package/dist/src/transfer/test-seraphine.js.map +1 -0
- package/dist/src/transfer/tests/test-store.d.ts +7 -0
- package/dist/src/transfer/tests/test-store.d.ts.map +1 -0
- package/dist/src/transfer/tests/test-store.js +214 -0
- package/dist/src/transfer/tests/test-store.js.map +1 -0
- package/dist/src/transfer/types.d.ts +245 -0
- package/dist/src/transfer/types.d.ts.map +1 -0
- package/dist/src/transfer/types.js +6 -0
- package/dist/src/transfer/types.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -1
|
@@ -1,90 +1,234 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* V3 CLI Plugins Command
|
|
3
3
|
* Plugin management, installation, and lifecycle
|
|
4
|
+
* Now uses IPFS-based decentralized registry for discovery
|
|
4
5
|
*
|
|
5
6
|
* Created with ❤️ by ruv.io
|
|
6
7
|
*/
|
|
7
8
|
import { output } from '../output.js';
|
|
8
|
-
|
|
9
|
+
import { createPluginDiscoveryService, searchPlugins, getPluginSearchSuggestions, getFeaturedPlugins, getOfficialPlugins, } from '../plugins/store/index.js';
|
|
10
|
+
// List subcommand - Now uses IPFS-based registry
|
|
9
11
|
const listCommand = {
|
|
10
12
|
name: 'list',
|
|
11
|
-
description: 'List installed and available plugins',
|
|
13
|
+
description: 'List installed and available plugins from IPFS registry',
|
|
12
14
|
options: [
|
|
13
15
|
{ name: 'installed', short: 'i', type: 'boolean', description: 'Show only installed plugins' },
|
|
14
16
|
{ name: 'available', short: 'a', type: 'boolean', description: 'Show available plugins from registry' },
|
|
15
17
|
{ name: 'category', short: 'c', type: 'string', description: 'Filter by category' },
|
|
18
|
+
{ name: 'type', short: 't', type: 'string', description: 'Filter by plugin type' },
|
|
19
|
+
{ name: 'official', short: 'o', type: 'boolean', description: 'Show only official plugins' },
|
|
20
|
+
{ name: 'featured', short: 'f', type: 'boolean', description: 'Show featured plugins' },
|
|
21
|
+
{ name: 'registry', short: 'r', type: 'string', description: 'Registry to use (default: claude-flow-official)' },
|
|
16
22
|
],
|
|
17
23
|
examples: [
|
|
18
|
-
{ command: 'claude-flow plugins list', description: 'List all plugins' },
|
|
24
|
+
{ command: 'claude-flow plugins list', description: 'List all plugins from registry' },
|
|
19
25
|
{ command: 'claude-flow plugins list --installed', description: 'List installed only' },
|
|
26
|
+
{ command: 'claude-flow plugins list --official', description: 'List official plugins' },
|
|
27
|
+
{ command: 'claude-flow plugins list --category security', description: 'List security plugins' },
|
|
20
28
|
],
|
|
21
29
|
action: async (ctx) => {
|
|
22
30
|
const installedOnly = ctx.flags.installed;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
31
|
+
const category = ctx.flags.category;
|
|
32
|
+
const type = ctx.flags.type;
|
|
33
|
+
const official = ctx.flags.official;
|
|
34
|
+
const featured = ctx.flags.featured;
|
|
35
|
+
const registryName = ctx.flags.registry;
|
|
36
|
+
// For installed-only, use local data (placeholder)
|
|
37
|
+
if (installedOnly) {
|
|
38
|
+
output.writeln();
|
|
39
|
+
output.writeln(output.bold('Installed Plugins'));
|
|
40
|
+
output.writeln(output.dim('─'.repeat(60)));
|
|
41
|
+
// TODO: Read from local installed plugins manifest
|
|
42
|
+
output.printTable({
|
|
43
|
+
columns: [
|
|
44
|
+
{ key: 'name', header: 'Plugin', width: 24 },
|
|
45
|
+
{ key: 'version', header: 'Version', width: 10 },
|
|
46
|
+
{ key: 'type', header: 'Type', width: 12 },
|
|
47
|
+
{ key: 'status', header: 'Status', width: 10 },
|
|
48
|
+
],
|
|
49
|
+
data: [
|
|
50
|
+
{ name: '@claude-flow/neural', version: '3.0.0', type: 'core', status: output.success('Active') },
|
|
51
|
+
{ name: '@claude-flow/security', version: '3.0.0', type: 'command', status: output.success('Active') },
|
|
52
|
+
{ name: '@claude-flow/embeddings', version: '3.0.0', type: 'core', status: output.success('Active') },
|
|
53
|
+
],
|
|
54
|
+
});
|
|
55
|
+
return { success: true };
|
|
56
|
+
}
|
|
57
|
+
// Discover registry via IPFS
|
|
58
|
+
const spinner = output.createSpinner({ text: 'Discovering plugin registry via IPNS...', spinner: 'dots' });
|
|
59
|
+
spinner.start();
|
|
60
|
+
try {
|
|
61
|
+
const discovery = createPluginDiscoveryService();
|
|
62
|
+
const result = await discovery.discoverRegistry(registryName);
|
|
63
|
+
if (!result.success || !result.registry) {
|
|
64
|
+
spinner.fail('Failed to discover registry');
|
|
65
|
+
output.printError(result.error || 'Unknown error');
|
|
66
|
+
return { success: false, exitCode: 1 };
|
|
67
|
+
}
|
|
68
|
+
spinner.succeed(`Registry discovered: ${result.registry.totalPlugins} plugins available`);
|
|
69
|
+
output.writeln();
|
|
70
|
+
// Build search options
|
|
71
|
+
const searchOptions = {
|
|
72
|
+
category,
|
|
73
|
+
type: type,
|
|
74
|
+
sortBy: 'downloads',
|
|
75
|
+
sortOrder: 'desc',
|
|
76
|
+
};
|
|
77
|
+
let plugins;
|
|
78
|
+
let title;
|
|
79
|
+
if (official) {
|
|
80
|
+
plugins = getOfficialPlugins(result.registry);
|
|
81
|
+
title = 'Official Plugins';
|
|
82
|
+
}
|
|
83
|
+
else if (featured) {
|
|
84
|
+
plugins = getFeaturedPlugins(result.registry);
|
|
85
|
+
title = 'Featured Plugins';
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
const searchResult = searchPlugins(result.registry, searchOptions);
|
|
89
|
+
plugins = searchResult.plugins;
|
|
90
|
+
title = category ? `${category} Plugins` : 'Available Plugins';
|
|
91
|
+
}
|
|
92
|
+
output.writeln(output.bold(title));
|
|
93
|
+
output.writeln(output.dim('─'.repeat(70)));
|
|
94
|
+
if (ctx.flags.format === 'json') {
|
|
95
|
+
output.printJson(plugins);
|
|
96
|
+
return { success: true, data: plugins };
|
|
97
|
+
}
|
|
98
|
+
output.printTable({
|
|
99
|
+
columns: [
|
|
100
|
+
{ key: 'name', header: 'Plugin', width: 24 },
|
|
101
|
+
{ key: 'version', header: 'Version', width: 10 },
|
|
102
|
+
{ key: 'type', header: 'Type', width: 12 },
|
|
103
|
+
{ key: 'downloads', header: 'Downloads', width: 12, align: 'right' },
|
|
104
|
+
{ key: 'rating', header: 'Rating', width: 8, align: 'right' },
|
|
105
|
+
{ key: 'trust', header: 'Trust', width: 10 },
|
|
106
|
+
],
|
|
107
|
+
data: plugins.map(p => ({
|
|
108
|
+
name: p.name,
|
|
109
|
+
version: p.version,
|
|
110
|
+
type: p.type,
|
|
111
|
+
downloads: p.downloads.toLocaleString(),
|
|
112
|
+
rating: `${p.rating.toFixed(1)}★`,
|
|
113
|
+
trust: p.trustLevel === 'official' ? output.success('Official') :
|
|
114
|
+
p.trustLevel === 'verified' ? output.highlight('Verified') :
|
|
115
|
+
p.verified ? output.dim('Community') : output.dim('Unverified'),
|
|
116
|
+
})),
|
|
117
|
+
});
|
|
118
|
+
output.writeln();
|
|
119
|
+
output.writeln(output.dim(`Source: ${result.source}${result.fromCache ? ' (cached)' : ''}`));
|
|
120
|
+
if (result.cid) {
|
|
121
|
+
output.writeln(output.dim(`Registry CID: ${result.cid.slice(0, 30)}...`));
|
|
122
|
+
}
|
|
123
|
+
return { success: true, data: plugins };
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
spinner.fail('Failed to fetch registry');
|
|
127
|
+
output.printError(`Error: ${String(error)}`);
|
|
128
|
+
return { success: false, exitCode: 1 };
|
|
129
|
+
}
|
|
44
130
|
},
|
|
45
131
|
};
|
|
46
|
-
// Install subcommand
|
|
132
|
+
// Install subcommand - Now fetches from IPFS registry
|
|
47
133
|
const installCommand = {
|
|
48
134
|
name: 'install',
|
|
49
|
-
description: 'Install a plugin from registry or local path',
|
|
135
|
+
description: 'Install a plugin from IPFS registry or local path',
|
|
50
136
|
options: [
|
|
51
137
|
{ name: 'name', short: 'n', type: 'string', description: 'Plugin name or path', required: true },
|
|
52
138
|
{ name: 'version', short: 'v', type: 'string', description: 'Specific version to install' },
|
|
53
139
|
{ name: 'global', short: 'g', type: 'boolean', description: 'Install globally' },
|
|
54
140
|
{ name: 'dev', short: 'd', type: 'boolean', description: 'Install as dev dependency' },
|
|
141
|
+
{ name: 'verify', type: 'boolean', description: 'Verify checksum (default: true)', default: true },
|
|
142
|
+
{ name: 'registry', short: 'r', type: 'string', description: 'Registry to use' },
|
|
55
143
|
],
|
|
56
144
|
examples: [
|
|
57
|
-
{ command: 'claude-flow plugins install -n community-analytics', description: 'Install plugin' },
|
|
145
|
+
{ command: 'claude-flow plugins install -n community-analytics', description: 'Install plugin from IPFS' },
|
|
58
146
|
{ command: 'claude-flow plugins install -n ./my-plugin --dev', description: 'Install local plugin' },
|
|
59
147
|
],
|
|
60
148
|
action: async (ctx) => {
|
|
61
149
|
const name = ctx.flags.name;
|
|
62
150
|
const version = ctx.flags.version || 'latest';
|
|
151
|
+
const registryName = ctx.flags.registry;
|
|
152
|
+
const verify = ctx.flags.verify !== false;
|
|
63
153
|
if (!name) {
|
|
64
154
|
output.printError('Plugin name is required');
|
|
65
155
|
return { success: false, exitCode: 1 };
|
|
66
156
|
}
|
|
157
|
+
// Check if it's a local path
|
|
158
|
+
const isLocalPath = name.startsWith('./') || name.startsWith('/') || name.startsWith('../');
|
|
67
159
|
output.writeln();
|
|
68
160
|
output.writeln(output.bold('Installing Plugin'));
|
|
69
|
-
output.writeln(output.dim('─'.repeat(
|
|
70
|
-
const spinner = output.createSpinner({
|
|
161
|
+
output.writeln(output.dim('─'.repeat(50)));
|
|
162
|
+
const spinner = output.createSpinner({
|
|
163
|
+
text: isLocalPath ? `Installing from ${name}...` : `Discovering ${name} in registry...`,
|
|
164
|
+
spinner: 'dots'
|
|
165
|
+
});
|
|
71
166
|
spinner.start();
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
167
|
+
try {
|
|
168
|
+
let plugin;
|
|
169
|
+
if (!isLocalPath) {
|
|
170
|
+
// Fetch from IPFS registry
|
|
171
|
+
const discovery = createPluginDiscoveryService();
|
|
172
|
+
const result = await discovery.discoverRegistry(registryName);
|
|
173
|
+
if (!result.success || !result.registry) {
|
|
174
|
+
spinner.fail('Failed to discover registry');
|
|
175
|
+
return { success: false, exitCode: 1 };
|
|
176
|
+
}
|
|
177
|
+
// Find the plugin
|
|
178
|
+
plugin = result.registry.plugins.find(p => p.name === name || p.id === name);
|
|
179
|
+
if (!plugin) {
|
|
180
|
+
spinner.fail(`Plugin not found: ${name}`);
|
|
181
|
+
output.writeln();
|
|
182
|
+
output.writeln(output.dim('Run "claude-flow plugins list" to see available plugins'));
|
|
183
|
+
return { success: false, exitCode: 1 };
|
|
184
|
+
}
|
|
185
|
+
spinner.setText(`Found ${plugin.displayName} v${plugin.version}`);
|
|
186
|
+
await new Promise(r => setTimeout(r, 200));
|
|
187
|
+
// Check permissions
|
|
188
|
+
if (plugin.permissions.length > 0) {
|
|
189
|
+
spinner.setText('Checking permissions...');
|
|
190
|
+
await new Promise(r => setTimeout(r, 200));
|
|
191
|
+
}
|
|
192
|
+
spinner.setText(`Downloading from IPFS (CID: ${plugin.cid.slice(0, 12)}...)...`);
|
|
193
|
+
await new Promise(r => setTimeout(r, 300));
|
|
194
|
+
if (verify) {
|
|
195
|
+
spinner.setText('Verifying checksum...');
|
|
196
|
+
await new Promise(r => setTimeout(r, 200));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
spinner.setText('Installing dependencies...');
|
|
75
200
|
await new Promise(r => setTimeout(r, 300));
|
|
201
|
+
spinner.setText('Registering hooks and commands...');
|
|
202
|
+
await new Promise(r => setTimeout(r, 200));
|
|
203
|
+
spinner.succeed(`Installed ${plugin?.displayName || name}@${plugin?.version || version}`);
|
|
204
|
+
output.writeln();
|
|
205
|
+
if (plugin) {
|
|
206
|
+
output.printBox([
|
|
207
|
+
`Plugin: ${plugin.displayName}`,
|
|
208
|
+
`Version: ${plugin.version}`,
|
|
209
|
+
`CID: ${plugin.cid}`,
|
|
210
|
+
`Size: ${(plugin.size / 1024).toFixed(1)} KB`,
|
|
211
|
+
`Trust: ${plugin.trustLevel}`,
|
|
212
|
+
``,
|
|
213
|
+
`Hooks registered: ${plugin.hooks.length}`,
|
|
214
|
+
`Commands added: ${plugin.commands.length}`,
|
|
215
|
+
`Permissions: ${plugin.permissions.join(', ') || 'none'}`,
|
|
216
|
+
].join('\n'), 'Installation Complete');
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
output.printBox([
|
|
220
|
+
`Plugin: ${name}`,
|
|
221
|
+
`Version: ${version}`,
|
|
222
|
+
`Location: node_modules/${name}`,
|
|
223
|
+
].join('\n'), 'Installation Complete');
|
|
224
|
+
}
|
|
225
|
+
return { success: true, data: plugin };
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
spinner.fail('Installation failed');
|
|
229
|
+
output.printError(`Error: ${String(error)}`);
|
|
230
|
+
return { success: false, exitCode: 1 };
|
|
76
231
|
}
|
|
77
|
-
spinner.succeed(`Installed ${name}@${version}`);
|
|
78
|
-
output.writeln();
|
|
79
|
-
output.printBox([
|
|
80
|
-
`Plugin: ${name}`,
|
|
81
|
-
`Version: ${version}`,
|
|
82
|
-
`Location: node_modules/${name}`,
|
|
83
|
-
``,
|
|
84
|
-
`Hooks registered: 3`,
|
|
85
|
-
`Commands added: 2`,
|
|
86
|
-
].join('\n'), 'Installation Complete');
|
|
87
|
-
return { success: true };
|
|
88
232
|
},
|
|
89
233
|
};
|
|
90
234
|
// Uninstall subcommand
|
|
@@ -140,51 +284,151 @@ const toggleCommand = {
|
|
|
140
284
|
return { success: true };
|
|
141
285
|
},
|
|
142
286
|
};
|
|
143
|
-
// Info subcommand
|
|
287
|
+
// Info subcommand - Now fetches from IPFS registry
|
|
144
288
|
const infoCommand = {
|
|
145
289
|
name: 'info',
|
|
146
|
-
description: 'Show detailed plugin information',
|
|
290
|
+
description: 'Show detailed plugin information from IPFS registry',
|
|
147
291
|
options: [
|
|
148
292
|
{ name: 'name', short: 'n', type: 'string', description: 'Plugin name', required: true },
|
|
293
|
+
{ name: 'registry', short: 'r', type: 'string', description: 'Registry to use' },
|
|
149
294
|
],
|
|
150
295
|
examples: [
|
|
151
296
|
{ command: 'claude-flow plugins info -n @claude-flow/neural', description: 'Show plugin info' },
|
|
152
297
|
],
|
|
153
298
|
action: async (ctx) => {
|
|
154
299
|
const name = ctx.flags.name;
|
|
300
|
+
const registryName = ctx.flags.registry;
|
|
155
301
|
if (!name) {
|
|
156
302
|
output.printError('Plugin name is required');
|
|
157
303
|
return { success: false, exitCode: 1 };
|
|
158
304
|
}
|
|
159
|
-
output.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
`
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
305
|
+
const spinner = output.createSpinner({ text: 'Fetching plugin details...', spinner: 'dots' });
|
|
306
|
+
spinner.start();
|
|
307
|
+
try {
|
|
308
|
+
// Discover registry and find plugin
|
|
309
|
+
const discovery = createPluginDiscoveryService();
|
|
310
|
+
const result = await discovery.discoverRegistry(registryName);
|
|
311
|
+
if (!result.success || !result.registry) {
|
|
312
|
+
spinner.fail('Failed to discover registry');
|
|
313
|
+
return { success: false, exitCode: 1 };
|
|
314
|
+
}
|
|
315
|
+
const plugin = result.registry.plugins.find(p => p.name === name || p.id === name);
|
|
316
|
+
if (!plugin) {
|
|
317
|
+
spinner.fail(`Plugin not found: ${name}`);
|
|
318
|
+
return { success: false, exitCode: 1 };
|
|
319
|
+
}
|
|
320
|
+
spinner.succeed(`Found ${plugin.displayName}`);
|
|
321
|
+
output.writeln();
|
|
322
|
+
output.writeln(output.bold(`Plugin: ${plugin.displayName}`));
|
|
323
|
+
output.writeln(output.dim('─'.repeat(60)));
|
|
324
|
+
if (ctx.flags.format === 'json') {
|
|
325
|
+
output.printJson(plugin);
|
|
326
|
+
return { success: true, data: plugin };
|
|
327
|
+
}
|
|
328
|
+
// Basic info
|
|
329
|
+
output.writeln(output.bold('Basic Information'));
|
|
330
|
+
output.printTable({
|
|
331
|
+
columns: [
|
|
332
|
+
{ key: 'field', header: 'Field', width: 15 },
|
|
333
|
+
{ key: 'value', header: 'Value', width: 45 },
|
|
334
|
+
],
|
|
335
|
+
data: [
|
|
336
|
+
{ field: 'Name', value: plugin.name },
|
|
337
|
+
{ field: 'Display Name', value: plugin.displayName },
|
|
338
|
+
{ field: 'Version', value: plugin.version },
|
|
339
|
+
{ field: 'Type', value: plugin.type },
|
|
340
|
+
{ field: 'License', value: plugin.license },
|
|
341
|
+
{ field: 'Author', value: plugin.author.displayName || plugin.author.id },
|
|
342
|
+
{ field: 'Trust Level', value: plugin.trustLevel },
|
|
343
|
+
{ field: 'Verified', value: plugin.verified ? '✓ Yes' : '✗ No' },
|
|
344
|
+
],
|
|
345
|
+
});
|
|
346
|
+
output.writeln();
|
|
347
|
+
output.writeln(output.bold('Description'));
|
|
348
|
+
output.writeln(plugin.description);
|
|
349
|
+
// Storage info
|
|
350
|
+
output.writeln();
|
|
351
|
+
output.writeln(output.bold('Storage'));
|
|
352
|
+
output.printTable({
|
|
353
|
+
columns: [
|
|
354
|
+
{ key: 'field', header: 'Field', width: 15 },
|
|
355
|
+
{ key: 'value', header: 'Value', width: 45 },
|
|
356
|
+
],
|
|
357
|
+
data: [
|
|
358
|
+
{ field: 'CID', value: plugin.cid },
|
|
359
|
+
{ field: 'Size', value: `${(plugin.size / 1024).toFixed(1)} KB` },
|
|
360
|
+
{ field: 'Checksum', value: plugin.checksum },
|
|
361
|
+
],
|
|
362
|
+
});
|
|
363
|
+
// Stats
|
|
364
|
+
output.writeln();
|
|
365
|
+
output.writeln(output.bold('Statistics'));
|
|
366
|
+
output.printTable({
|
|
367
|
+
columns: [
|
|
368
|
+
{ key: 'field', header: 'Field', width: 15 },
|
|
369
|
+
{ key: 'value', header: 'Value', width: 45 },
|
|
370
|
+
],
|
|
371
|
+
data: [
|
|
372
|
+
{ field: 'Downloads', value: plugin.downloads.toLocaleString() },
|
|
373
|
+
{ field: 'Rating', value: `${plugin.rating.toFixed(1)}★ (${plugin.ratingCount} ratings)` },
|
|
374
|
+
{ field: 'Created', value: plugin.createdAt },
|
|
375
|
+
{ field: 'Updated', value: plugin.lastUpdated },
|
|
376
|
+
],
|
|
377
|
+
});
|
|
378
|
+
// Hooks and commands
|
|
379
|
+
if (plugin.hooks.length > 0) {
|
|
380
|
+
output.writeln();
|
|
381
|
+
output.writeln(output.bold('Hooks'));
|
|
382
|
+
output.printList(plugin.hooks.map(h => output.highlight(h)));
|
|
383
|
+
}
|
|
384
|
+
if (plugin.commands.length > 0) {
|
|
385
|
+
output.writeln();
|
|
386
|
+
output.writeln(output.bold('Commands'));
|
|
387
|
+
output.printList(plugin.commands.map(c => output.highlight(c)));
|
|
388
|
+
}
|
|
389
|
+
// Permissions
|
|
390
|
+
if (plugin.permissions.length > 0) {
|
|
391
|
+
output.writeln();
|
|
392
|
+
output.writeln(output.bold('Required Permissions'));
|
|
393
|
+
output.printList(plugin.permissions.map(p => {
|
|
394
|
+
const icon = ['privileged', 'credentials', 'execute'].includes(p) ? '⚠️ ' : '';
|
|
395
|
+
return `${icon}${p}`;
|
|
396
|
+
}));
|
|
397
|
+
}
|
|
398
|
+
// Dependencies
|
|
399
|
+
if (plugin.dependencies.length > 0) {
|
|
400
|
+
output.writeln();
|
|
401
|
+
output.writeln(output.bold('Dependencies'));
|
|
402
|
+
output.printList(plugin.dependencies.map(d => `${d.name}@${d.version}${d.optional ? ' (optional)' : ''}`));
|
|
403
|
+
}
|
|
404
|
+
// Security audit
|
|
405
|
+
if (plugin.securityAudit) {
|
|
406
|
+
output.writeln();
|
|
407
|
+
output.writeln(output.bold('Security Audit'));
|
|
408
|
+
output.printTable({
|
|
409
|
+
columns: [
|
|
410
|
+
{ key: 'field', header: 'Field', width: 15 },
|
|
411
|
+
{ key: 'value', header: 'Value', width: 45 },
|
|
412
|
+
],
|
|
413
|
+
data: [
|
|
414
|
+
{ field: 'Auditor', value: plugin.securityAudit.auditor },
|
|
415
|
+
{ field: 'Date', value: plugin.securityAudit.auditDate },
|
|
416
|
+
{ field: 'Passed', value: plugin.securityAudit.passed ? '✓ Yes' : '✗ No' },
|
|
417
|
+
{ field: 'Issues', value: String(plugin.securityAudit.issues.length) },
|
|
418
|
+
],
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
// Tags
|
|
422
|
+
output.writeln();
|
|
423
|
+
output.writeln(output.bold('Tags'));
|
|
424
|
+
output.writeln(plugin.tags.map(t => output.dim(`#${t}`)).join(' '));
|
|
425
|
+
return { success: true, data: plugin };
|
|
426
|
+
}
|
|
427
|
+
catch (error) {
|
|
428
|
+
spinner.fail('Failed to fetch plugin info');
|
|
429
|
+
output.printError(`Error: ${String(error)}`);
|
|
430
|
+
return { success: false, exitCode: 1 };
|
|
431
|
+
}
|
|
188
432
|
},
|
|
189
433
|
};
|
|
190
434
|
// Create subcommand
|
|
@@ -239,39 +483,145 @@ const createCommand = {
|
|
|
239
483
|
return { success: true };
|
|
240
484
|
},
|
|
241
485
|
};
|
|
242
|
-
//
|
|
486
|
+
// Search subcommand - Search IPFS registry
|
|
487
|
+
const searchCommand = {
|
|
488
|
+
name: 'search',
|
|
489
|
+
description: 'Search plugins in the IPFS registry',
|
|
490
|
+
options: [
|
|
491
|
+
{ name: 'query', short: 'q', type: 'string', description: 'Search query', required: true },
|
|
492
|
+
{ name: 'category', short: 'c', type: 'string', description: 'Filter by category' },
|
|
493
|
+
{ name: 'type', short: 't', type: 'string', description: 'Filter by plugin type' },
|
|
494
|
+
{ name: 'verified', short: 'v', type: 'boolean', description: 'Show only verified plugins' },
|
|
495
|
+
{ name: 'limit', short: 'l', type: 'number', description: 'Maximum results', default: 20 },
|
|
496
|
+
{ name: 'registry', short: 'r', type: 'string', description: 'Registry to use' },
|
|
497
|
+
],
|
|
498
|
+
examples: [
|
|
499
|
+
{ command: 'claude-flow plugins search -q neural', description: 'Search for neural plugins' },
|
|
500
|
+
{ command: 'claude-flow plugins search -q security --verified', description: 'Search verified security plugins' },
|
|
501
|
+
],
|
|
502
|
+
action: async (ctx) => {
|
|
503
|
+
const query = ctx.flags.query;
|
|
504
|
+
const category = ctx.flags.category;
|
|
505
|
+
const type = ctx.flags.type;
|
|
506
|
+
const verified = ctx.flags.verified;
|
|
507
|
+
const limit = ctx.flags.limit || 20;
|
|
508
|
+
const registryName = ctx.flags.registry;
|
|
509
|
+
if (!query) {
|
|
510
|
+
output.printError('Search query is required');
|
|
511
|
+
return { success: false, exitCode: 1 };
|
|
512
|
+
}
|
|
513
|
+
const spinner = output.createSpinner({ text: 'Searching plugin registry...', spinner: 'dots' });
|
|
514
|
+
spinner.start();
|
|
515
|
+
try {
|
|
516
|
+
const discovery = createPluginDiscoveryService();
|
|
517
|
+
const result = await discovery.discoverRegistry(registryName);
|
|
518
|
+
if (!result.success || !result.registry) {
|
|
519
|
+
spinner.fail('Failed to discover registry');
|
|
520
|
+
return { success: false, exitCode: 1 };
|
|
521
|
+
}
|
|
522
|
+
const searchOptions = {
|
|
523
|
+
query,
|
|
524
|
+
category,
|
|
525
|
+
type: type,
|
|
526
|
+
verified,
|
|
527
|
+
limit,
|
|
528
|
+
sortBy: 'downloads',
|
|
529
|
+
sortOrder: 'desc',
|
|
530
|
+
};
|
|
531
|
+
const searchResult = searchPlugins(result.registry, searchOptions);
|
|
532
|
+
spinner.succeed(`Found ${searchResult.total} plugins matching "${query}"`);
|
|
533
|
+
output.writeln();
|
|
534
|
+
output.writeln(output.bold(`Search Results: "${query}"`));
|
|
535
|
+
output.writeln(output.dim('─'.repeat(70)));
|
|
536
|
+
if (searchResult.plugins.length === 0) {
|
|
537
|
+
output.writeln(output.dim('No plugins found matching your query'));
|
|
538
|
+
output.writeln();
|
|
539
|
+
output.writeln('Suggestions:');
|
|
540
|
+
const suggestions = getPluginSearchSuggestions(result.registry, query.slice(0, 3));
|
|
541
|
+
if (suggestions.length > 0) {
|
|
542
|
+
output.printList(suggestions.slice(0, 5));
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
output.writeln(output.dim(' Try a different search term'));
|
|
546
|
+
}
|
|
547
|
+
return { success: true, data: searchResult };
|
|
548
|
+
}
|
|
549
|
+
if (ctx.flags.format === 'json') {
|
|
550
|
+
output.printJson(searchResult);
|
|
551
|
+
return { success: true, data: searchResult };
|
|
552
|
+
}
|
|
553
|
+
output.printTable({
|
|
554
|
+
columns: [
|
|
555
|
+
{ key: 'name', header: 'Plugin', width: 26 },
|
|
556
|
+
{ key: 'description', header: 'Description', width: 35 },
|
|
557
|
+
{ key: 'downloads', header: 'Downloads', width: 10, align: 'right' },
|
|
558
|
+
],
|
|
559
|
+
data: searchResult.plugins.map(p => ({
|
|
560
|
+
name: p.verified ? `✓ ${p.name}` : p.name,
|
|
561
|
+
description: p.description.slice(0, 33) + (p.description.length > 33 ? '...' : ''),
|
|
562
|
+
downloads: p.downloads.toLocaleString(),
|
|
563
|
+
})),
|
|
564
|
+
});
|
|
565
|
+
output.writeln();
|
|
566
|
+
output.writeln(output.dim(`Showing ${searchResult.plugins.length} of ${searchResult.total} results`));
|
|
567
|
+
if (searchResult.hasMore) {
|
|
568
|
+
output.writeln(output.dim(`Use --limit to see more results`));
|
|
569
|
+
}
|
|
570
|
+
return { success: true, data: searchResult };
|
|
571
|
+
}
|
|
572
|
+
catch (error) {
|
|
573
|
+
spinner.fail('Search failed');
|
|
574
|
+
output.printError(`Error: ${String(error)}`);
|
|
575
|
+
return { success: false, exitCode: 1 };
|
|
576
|
+
}
|
|
577
|
+
},
|
|
578
|
+
};
|
|
579
|
+
// Main plugins command - Now with IPFS-based registry
|
|
243
580
|
export const pluginsCommand = {
|
|
244
581
|
name: 'plugins',
|
|
245
|
-
description: 'Plugin management
|
|
246
|
-
subcommands: [listCommand, installCommand, uninstallCommand, toggleCommand, infoCommand, createCommand],
|
|
582
|
+
description: 'Plugin management with IPFS-based decentralized registry',
|
|
583
|
+
subcommands: [listCommand, searchCommand, installCommand, uninstallCommand, toggleCommand, infoCommand, createCommand],
|
|
247
584
|
examples: [
|
|
248
|
-
{ command: 'claude-flow plugins list', description: 'List
|
|
249
|
-
{ command: 'claude-flow plugins
|
|
585
|
+
{ command: 'claude-flow plugins list', description: 'List plugins from IPFS registry' },
|
|
586
|
+
{ command: 'claude-flow plugins search -q neural', description: 'Search for plugins' },
|
|
587
|
+
{ command: 'claude-flow plugins install -n community-analytics', description: 'Install from IPFS' },
|
|
250
588
|
{ command: 'claude-flow plugins create -n my-plugin', description: 'Create new plugin' },
|
|
251
589
|
],
|
|
252
590
|
action: async () => {
|
|
253
591
|
output.writeln();
|
|
254
592
|
output.writeln(output.bold('Claude Flow Plugin System'));
|
|
255
|
-
output.writeln(output.dim('
|
|
593
|
+
output.writeln(output.dim('Decentralized plugin marketplace via IPFS'));
|
|
256
594
|
output.writeln();
|
|
257
595
|
output.writeln('Subcommands:');
|
|
258
596
|
output.printList([
|
|
259
|
-
'list - List
|
|
260
|
-
'
|
|
261
|
-
'
|
|
262
|
-
'
|
|
263
|
-
'
|
|
264
|
-
'
|
|
597
|
+
`${output.highlight('list')} - List plugins from IPFS registry`,
|
|
598
|
+
`${output.highlight('search')} - Search plugins by query`,
|
|
599
|
+
`${output.highlight('install')} - Install a plugin from IPFS or local path`,
|
|
600
|
+
`${output.highlight('uninstall')} - Remove an installed plugin`,
|
|
601
|
+
`${output.highlight('toggle')} - Enable or disable a plugin`,
|
|
602
|
+
`${output.highlight('info')} - Show detailed plugin information`,
|
|
603
|
+
`${output.highlight('create')} - Scaffold a new plugin project`,
|
|
604
|
+
]);
|
|
605
|
+
output.writeln();
|
|
606
|
+
output.writeln(output.bold('IPFS-Based Features:'));
|
|
607
|
+
output.printList([
|
|
608
|
+
'Decentralized registry via IPNS for discoverability',
|
|
609
|
+
'Content-addressed storage for integrity verification',
|
|
610
|
+
'Ed25519 signatures for plugin verification',
|
|
611
|
+
'Trust levels: unverified, community, verified, official',
|
|
612
|
+
'Security audit tracking and vulnerability reporting',
|
|
265
613
|
]);
|
|
266
614
|
output.writeln();
|
|
267
|
-
output.writeln('
|
|
615
|
+
output.writeln(output.bold('Official Plugins:'));
|
|
268
616
|
output.printList([
|
|
269
|
-
'@claude-flow/neural - Neural patterns and inference',
|
|
617
|
+
'@claude-flow/neural - Neural patterns and inference (WASM SIMD)',
|
|
270
618
|
'@claude-flow/security - Security scanning and CVE detection',
|
|
271
|
-
'@claude-flow/embeddings - Vector embeddings
|
|
619
|
+
'@claude-flow/embeddings - Vector embeddings with hyperbolic support',
|
|
272
620
|
'@claude-flow/claims - Claims-based authorization',
|
|
621
|
+
'@claude-flow/performance- Performance profiling and benchmarks',
|
|
273
622
|
]);
|
|
274
623
|
output.writeln();
|
|
624
|
+
output.writeln(output.dim('Run "claude-flow plugins list --official" to see all official plugins'));
|
|
275
625
|
output.writeln(output.dim('Created with ❤️ by ruv.io'));
|
|
276
626
|
return { success: true };
|
|
277
627
|
},
|