@btc-vision/cli 1.0.0

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.
Files changed (110) hide show
  1. package/.gitattributes +2 -0
  2. package/.github/dependabot.yml +9 -0
  3. package/.github/workflows/ci.yml +48 -0
  4. package/.prettierrc.json +12 -0
  5. package/CONTRIBUTING.md +56 -0
  6. package/LICENSE +190 -0
  7. package/NOTICE +17 -0
  8. package/README.md +509 -0
  9. package/SECURITY.md +35 -0
  10. package/build/commands/AcceptCommand.d.ts +7 -0
  11. package/build/commands/AcceptCommand.js +110 -0
  12. package/build/commands/BaseCommand.d.ts +12 -0
  13. package/build/commands/BaseCommand.js +27 -0
  14. package/build/commands/CompileCommand.d.ts +7 -0
  15. package/build/commands/CompileCommand.js +138 -0
  16. package/build/commands/ConfigCommand.d.ts +17 -0
  17. package/build/commands/ConfigCommand.js +124 -0
  18. package/build/commands/DeprecateCommand.d.ts +7 -0
  19. package/build/commands/DeprecateCommand.js +112 -0
  20. package/build/commands/InfoCommand.d.ts +10 -0
  21. package/build/commands/InfoCommand.js +223 -0
  22. package/build/commands/InitCommand.d.ts +16 -0
  23. package/build/commands/InitCommand.js +336 -0
  24. package/build/commands/InstallCommand.d.ts +7 -0
  25. package/build/commands/InstallCommand.js +130 -0
  26. package/build/commands/KeygenCommand.d.ts +13 -0
  27. package/build/commands/KeygenCommand.js +133 -0
  28. package/build/commands/ListCommand.d.ts +7 -0
  29. package/build/commands/ListCommand.js +117 -0
  30. package/build/commands/LoginCommand.d.ts +9 -0
  31. package/build/commands/LoginCommand.js +139 -0
  32. package/build/commands/LogoutCommand.d.ts +7 -0
  33. package/build/commands/LogoutCommand.js +57 -0
  34. package/build/commands/PublishCommand.d.ts +7 -0
  35. package/build/commands/PublishCommand.js +163 -0
  36. package/build/commands/SearchCommand.d.ts +7 -0
  37. package/build/commands/SearchCommand.js +97 -0
  38. package/build/commands/SignCommand.d.ts +7 -0
  39. package/build/commands/SignCommand.js +80 -0
  40. package/build/commands/TransferCommand.d.ts +8 -0
  41. package/build/commands/TransferCommand.js +179 -0
  42. package/build/commands/UndeprecateCommand.d.ts +7 -0
  43. package/build/commands/UndeprecateCommand.js +95 -0
  44. package/build/commands/UpdateCommand.d.ts +7 -0
  45. package/build/commands/UpdateCommand.js +130 -0
  46. package/build/commands/VerifyCommand.d.ts +7 -0
  47. package/build/commands/VerifyCommand.js +167 -0
  48. package/build/commands/WhoamiCommand.d.ts +7 -0
  49. package/build/commands/WhoamiCommand.js +84 -0
  50. package/build/index.d.ts +2 -0
  51. package/build/index.js +64 -0
  52. package/build/lib/PackageRegistry.abi.d.ts +2 -0
  53. package/build/lib/PackageRegistry.abi.js +356 -0
  54. package/build/lib/binary.d.ts +16 -0
  55. package/build/lib/binary.js +165 -0
  56. package/build/lib/config.d.ts +11 -0
  57. package/build/lib/config.js +160 -0
  58. package/build/lib/credentials.d.ts +10 -0
  59. package/build/lib/credentials.js +89 -0
  60. package/build/lib/ipfs.d.ts +16 -0
  61. package/build/lib/ipfs.js +209 -0
  62. package/build/lib/manifest.d.ts +14 -0
  63. package/build/lib/manifest.js +88 -0
  64. package/build/lib/provider.d.ts +9 -0
  65. package/build/lib/provider.js +48 -0
  66. package/build/lib/registry.d.ts +58 -0
  67. package/build/lib/registry.js +197 -0
  68. package/build/lib/wallet.d.ts +32 -0
  69. package/build/lib/wallet.js +114 -0
  70. package/build/types/PackageRegistry.d.ts +177 -0
  71. package/build/types/PackageRegistry.js +1 -0
  72. package/build/types/index.d.ts +30 -0
  73. package/build/types/index.js +52 -0
  74. package/eslint.config.js +41 -0
  75. package/gulpfile.js +41 -0
  76. package/package.json +83 -0
  77. package/src/commands/AcceptCommand.ts +151 -0
  78. package/src/commands/BaseCommand.ts +59 -0
  79. package/src/commands/CompileCommand.ts +196 -0
  80. package/src/commands/ConfigCommand.ts +144 -0
  81. package/src/commands/DeprecateCommand.ts +156 -0
  82. package/src/commands/InfoCommand.ts +293 -0
  83. package/src/commands/InitCommand.ts +465 -0
  84. package/src/commands/InstallCommand.ts +179 -0
  85. package/src/commands/KeygenCommand.ts +157 -0
  86. package/src/commands/ListCommand.ts +169 -0
  87. package/src/commands/LoginCommand.ts +197 -0
  88. package/src/commands/LogoutCommand.ts +76 -0
  89. package/src/commands/PublishCommand.ts +230 -0
  90. package/src/commands/SearchCommand.ts +141 -0
  91. package/src/commands/SignCommand.ts +122 -0
  92. package/src/commands/TransferCommand.ts +235 -0
  93. package/src/commands/UndeprecateCommand.ts +134 -0
  94. package/src/commands/UpdateCommand.ts +200 -0
  95. package/src/commands/VerifyCommand.ts +228 -0
  96. package/src/commands/WhoamiCommand.ts +113 -0
  97. package/src/index.ts +86 -0
  98. package/src/lib/PackageRegistry.abi.json +765 -0
  99. package/src/lib/PackageRegistry.abi.ts +365 -0
  100. package/src/lib/binary.ts +336 -0
  101. package/src/lib/config.ts +265 -0
  102. package/src/lib/credentials.ts +176 -0
  103. package/src/lib/ipfs.ts +369 -0
  104. package/src/lib/manifest.ts +172 -0
  105. package/src/lib/provider.ts +121 -0
  106. package/src/lib/registry.ts +464 -0
  107. package/src/lib/wallet.ts +271 -0
  108. package/src/types/PackageRegistry.ts +344 -0
  109. package/src/types/index.ts +145 -0
  110. package/tsconfig.json +25 -0
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Verify command - Verify .opnet binary signature
3
+ *
4
+ * @module commands/VerifyCommand
5
+ */
6
+
7
+ import * as fs from 'fs';
8
+ import * as crypto from 'crypto';
9
+ import { BaseCommand } from './BaseCommand.js';
10
+ import { formatFileSize, parseOpnetBinary, verifyChecksum } from '../lib/binary.js';
11
+ import { CLIWallet } from '../lib/wallet.js';
12
+ import { CLIMldsaLevel } from '../types/index.js';
13
+
14
+ interface VerifyOptions {
15
+ verbose?: boolean;
16
+ json?: boolean;
17
+ }
18
+
19
+ export class VerifyCommand extends BaseCommand {
20
+ constructor() {
21
+ super('verify', 'Verify a .opnet binary signature and integrity');
22
+ }
23
+
24
+ protected configure(): void {
25
+ this.command
26
+ .argument('<file>', 'Path to .opnet file')
27
+ .option('-v, --verbose', 'Show detailed information')
28
+ .option('--json', 'Output as JSON')
29
+ .action((file: string, options: VerifyOptions) => this.execute(file, options));
30
+ }
31
+
32
+ private execute(file: string, options: VerifyOptions): void {
33
+ try {
34
+ if (!fs.existsSync(file)) {
35
+ if (options.json) {
36
+ this.logger.log(
37
+ JSON.stringify({ valid: false, error: `File not found: ${file}` }),
38
+ );
39
+ process.exit(1);
40
+ }
41
+ this.exitWithError(`File not found: ${file}`);
42
+ }
43
+
44
+ const data = fs.readFileSync(file);
45
+ const fileSize = data.length;
46
+
47
+ // Parse binary
48
+ let parsed;
49
+ try {
50
+ parsed = parseOpnetBinary(data);
51
+ } catch (error) {
52
+ if (options.json) {
53
+ this.logger.log(
54
+ JSON.stringify({
55
+ valid: false,
56
+ error: `Parse error: ${error instanceof Error ? error.message : String(error)}`,
57
+ }),
58
+ );
59
+ process.exit(1);
60
+ }
61
+ this.exitWithError(
62
+ `Parse error: ${error instanceof Error ? error.message : String(error)}`,
63
+ );
64
+ }
65
+
66
+ // Get MLDSA level from binary
67
+ const mldsaLevel = ([44, 65, 87] as const)[parsed.mldsaLevel] as CLIMldsaLevel;
68
+
69
+ // Verify checksum
70
+ const checksumValid = verifyChecksum(parsed);
71
+
72
+ // Verify signature
73
+ let signatureValid = false;
74
+ let signatureError: string | undefined;
75
+
76
+ // Check if public key is all zeros (unsigned)
77
+ const isUnsigned = parsed.publicKey.every((b) => b === 0);
78
+
79
+ if (isUnsigned) {
80
+ signatureError = 'Binary is unsigned (public key is empty)';
81
+ } else {
82
+ try {
83
+ signatureValid = CLIWallet.verifyMLDSA(
84
+ parsed.checksum,
85
+ parsed.signature,
86
+ parsed.publicKey,
87
+ mldsaLevel,
88
+ );
89
+ } catch (error) {
90
+ signatureError = error instanceof Error ? error.message : String(error);
91
+ }
92
+ }
93
+
94
+ const isValid = checksumValid && signatureValid;
95
+
96
+ if (options.json) {
97
+ const output = {
98
+ valid: isValid,
99
+ file,
100
+ fileSize,
101
+ formatVersion: parsed.formatVersion,
102
+ mldsaLevel,
103
+ checksumValid,
104
+ signatureValid,
105
+ signatureError,
106
+ isUnsigned,
107
+ metadata: parsed.metadata,
108
+ publicKeyHash: crypto
109
+ .createHash('sha256')
110
+ .update(parsed.publicKey)
111
+ .digest('hex'),
112
+ bytecodeSize: parsed.bytecode.length,
113
+ protoSize: parsed.proto?.length ?? 0,
114
+ };
115
+ this.logger.log(JSON.stringify(output, null, 2));
116
+ process.exit(isValid ? 0 : 1);
117
+ }
118
+
119
+ // Display results
120
+ this.logger.info('\nOPNet Binary Verification\n');
121
+ this.logger.log('─'.repeat(60));
122
+
123
+ // File info
124
+ this.logger.log(`File: ${file}`);
125
+ this.logger.log(`Size: ${formatFileSize(fileSize)}`);
126
+ this.logger.log(`Format Version: ${parsed.formatVersion}`);
127
+ this.logger.log('');
128
+
129
+ // Plugin info
130
+ this.logger.log('Plugin:');
131
+ this.logger.log(` Name: ${parsed.metadata.name}`);
132
+ this.logger.log(` Version: ${parsed.metadata.version}`);
133
+ this.logger.log(` Type: ${parsed.metadata.pluginType}`);
134
+ this.logger.log(` OPNet Version: ${parsed.metadata.opnetVersion}`);
135
+ this.logger.log('');
136
+
137
+ // Cryptographic info
138
+ this.logger.log('Cryptography:');
139
+ this.logger.log(` MLDSA Level: MLDSA-${mldsaLevel}`);
140
+ this.logger.log(` Public Key: ${formatFileSize(parsed.publicKey.length)}`);
141
+ this.logger.log(` Signature: ${formatFileSize(parsed.signature.length)}`);
142
+
143
+ if (!isUnsigned) {
144
+ const pkHash = crypto.createHash('sha256').update(parsed.publicKey).digest('hex');
145
+ this.logger.log(` PubKey Hash: ${pkHash.substring(0, 16)}...`);
146
+ }
147
+ this.logger.log('');
148
+
149
+ // Verification results
150
+ this.logger.log('Verification:');
151
+ this.logger.log(` Checksum: ${checksumValid ? 'VALID' : 'INVALID'}`);
152
+
153
+ if (isUnsigned) {
154
+ this.logger.log(` Signature: UNSIGNED`);
155
+ } else if (signatureError) {
156
+ this.logger.log(` Signature: ERROR - ${signatureError}`);
157
+ } else {
158
+ this.logger.log(` Signature: ${signatureValid ? 'VALID' : 'INVALID'}`);
159
+ }
160
+
161
+ this.logger.log('');
162
+ this.logger.log('─'.repeat(60));
163
+
164
+ if (isUnsigned) {
165
+ this.logger.warn('WARNING: This binary is unsigned and cannot be published.');
166
+ this.logger.warn('Use `opnet sign` to sign it.');
167
+ } else if (isValid) {
168
+ this.logger.success('VERIFIED: Binary is valid and properly signed.');
169
+ } else {
170
+ this.logger.fail('FAILED: Binary verification failed.');
171
+ if (!checksumValid) {
172
+ this.logger.error(' - Checksum mismatch (binary may be corrupted)');
173
+ }
174
+ if (!signatureValid && !signatureError) {
175
+ this.logger.error(' - Signature invalid (binary may be tampered)');
176
+ }
177
+ }
178
+ this.logger.log('');
179
+
180
+ // Verbose output
181
+ if (options.verbose) {
182
+ this.logger.log('Sizes:');
183
+ this.logger.log(` Metadata: ${formatFileSize(parsed.rawMetadata.length)}`);
184
+ this.logger.log(` Bytecode: ${formatFileSize(parsed.bytecode.length)}`);
185
+ this.logger.log(` Proto: ${formatFileSize(parsed.proto?.length ?? 0)}`);
186
+ this.logger.log('');
187
+
188
+ this.logger.log('Checksums:');
189
+ this.logger.log(` Stored: ${parsed.checksum.toString('hex')}`);
190
+ this.logger.log('');
191
+
192
+ this.logger.log('Author:');
193
+ this.logger.log(` Name: ${parsed.metadata.author.name}`);
194
+ if (parsed.metadata.author.email) {
195
+ this.logger.log(` Email: ${parsed.metadata.author.email}`);
196
+ }
197
+ this.logger.log('');
198
+
199
+ this.logger.log('Permissions:');
200
+ const perms = parsed.metadata.permissions;
201
+ if (perms) {
202
+ this.logger.log(` Database: ${perms.database?.enabled ? 'Yes' : 'No'}`);
203
+ this.logger.log(
204
+ ` Block Hooks: ${perms.blocks?.preProcess || perms.blocks?.postProcess || perms.blocks?.onChange ? 'Yes' : 'No'}`,
205
+ );
206
+ this.logger.log(
207
+ ` Epoch Hooks: ${perms.epochs?.onChange || perms.epochs?.onFinalized ? 'Yes' : 'No'}`,
208
+ );
209
+ this.logger.log(` Mempool Feed: ${perms.mempool?.txFeed ? 'Yes' : 'No'}`);
210
+ this.logger.log(` API Endpoints: ${perms.api?.addEndpoints ? 'Yes' : 'No'}`);
211
+ this.logger.log(` Websocket: ${perms.api?.addWebsocket ? 'Yes' : 'No'}`);
212
+ this.logger.log(
213
+ ` Filesystem: ${perms.filesystem?.configDir || perms.filesystem?.tempDir ? 'Yes' : 'No'}`,
214
+ );
215
+ } else {
216
+ this.logger.log(' (none configured)');
217
+ }
218
+ this.logger.log('');
219
+ }
220
+
221
+ process.exit(isValid ? 0 : 1);
222
+ } catch (error) {
223
+ this.exitWithError(this.formatError(error));
224
+ }
225
+ }
226
+ }
227
+
228
+ export const verifyCommand = new VerifyCommand().getCommand();
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Whoami command - Display current identity
3
+ *
4
+ * @module commands/WhoamiCommand
5
+ */
6
+
7
+ import { BaseCommand } from './BaseCommand.js';
8
+ import {
9
+ getCredentialSource,
10
+ hasCredentials,
11
+ loadCredentials,
12
+ maskSensitive,
13
+ } from '../lib/credentials.js';
14
+ import { CLIWallet } from '../lib/wallet.js';
15
+
16
+ interface WhoamiOptions {
17
+ verbose?: boolean;
18
+ publicKey?: boolean;
19
+ }
20
+
21
+ export class WhoamiCommand extends BaseCommand {
22
+ constructor() {
23
+ super('whoami', 'Display current wallet identity and configuration');
24
+ }
25
+
26
+ protected configure(): void {
27
+ this.command
28
+ .option('-v, --verbose', 'Show detailed information')
29
+ .option('--public-key', 'Show full MLDSA public key')
30
+ .action((options: WhoamiOptions) => this.execute(options));
31
+ }
32
+
33
+ private execute(options: WhoamiOptions): void {
34
+ try {
35
+ if (!hasCredentials()) {
36
+ this.logger.warn('Not logged in.');
37
+ this.logger.info('Run `opnet login` to configure your wallet.');
38
+ return;
39
+ }
40
+
41
+ const credentials = loadCredentials();
42
+ if (!credentials) {
43
+ this.logger.warn('No credentials found.');
44
+ return;
45
+ }
46
+
47
+ const source = getCredentialSource();
48
+
49
+ this.logger.info('\nOPNet Identity\n');
50
+ this.logger.log('─'.repeat(50));
51
+
52
+ this.logger.log(`Network: ${credentials.network}`);
53
+ this.logger.log(`MLDSA Level: ${credentials.mldsaLevel}`);
54
+ this.logger.log(`Auth Source: ${source}`);
55
+
56
+ try {
57
+ const wallet = CLIWallet.fromCredentials(credentials);
58
+
59
+ this.logger.log('');
60
+ this.logger.log(`P2TR Address: ${wallet.p2trAddress}`);
61
+ this.logger.log(`MLDSA PubKey Hash: ${wallet.mldsaPublicKeyHash}`);
62
+
63
+ if (options.publicKey) {
64
+ this.logger.log('');
65
+ this.logger.log('MLDSA Public Key:');
66
+ this.logger.log(wallet.mldsaPublicKey.toString('hex'));
67
+ }
68
+
69
+ if (options.verbose) {
70
+ this.logger.log('');
71
+ this.logger.log('─'.repeat(50));
72
+ this.logger.log('Details:');
73
+ this.logger.log(` Security Level: MLDSA-${credentials.mldsaLevel}`);
74
+ this.logger.log(` Public Key Size: ${wallet.mldsaPublicKey.length} bytes`);
75
+
76
+ if (credentials.mnemonic) {
77
+ this.logger.log(' Auth Method: BIP-39 Mnemonic');
78
+ this.logger.log(` Mnemonic: ${maskSensitive(credentials.mnemonic, 8)}`);
79
+ } else {
80
+ this.logger.log(' Auth Method: WIF + MLDSA Keys');
81
+ if (credentials.wif) {
82
+ this.logger.log(` WIF: ${maskSensitive(credentials.wif, 4)}`);
83
+ }
84
+ }
85
+ }
86
+ } catch (error) {
87
+ this.logger.log('');
88
+ this.logger.warn('Could not load wallet details.');
89
+ if (options.verbose) {
90
+ this.logger.debug(` Error: ${this.formatError(error)}`);
91
+ }
92
+
93
+ this.logger.log('');
94
+ if (credentials.mnemonic) {
95
+ this.logger.log(`Auth Method: BIP-39 Mnemonic`);
96
+ if (options.verbose) {
97
+ this.logger.log(
98
+ `Mnemonic: ${maskSensitive(credentials.mnemonic, 8)}`,
99
+ );
100
+ }
101
+ } else {
102
+ this.logger.log(`Auth Method: WIF + MLDSA Keys`);
103
+ }
104
+ }
105
+
106
+ this.logger.log('');
107
+ } catch (error) {
108
+ this.exitWithError(this.formatError(error));
109
+ }
110
+ }
111
+ }
112
+
113
+ export const whoamiCommand = new WhoamiCommand().getCommand();
package/src/index.ts ADDED
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * OPNet CLI - Command Line Interface for OPNet Plugin Ecosystem
4
+ *
5
+ * @module @btc-vision/cli
6
+ */
7
+
8
+ import { Command } from 'commander';
9
+ import { Logger } from '@btc-vision/logger';
10
+
11
+ // Commands
12
+ import { configCommand } from './commands/ConfigCommand.js';
13
+ import { loginCommand } from './commands/LoginCommand.js';
14
+ import { logoutCommand } from './commands/LogoutCommand.js';
15
+ import { whoamiCommand } from './commands/WhoamiCommand.js';
16
+ import { keygenCommand } from './commands/KeygenCommand.js';
17
+ import { initCommand } from './commands/InitCommand.js';
18
+ import { compileCommand } from './commands/CompileCommand.js';
19
+ import { verifyCommand } from './commands/VerifyCommand.js';
20
+ import { infoCommand } from './commands/InfoCommand.js';
21
+ import { signCommand } from './commands/SignCommand.js';
22
+ import { publishCommand } from './commands/PublishCommand.js';
23
+ import { deprecateCommand } from './commands/DeprecateCommand.js';
24
+ import { undeprecateCommand } from './commands/UndeprecateCommand.js';
25
+ import { transferCommand } from './commands/TransferCommand.js';
26
+ import { acceptCommand } from './commands/AcceptCommand.js';
27
+ import { installCommand } from './commands/InstallCommand.js';
28
+ import { updateCommand } from './commands/UpdateCommand.js';
29
+ import { listCommand } from './commands/ListCommand.js';
30
+ import { searchCommand } from './commands/SearchCommand.js';
31
+
32
+ const logger = new Logger();
33
+ const program = new Command();
34
+
35
+ program
36
+ .name('opnet')
37
+ .description('OPNet CLI - Build, sign, and publish plugins for the OPNet ecosystem')
38
+ .version('1.0.0');
39
+
40
+ // Configuration commands
41
+ program.addCommand(configCommand);
42
+ program.addCommand(loginCommand);
43
+ program.addCommand(logoutCommand);
44
+ program.addCommand(whoamiCommand);
45
+ program.addCommand(keygenCommand);
46
+
47
+ // Plugin development commands
48
+ program.addCommand(initCommand);
49
+ program.addCommand(compileCommand);
50
+ program.addCommand(verifyCommand);
51
+ program.addCommand(infoCommand);
52
+ program.addCommand(signCommand);
53
+
54
+ // Registry commands
55
+ program.addCommand(publishCommand);
56
+ program.addCommand(deprecateCommand);
57
+ program.addCommand(undeprecateCommand);
58
+ program.addCommand(transferCommand);
59
+ program.addCommand(acceptCommand);
60
+ program.addCommand(installCommand);
61
+ program.addCommand(updateCommand);
62
+ program.addCommand(listCommand);
63
+ program.addCommand(searchCommand);
64
+
65
+ // Error handling
66
+ program.showHelpAfterError();
67
+ program.showSuggestionAfterError();
68
+
69
+ // Custom error handling
70
+ program.exitOverride((err) => {
71
+ if (err.code === 'commander.help') {
72
+ process.exit(0);
73
+ }
74
+ if (err.code === 'commander.version') {
75
+ process.exit(0);
76
+ }
77
+ logger.error(`Error: ${err.message}`);
78
+ process.exit(1);
79
+ });
80
+
81
+ // Parse command line arguments
82
+ program.parseAsync(process.argv).catch((error: unknown) => {
83
+ const message = error instanceof Error ? error.message : String(error);
84
+ logger.error(`Error: ${message}`);
85
+ process.exit(1);
86
+ });