zstdify-cli 1.0.2 → 1.1.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/README.md +45 -0
- package/dist/commands/compress.d.ts +6 -0
- package/dist/commands/compress.js +27 -1
- package/dist/commands/compress.js.map +1 -1
- package/dist/commands/dict.d.ts +31 -0
- package/dist/commands/dict.js +129 -0
- package/dist/commands/dict.js.map +1 -0
- package/dist/commands/extract.d.ts +4 -0
- package/dist/commands/extract.js +21 -2
- package/dist/commands/extract.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -7,6 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
Command-line tool for compressing and decompressing files with zstd. Built on the [zstdify](https://www.npmjs.com/package/zstdify) package (pure TypeScript, no native dependencies).
|
|
9
9
|
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Pure JS/TS zstd CLI**: No native addon dependency, portable across Node.js environments.
|
|
13
|
+
- **Compression + extraction workflows**: Simple file-to-file commands with level/checksum controls.
|
|
14
|
+
- **Interop-focused**: Files produced by `zstdify` are decoded by the official `zstd` CLI, and `zstd` output is decoded by `zstdify`.
|
|
15
|
+
- **Robust command UX**: Clear subcommands, aliases, and actionable error messages.
|
|
16
|
+
- **Optional dictionary support**: Train dictionaries from samples and use them with `compress`/`extract` when needed.
|
|
17
|
+
|
|
10
18
|
## Installation
|
|
11
19
|
|
|
12
20
|
```sh
|
|
@@ -19,6 +27,7 @@ pnpm add -g zstdify-cli
|
|
|
19
27
|
| ------- | ----------- |
|
|
20
28
|
| `zstdify compress <input> <output>` | Compress a file with zstd |
|
|
21
29
|
| `zstdify extract <input> <output>` | Decompress a zstd-compressed file |
|
|
30
|
+
| `zstdify dict train <output> --input <path>...` | Train a dictionary from sample files/directories |
|
|
22
31
|
|
|
23
32
|
Aliases: `compress` / `c`, `extract` / `x`.
|
|
24
33
|
|
|
@@ -26,6 +35,23 @@ Aliases: `compress` / `c`, `extract` / `x`.
|
|
|
26
35
|
|
|
27
36
|
- `--level`, `-l` — Compression level (0=raw, 1+=RLE, 2+=compressed blocks)
|
|
28
37
|
- `--checksum` — Add content checksum to the frame
|
|
38
|
+
- `--dict` — Dictionary file path to use for compression
|
|
39
|
+
- `--dictID` — Dictionary ID to store in the frame header
|
|
40
|
+
- `--noDictId` — Do not write dictID in frame header
|
|
41
|
+
|
|
42
|
+
### Options (extract)
|
|
43
|
+
|
|
44
|
+
- `--dict` — Dictionary file path for dictionary-compressed input
|
|
45
|
+
- `--dictID` — Expected dictionary ID for validation
|
|
46
|
+
|
|
47
|
+
### Options (dict train)
|
|
48
|
+
|
|
49
|
+
- `--recursive` — Recursively collect files from input directories
|
|
50
|
+
- `--maxSamples` — Maximum number of sample files to load
|
|
51
|
+
- `--algorithm` — `fastcover`, `cover`, or `legacy`
|
|
52
|
+
- `--maxdict` — Maximum dictionary size in bytes
|
|
53
|
+
- `--dictID` — Optional dictionary ID metadata setting
|
|
54
|
+
- Advanced tuning knobs: `--k`, `--d`, `--steps`, `--split`, `--f`, `--accel`, `--selectivity`, `--shrink`
|
|
29
55
|
|
|
30
56
|
## Examples
|
|
31
57
|
|
|
@@ -33,8 +59,27 @@ Aliases: `compress` / `c`, `extract` / `x`.
|
|
|
33
59
|
zstdify compress input.txt output.zst
|
|
34
60
|
zstdify compress input.txt output.zst --level 2
|
|
35
61
|
zstdify extract output.zst restored.txt
|
|
62
|
+
zstdify dict train my.dict --input samples/ --recursive --maxdict 2048
|
|
63
|
+
zstdify compress input.txt output.zst --dict my.dict --dictID 42
|
|
64
|
+
zstdify extract output.zst restored.txt --dict my.dict --dictID 42
|
|
36
65
|
```
|
|
37
66
|
|
|
67
|
+
## How we validate
|
|
68
|
+
|
|
69
|
+
CLI behavior is covered by automated tests (`pnpm vitest`, including `packages/cli-tests`):
|
|
70
|
+
|
|
71
|
+
- **CLI round-trip**: `zstdify compress` -> `zstdify extract` restores original file bytes.
|
|
72
|
+
- **Core flags and aliases**: Compression levels, checksums, and command aliases are exercised.
|
|
73
|
+
- **Differential interop with official zstd CLI**:
|
|
74
|
+
- `zstd` output is extracted by `zstdify-cli`.
|
|
75
|
+
- `zstdify-cli` output is decompressed by `zstd`.
|
|
76
|
+
- These checks run across standard (non-dictionary) workflows.
|
|
77
|
+
- **Dictionary interop coverage**:
|
|
78
|
+
- `zstd -D dict` compressed streams are extracted by `zstdify-cli --dict`.
|
|
79
|
+
- `zstdify-cli --dict` compressed streams are decompressed by `zstd -D dict`.
|
|
80
|
+
- Coverage includes both zstd-trained and zstdify-trained dictionaries.
|
|
81
|
+
- **Error paths**: Missing files and invalid inputs produce non-zero exits and actionable messages.
|
|
82
|
+
|
|
38
83
|
# License
|
|
39
84
|
|
|
40
85
|
MIT
|
|
@@ -26,16 +26,40 @@ export const command = defineCommand({
|
|
|
26
26
|
describe: 'Add content checksum to the frame',
|
|
27
27
|
type: 'boolean',
|
|
28
28
|
default: false,
|
|
29
|
+
})
|
|
30
|
+
.option('dict', {
|
|
31
|
+
describe: 'Dictionary file path to use for compression',
|
|
32
|
+
type: 'string',
|
|
33
|
+
})
|
|
34
|
+
.option('dictID', {
|
|
35
|
+
describe: 'Dictionary ID to store in frame header',
|
|
36
|
+
type: 'number',
|
|
37
|
+
})
|
|
38
|
+
.option('noDictId', {
|
|
39
|
+
describe: "Don't write dictID into frame header",
|
|
40
|
+
type: 'boolean',
|
|
41
|
+
default: false,
|
|
29
42
|
}),
|
|
30
43
|
handler: async (argv) => {
|
|
31
|
-
const { input, output, level, checksum } = argv;
|
|
44
|
+
const { input, output, level, checksum, dict, dictID, noDictId } = argv;
|
|
32
45
|
if (!fs.existsSync(input)) {
|
|
33
46
|
console.error(`Error: Input file not found: ${input}`);
|
|
34
47
|
process.exit(1);
|
|
35
48
|
}
|
|
49
|
+
if (dict && !fs.existsSync(dict)) {
|
|
50
|
+
console.error(`Error: Dictionary file not found: ${dict}`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
36
53
|
try {
|
|
37
54
|
const inputBuf = fs.readFileSync(input);
|
|
38
55
|
const data = new Uint8Array(inputBuf.buffer, inputBuf.byteOffset, inputBuf.byteLength);
|
|
56
|
+
const dictionary = dict
|
|
57
|
+
? (() => {
|
|
58
|
+
const dictBuf = fs.readFileSync(dict);
|
|
59
|
+
const bytes = new Uint8Array(dictBuf.buffer, dictBuf.byteOffset, dictBuf.byteLength);
|
|
60
|
+
return dictID !== undefined ? { bytes, id: dictID } : bytes;
|
|
61
|
+
})()
|
|
62
|
+
: undefined;
|
|
39
63
|
const outDir = path.dirname(output);
|
|
40
64
|
if (outDir) {
|
|
41
65
|
fs.mkdirSync(outDir, { recursive: true });
|
|
@@ -43,6 +67,8 @@ export const command = defineCommand({
|
|
|
43
67
|
const result = compress(data, {
|
|
44
68
|
level,
|
|
45
69
|
checksum,
|
|
70
|
+
dictionary,
|
|
71
|
+
noDictId,
|
|
46
72
|
});
|
|
47
73
|
fs.writeFileSync(output, result);
|
|
48
74
|
console.log(`Compressed ${input} -> ${output}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compress.js","sourceRoot":"","sources":["../../src/commands/compress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC;IACnC,OAAO,EAAE,2BAA2B;IACpC,QAAQ,EAAE,2BAA2B;IACrC,OAAO,EAAE,CAAC,GAAG,CAAC;IACd,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CACjB,KAAK;SACF,UAAU,CAAC,OAAO,EAAE;QACnB,QAAQ,EAAE,iBAAiB;QAC3B,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI;KACnB,CAAC;SACD,UAAU,CAAC,QAAQ,EAAE;QACpB,QAAQ,EAAE,gCAAgC;QAC1C,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI;KACnB,CAAC;SACD,MAAM,CAAC,OAAO,EAAE;QACf,QAAQ,EAAE,yDAAyD;QACnE,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,GAAG;KACX,CAAC;SACD,MAAM,CAAC,UAAU,EAAE;QAClB,QAAQ,EAAE,mCAAmC;QAC7C,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,KAAK;KACf,CAAC;IACN,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC;QACvB,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"compress.js","sourceRoot":"","sources":["../../src/commands/compress.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export declare const command: import("yargs-file-commands").DefineCommandResult<{}, {
|
|
2
|
+
output: string;
|
|
3
|
+
} & {
|
|
4
|
+
input: string[];
|
|
5
|
+
} & {
|
|
6
|
+
recursive: boolean;
|
|
7
|
+
} & {
|
|
8
|
+
maxSamples: number;
|
|
9
|
+
} & {
|
|
10
|
+
algorithm: string;
|
|
11
|
+
} & {
|
|
12
|
+
maxdict: number | undefined;
|
|
13
|
+
} & {
|
|
14
|
+
dictID: number | undefined;
|
|
15
|
+
} & {
|
|
16
|
+
k: number | undefined;
|
|
17
|
+
} & {
|
|
18
|
+
d: number | undefined;
|
|
19
|
+
} & {
|
|
20
|
+
steps: number | undefined;
|
|
21
|
+
} & {
|
|
22
|
+
split: number | undefined;
|
|
23
|
+
} & {
|
|
24
|
+
f: number | undefined;
|
|
25
|
+
} & {
|
|
26
|
+
accel: number | undefined;
|
|
27
|
+
} & {
|
|
28
|
+
selectivity: number | undefined;
|
|
29
|
+
} & {
|
|
30
|
+
shrink: unknown;
|
|
31
|
+
}>;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { defineCommand } from 'yargs-file-commands';
|
|
4
|
+
import { generateDictionary } from 'zstdify';
|
|
5
|
+
function collectFiles(inputPath, recursive, out) {
|
|
6
|
+
const stat = fs.statSync(inputPath);
|
|
7
|
+
if (stat.isFile()) {
|
|
8
|
+
out.push(inputPath);
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (!stat.isDirectory()) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const entries = fs.readdirSync(inputPath, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
15
|
+
for (const entry of entries) {
|
|
16
|
+
const fullPath = path.join(inputPath, entry.name);
|
|
17
|
+
if (entry.isFile()) {
|
|
18
|
+
out.push(fullPath);
|
|
19
|
+
}
|
|
20
|
+
else if (entry.isDirectory() && recursive) {
|
|
21
|
+
collectFiles(fullPath, recursive, out);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export const command = defineCommand({
|
|
26
|
+
command: 'dict train <output>',
|
|
27
|
+
describe: 'Train and write a dictionary from sample files',
|
|
28
|
+
builder: (yargs) => yargs
|
|
29
|
+
.positional('output', {
|
|
30
|
+
describe: 'Output dictionary file path',
|
|
31
|
+
type: 'string',
|
|
32
|
+
demandOption: true,
|
|
33
|
+
})
|
|
34
|
+
.option('input', {
|
|
35
|
+
describe: 'Input sample file or directory path (repeat for multiple)',
|
|
36
|
+
type: 'string',
|
|
37
|
+
array: true,
|
|
38
|
+
alias: 'i',
|
|
39
|
+
demandOption: true,
|
|
40
|
+
})
|
|
41
|
+
.option('recursive', {
|
|
42
|
+
describe: 'Recursively read files inside input directories',
|
|
43
|
+
type: 'boolean',
|
|
44
|
+
default: false,
|
|
45
|
+
})
|
|
46
|
+
.option('maxSamples', {
|
|
47
|
+
describe: 'Maximum number of sample files to load',
|
|
48
|
+
type: 'number',
|
|
49
|
+
default: 10_000,
|
|
50
|
+
})
|
|
51
|
+
.option('algorithm', {
|
|
52
|
+
describe: 'Training algorithm style',
|
|
53
|
+
choices: ['fastcover', 'cover', 'legacy'],
|
|
54
|
+
default: 'fastcover',
|
|
55
|
+
})
|
|
56
|
+
.option('maxdict', {
|
|
57
|
+
describe: 'Maximum dictionary size in bytes',
|
|
58
|
+
type: 'number',
|
|
59
|
+
})
|
|
60
|
+
.option('dictID', {
|
|
61
|
+
describe: 'Dictionary ID value (for metadata parity with zstd)',
|
|
62
|
+
type: 'number',
|
|
63
|
+
})
|
|
64
|
+
.option('k', { type: 'number', describe: 'Candidate segment size' })
|
|
65
|
+
.option('d', { type: 'number', describe: 'Distance step between candidate probes' })
|
|
66
|
+
.option('steps', { type: 'number', describe: 'Score refinement passes' })
|
|
67
|
+
.option('split', { type: 'number', describe: 'Percent of each sample to use (1-100)' })
|
|
68
|
+
.option('f', { type: 'number', describe: 'fastcover-style score multiplier' })
|
|
69
|
+
.option('accel', { type: 'number', describe: 'Probe stride accelerator (1-10)' })
|
|
70
|
+
.option('selectivity', { type: 'number', describe: 'legacy-style density control (1-10)' })
|
|
71
|
+
.option('shrink', {
|
|
72
|
+
describe: 'Optional shrink pass, true or numeric factor',
|
|
73
|
+
}),
|
|
74
|
+
handler: async (argv) => {
|
|
75
|
+
const { output, input, recursive, maxSamples, algorithm, maxdict, dictID, k, d, steps, split, f, accel, selectivity, shrink, } = argv;
|
|
76
|
+
const inputPaths = input ?? [];
|
|
77
|
+
const files = [];
|
|
78
|
+
for (const inputPath of inputPaths) {
|
|
79
|
+
if (!fs.existsSync(inputPath)) {
|
|
80
|
+
console.error(`Error: Input path not found: ${inputPath}`);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
collectFiles(inputPath, recursive, files);
|
|
84
|
+
if (files.length >= maxSamples)
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
if (files.length === 0) {
|
|
88
|
+
console.error('Error: No sample files found for dictionary training');
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
const selectedFiles = files.slice(0, maxSamples);
|
|
92
|
+
try {
|
|
93
|
+
const samples = selectedFiles
|
|
94
|
+
.map((filePath) => {
|
|
95
|
+
const buf = fs.readFileSync(filePath);
|
|
96
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
97
|
+
})
|
|
98
|
+
.filter((sample) => sample.length > 0);
|
|
99
|
+
if (samples.length === 0) {
|
|
100
|
+
console.error('Error: No non-empty sample files found');
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
const dictionary = generateDictionary(samples, {
|
|
104
|
+
algorithm: algorithm,
|
|
105
|
+
maxDictSize: maxdict,
|
|
106
|
+
dictId: dictID,
|
|
107
|
+
k,
|
|
108
|
+
d,
|
|
109
|
+
steps,
|
|
110
|
+
split,
|
|
111
|
+
f,
|
|
112
|
+
accel,
|
|
113
|
+
selectivity,
|
|
114
|
+
shrink: typeof shrink === 'string' ? Number(shrink) : shrink,
|
|
115
|
+
});
|
|
116
|
+
const outDir = path.dirname(output);
|
|
117
|
+
if (outDir) {
|
|
118
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
119
|
+
}
|
|
120
|
+
fs.writeFileSync(output, dictionary);
|
|
121
|
+
console.log(`Trained dictionary (${dictionary.length} bytes) -> ${output}`);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
console.error(`Error during dictionary training:`, error instanceof Error ? error.message : error);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
//# sourceMappingURL=dict.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dict.js","sourceRoot":"","sources":["../../src/commands/dict.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/extract.js
CHANGED
|
@@ -16,21 +16,40 @@ export const command = defineCommand({
|
|
|
16
16
|
describe: 'Output file path',
|
|
17
17
|
type: 'string',
|
|
18
18
|
demandOption: true,
|
|
19
|
+
})
|
|
20
|
+
.option('dict', {
|
|
21
|
+
describe: 'Dictionary file path for dictionary-compressed input',
|
|
22
|
+
type: 'string',
|
|
23
|
+
})
|
|
24
|
+
.option('dictID', {
|
|
25
|
+
describe: 'Expected dictionary ID for validation',
|
|
26
|
+
type: 'number',
|
|
19
27
|
}),
|
|
20
28
|
handler: async (argv) => {
|
|
21
|
-
const { input, output } = argv;
|
|
29
|
+
const { input, output, dict, dictID } = argv;
|
|
22
30
|
if (!fs.existsSync(input)) {
|
|
23
31
|
console.error(`Error: Input file not found: ${input}`);
|
|
24
32
|
process.exit(1);
|
|
25
33
|
}
|
|
34
|
+
if (dict && !fs.existsSync(dict)) {
|
|
35
|
+
console.error(`Error: Dictionary file not found: ${dict}`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
26
38
|
try {
|
|
27
39
|
const inputBuf = fs.readFileSync(input);
|
|
28
40
|
const data = new Uint8Array(inputBuf.buffer, inputBuf.byteOffset, inputBuf.byteLength);
|
|
41
|
+
const dictionary = dict
|
|
42
|
+
? (() => {
|
|
43
|
+
const dictBuf = fs.readFileSync(dict);
|
|
44
|
+
const bytes = new Uint8Array(dictBuf.buffer, dictBuf.byteOffset, dictBuf.byteLength);
|
|
45
|
+
return dictID !== undefined ? { bytes, id: dictID } : bytes;
|
|
46
|
+
})()
|
|
47
|
+
: undefined;
|
|
29
48
|
const outDir = path.dirname(output);
|
|
30
49
|
if (outDir) {
|
|
31
50
|
fs.mkdirSync(outDir, { recursive: true });
|
|
32
51
|
}
|
|
33
|
-
const result = decompress(data);
|
|
52
|
+
const result = decompress(data, dictionary ? { dictionary } : undefined);
|
|
34
53
|
fs.writeFileSync(output, result);
|
|
35
54
|
console.log(`Decompressed ${input} -> ${output}`);
|
|
36
55
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/commands/extract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC;IACnC,OAAO,EAAE,0BAA0B;IACnC,QAAQ,EAAE,mCAAmC;IAC7C,OAAO,EAAE,CAAC,GAAG,CAAC;IACd,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CACjB,KAAK;SACF,UAAU,CAAC,OAAO,EAAE;QACnB,QAAQ,EAAE,4BAA4B;QACtC,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI;KACnB,CAAC;SACD,UAAU,CAAC,QAAQ,EAAE;QACpB,QAAQ,EAAE,kBAAkB;QAC5B,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI;KACnB,CAAC;IACN,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC;QACvB,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/commands/extract.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zstdify-cli",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI for zstd compression and decompression using zstdify",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"yargs": "^17.7.2",
|
|
19
19
|
"yargs-file-commands": "^1.2.2",
|
|
20
|
-
"zstdify": "^1.0
|
|
20
|
+
"zstdify": "^1.1.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@types/node": "^24",
|