neozip-cli 0.80.0 → 0.95.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.
- package/AGENTS.md +93 -0
- package/CHANGELOG.md +117 -12
- package/DOCUMENTATION.md +33 -38
- package/README.md +137 -63
- package/dist/src/account/account-state.js +95 -0
- package/dist/src/account/format-account-status.js +62 -0
- package/dist/src/account/identity-provision.js +79 -0
- package/dist/src/account/identity-wrap.js +106 -0
- package/dist/src/account/profile-crypto.js +85 -0
- package/dist/src/account/profile-store.js +129 -0
- package/dist/src/account/require-account.js +32 -0
- package/dist/src/account/types.js +3 -0
- package/dist/src/account/wallet-evm.js +46 -0
- package/dist/src/account/wallet-setup.js +33 -0
- package/dist/src/archive/crypto-self.js +117 -0
- package/dist/src/archive/identity-key.js +217 -0
- package/dist/src/archive/recipient-lookup.js +61 -0
- package/dist/src/cli/output.js +100 -0
- package/dist/src/cli/params.js +122 -0
- package/dist/src/cli/schema.js +186 -0
- package/dist/src/cli/validate.js +119 -0
- package/dist/src/commands/mintTimestampProof.js +26 -14
- package/dist/src/config/ConfigSetup.js +82 -423
- package/dist/src/connect/command.js +364 -0
- package/dist/src/connection/bootstrap.js +50 -0
- package/dist/src/connection/cli-guidance.js +101 -0
- package/dist/src/connection/cli-prefs.js +180 -0
- package/dist/src/connection/cli-settings.js +140 -0
- package/dist/src/connection/cli-types.js +14 -0
- package/dist/src/connection/coordinator.js +83 -0
- package/dist/src/connection/credentials.js +33 -0
- package/dist/src/connection/crypto.js +96 -0
- package/dist/src/connection/dump.js +117 -0
- package/dist/src/connection/funding.js +187 -0
- package/dist/src/connection/incomplete-setup.js +89 -0
- package/dist/src/connection/interactive.js +871 -0
- package/dist/src/connection/legacy-profile-reader.js +87 -0
- package/dist/src/connection/magic-link.js +142 -0
- package/dist/src/connection/migrate.js +115 -0
- package/dist/src/connection/onboarding.js +616 -0
- package/dist/src/connection/origin.js +69 -0
- package/dist/src/connection/phase.js +101 -0
- package/dist/src/connection/phone.js +26 -0
- package/dist/src/connection/promote-active.js +56 -0
- package/dist/src/connection/reset.js +56 -0
- package/dist/src/connection/status-report.js +52 -0
- package/dist/src/connection/store.js +406 -0
- package/dist/src/connection/token-auth.js +44 -0
- package/dist/src/connection/types.js +3 -0
- package/dist/src/connection/wallet-json-migration.js +155 -0
- package/dist/src/connection/wallet-login.js +65 -0
- package/dist/src/connection/wallet-setup.js +83 -0
- package/dist/src/constants/wallet-identity.js +14 -0
- package/dist/src/exit-codes.js +54 -10
- package/dist/src/neolist.js +100 -10
- package/dist/src/neounzip.js +236 -65
- package/dist/src/neozip/blockchain.js +18 -18
- package/dist/src/neozip/createZip.js +118 -94
- package/dist/src/neozip/upgradeZip.js +14 -11
- package/dist/src/neozip.js +269 -91
- package/dist/src/skills/command.js +256 -0
- package/dist/src/skills/locate.js +99 -0
- package/dist/src/util/mask.js +34 -0
- package/dist/src/util/token-service-fetch.js +26 -0
- package/env.example +18 -85
- package/package.json +89 -73
- package/skills/neozip-connect/SKILL.md +95 -0
- package/skills/neozip-create/SKILL.md +57 -0
- package/skills/neozip-extract/SKILL.md +58 -0
- package/skills/neozip-legacy/SKILL.md +48 -0
- package/skills/neozip-list/SKILL.md +56 -0
- package/skills/neozip-shared/SKILL.md +60 -0
- package/dist/src/commands/verifyEmail.js +0 -146
- package/dist/src/config/ConfigStore.js +0 -406
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Upgrade
|
|
3
|
+
* Upgrade Token Service timestamp from pending (TS-SUBMIT.NZIP) to confirmed (TIMESTAMP.NZIP)
|
|
4
4
|
*/
|
|
5
5
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
6
|
if (k2 === undefined) k2 = k;
|
|
@@ -45,15 +45,16 @@ const path = __importStar(require("path"));
|
|
|
45
45
|
const os = __importStar(require("os"));
|
|
46
46
|
const node_1 = __importDefault(require("neozipkit/node"));
|
|
47
47
|
const node_2 = require("neozipkit/node");
|
|
48
|
-
const
|
|
48
|
+
const token_service_1 = require("neozip-blockchain/token-service");
|
|
49
49
|
const exit_codes_1 = require("../exit-codes");
|
|
50
|
+
const bootstrap_1 = require("../connection/bootstrap");
|
|
50
51
|
/**
|
|
51
52
|
* Extract timestamp metadata from a ZIP entry.
|
|
52
53
|
* Tries the library's extractTimestampData first; if it fails (e.g. file-based ZIP),
|
|
53
54
|
* fall back to extracting to a temp file and parsing JSON.
|
|
54
55
|
*/
|
|
55
56
|
async function extractTimestampMetadata(zip, entry) {
|
|
56
|
-
let metadata = await (0,
|
|
57
|
+
let metadata = await (0, token_service_1.extractTimestampData)(zip, entry);
|
|
57
58
|
if (metadata)
|
|
58
59
|
return metadata;
|
|
59
60
|
// Fallback for file-based ZIPs where zip.extract() may not work
|
|
@@ -74,7 +75,7 @@ async function extractTimestampMetadata(zip, entry) {
|
|
|
74
75
|
}
|
|
75
76
|
}
|
|
76
77
|
/**
|
|
77
|
-
* Upgrade a ZIP file with pending
|
|
78
|
+
* Upgrade a ZIP file with pending Token Service timestamp to confirmed status.
|
|
78
79
|
* Replaces TS-SUBMIT.NZIP with TIMESTAMP.NZIP when the batch is confirmed on the blockchain.
|
|
79
80
|
*/
|
|
80
81
|
async function upgradeZipForTimestamp(inputPath, outputPath, options = {}) {
|
|
@@ -85,9 +86,9 @@ async function upgradeZipForTimestamp(inputPath, outputPath, options = {}) {
|
|
|
85
86
|
const zip = new node_1.default();
|
|
86
87
|
await zip.loadZipFile(inputPath);
|
|
87
88
|
const entries = zip.getDirectory() || [];
|
|
88
|
-
const metadataResult = (0,
|
|
89
|
+
const metadataResult = (0, token_service_1.findMetadataEntry)(entries);
|
|
89
90
|
if (!metadataResult) {
|
|
90
|
-
console.log('No
|
|
91
|
+
console.log('No Token Service timestamp found in ZIP file');
|
|
91
92
|
return;
|
|
92
93
|
}
|
|
93
94
|
if (metadataResult.type === 'confirmed') {
|
|
@@ -98,21 +99,23 @@ async function upgradeZipForTimestamp(inputPath, outputPath, options = {}) {
|
|
|
98
99
|
if (!metadata || !metadata.digest) {
|
|
99
100
|
(0, exit_codes_1.exitZip)(exit_codes_1.ZIP_EXIT_CODES.BAD_ARCHIVE_FORMAT, 'Error: Failed to extract timestamp metadata');
|
|
100
101
|
}
|
|
101
|
-
if (!(0,
|
|
102
|
+
if (!(0, token_service_1.shouldUpgrade)(metadata, metadataResult.type)) {
|
|
102
103
|
console.log('✓ Timestamp does not need upgrade');
|
|
103
104
|
return;
|
|
104
105
|
}
|
|
105
106
|
const digest = metadata.digest;
|
|
106
107
|
const chainId = metadata.chainId && metadata.chainId > 0 ? metadata.chainId : undefined;
|
|
107
108
|
const batchId = metadata.batchId ?? undefined;
|
|
109
|
+
const serverUrl = (0, bootstrap_1.resolveVerifyServerUrl)(metadata.serverUrl);
|
|
110
|
+
const verifyOpts = { debug, serverUrl };
|
|
108
111
|
let verified = null;
|
|
109
112
|
if (wait) {
|
|
110
113
|
if (verbose || debug)
|
|
111
114
|
console.log('Polling for confirmation (--wait)...');
|
|
112
|
-
verified = await (0,
|
|
115
|
+
verified = await (0, token_service_1.pollForConfirmation)(digest, chainId, batchId, 300000, 5000, verifyOpts);
|
|
113
116
|
}
|
|
114
117
|
else {
|
|
115
|
-
const verifyRes = await (0,
|
|
118
|
+
const verifyRes = await (0, token_service_1.verifyDigest)(digest, chainId, batchId, undefined, verifyOpts);
|
|
116
119
|
if (verifyRes.verified) {
|
|
117
120
|
verified = verifyRes;
|
|
118
121
|
}
|
|
@@ -135,7 +138,7 @@ async function upgradeZipForTimestamp(inputPath, outputPath, options = {}) {
|
|
|
135
138
|
blockNumber: verified.blockNumber ?? metadata.blockNumber,
|
|
136
139
|
timestamp: verified.timestamp ?? metadata.timestamp
|
|
137
140
|
};
|
|
138
|
-
const metadataFiles = (0,
|
|
141
|
+
const metadataFiles = (0, token_service_1.getMetadataFileNames)();
|
|
139
142
|
const outPath = outputPath ?? inputPath.replace(/(\.nzip|\.zip)$/i, '-upgrade$1');
|
|
140
143
|
const tempDir = path.dirname(outPath) || '.';
|
|
141
144
|
const tempPath = path.join(tempDir, `.neozip-upgrade-${Date.now()}.tmp`);
|
|
@@ -144,7 +147,7 @@ async function upgradeZipForTimestamp(inputPath, outputPath, options = {}) {
|
|
|
144
147
|
const { destPath, dataEndOffset, copiedEntries } = await zipCopy.copyZipEntriesOnly(inputPath, tempPath, {
|
|
145
148
|
entryFilter: (entry) => !metadataFiles.includes(entry.filename || '')
|
|
146
149
|
});
|
|
147
|
-
const newEntry = (0,
|
|
150
|
+
const newEntry = (0, token_service_1.createTimestampMetadataEntry)(zip, confirmedMetadata);
|
|
148
151
|
if (!newEntry) {
|
|
149
152
|
throw new Error('Failed to create timestamp metadata entry');
|
|
150
153
|
}
|
package/dist/src/neozip.js
CHANGED
|
@@ -4,11 +4,7 @@
|
|
|
4
4
|
* NEOZIP - Standalone ZIP creation tool with blockchain tokenization
|
|
5
5
|
* Usage: neozip [options] <archive> <files...>
|
|
6
6
|
*
|
|
7
|
-
* Configuration:
|
|
8
|
-
* For blockchain features, wallet key can be provided via:
|
|
9
|
-
* 1. CLI flag: -w 0x...
|
|
10
|
-
* 2. Config file: ~/.neozip/wallet.json (recommended)
|
|
11
|
-
* 3. ENV var: NEOZIP_WALLET_PASSKEY
|
|
7
|
+
* Configuration: neozip connect (alias: neozip init) — Token Service account + wallet
|
|
12
8
|
*/
|
|
13
9
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
10
|
if (k2 === undefined) k2 = k;
|
|
@@ -56,11 +52,13 @@ const fs = __importStar(require("fs"));
|
|
|
56
52
|
// Try to load .env.local first, then .env as fallback
|
|
57
53
|
const envLocalPath = path.join(process.cwd(), '.env.local');
|
|
58
54
|
const envPath = path.join(process.cwd(), '.env');
|
|
55
|
+
// quiet: true suppresses dotenv's startup banner so it never pollutes
|
|
56
|
+
// machine-readable JSON written to stdout.
|
|
59
57
|
if (fs.existsSync(envLocalPath)) {
|
|
60
|
-
dotenv.config({ path: envLocalPath });
|
|
58
|
+
dotenv.config({ path: envLocalPath, quiet: true });
|
|
61
59
|
}
|
|
62
60
|
else if (fs.existsSync(envPath)) {
|
|
63
|
-
dotenv.config({ path: envPath });
|
|
61
|
+
dotenv.config({ path: envPath, quiet: true });
|
|
64
62
|
}
|
|
65
63
|
const utils_1 = require("./neozip/utils");
|
|
66
64
|
const user_interaction_1 = require("./neozip/user-interaction");
|
|
@@ -68,8 +66,13 @@ const createZip_1 = require("./neozip/createZip");
|
|
|
68
66
|
const file_operations_1 = require("./neozip/file-operations");
|
|
69
67
|
// ConfigSetup is lazy-loaded only when needed (init/config commands)
|
|
70
68
|
const neozip_blockchain_1 = require("neozip-blockchain");
|
|
71
|
-
const
|
|
69
|
+
const bootstrap_1 = require("./connection/bootstrap");
|
|
70
|
+
const cli_prefs_1 = require("./connection/cli-prefs");
|
|
72
71
|
const exit_codes_1 = require("./exit-codes");
|
|
72
|
+
const output_1 = require("./cli/output");
|
|
73
|
+
const params_1 = require("./cli/params");
|
|
74
|
+
const validate_1 = require("./cli/validate");
|
|
75
|
+
const schema_1 = require("./cli/schema");
|
|
73
76
|
const version_1 = require("./version");
|
|
74
77
|
/**
|
|
75
78
|
* Resolve dynamic import path so ts-node loads .ts and compiled dist loads .js
|
|
@@ -80,10 +83,49 @@ function resolveScriptPath(jsPath) {
|
|
|
80
83
|
}
|
|
81
84
|
return jsPath;
|
|
82
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Map an agent-supplied `--params` object onto ZipOptions (whitelisted keys).
|
|
88
|
+
*/
|
|
89
|
+
function zipParamsToOptions(params) {
|
|
90
|
+
const allowed = [
|
|
91
|
+
'verbose', 'quiet', 'level', 'blockchain', 'blockchainOts', 'blockchainTokenService',
|
|
92
|
+
'blockchainDefault', 'blockchainMint', 'network', 'walletPasskey', 'walletKey',
|
|
93
|
+
'compression', 'blockSize', 'encrypt', 'password', 'encryptionMethod', 'exclude',
|
|
94
|
+
'include', 'inMemory', 'recurse', 'junkPaths', 'update', 'freshen', 'move',
|
|
95
|
+
'archiveComment', 'commentFile', 'suffixes', 'debug', 'showFiles', 'toCrlf',
|
|
96
|
+
'fromCrlf', 'preservePerms', 'symlinks', 'hardLinks', 'oldTimestamp', 'tempPath',
|
|
97
|
+
'testIntegrity', 'nonInteractive', 'legacy', 'dryRun',
|
|
98
|
+
];
|
|
99
|
+
const out = {};
|
|
100
|
+
for (const key of allowed) {
|
|
101
|
+
if (key in params) {
|
|
102
|
+
out[key] = params[key];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Map an agent-supplied `--json` payload onto seed positional args.
|
|
109
|
+
*/
|
|
110
|
+
function zipPayloadToSeed(payload) {
|
|
111
|
+
const seed = {};
|
|
112
|
+
if (typeof payload.archive === 'string')
|
|
113
|
+
seed.archive = payload.archive;
|
|
114
|
+
if (Array.isArray(payload.files))
|
|
115
|
+
seed.files = payload.files.map(String);
|
|
116
|
+
const options = {};
|
|
117
|
+
if (Array.isArray(payload.include))
|
|
118
|
+
options.include = payload.include.map(String);
|
|
119
|
+
if (Array.isArray(payload.exclude))
|
|
120
|
+
options.exclude = payload.exclude.map(String);
|
|
121
|
+
if (Object.keys(options).length > 0)
|
|
122
|
+
seed.options = options;
|
|
123
|
+
return seed;
|
|
124
|
+
}
|
|
83
125
|
/**
|
|
84
126
|
* Parse command line arguments
|
|
85
127
|
*/
|
|
86
|
-
function parseArgs(args) {
|
|
128
|
+
function parseArgs(args, seed) {
|
|
87
129
|
const options = {
|
|
88
130
|
verbose: false,
|
|
89
131
|
quiet: false,
|
|
@@ -93,8 +135,7 @@ function parseArgs(args) {
|
|
|
93
135
|
blockchainDefault: false, // Auto-select default option disabled by default
|
|
94
136
|
blockchainMint: false, // Force mint new token disabled by default
|
|
95
137
|
network: 'base-sepolia',
|
|
96
|
-
walletPasskey:
|
|
97
|
-
timestampEmail: process.env.NEOZIP_TIMESTAMP_EMAIL,
|
|
138
|
+
walletPasskey: undefined,
|
|
98
139
|
compression: 'zstd',
|
|
99
140
|
blockSize: 128 * 1024, // 128KB default
|
|
100
141
|
enableProgress: true,
|
|
@@ -103,10 +144,12 @@ function parseArgs(args) {
|
|
|
103
144
|
freshen: false,
|
|
104
145
|
move: false,
|
|
105
146
|
interactiveComments: false,
|
|
106
|
-
walletKey: undefined
|
|
147
|
+
walletKey: undefined,
|
|
148
|
+
// Seed from agent --params/--json first; explicit CLI flags below override.
|
|
149
|
+
...(seed?.options ?? {}),
|
|
107
150
|
};
|
|
108
|
-
const files = [];
|
|
109
|
-
let archive = '';
|
|
151
|
+
const files = seed?.files ? [...seed.files] : [];
|
|
152
|
+
let archive = seed?.archive ?? '';
|
|
110
153
|
for (let i = 0; i < args.length; i++) {
|
|
111
154
|
const arg = args[i];
|
|
112
155
|
switch (arg) {
|
|
@@ -180,14 +223,7 @@ function parseArgs(args) {
|
|
|
180
223
|
break;
|
|
181
224
|
case '-ts':
|
|
182
225
|
case '--timestamp':
|
|
183
|
-
options.
|
|
184
|
-
break;
|
|
185
|
-
case '--timestamp-email':
|
|
186
|
-
options.timestampEmail = args[++i];
|
|
187
|
-
if (!options.timestampEmail) {
|
|
188
|
-
console.error('Error: --timestamp-email requires an email address');
|
|
189
|
-
(0, exit_codes_1.exitZip)(exit_codes_1.ZIP_EXIT_CODES.PARAMETER_ERROR);
|
|
190
|
-
}
|
|
226
|
+
options.blockchainTokenService = true;
|
|
191
227
|
break;
|
|
192
228
|
case '-bt':
|
|
193
229
|
case '--blockchain-token':
|
|
@@ -260,45 +296,45 @@ function parseArgs(args) {
|
|
|
260
296
|
break;
|
|
261
297
|
case '-e':
|
|
262
298
|
case '--encrypt':
|
|
263
|
-
// InfoZip-compatible encryption option
|
|
264
299
|
options.encrypt = true;
|
|
265
|
-
// Only set encryption method if not already set
|
|
266
300
|
if (!options.encryptionMethod) {
|
|
267
|
-
options.encryptionMethod = '
|
|
301
|
+
options.encryptionMethod = 'aes256';
|
|
268
302
|
}
|
|
269
|
-
// Only prompt for password if not already provided
|
|
270
303
|
if (!options.password) {
|
|
271
|
-
options.password = 'PROMPT';
|
|
304
|
+
options.password = 'PROMPT';
|
|
272
305
|
}
|
|
273
306
|
break;
|
|
274
307
|
case '-P':
|
|
275
308
|
case '--password':
|
|
276
|
-
// InfoZip-compatible password option (uppercase P)
|
|
277
309
|
options.encrypt = true;
|
|
278
|
-
// Only set encryption method if not already set (e.g., by --pkzip-encrypt)
|
|
279
310
|
if (!options.encryptionMethod) {
|
|
280
|
-
options.encryptionMethod = '
|
|
311
|
+
options.encryptionMethod = 'aes256';
|
|
281
312
|
}
|
|
282
313
|
if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
|
|
283
|
-
// Password provided directly
|
|
284
314
|
options.password = args[++i];
|
|
285
315
|
}
|
|
286
316
|
else {
|
|
287
|
-
// No password provided, will prompt later
|
|
288
317
|
options.password = 'PROMPT';
|
|
289
318
|
}
|
|
290
319
|
break;
|
|
291
320
|
case '-p':
|
|
292
321
|
case '--show-progress':
|
|
293
|
-
// InfoZip-compatible show-progress option (lowercase p)
|
|
294
322
|
options.showFiles = true;
|
|
295
323
|
break;
|
|
324
|
+
case '--aes256':
|
|
325
|
+
case '--aes-256':
|
|
326
|
+
options.encrypt = true;
|
|
327
|
+
options.encryptionMethod = 'aes256';
|
|
328
|
+
if (!options.password) {
|
|
329
|
+
options.password = 'PROMPT';
|
|
330
|
+
}
|
|
331
|
+
break;
|
|
332
|
+
case '--pkzip':
|
|
296
333
|
case '--pkzip-encrypt':
|
|
297
334
|
options.encrypt = true;
|
|
298
335
|
options.encryptionMethod = 'pkzip';
|
|
299
|
-
// Only prompt for password if not already provided
|
|
300
336
|
if (!options.password) {
|
|
301
|
-
options.password = 'PROMPT';
|
|
337
|
+
options.password = 'PROMPT';
|
|
302
338
|
}
|
|
303
339
|
break;
|
|
304
340
|
case '-x':
|
|
@@ -414,6 +450,12 @@ function parseArgs(args) {
|
|
|
414
450
|
case '--overwrite':
|
|
415
451
|
options.overwrite = true;
|
|
416
452
|
break;
|
|
453
|
+
case '--legacy':
|
|
454
|
+
options.legacy = true;
|
|
455
|
+
break;
|
|
456
|
+
case '--dry-run':
|
|
457
|
+
options.dryRun = true;
|
|
458
|
+
break;
|
|
417
459
|
case '-@':
|
|
418
460
|
options.stdinFilenames = true;
|
|
419
461
|
break;
|
|
@@ -432,12 +474,34 @@ function parseArgs(args) {
|
|
|
432
474
|
break;
|
|
433
475
|
}
|
|
434
476
|
}
|
|
435
|
-
// -ots and -ts are mutually exclusive (choose Bitcoin OTS or
|
|
436
|
-
if (options.blockchainOts && options.
|
|
437
|
-
console.error('Error: Cannot use both -ots (OpenTimestamps) and -ts (
|
|
438
|
-
console.error(' Use -
|
|
477
|
+
// -ots and -ts are mutually exclusive (choose Bitcoin OTS or Token Service)
|
|
478
|
+
if (options.blockchainOts && options.blockchainTokenService) {
|
|
479
|
+
console.error('Error: Cannot use both -ots (OpenTimestamps) and -ts (Token Service) in the same run');
|
|
480
|
+
console.error(' Use -ts for Token Service timestamping or -ots for Bitcoin timestamping');
|
|
439
481
|
(0, exit_codes_1.exitZip)(exit_codes_1.ZIP_EXIT_CODES.PARAMETER_ERROR);
|
|
440
482
|
}
|
|
483
|
+
// --legacy: produce an InfoZip/PKZIP-compatible archive.
|
|
484
|
+
if (options.legacy) {
|
|
485
|
+
if (options.blockchain ||
|
|
486
|
+
options.blockchainOts ||
|
|
487
|
+
options.blockchainTokenService ||
|
|
488
|
+
options.blockchainMint ||
|
|
489
|
+
options.blockchainDefault ||
|
|
490
|
+
options.upgrade) {
|
|
491
|
+
(0, exit_codes_1.exitZip)(exit_codes_1.ZIP_EXIT_CODES.PARAMETER_ERROR, 'Error: --legacy cannot be combined with blockchain features (-b, -bd, -bm, -ots, -ts, --upgrade)');
|
|
492
|
+
}
|
|
493
|
+
// Force standard deflate (or store at level 0); zstd is not InfoZip-compatible.
|
|
494
|
+
if (options.compression !== 'deflate') {
|
|
495
|
+
options.compression = 'deflate';
|
|
496
|
+
}
|
|
497
|
+
// AES-256 is not readable by stock InfoZip unzip; fall back to PKZIP.
|
|
498
|
+
if (options.encrypt && options.encryptionMethod !== 'pkzip') {
|
|
499
|
+
if (!(0, output_1.isJsonOutput)()) {
|
|
500
|
+
console.error('Warning: --legacy forces PKZIP encryption (AES-256 is not InfoZip-compatible)');
|
|
501
|
+
}
|
|
502
|
+
options.encryptionMethod = 'pkzip';
|
|
503
|
+
}
|
|
504
|
+
}
|
|
441
505
|
if (!archive) {
|
|
442
506
|
console.error('Error: Archive name is required');
|
|
443
507
|
showHelp();
|
|
@@ -457,6 +521,16 @@ function parseArgs(args) {
|
|
|
457
521
|
archive = archive + '.nzip';
|
|
458
522
|
}
|
|
459
523
|
}
|
|
524
|
+
// Input hardening: reject control characters / dangerous Unicode in the name.
|
|
525
|
+
try {
|
|
526
|
+
(0, validate_1.assertSafeArchiveName)(archive);
|
|
527
|
+
}
|
|
528
|
+
catch (err) {
|
|
529
|
+
if (err instanceof validate_1.ValidationError) {
|
|
530
|
+
(0, exit_codes_1.exitZip)(exit_codes_1.ZIP_EXIT_CODES.PARAMETER_ERROR, `Error: ${err.message}`);
|
|
531
|
+
}
|
|
532
|
+
throw err;
|
|
533
|
+
}
|
|
460
534
|
// Skip file validation for upgrade mode (only needs archive path)
|
|
461
535
|
if (files.length === 0 && !options.stdinFilenames && !options.upgrade) {
|
|
462
536
|
console.error('Error: At least one file or directory must be specified');
|
|
@@ -469,17 +543,20 @@ function parseArgs(args) {
|
|
|
469
543
|
* Show help information
|
|
470
544
|
*/
|
|
471
545
|
function showHelp() {
|
|
546
|
+
// In JSON mode, never print human help to stdout (keeps stdout pure JSON).
|
|
547
|
+
if ((0, output_1.isJsonOutput)())
|
|
548
|
+
return;
|
|
472
549
|
console.log(`
|
|
473
550
|
NeoZip Version: ${version_1.APP_VERSION} (${version_1.APP_RELEASE_DATE})
|
|
474
551
|
|
|
475
552
|
Usage: neozip [options] <archive> <files...>
|
|
476
553
|
|
|
477
554
|
Configuration Commands:
|
|
478
|
-
neozip
|
|
479
|
-
neozip config
|
|
480
|
-
neozip
|
|
555
|
+
neozip connect [subcommand] Token Service account setup (alias: neozip init)
|
|
556
|
+
neozip config Connection dashboard (status, prefs, migrate)
|
|
557
|
+
neozip skills [subcommand] Install bundled Agent Skills for Claude/Cursor
|
|
558
|
+
neozip upgrade <archive> [output] [--wait] Upgrade pending Token Service timestamp to confirmed
|
|
481
559
|
neozip mint <archive> [output] Mint TimestampProofNFT from confirmed timestamped ZIP
|
|
482
|
-
neozip verify-email [--email <email>] [--set-default] Configure email for Zipstamp timestamping
|
|
483
560
|
|
|
484
561
|
Options:
|
|
485
562
|
-h, --help Show this help message
|
|
@@ -500,6 +577,12 @@ Options:
|
|
|
500
577
|
--non-interactive Skip interactive prompts (exit on minting errors)
|
|
501
578
|
--upgrade Upgrade existing ZIP file for tokenization (add SHA-256 hashes)
|
|
502
579
|
--overwrite Overwrite input file when upgrading (default: create new file)
|
|
580
|
+
--legacy Create an InfoZip/PKZIP-compatible archive (deflate/store + PKZIP,
|
|
581
|
+
no blockchain/zstd; readable by stock unzip)
|
|
582
|
+
--dry-run Show what would be created without writing the archive
|
|
583
|
+
--format <fmt> Output format: text (default) or json (machine-readable)
|
|
584
|
+
--params <json> Provide options as a JSON object (agent input; '-' = stdin)
|
|
585
|
+
--json <json> Provide payload {archive, files, include, exclude} as JSON ('-' = stdin)
|
|
503
586
|
-@ Read file names from stdin (one per line)
|
|
504
587
|
-0 Store only (no compression)
|
|
505
588
|
-1 to -9 Compression level (1=fastest, 9=best, default: 6)
|
|
@@ -508,10 +591,9 @@ Options:
|
|
|
508
591
|
-bd, --blockchain-default Auto-select default token option (use existing or mint new)
|
|
509
592
|
-bm, --blockchain-mint Force mint new token (skip existing token selection)
|
|
510
593
|
-ots, --opentimestamp Enable OpenTimestamp proof on Bitcoin blockchain
|
|
511
|
-
-ts, --timestamp Enable
|
|
512
|
-
--timestamp-email <email> Email for Zipstamp server (some servers require verified email)
|
|
594
|
+
-ts, --timestamp Enable Token Service timestamp (blockchain; requires neozip connect)
|
|
513
595
|
-n, --network <network> Blockchain network (base-sepolia, base-mainnet, default: base-sepolia)
|
|
514
|
-
-w, --wallet-key <key> Wallet private key (
|
|
596
|
+
-w, --wallet-key <key> Wallet private key (one-off override; default: connection store)
|
|
515
597
|
-c Add one-line comments for files
|
|
516
598
|
--compression <alg> Compression algorithm (zstd, deflate, default: zstd)
|
|
517
599
|
--deflate Use deflate compression (same as --compression deflate)
|
|
@@ -519,10 +601,11 @@ Options:
|
|
|
519
601
|
--block-size <bytes> Block size for streaming (default: 131072)
|
|
520
602
|
--no-progress Disable progress reporting
|
|
521
603
|
--progress Enable enhanced progress reporting
|
|
522
|
-
-e, --encrypt Encrypt files (
|
|
523
|
-
-P, --password [pwd] Encrypt files with password
|
|
604
|
+
-e, --encrypt Encrypt files with AES-256 (default). Will prompt for password
|
|
605
|
+
-P, --password [pwd] Encrypt files with password. Provide password or will prompt
|
|
606
|
+
--aes256 Use AES-256 encryption (default, recommended)
|
|
607
|
+
--pkzip, --pkzip-encrypt Use legacy PKZIP encryption (weak, for compatibility only)
|
|
524
608
|
-p, --show-progress Show progress during compression (InfoZip-compatible)
|
|
525
|
-
--pkzip-encrypt Use PKZIP encryption (legacy compatibility only, same as -e)
|
|
526
609
|
-x, --exclude <pattern> Exclude files matching pattern (can be used multiple times)
|
|
527
610
|
-i, --include <pattern> Include only files matching pattern (can be used multiple times)
|
|
528
611
|
--suffixes <list> Don't compress files with these suffixes (can be used multiple times)
|
|
@@ -550,6 +633,8 @@ Examples:
|
|
|
550
633
|
* Show extended help information (equivalent to InfoZip's -h2)
|
|
551
634
|
*/
|
|
552
635
|
function showExtendedHelp() {
|
|
636
|
+
if ((0, output_1.isJsonOutput)())
|
|
637
|
+
return;
|
|
553
638
|
console.log('Extended Help for NeoZip');
|
|
554
639
|
console.log('');
|
|
555
640
|
console.log('NeoZip is a next-generation ZIP utility that builds upon the strengths of the ZIP format');
|
|
@@ -650,12 +735,23 @@ function showExtendedHelp() {
|
|
|
650
735
|
console.log('');
|
|
651
736
|
console.log('Blockchain Features:');
|
|
652
737
|
console.log(' -b, --blockchain enable blockchain tokenization');
|
|
653
|
-
console.log('
|
|
654
|
-
console.log(' --
|
|
655
|
-
console.log(' --
|
|
656
|
-
console.log('
|
|
657
|
-
console.log('
|
|
658
|
-
console.log(' --
|
|
738
|
+
console.log(' -bd, --blockchain-default auto-select default token option');
|
|
739
|
+
console.log(' -bm, --blockchain-mint force mint a new token');
|
|
740
|
+
console.log(' -ots, --opentimestamp add an OpenTimestamps (Bitcoin) proof');
|
|
741
|
+
console.log(' -ts, --timestamp add a Token Service timestamp (requires neozip connect)');
|
|
742
|
+
console.log(' -n, --network <network> specify blockchain network (base-sepolia, base-mainnet, etc.)');
|
|
743
|
+
console.log(' -w, --wallet-key <key> one-off wallet private key (default: connection store)');
|
|
744
|
+
console.log('');
|
|
745
|
+
console.log('Legacy / InfoZip compatibility:');
|
|
746
|
+
console.log(' --legacy create a standard ZIP readable by stock InfoZip unzip');
|
|
747
|
+
console.log(' (forces deflate/store + PKZIP, disables zstd and blockchain extensions)');
|
|
748
|
+
console.log('');
|
|
749
|
+
console.log('Agent / automation:');
|
|
750
|
+
console.log(' --format json emit a machine-readable JSON result on stdout');
|
|
751
|
+
console.log(' --params <json> supply options as a JSON object ("-" reads stdin)');
|
|
752
|
+
console.log(' --json <json> supply payload {archive, files, include, exclude} ("-" reads stdin)');
|
|
753
|
+
console.log(' --dry-run resolve and print the plan without writing');
|
|
754
|
+
console.log(' neozip schema neozip print the machine-readable command schema');
|
|
659
755
|
console.log('');
|
|
660
756
|
console.log('Testing archives:');
|
|
661
757
|
console.log(' -T test completed archive with neounzip before finalizing');
|
|
@@ -695,49 +791,56 @@ function showExtendedHelp() {
|
|
|
695
791
|
*/
|
|
696
792
|
async function main() {
|
|
697
793
|
try {
|
|
794
|
+
(0, bootstrap_1.bootstrapConnectionContext)();
|
|
698
795
|
// Parse command line arguments
|
|
699
796
|
const args = process.argv.slice(2);
|
|
797
|
+
// Resolve machine-readable output mode early so error exits are structured.
|
|
798
|
+
(0, output_1.setOutputFormat)((0, output_1.detectOutputFormat)(args));
|
|
700
799
|
// Handle configuration commands first
|
|
701
800
|
if (args.length > 0) {
|
|
702
801
|
const command = args[0];
|
|
703
|
-
//
|
|
802
|
+
// `neozip schema <command>` — machine-readable command introspection
|
|
803
|
+
if (command === 'schema') {
|
|
804
|
+
const code = (0, schema_1.handleSchemaCommand)(args.slice(1));
|
|
805
|
+
process.exit(code);
|
|
806
|
+
}
|
|
807
|
+
// `neozip init` is an alias for `neozip connect`
|
|
704
808
|
if (command === 'init') {
|
|
705
|
-
|
|
706
|
-
const {
|
|
707
|
-
const
|
|
708
|
-
|
|
709
|
-
process.exit(success ? exit_codes_1.ZIP_EXIT_CODES.SUCCESS : exit_codes_1.ZIP_EXIT_CODES.BAD_ARCHIVE_FORMAT);
|
|
809
|
+
console.error('Note: neozip init is an alias for neozip connect.\n');
|
|
810
|
+
const { runConnectCommand } = await import(resolveScriptPath('./connect/command.js'));
|
|
811
|
+
const code = await runConnectCommand([]);
|
|
812
|
+
process.exit(code === 0 ? exit_codes_1.ZIP_EXIT_CODES.SUCCESS : exit_codes_1.ZIP_EXIT_CODES.BAD_ARCHIVE_FORMAT);
|
|
710
813
|
}
|
|
711
|
-
// Handle `neozip config`
|
|
814
|
+
// Handle `neozip config` — connection dashboard
|
|
712
815
|
if (command === 'config') {
|
|
713
|
-
// Lazy-load ConfigSetup only when needed
|
|
714
816
|
const { ConfigSetup } = await import(resolveScriptPath('./config/ConfigSetup.js'));
|
|
715
817
|
await ConfigSetup.showAndManage();
|
|
716
|
-
// showAndManage handles its own exit
|
|
717
818
|
}
|
|
718
|
-
// Handle `neozip
|
|
719
|
-
if (command === '
|
|
720
|
-
const
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
const arg = verifyArgs[i];
|
|
726
|
-
if (arg === '--email' && verifyArgs[i + 1]) {
|
|
727
|
-
email = verifyArgs[++i];
|
|
728
|
-
}
|
|
729
|
-
else if (arg === '--set-default') {
|
|
730
|
-
setDefaultOnly = true;
|
|
731
|
-
}
|
|
732
|
-
else if (arg === '--debug') {
|
|
733
|
-
debug = true;
|
|
734
|
-
}
|
|
819
|
+
// Handle `neozip connect` — Token Service account setup
|
|
820
|
+
if (command === 'connect') {
|
|
821
|
+
const { runConnectCommand, connectUsage } = await import(resolveScriptPath('./connect/command.js'));
|
|
822
|
+
const connectArgv = args.slice(1);
|
|
823
|
+
if (connectArgv.length === 1 && (connectArgv[0] === '--help' || connectArgv[0] === '-h')) {
|
|
824
|
+
connectUsage();
|
|
825
|
+
process.exit(exit_codes_1.ZIP_EXIT_CODES.SUCCESS);
|
|
735
826
|
}
|
|
736
|
-
const
|
|
737
|
-
|
|
738
|
-
|
|
827
|
+
const code = await runConnectCommand(connectArgv);
|
|
828
|
+
process.exit(code === 0 ? exit_codes_1.ZIP_EXIT_CODES.SUCCESS : exit_codes_1.ZIP_EXIT_CODES.BAD_ARCHIVE_FORMAT);
|
|
829
|
+
}
|
|
830
|
+
// Handle `neozip skills` — install bundled Agent Skills
|
|
831
|
+
if (command === 'skills') {
|
|
832
|
+
const { runSkillsCommand, skillsUsage } = await import(resolveScriptPath('./skills/command.js'));
|
|
833
|
+
const skillsArgv = args.slice(1);
|
|
834
|
+
if (skillsArgv.length === 0 ||
|
|
835
|
+
skillsArgv.includes('--help') ||
|
|
836
|
+
skillsArgv.includes('-h')) {
|
|
837
|
+
skillsUsage();
|
|
838
|
+
process.exit(exit_codes_1.ZIP_EXIT_CODES.SUCCESS);
|
|
839
|
+
}
|
|
840
|
+
const code = runSkillsCommand(skillsArgv);
|
|
841
|
+
process.exit(code === 0 ? exit_codes_1.ZIP_EXIT_CODES.SUCCESS : exit_codes_1.ZIP_EXIT_CODES.PARAMETER_ERROR);
|
|
739
842
|
}
|
|
740
|
-
// Handle `neozip upgrade` - upgrade pending
|
|
843
|
+
// Handle `neozip upgrade` - upgrade pending Token Service timestamp to confirmed
|
|
741
844
|
if (command === 'upgrade') {
|
|
742
845
|
const upgradeArgs = args.slice(1);
|
|
743
846
|
let inputPath = '';
|
|
@@ -819,14 +922,30 @@ async function main() {
|
|
|
819
922
|
process.exit(success ? exit_codes_1.ZIP_EXIT_CODES.SUCCESS : exit_codes_1.ZIP_EXIT_CODES.BAD_ARCHIVE_FORMAT);
|
|
820
923
|
}
|
|
821
924
|
}
|
|
822
|
-
|
|
823
|
-
//
|
|
925
|
+
// Extract agent input (--params/--json) and strip the --format flag, then
|
|
926
|
+
// parse the remaining argv. Seed values are overridden by explicit flags.
|
|
927
|
+
const agent = (0, params_1.extractAgentInput)((0, output_1.stripFormatFlag)(args));
|
|
928
|
+
const seed = {};
|
|
929
|
+
if (agent.params)
|
|
930
|
+
seed.options = zipParamsToOptions(agent.params);
|
|
931
|
+
if (agent.payload) {
|
|
932
|
+
const payloadSeed = zipPayloadToSeed(agent.payload);
|
|
933
|
+
if (payloadSeed.archive)
|
|
934
|
+
seed.archive = payloadSeed.archive;
|
|
935
|
+
if (payloadSeed.files)
|
|
936
|
+
seed.files = payloadSeed.files;
|
|
937
|
+
if (payloadSeed.options) {
|
|
938
|
+
seed.options = { ...(seed.options ?? {}), ...payloadSeed.options };
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
let { archive, files, options } = parseArgs(agent.argv, seed);
|
|
942
|
+
// In JSON mode, suppress decorative human logs so stdout stays pure JSON.
|
|
943
|
+
if ((0, output_1.isJsonOutput)()) {
|
|
944
|
+
options.quiet = true;
|
|
945
|
+
}
|
|
824
946
|
const networkProvidedViaCLI = args.includes('--network') || args.includes('-n');
|
|
825
947
|
if (!networkProvidedViaCLI) {
|
|
826
|
-
|
|
827
|
-
if (config.network) {
|
|
828
|
-
options.network = config.network;
|
|
829
|
-
}
|
|
948
|
+
options.network = (0, cli_prefs_1.resolveNetwork)(options.network);
|
|
830
949
|
}
|
|
831
950
|
// Handle stdin filenames
|
|
832
951
|
if (options.stdinFilenames) {
|
|
@@ -852,6 +971,41 @@ async function main() {
|
|
|
852
971
|
(0, exit_codes_1.exitZip)(exit_codes_1.ZIP_EXIT_CODES.PARAMETER_ERROR);
|
|
853
972
|
}
|
|
854
973
|
}
|
|
974
|
+
// Dry-run: resolve and report the plan without writing anything.
|
|
975
|
+
if (options.dryRun) {
|
|
976
|
+
const action = options.delete ? 'delete' : options.upgrade ? 'upgrade' : 'create';
|
|
977
|
+
const plan = {
|
|
978
|
+
command: 'neozip',
|
|
979
|
+
action,
|
|
980
|
+
dryRun: true,
|
|
981
|
+
archive,
|
|
982
|
+
files: options.delete ? undefined : files,
|
|
983
|
+
deleteFiles: options.delete ? files : undefined,
|
|
984
|
+
legacy: !!options.legacy,
|
|
985
|
+
resolvedOptions: {
|
|
986
|
+
level: options.level,
|
|
987
|
+
compression: options.level === 0 ? 'store' : options.compression,
|
|
988
|
+
encrypt: !!options.encrypt,
|
|
989
|
+
encryptionMethod: options.encrypt ? options.encryptionMethod : undefined,
|
|
990
|
+
blockchain: !!options.blockchain,
|
|
991
|
+
blockchainOts: !!options.blockchainOts,
|
|
992
|
+
blockchainTokenService: !!options.blockchainTokenService,
|
|
993
|
+
network: options.network,
|
|
994
|
+
recurse: !!options.recurse,
|
|
995
|
+
junkPaths: !!options.junkPaths,
|
|
996
|
+
include: options.include,
|
|
997
|
+
exclude: options.exclude,
|
|
998
|
+
},
|
|
999
|
+
};
|
|
1000
|
+
if ((0, output_1.isJsonOutput)()) {
|
|
1001
|
+
(0, output_1.emitResult)(plan);
|
|
1002
|
+
}
|
|
1003
|
+
else {
|
|
1004
|
+
console.log('Dry run — no archive will be written.');
|
|
1005
|
+
console.log(JSON.stringify(plan, null, 2));
|
|
1006
|
+
}
|
|
1007
|
+
process.exit(exit_codes_1.ZIP_EXIT_CODES.SUCCESS);
|
|
1008
|
+
}
|
|
855
1009
|
// Handle upgrade operation
|
|
856
1010
|
if (options.upgrade) {
|
|
857
1011
|
// Validate: upgrade requires exactly one argument (the ZIP file path)
|
|
@@ -878,6 +1032,9 @@ async function main() {
|
|
|
878
1032
|
if (options.delete) {
|
|
879
1033
|
await (0, file_operations_1.deleteFromArchive)(archive, files, options);
|
|
880
1034
|
(0, utils_1.log)('✓ Delete operation completed successfully', options);
|
|
1035
|
+
if ((0, output_1.isJsonOutput)()) {
|
|
1036
|
+
(0, output_1.emitResult)({ command: 'neozip', action: 'delete', archive, deleteFiles: files });
|
|
1037
|
+
}
|
|
881
1038
|
return;
|
|
882
1039
|
}
|
|
883
1040
|
// Create ZIP archive
|
|
@@ -887,6 +1044,27 @@ async function main() {
|
|
|
887
1044
|
await (0, file_operations_1.moveFiles)(files, options);
|
|
888
1045
|
}
|
|
889
1046
|
(0, utils_1.log)('✓ NeoZip completed successfully', options);
|
|
1047
|
+
if ((0, output_1.isJsonOutput)()) {
|
|
1048
|
+
let size;
|
|
1049
|
+
try {
|
|
1050
|
+
size = fs.existsSync(archive) ? fs.statSync(archive).size : undefined;
|
|
1051
|
+
}
|
|
1052
|
+
catch {
|
|
1053
|
+
size = undefined;
|
|
1054
|
+
}
|
|
1055
|
+
(0, output_1.emitResult)({
|
|
1056
|
+
command: 'neozip',
|
|
1057
|
+
action: 'create',
|
|
1058
|
+
archive,
|
|
1059
|
+
size,
|
|
1060
|
+
fileCount: files.length,
|
|
1061
|
+
legacy: !!options.legacy,
|
|
1062
|
+
compression: options.level === 0 ? 'store' : options.compression,
|
|
1063
|
+
encrypted: !!options.encrypt,
|
|
1064
|
+
encryptionMethod: options.encrypt ? options.encryptionMethod : undefined,
|
|
1065
|
+
blockchain: !!options.blockchain,
|
|
1066
|
+
});
|
|
1067
|
+
}
|
|
890
1068
|
// Explicitly exit to ensure process terminates (provider cleanup should allow this)
|
|
891
1069
|
process.exit(exit_codes_1.ZIP_EXIT_CODES.SUCCESS);
|
|
892
1070
|
}
|