neozip-cli 0.90.0 → 0.95.1
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 +70 -1
- package/DOCUMENTATION.md +22 -30
- package/README.md +214 -48
- 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/token-service-funding.js +151 -0
- package/dist/src/account/token-service-identity.js +488 -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/commands/verifyEmail.js +9 -9
- package/dist/src/config/ConfigSetup.js +82 -423
- package/dist/src/config/ConfigStore.js +0 -33
- 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 +93 -9
- package/dist/src/neounzip.js +217 -59
- package/dist/src/neozip/blockchain.js +18 -18
- package/dist/src/neozip/createZip.js +114 -91
- package/dist/src/neozip/upgradeZip.js +14 -11
- package/dist/src/neozip.js +252 -75
- 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 -82
- 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
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WALLET_SETUP_HINT = void 0;
|
|
4
|
+
exports.fetchServerLinkedWalletAddress = fetchServerLinkedWalletAddress;
|
|
5
|
+
exports.validateWalletImportAgainstServer = validateWalletImportAgainstServer;
|
|
6
|
+
exports.requireWalletPreconditions = requireWalletPreconditions;
|
|
7
|
+
exports.requirePhonePreconditions = requirePhonePreconditions;
|
|
8
|
+
exports.walletAlreadyConfigured = walletAlreadyConfigured;
|
|
9
|
+
exports.saveImportedWallet = saveImportedWallet;
|
|
10
|
+
exports.createLocalWalletIdentity = createLocalWalletIdentity;
|
|
11
|
+
exports.importWalletFromMnemonic = importWalletFromMnemonic;
|
|
12
|
+
exports.importWalletFromPrivateKey = importWalletFromPrivateKey;
|
|
13
|
+
exports.activeWalletContext = activeWalletContext;
|
|
14
|
+
const ethers_1 = require("ethers");
|
|
15
|
+
const crypto_self_1 = require("../archive/crypto-self");
|
|
16
|
+
const wallet_evm_1 = require("../account/wallet-evm");
|
|
17
|
+
const store_1 = require("./store");
|
|
18
|
+
const phone_1 = require("./phone");
|
|
19
|
+
exports.WALLET_SETUP_HINT = "Configure a Data Wallet first: neozip connect wallet create --ack-backup, wallet import-mnemonic, or wallet import-key. Or use finish --create-wallet to generate one (no recovery phrase shown).";
|
|
20
|
+
async function fetchServerLinkedWalletAddress(baseUrl, accessToken) {
|
|
21
|
+
const result = await (0, crypto_self_1.fetchCryptoSelf)({
|
|
22
|
+
tokenServiceAccessToken: accessToken,
|
|
23
|
+
tokenServiceUrl: baseUrl,
|
|
24
|
+
}, { serverUrl: baseUrl });
|
|
25
|
+
if (!result.ok)
|
|
26
|
+
return null;
|
|
27
|
+
try {
|
|
28
|
+
return (0, ethers_1.getAddress)(result.data.evmAddress);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function validateWalletImportAgainstServer(input) {
|
|
35
|
+
if (input.force)
|
|
36
|
+
return;
|
|
37
|
+
const serverAddress = await fetchServerLinkedWalletAddress(input.origin, input.accessToken);
|
|
38
|
+
if (!serverAddress)
|
|
39
|
+
return;
|
|
40
|
+
const derived = (0, ethers_1.getAddress)(input.derivedAddress);
|
|
41
|
+
if (derived.toLowerCase() !== serverAddress.toLowerCase()) {
|
|
42
|
+
throw new Error(`Imported wallet (${derived}) differs from the wallet linked on Token Service (${serverAddress}). ` +
|
|
43
|
+
"Restore the correct recovery phrase or private key, or pass --force to replace the server wallet.");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function requireWalletPreconditions(conn, secrets) {
|
|
47
|
+
if (!secrets?.accessToken || !conn.emailVerified) {
|
|
48
|
+
throw new Error("Verify email first. Run neozip connect verify.");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function requirePhonePreconditions(conn, origin) {
|
|
52
|
+
if (await (0, phone_1.needsPhoneVerification)(conn, origin)) {
|
|
53
|
+
throw new Error("Phone verification required. Run neozip connect phone request and phone verify.");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function walletAlreadyConfigured(conn, secrets) {
|
|
57
|
+
return Boolean(secrets?.evmPrivateKeyHex && conn.evmAddress);
|
|
58
|
+
}
|
|
59
|
+
async function saveImportedWallet(connectionId, evm) {
|
|
60
|
+
return (0, store_1.saveEvmWallet)(connectionId, evm.privateKey, evm.address);
|
|
61
|
+
}
|
|
62
|
+
function createLocalWalletIdentity() {
|
|
63
|
+
const evm = (0, wallet_evm_1.generateEvmIdentity)();
|
|
64
|
+
if (!evm.mnemonic) {
|
|
65
|
+
throw new Error("Failed to generate recovery phrase for new Data Wallet");
|
|
66
|
+
}
|
|
67
|
+
return evm;
|
|
68
|
+
}
|
|
69
|
+
function importWalletFromMnemonic(mnemonic) {
|
|
70
|
+
return (0, wallet_evm_1.evmIdentityFromMnemonic)(mnemonic);
|
|
71
|
+
}
|
|
72
|
+
function importWalletFromPrivateKey(privateKey) {
|
|
73
|
+
return (0, wallet_evm_1.evmIdentityFromPrivateKey)(privateKey);
|
|
74
|
+
}
|
|
75
|
+
function activeWalletContext() {
|
|
76
|
+
const conn = (0, store_1.getActiveConnection)();
|
|
77
|
+
const secrets = (0, store_1.readActiveConnectionSecrets)();
|
|
78
|
+
if (!conn || !secrets) {
|
|
79
|
+
throw new Error("No active connection. Run neozip connect first.");
|
|
80
|
+
}
|
|
81
|
+
return { conn, secrets, origin: conn.tokenServiceOrigin };
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=wallet-setup.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TOKEN_SERVICE_RECIPIENT_IDENTITY_TYPE = exports.X25519_SPKI_PREFIX = exports.WRAP_IV_LEN = exports.WRAP_KDF_SALT_LEN = exports.WRAP_AEAD = exports.WRAP_KDF_INFO = exports.WRAP_FORMAT_VERSION = void 0;
|
|
4
|
+
/** Wallet-encrypted X25519 identity key wrap format (Token Service API_IDENTITY.md). */
|
|
5
|
+
exports.WRAP_FORMAT_VERSION = 1;
|
|
6
|
+
exports.WRAP_KDF_INFO = "NeoZip/WalletEncIK/v1";
|
|
7
|
+
exports.WRAP_AEAD = "AES-256-GCM";
|
|
8
|
+
exports.WRAP_KDF_SALT_LEN = 32;
|
|
9
|
+
exports.WRAP_IV_LEN = 12;
|
|
10
|
+
/** SPKI-DER prefix for X25519 public keys (12 bytes). */
|
|
11
|
+
exports.X25519_SPKI_PREFIX = Buffer.from("302a300506032b656e032100", "hex");
|
|
12
|
+
/** neozipkit-pro identity type for Token Service email recipients. */
|
|
13
|
+
exports.TOKEN_SERVICE_RECIPIENT_IDENTITY_TYPE = "zipstamp";
|
|
14
|
+
//# sourceMappingURL=wallet-identity.js.map
|
package/dist/src/exit-codes.js
CHANGED
|
@@ -11,6 +11,7 @@ exports.exitZip = exitZip;
|
|
|
11
11
|
exports.exitUnzip = exitUnzip;
|
|
12
12
|
exports.exitZipinfo = exitZipinfo;
|
|
13
13
|
exports.getExitCodeDescription = getExitCodeDescription;
|
|
14
|
+
const output_1 = require("./cli/output");
|
|
14
15
|
/**
|
|
15
16
|
* Exit codes for NEOZIP application
|
|
16
17
|
* Based on InfoZip ZIP exit codes
|
|
@@ -97,31 +98,74 @@ exports.ZIPINFO_EXIT_CODES = {
|
|
|
97
98
|
OTS_VERIFY_FAILED: 89, // OpenTimestamp verification failed
|
|
98
99
|
};
|
|
99
100
|
/**
|
|
100
|
-
*
|
|
101
|
+
* Reverse lookup: numeric exit code -> symbolic name, per application.
|
|
101
102
|
*/
|
|
102
|
-
function
|
|
103
|
+
function symbolicName(table, code) {
|
|
104
|
+
for (const [name, value] of Object.entries(table)) {
|
|
105
|
+
if (value === code)
|
|
106
|
+
return name;
|
|
107
|
+
}
|
|
108
|
+
return 'UNKNOWN_ERROR';
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Suggested recovery command for an agent, keyed by symbolic error name.
|
|
112
|
+
* Only a subset of codes have a meaningful next step.
|
|
113
|
+
*/
|
|
114
|
+
const NEXT_COMMAND_HINTS = {
|
|
115
|
+
BLOCKCHAIN_CONFIG_ERROR: 'neozip connect',
|
|
116
|
+
TOKEN_MINT_FAILED: 'neozip connect status',
|
|
117
|
+
TOKEN_MINT_TIMEOUT: 'neozip upgrade <archive> --wait',
|
|
118
|
+
TOKEN_MINT_INSUFFICIENT_BALANCE: 'neozip connect status',
|
|
119
|
+
TOKEN_MINT_USER_CANCELLED: 'neozip connect status',
|
|
120
|
+
BAD_PASSWORD: 'neounzip -P <password> <archive>',
|
|
121
|
+
TOKEN_VERIFY_FAILED: 'neounzip --skip-blockchain <archive>',
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Emit a structured JSON error (when in JSON mode) and exit.
|
|
125
|
+
*
|
|
126
|
+
* In text mode this preserves the original behavior: print the message to stderr
|
|
127
|
+
* and exit with the numeric code. In JSON mode a structured error object is
|
|
128
|
+
* written to stdout so callers can parse it, and the human message (if any) goes
|
|
129
|
+
* to stderr as a hint.
|
|
130
|
+
*/
|
|
131
|
+
function exitWithError(app, table, code, message) {
|
|
132
|
+
if ((0, output_1.isJsonOutput)()) {
|
|
133
|
+
const name = symbolicName(table, code);
|
|
134
|
+
const cleanMessage = (message ?? getExitCodeDescription(app, code)).replace(/^Error:\s*/i, '');
|
|
135
|
+
(0, output_1.emitError)({
|
|
136
|
+
app,
|
|
137
|
+
code: name,
|
|
138
|
+
exitCode: code,
|
|
139
|
+
message: cleanMessage,
|
|
140
|
+
...(NEXT_COMMAND_HINTS[name] ? { nextCommand: NEXT_COMMAND_HINTS[name] } : {}),
|
|
141
|
+
});
|
|
142
|
+
if (message) {
|
|
143
|
+
console.error(message);
|
|
144
|
+
}
|
|
145
|
+
process.exit(code);
|
|
146
|
+
}
|
|
103
147
|
if (message) {
|
|
104
148
|
console.error(message);
|
|
105
149
|
}
|
|
106
150
|
process.exit(code);
|
|
107
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Helper function to exit with a ZIP exit code
|
|
154
|
+
*/
|
|
155
|
+
function exitZip(code, message) {
|
|
156
|
+
return exitWithError('zip', exports.ZIP_EXIT_CODES, code, message);
|
|
157
|
+
}
|
|
108
158
|
/**
|
|
109
159
|
* Helper function to exit with an UNZIP exit code
|
|
110
160
|
*/
|
|
111
161
|
function exitUnzip(code, message) {
|
|
112
|
-
|
|
113
|
-
console.error(message);
|
|
114
|
-
}
|
|
115
|
-
process.exit(code);
|
|
162
|
+
return exitWithError('unzip', exports.UNZIP_EXIT_CODES, code, message);
|
|
116
163
|
}
|
|
117
164
|
/**
|
|
118
165
|
* Helper function to exit with a ZIPINFO exit code
|
|
119
166
|
*/
|
|
120
167
|
function exitZipinfo(code, message) {
|
|
121
|
-
|
|
122
|
-
console.error(message);
|
|
123
|
-
}
|
|
124
|
-
process.exit(code);
|
|
168
|
+
return exitWithError('zipinfo', exports.ZIPINFO_EXIT_CODES, code, message);
|
|
125
169
|
}
|
|
126
170
|
/**
|
|
127
171
|
* Get exit code description for documentation
|
package/dist/src/neolist.js
CHANGED
|
@@ -49,11 +49,14 @@ const fs = __importStar(require("fs"));
|
|
|
49
49
|
const node_1 = __importDefault(require("neozipkit/node"));
|
|
50
50
|
const neozip_blockchain_1 = require("neozip-blockchain");
|
|
51
51
|
const ots_1 = require("neozip-blockchain/ots");
|
|
52
|
-
const
|
|
52
|
+
const token_service_1 = require("neozip-blockchain/token-service");
|
|
53
53
|
const chalk_1 = __importDefault(require("chalk"));
|
|
54
54
|
const ora_1 = __importDefault(require("ora"));
|
|
55
55
|
const version_1 = require("./version");
|
|
56
56
|
const exit_codes_1 = require("./exit-codes");
|
|
57
|
+
const output_1 = require("./cli/output");
|
|
58
|
+
const params_1 = require("./cli/params");
|
|
59
|
+
const validate_1 = require("./cli/validate");
|
|
57
60
|
/**
|
|
58
61
|
* Helper function to check if ZIP is file-based
|
|
59
62
|
*/
|
|
@@ -259,11 +262,11 @@ function formatEntryName(entry) {
|
|
|
259
262
|
if (entry.filename === ots_1.TIMESTAMP_SUBMITTED) {
|
|
260
263
|
return `${ots_1.TIMESTAMP_SUBMITTED} (OTS Pending)`;
|
|
261
264
|
}
|
|
262
|
-
if (entry.filename ===
|
|
263
|
-
return `${
|
|
265
|
+
if (entry.filename === token_service_1.SUBMIT_METADATA) {
|
|
266
|
+
return `${token_service_1.SUBMIT_METADATA} (Token Service Pending)`;
|
|
264
267
|
}
|
|
265
|
-
if (entry.filename ===
|
|
266
|
-
return `${
|
|
268
|
+
if (entry.filename === token_service_1.TIMESTAMP_METADATA) {
|
|
269
|
+
return `${token_service_1.TIMESTAMP_METADATA} (Token Service Timestamp)`;
|
|
267
270
|
}
|
|
268
271
|
return entry.filename;
|
|
269
272
|
}
|
|
@@ -839,6 +842,44 @@ function parseArgs(args) {
|
|
|
839
842
|
case '--json':
|
|
840
843
|
options.json = true;
|
|
841
844
|
break;
|
|
845
|
+
case '--format': {
|
|
846
|
+
const value = args[++i];
|
|
847
|
+
if (value === 'json') {
|
|
848
|
+
options.json = true;
|
|
849
|
+
}
|
|
850
|
+
else if (value !== 'text') {
|
|
851
|
+
console.error("Error: --format must be 'json' or 'text'");
|
|
852
|
+
showHelp();
|
|
853
|
+
(0, exit_codes_1.exitZipinfo)(exit_codes_1.ZIPINFO_EXIT_CODES.INVALID_OPTIONS);
|
|
854
|
+
}
|
|
855
|
+
break;
|
|
856
|
+
}
|
|
857
|
+
case '--params': {
|
|
858
|
+
const value = args[++i];
|
|
859
|
+
if (value === undefined) {
|
|
860
|
+
console.error("Error: --params requires a JSON value (or '-' for stdin)");
|
|
861
|
+
(0, exit_codes_1.exitZipinfo)(exit_codes_1.ZIPINFO_EXIT_CODES.INVALID_OPTIONS);
|
|
862
|
+
}
|
|
863
|
+
try {
|
|
864
|
+
const params = (0, params_1.parseJsonObjectArg)(value, '--params');
|
|
865
|
+
const allowed = [
|
|
866
|
+
'verbose', 'quiet', 'json', 'short', 'unix', 'basic', 'include', 'exclude',
|
|
867
|
+
'sortBy', 'noComments', 'debug', 'inMemory',
|
|
868
|
+
];
|
|
869
|
+
for (const key of allowed) {
|
|
870
|
+
if (key in params) {
|
|
871
|
+
options[key] = params[key];
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
catch (err) {
|
|
876
|
+
if (err instanceof validate_1.ValidationError) {
|
|
877
|
+
(0, exit_codes_1.exitZipinfo)(exit_codes_1.ZIPINFO_EXIT_CODES.INVALID_OPTIONS, `Error: ${err.message}`);
|
|
878
|
+
}
|
|
879
|
+
throw err;
|
|
880
|
+
}
|
|
881
|
+
break;
|
|
882
|
+
}
|
|
842
883
|
case '-s':
|
|
843
884
|
case '--short':
|
|
844
885
|
options.short = true;
|
|
@@ -914,7 +955,39 @@ function parseArgs(args) {
|
|
|
914
955
|
options.inMemory = true;
|
|
915
956
|
break;
|
|
916
957
|
default:
|
|
917
|
-
if (arg.startsWith('
|
|
958
|
+
if (arg.startsWith('--format=')) {
|
|
959
|
+
const value = arg.slice('--format='.length);
|
|
960
|
+
if (value === 'json') {
|
|
961
|
+
options.json = true;
|
|
962
|
+
}
|
|
963
|
+
else if (value !== 'text') {
|
|
964
|
+
console.error("Error: --format must be 'json' or 'text'");
|
|
965
|
+
showHelp();
|
|
966
|
+
(0, exit_codes_1.exitZipinfo)(exit_codes_1.ZIPINFO_EXIT_CODES.INVALID_OPTIONS);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
else if (arg.startsWith('--params=')) {
|
|
970
|
+
const value = arg.slice('--params='.length);
|
|
971
|
+
try {
|
|
972
|
+
const params = (0, params_1.parseJsonObjectArg)(value, '--params');
|
|
973
|
+
const allowed = [
|
|
974
|
+
'verbose', 'quiet', 'json', 'short', 'unix', 'basic', 'include', 'exclude',
|
|
975
|
+
'sortBy', 'noComments', 'debug', 'inMemory',
|
|
976
|
+
];
|
|
977
|
+
for (const key of allowed) {
|
|
978
|
+
if (key in params) {
|
|
979
|
+
options[key] = params[key];
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
catch (err) {
|
|
984
|
+
if (err instanceof validate_1.ValidationError) {
|
|
985
|
+
(0, exit_codes_1.exitZipinfo)(exit_codes_1.ZIPINFO_EXIT_CODES.INVALID_OPTIONS, `Error: ${err.message}`);
|
|
986
|
+
}
|
|
987
|
+
throw err;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
else if (arg.startsWith('-')) {
|
|
918
991
|
console.error(`Error: Unknown option ${arg}`);
|
|
919
992
|
showHelp();
|
|
920
993
|
(0, exit_codes_1.exitZipinfo)(exit_codes_1.ZIPINFO_EXIT_CODES.INVALID_OPTIONS);
|
|
@@ -940,6 +1013,8 @@ function parseArgs(args) {
|
|
|
940
1013
|
* Show help information
|
|
941
1014
|
*/
|
|
942
1015
|
function showHelp() {
|
|
1016
|
+
if ((0, output_1.isJsonOutput)())
|
|
1017
|
+
return;
|
|
943
1018
|
console.log(`
|
|
944
1019
|
NeoList Version: ${version_1.APP_VERSION} (${version_1.APP_RELEASE_DATE})
|
|
945
1020
|
|
|
@@ -950,7 +1025,9 @@ Options:
|
|
|
950
1025
|
-V, --version Show version information
|
|
951
1026
|
-v, --verbose Detailed central directory information
|
|
952
1027
|
-q, --quiet Suppress output
|
|
953
|
-
-j, --json Output in JSON format
|
|
1028
|
+
-j, --json Output in JSON format (alias for --format json)
|
|
1029
|
+
--format <fmt> Output format: text (default) or json (machine-readable)
|
|
1030
|
+
--params <json> Provide options as a JSON object (agent input; '-' = stdin)
|
|
954
1031
|
-s, --short Short output (names only)
|
|
955
1032
|
-u, --unix Unix-style output
|
|
956
1033
|
-b, --basic Basic table output
|
|
@@ -978,6 +1055,8 @@ Examples:
|
|
|
978
1055
|
* Show extended help information (equivalent to InfoZip's -h2)
|
|
979
1056
|
*/
|
|
980
1057
|
function showExtendedHelp() {
|
|
1058
|
+
if ((0, output_1.isJsonOutput)())
|
|
1059
|
+
return;
|
|
981
1060
|
console.log('Extended Help for NeoList');
|
|
982
1061
|
console.log('');
|
|
983
1062
|
console.log('NeoList is a next-generation ZIP listing utility that builds upon the strengths');
|
|
@@ -1095,6 +1174,11 @@ async function main() {
|
|
|
1095
1174
|
try {
|
|
1096
1175
|
// Parse command line arguments
|
|
1097
1176
|
const args = process.argv.slice(2);
|
|
1177
|
+
// Resolve machine-readable output mode early so error exits are structured.
|
|
1178
|
+
// neolist's legacy -j/--json flag and the shared --format json both select JSON.
|
|
1179
|
+
if (args.includes('-j') || args.includes('--json') || (0, output_1.detectOutputFormat)(args) === 'json') {
|
|
1180
|
+
(0, output_1.setOutputFormat)('json');
|
|
1181
|
+
}
|
|
1098
1182
|
const parsed = parseArgs(args);
|
|
1099
1183
|
const { archive } = parsed;
|
|
1100
1184
|
options = parsed.options;
|
|
@@ -1149,8 +1233,8 @@ async function main() {
|
|
|
1149
1233
|
// Default is now the unzip -v format (verbose table)
|
|
1150
1234
|
outputTable(entries, archive, true, zip, options);
|
|
1151
1235
|
}
|
|
1152
|
-
// Don't show success message for filenames-only modes
|
|
1153
|
-
if (!options.opt1 && !options.opt2 && !options.optT) {
|
|
1236
|
+
// Don't show success message for filenames-only modes or JSON output
|
|
1237
|
+
if (!options.opt1 && !options.opt2 && !options.optT && !options.json) {
|
|
1154
1238
|
log('✓ NeoList completed successfully', options);
|
|
1155
1239
|
}
|
|
1156
1240
|
// Close file handle if file-based ZIP was loaded
|