@btc-vision/cli 1.0.5 → 1.0.6
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/package.json +4 -1
- package/.gitattributes +0 -2
- package/.github/dependabot.yml +0 -9
- package/.github/workflows/ci.yml +0 -48
- package/.prettierrc.json +0 -12
- package/CONTRIBUTING.md +0 -56
- package/NOTICE +0 -17
- package/SECURITY.md +0 -35
- package/eslint.config.js +0 -41
- package/gulpfile.js +0 -41
- package/src/commands/AcceptCommand.ts +0 -224
- package/src/commands/BaseCommand.ts +0 -59
- package/src/commands/CompileCommand.ts +0 -195
- package/src/commands/ConfigCommand.ts +0 -117
- package/src/commands/DeprecateCommand.ts +0 -193
- package/src/commands/InfoCommand.ts +0 -293
- package/src/commands/InitCommand.ts +0 -541
- package/src/commands/InstallCommand.ts +0 -179
- package/src/commands/KeygenCommand.ts +0 -157
- package/src/commands/ListCommand.ts +0 -169
- package/src/commands/LoginCommand.ts +0 -197
- package/src/commands/LogoutCommand.ts +0 -76
- package/src/commands/PublishCommand.ts +0 -340
- package/src/commands/ScopeRegisterCommand.ts +0 -164
- package/src/commands/SearchCommand.ts +0 -140
- package/src/commands/SignCommand.ts +0 -110
- package/src/commands/TransferCommand.ts +0 -363
- package/src/commands/UndeprecateCommand.ts +0 -167
- package/src/commands/UpdateCommand.ts +0 -200
- package/src/commands/VerifyCommand.ts +0 -228
- package/src/commands/WhoamiCommand.ts +0 -113
- package/src/index.ts +0 -88
- package/src/lib/PackageRegistry.abi.json +0 -765
- package/src/lib/PackageRegistry.abi.ts +0 -365
- package/src/lib/binary.ts +0 -338
- package/src/lib/config.ts +0 -265
- package/src/lib/credentials.ts +0 -176
- package/src/lib/ipfs.ts +0 -382
- package/src/lib/manifest.ts +0 -195
- package/src/lib/provider.ts +0 -121
- package/src/lib/registry.ts +0 -467
- package/src/lib/transaction.ts +0 -205
- package/src/lib/wallet.ts +0 -262
- package/src/types/PackageRegistry.ts +0 -344
- package/src/types/index.ts +0 -147
- package/tsconfig.json +0 -25
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Install command - Download and verify plugins from registry
|
|
3
|
-
*
|
|
4
|
-
* @module commands/InstallCommand
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import * as fs from 'fs';
|
|
8
|
-
import * as path from 'path';
|
|
9
|
-
import { BaseCommand } from './BaseCommand.js';
|
|
10
|
-
import { getPackage, getVersion, registryToMldsaLevel } from '../lib/registry.js';
|
|
11
|
-
import { fetchFromIPFS, isValidCid } from '../lib/ipfs.js';
|
|
12
|
-
import { formatFileSize, parseOpnetBinary, verifyChecksum } from '../lib/binary.js';
|
|
13
|
-
import { CLIWallet } from '../lib/wallet.js';
|
|
14
|
-
import { NetworkName } from '../types/index.js';
|
|
15
|
-
|
|
16
|
-
interface InstallOptions {
|
|
17
|
-
output?: string;
|
|
18
|
-
network: string;
|
|
19
|
-
skipVerify?: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export class InstallCommand extends BaseCommand {
|
|
23
|
-
constructor() {
|
|
24
|
-
super('install', 'Download and verify a plugin from the registry');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
protected configure(): void {
|
|
28
|
-
this.command
|
|
29
|
-
.argument('<package>', 'Package name[@version] or IPFS CID')
|
|
30
|
-
.option('-o, --output <path>', 'Output directory (default: ./plugins/)')
|
|
31
|
-
.option('-n, --network <network>', 'Network', 'mainnet')
|
|
32
|
-
.option('--skip-verify', 'Skip signature verification')
|
|
33
|
-
.action((packageInput: string, options?: InstallOptions) =>
|
|
34
|
-
this.execute(packageInput, options || { network: 'mainnet' }),
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
private async execute(packageInput: string, options?: InstallOptions): Promise<void> {
|
|
39
|
-
try {
|
|
40
|
-
let cid: string;
|
|
41
|
-
let packageName: string;
|
|
42
|
-
let version: string;
|
|
43
|
-
|
|
44
|
-
// Check if input is a CID
|
|
45
|
-
if (isValidCid(packageInput)) {
|
|
46
|
-
cid = packageInput;
|
|
47
|
-
packageName = 'unknown';
|
|
48
|
-
version = 'unknown';
|
|
49
|
-
this.logger.info(`Installing from CID: ${cid}`);
|
|
50
|
-
} else {
|
|
51
|
-
// Parse package name and version
|
|
52
|
-
const atIndex = packageInput.lastIndexOf('@');
|
|
53
|
-
if (atIndex > 0 && !packageInput.startsWith('@')) {
|
|
54
|
-
packageName = packageInput.substring(0, atIndex);
|
|
55
|
-
version = packageInput.substring(atIndex + 1);
|
|
56
|
-
} else if (packageInput.startsWith('@') && packageInput.indexOf('@', 1) > 0) {
|
|
57
|
-
const secondAt = packageInput.indexOf('@', 1);
|
|
58
|
-
packageName = packageInput.substring(0, secondAt);
|
|
59
|
-
version = packageInput.substring(secondAt + 1);
|
|
60
|
-
} else {
|
|
61
|
-
packageName = packageInput;
|
|
62
|
-
version = 'latest';
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Fetch from registry
|
|
66
|
-
this.logger.info(`Fetching ${packageName}...`);
|
|
67
|
-
const network = (options?.network || 'mainnet') as NetworkName;
|
|
68
|
-
|
|
69
|
-
const packageInfo = await getPackage(packageName, network);
|
|
70
|
-
if (!packageInfo) {
|
|
71
|
-
this.logger.fail('Package not found');
|
|
72
|
-
this.logger.error(`Package "${packageName}" does not exist.`);
|
|
73
|
-
process.exit(1);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Resolve version
|
|
77
|
-
if (version === 'latest') {
|
|
78
|
-
version = packageInfo.latestVersion;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const versionInfo = await getVersion(packageName, version, network);
|
|
82
|
-
if (!versionInfo) {
|
|
83
|
-
this.logger.fail('Version not found');
|
|
84
|
-
this.logger.error(`Version "${version}" does not exist.`);
|
|
85
|
-
process.exit(1);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (versionInfo.deprecated) {
|
|
89
|
-
this.logger.warn(`Version ${version} is deprecated`);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
cid = versionInfo.ipfsCid;
|
|
93
|
-
this.logger.success(`Found: ${packageName}@${version}`);
|
|
94
|
-
|
|
95
|
-
// Display info
|
|
96
|
-
this.logger.log('');
|
|
97
|
-
this.logger.log(`IPFS CID: ${cid}`);
|
|
98
|
-
this.logger.log(`MLDSA Level: ${registryToMldsaLevel(versionInfo.mldsaLevel)}`);
|
|
99
|
-
this.logger.log(`Publisher: ${versionInfo.publisher}`);
|
|
100
|
-
this.logger.log('');
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Download from IPFS
|
|
104
|
-
this.logger.info('Downloading from IPFS...');
|
|
105
|
-
const result = await fetchFromIPFS(cid);
|
|
106
|
-
this.logger.success(`Downloaded (${formatFileSize(result.size)})`);
|
|
107
|
-
|
|
108
|
-
// Parse and verify
|
|
109
|
-
this.logger.info('Verifying binary...');
|
|
110
|
-
const parsed = parseOpnetBinary(result.data);
|
|
111
|
-
|
|
112
|
-
// Verify checksum
|
|
113
|
-
if (!verifyChecksum(parsed)) {
|
|
114
|
-
this.logger.fail('Checksum verification failed');
|
|
115
|
-
this.logger.error('The binary appears to be corrupted.');
|
|
116
|
-
process.exit(1);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Verify signature
|
|
120
|
-
if (!options?.skipVerify) {
|
|
121
|
-
const isUnsigned = parsed.publicKey.every((b) => b === 0);
|
|
122
|
-
if (isUnsigned) {
|
|
123
|
-
this.logger.warn('Binary is unsigned');
|
|
124
|
-
} else {
|
|
125
|
-
const actualMldsaLevel = ([44, 65, 87] as const)[parsed.mldsaLevel];
|
|
126
|
-
const signatureValid = CLIWallet.verifyMLDSA(
|
|
127
|
-
parsed.checksum,
|
|
128
|
-
parsed.signature,
|
|
129
|
-
parsed.publicKey,
|
|
130
|
-
actualMldsaLevel,
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
if (!signatureValid) {
|
|
134
|
-
this.logger.fail('Signature verification failed');
|
|
135
|
-
this.logger.error('The binary signature is invalid.');
|
|
136
|
-
process.exit(1);
|
|
137
|
-
}
|
|
138
|
-
this.logger.success('Signature verified');
|
|
139
|
-
}
|
|
140
|
-
} else {
|
|
141
|
-
this.logger.warn('Skipping signature verification');
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Update package name from metadata
|
|
145
|
-
if (packageName === 'unknown') {
|
|
146
|
-
packageName = parsed.metadata.name;
|
|
147
|
-
version = parsed.metadata.version;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Determine output path
|
|
151
|
-
const outputDir = options?.output || path.join(process.cwd(), 'plugins');
|
|
152
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
153
|
-
|
|
154
|
-
const fileName = `${packageName.replace(/^@/, '').replace(/\//g, '-')}-${version}.opnet`;
|
|
155
|
-
const outputPath = path.join(outputDir, fileName);
|
|
156
|
-
|
|
157
|
-
// Save file
|
|
158
|
-
this.logger.info('Saving plugin...');
|
|
159
|
-
fs.writeFileSync(outputPath, result.data);
|
|
160
|
-
this.logger.success('Plugin installed');
|
|
161
|
-
|
|
162
|
-
// Summary
|
|
163
|
-
this.logger.log('');
|
|
164
|
-
this.logger.success('Plugin installed successfully!');
|
|
165
|
-
this.logger.log('');
|
|
166
|
-
this.logger.log(`Package: ${parsed.metadata.name}`);
|
|
167
|
-
this.logger.log(`Version: ${parsed.metadata.version}`);
|
|
168
|
-
this.logger.log(`Type: ${parsed.metadata.pluginType}`);
|
|
169
|
-
this.logger.log(`Size: ${formatFileSize(result.size)}`);
|
|
170
|
-
this.logger.log(`Output: ${outputPath}`);
|
|
171
|
-
this.logger.log('');
|
|
172
|
-
} catch (error) {
|
|
173
|
-
this.logger.fail('Installation failed');
|
|
174
|
-
this.exitWithError(this.formatError(error));
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
export const installCommand = new InstallCommand().getCommand();
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Keygen command - Generate MLDSA keypairs and mnemonics
|
|
3
|
-
*
|
|
4
|
-
* @module commands/KeygenCommand
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { Command } from 'commander';
|
|
8
|
-
import * as fs from 'fs';
|
|
9
|
-
import { BaseCommand } from './BaseCommand.js';
|
|
10
|
-
import { computePublicKeyHash, generateMLDSAKeypair, generateMnemonic } from '../lib/wallet.js';
|
|
11
|
-
import { isValidMldsaLevel } from '../lib/credentials.js';
|
|
12
|
-
|
|
13
|
-
export class KeygenCommand extends BaseCommand {
|
|
14
|
-
constructor() {
|
|
15
|
-
super('keygen', 'Generate cryptographic keys');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
protected configure(): void {
|
|
19
|
-
this.command
|
|
20
|
-
.addCommand(this.createMnemonicCommand())
|
|
21
|
-
.addCommand(this.createMldsaCommand())
|
|
22
|
-
.addCommand(this.createInfoCommand());
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
private createMnemonicCommand(): Command {
|
|
26
|
-
return new Command('mnemonic')
|
|
27
|
-
.description('Generate a new BIP-39 mnemonic phrase')
|
|
28
|
-
.option('-o, --output <file>', 'Write mnemonic to file (secure permissions)')
|
|
29
|
-
.action((options: { output?: string }) => this.handleMnemonic(options));
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
private createMldsaCommand(): Command {
|
|
33
|
-
return new Command('mldsa')
|
|
34
|
-
.description('Generate a standalone MLDSA keypair')
|
|
35
|
-
.option('-l, --level <level>', 'MLDSA security level (44, 65, 87)', '44')
|
|
36
|
-
.option('-o, --output <prefix>', 'Write keys to files with prefix')
|
|
37
|
-
.option('--json', 'Output as JSON')
|
|
38
|
-
.action((options: { level: string; output?: string; json?: boolean }) => {
|
|
39
|
-
this.handleMldsa(options);
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
private createInfoCommand(): Command {
|
|
44
|
-
return new Command('info')
|
|
45
|
-
.description('Show information about MLDSA key sizes')
|
|
46
|
-
.action(() => this.handleInfo());
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
private handleMnemonic(options: { output?: string }): void {
|
|
50
|
-
try {
|
|
51
|
-
const mnemonic = generateMnemonic();
|
|
52
|
-
|
|
53
|
-
if (options.output) {
|
|
54
|
-
fs.writeFileSync(options.output, mnemonic + '\n', { mode: 0o600 });
|
|
55
|
-
this.logger.success(`Mnemonic saved to: ${options.output}`);
|
|
56
|
-
this.logger.warn('Keep this file secure and backed up!');
|
|
57
|
-
} else {
|
|
58
|
-
this.logger.info('\nNew BIP-39 Mnemonic Phrase:\n');
|
|
59
|
-
this.logger.log(mnemonic);
|
|
60
|
-
this.logger.log('');
|
|
61
|
-
this.logger.warn('IMPORTANT: Write down these words and store them securely.');
|
|
62
|
-
this.logger.warn('Anyone with this phrase can access your wallet.');
|
|
63
|
-
this.logger.warn('Never share this phrase with anyone.');
|
|
64
|
-
}
|
|
65
|
-
} catch (error) {
|
|
66
|
-
this.exitWithError(this.formatError(error));
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
private handleMldsa(options: { level: string; output?: string; json?: boolean }): void {
|
|
71
|
-
try {
|
|
72
|
-
const levelNum = parseInt(options.level, 10);
|
|
73
|
-
if (!isValidMldsaLevel(levelNum)) {
|
|
74
|
-
this.exitWithError(`Invalid MLDSA level: ${options.level}. Valid: 44, 65, 87`);
|
|
75
|
-
return; // Unreachable, but helps TypeScript
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
this.logger.info(`Generating MLDSA-${levelNum} keypair...`);
|
|
79
|
-
|
|
80
|
-
const keypair = generateMLDSAKeypair(levelNum);
|
|
81
|
-
const publicKeyHash = computePublicKeyHash(keypair.publicKey);
|
|
82
|
-
|
|
83
|
-
if (options.output) {
|
|
84
|
-
const privateKeyPath = `${options.output}.private.key`;
|
|
85
|
-
const publicKeyPath = `${options.output}.public.key`;
|
|
86
|
-
|
|
87
|
-
fs.writeFileSync(privateKeyPath, keypair.privateKey.toString('hex') + '\n', {
|
|
88
|
-
mode: 0o600,
|
|
89
|
-
});
|
|
90
|
-
fs.writeFileSync(publicKeyPath, keypair.publicKey.toString('hex') + '\n', {
|
|
91
|
-
mode: 0o644,
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
this.logger.success('Keys generated successfully!');
|
|
95
|
-
this.logger.info(` Private key: ${privateKeyPath}`);
|
|
96
|
-
this.logger.info(` Public key: ${publicKeyPath}`);
|
|
97
|
-
this.logger.log('');
|
|
98
|
-
this.logger.log(`Public Key Hash: ${publicKeyHash}`);
|
|
99
|
-
this.logger.log('');
|
|
100
|
-
this.logger.warn('IMPORTANT: Keep the private key secure!');
|
|
101
|
-
} else if (options.json) {
|
|
102
|
-
const output = {
|
|
103
|
-
level: levelNum,
|
|
104
|
-
privateKey: keypair.privateKey.toString('hex'),
|
|
105
|
-
publicKey: keypair.publicKey.toString('hex'),
|
|
106
|
-
publicKeyHash,
|
|
107
|
-
privateKeySize: keypair.privateKey.length,
|
|
108
|
-
publicKeySize: keypair.publicKey.length,
|
|
109
|
-
};
|
|
110
|
-
this.logger.log(JSON.stringify(output, null, 2));
|
|
111
|
-
} else {
|
|
112
|
-
this.logger.info(`\nMLDSA-${levelNum} Keypair:\n`);
|
|
113
|
-
this.logger.log(`Public Key Hash: ${publicKeyHash}`);
|
|
114
|
-
this.logger.log(`Public Key Size: ${keypair.publicKey.length} bytes`);
|
|
115
|
-
this.logger.log(`Private Key Size: ${keypair.privateKey.length} bytes`);
|
|
116
|
-
this.logger.log('');
|
|
117
|
-
this.logger.log('Public Key (hex):');
|
|
118
|
-
this.logger.log(keypair.publicKey.toString('hex'));
|
|
119
|
-
this.logger.log('');
|
|
120
|
-
this.logger.log('Private Key (hex):');
|
|
121
|
-
this.logger.log(keypair.privateKey.toString('hex'));
|
|
122
|
-
this.logger.log('');
|
|
123
|
-
this.logger.warn('IMPORTANT: Store the private key securely!');
|
|
124
|
-
this.logger.warn('Use --output <prefix> to save to files.');
|
|
125
|
-
}
|
|
126
|
-
} catch (error) {
|
|
127
|
-
this.exitWithError(this.formatError(error));
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
private handleInfo(): void {
|
|
132
|
-
this.logger.info('\nMLDSA Key Sizes:\n');
|
|
133
|
-
this.logger.log('─'.repeat(60));
|
|
134
|
-
this.logger.log(
|
|
135
|
-
`${'Level'.padEnd(12)}${'Public Key'.padEnd(15)}${'Private Key'.padEnd(15)}${'Signature'.padEnd(15)}`,
|
|
136
|
-
);
|
|
137
|
-
this.logger.log('─'.repeat(60));
|
|
138
|
-
this.logger.log(
|
|
139
|
-
`${'MLDSA-44'.padEnd(12)}${'1,312 bytes'.padEnd(15)}${'2,560 bytes'.padEnd(15)}${'2,420 bytes'.padEnd(15)}`,
|
|
140
|
-
);
|
|
141
|
-
this.logger.log(
|
|
142
|
-
`${'MLDSA-65'.padEnd(12)}${'1,952 bytes'.padEnd(15)}${'4,032 bytes'.padEnd(15)}${'3,309 bytes'.padEnd(15)}`,
|
|
143
|
-
);
|
|
144
|
-
this.logger.log(
|
|
145
|
-
`${'MLDSA-87'.padEnd(12)}${'2,592 bytes'.padEnd(15)}${'4,896 bytes'.padEnd(15)}${'4,627 bytes'.padEnd(15)}`,
|
|
146
|
-
);
|
|
147
|
-
this.logger.log('─'.repeat(60));
|
|
148
|
-
this.logger.log('');
|
|
149
|
-
this.logger.log('Security levels:');
|
|
150
|
-
this.logger.log(' MLDSA-44: ~128-bit security (fastest, smallest)');
|
|
151
|
-
this.logger.log(' MLDSA-65: ~192-bit security (balanced)');
|
|
152
|
-
this.logger.log(' MLDSA-87: ~256-bit security (highest security)');
|
|
153
|
-
this.logger.log('');
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export const keygenCommand = new KeygenCommand().getCommand();
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* List command - List installed plugins
|
|
3
|
-
*
|
|
4
|
-
* @module commands/ListCommand
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import * as fs from 'fs';
|
|
8
|
-
import * as path from 'path';
|
|
9
|
-
import { BaseCommand } from './BaseCommand.js';
|
|
10
|
-
import { formatFileSize, parseOpnetBinary } from '../lib/binary.js';
|
|
11
|
-
import { CLIMldsaLevel } from '../types/index.js';
|
|
12
|
-
|
|
13
|
-
interface ListOptions {
|
|
14
|
-
dir?: string;
|
|
15
|
-
json?: boolean;
|
|
16
|
-
verbose?: boolean;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
interface PluginInfo {
|
|
20
|
-
file: string;
|
|
21
|
-
name: string;
|
|
22
|
-
version: string;
|
|
23
|
-
type: string;
|
|
24
|
-
size: number;
|
|
25
|
-
signed: boolean;
|
|
26
|
-
mldsaLevel: CLIMldsaLevel;
|
|
27
|
-
author: string;
|
|
28
|
-
description?: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export class ListCommand extends BaseCommand {
|
|
32
|
-
constructor() {
|
|
33
|
-
super('list', 'List installed plugins');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
protected configure(): void {
|
|
37
|
-
this.command
|
|
38
|
-
.alias('ls')
|
|
39
|
-
.option('-d, --dir <path>', 'Plugins directory (default: ./plugins/)')
|
|
40
|
-
.option('--json', 'Output as JSON')
|
|
41
|
-
.option('-v, --verbose', 'Show detailed information')
|
|
42
|
-
.action((options?: ListOptions) => this.execute(options));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
private execute(options?: ListOptions): void {
|
|
46
|
-
try {
|
|
47
|
-
const pluginsDir = options?.dir || path.join(process.cwd(), 'plugins');
|
|
48
|
-
|
|
49
|
-
if (!fs.existsSync(pluginsDir)) {
|
|
50
|
-
if (options?.json) {
|
|
51
|
-
this.logger.log(JSON.stringify({ plugins: [], directory: pluginsDir }));
|
|
52
|
-
} else {
|
|
53
|
-
this.logger.warn('No plugins directory found.');
|
|
54
|
-
this.logger.info(`Expected: ${pluginsDir}`);
|
|
55
|
-
}
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Find all .opnet files
|
|
60
|
-
const files = fs.readdirSync(pluginsDir).filter((f) => f.endsWith('.opnet'));
|
|
61
|
-
|
|
62
|
-
if (files.length === 0) {
|
|
63
|
-
if (options?.json) {
|
|
64
|
-
this.logger.log(JSON.stringify({ plugins: [], directory: pluginsDir }));
|
|
65
|
-
} else {
|
|
66
|
-
this.logger.warn('No plugins installed.');
|
|
67
|
-
}
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const plugins: PluginInfo[] = [];
|
|
72
|
-
|
|
73
|
-
// Parse each plugin
|
|
74
|
-
for (const file of files) {
|
|
75
|
-
const filePath = path.join(pluginsDir, file);
|
|
76
|
-
|
|
77
|
-
try {
|
|
78
|
-
const data = fs.readFileSync(filePath);
|
|
79
|
-
const parsed = parseOpnetBinary(data);
|
|
80
|
-
const isUnsigned = parsed.publicKey.every((b) => b === 0);
|
|
81
|
-
const mldsaLevel = ([44, 65, 87] as const)[parsed.mldsaLevel];
|
|
82
|
-
|
|
83
|
-
plugins.push({
|
|
84
|
-
file,
|
|
85
|
-
name: parsed.metadata.name,
|
|
86
|
-
version: parsed.metadata.version,
|
|
87
|
-
type: parsed.metadata.pluginType,
|
|
88
|
-
size: data.length,
|
|
89
|
-
signed: !isUnsigned,
|
|
90
|
-
mldsaLevel,
|
|
91
|
-
author: parsed.metadata.author.name,
|
|
92
|
-
description: parsed.metadata.description,
|
|
93
|
-
});
|
|
94
|
-
} catch {
|
|
95
|
-
plugins.push({
|
|
96
|
-
file,
|
|
97
|
-
name: '(invalid)',
|
|
98
|
-
version: '-',
|
|
99
|
-
type: '-',
|
|
100
|
-
size: fs.statSync(filePath).size,
|
|
101
|
-
signed: false,
|
|
102
|
-
mldsaLevel: 44,
|
|
103
|
-
author: '-',
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Sort by name
|
|
109
|
-
plugins.sort((a, b) => a.name.localeCompare(b.name));
|
|
110
|
-
|
|
111
|
-
if (options?.json) {
|
|
112
|
-
this.logger.log(JSON.stringify({ plugins, directory: pluginsDir }, null, 2));
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Display
|
|
117
|
-
this.logger.info('\nInstalled Plugins\n');
|
|
118
|
-
this.logger.info(`Directory: ${pluginsDir}`);
|
|
119
|
-
this.logger.log('');
|
|
120
|
-
|
|
121
|
-
if (options?.verbose) {
|
|
122
|
-
// Detailed list
|
|
123
|
-
for (const plugin of plugins) {
|
|
124
|
-
this.logger.info('─'.repeat(60));
|
|
125
|
-
this.logger.info(`${plugin.name} @ ${plugin.version}`);
|
|
126
|
-
this.logger.info(` Type: ${plugin.type}`);
|
|
127
|
-
this.logger.info(` Size: ${formatFileSize(plugin.size)}`);
|
|
128
|
-
this.logger.info(` Signed: ${plugin.signed ? 'Yes' : 'No'}`);
|
|
129
|
-
this.logger.info(` MLDSA: ${plugin.mldsaLevel}`);
|
|
130
|
-
this.logger.info(` Author: ${plugin.author}`);
|
|
131
|
-
if (plugin.description) {
|
|
132
|
-
this.logger.info(` Desc: ${plugin.description}`);
|
|
133
|
-
}
|
|
134
|
-
this.logger.info(` File: ${plugin.file}`);
|
|
135
|
-
}
|
|
136
|
-
} else {
|
|
137
|
-
// Simple table
|
|
138
|
-
const nameWidth = Math.max(20, ...plugins.map((p) => p.name.length)) + 2;
|
|
139
|
-
const versionWidth = 12;
|
|
140
|
-
const typeWidth = 12;
|
|
141
|
-
const sizeWidth = 10;
|
|
142
|
-
|
|
143
|
-
this.logger.info(
|
|
144
|
-
'Name'.padEnd(nameWidth) +
|
|
145
|
-
'Version'.padEnd(versionWidth) +
|
|
146
|
-
'Type'.padEnd(typeWidth) +
|
|
147
|
-
'Size'.padEnd(sizeWidth) +
|
|
148
|
-
'Signed',
|
|
149
|
-
);
|
|
150
|
-
this.logger.info('─'.repeat(nameWidth + versionWidth + typeWidth + sizeWidth + 8));
|
|
151
|
-
|
|
152
|
-
for (const plugin of plugins) {
|
|
153
|
-
const signedText = plugin.signed ? 'Yes' : 'No';
|
|
154
|
-
this.logger.info(
|
|
155
|
-
`${plugin.name.padEnd(nameWidth)}${plugin.version.padEnd(versionWidth)}${plugin.type.padEnd(typeWidth)}${formatFileSize(plugin.size).padEnd(sizeWidth)}${signedText}`,
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
this.logger.log('');
|
|
161
|
-
this.logger.info(`Total: ${plugins.length} plugin${plugins.length === 1 ? '' : 's'}`);
|
|
162
|
-
this.logger.log('');
|
|
163
|
-
} catch (error) {
|
|
164
|
-
this.exitWithError(this.formatError(error));
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export const listCommand = new ListCommand().getCommand();
|