wyvrnpm 2.10.2 → 2.12.2

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 (49) hide show
  1. package/README.md +1914 -1860
  2. package/bin/{wyvrn.js → wyvrnpm.js} +66 -0
  3. package/cmake/cpp.cmake +9 -9
  4. package/cmake/functions.cmake +224 -224
  5. package/cmake/macros.cmake +284 -284
  6. package/package.json +3 -2
  7. package/src/auth.js +66 -66
  8. package/src/binary-dir.js +95 -0
  9. package/src/bootstrap/cookbook.js +196 -196
  10. package/src/bootstrap/detect.js +150 -150
  11. package/src/bootstrap/index.js +220 -220
  12. package/src/bootstrap/version.js +72 -72
  13. package/src/build/cache.js +344 -344
  14. package/src/build/clone.js +170 -170
  15. package/src/build/cmake.js +342 -342
  16. package/src/build/index.js +299 -297
  17. package/src/build/msvc-env.js +260 -260
  18. package/src/build/recipe.js +188 -188
  19. package/src/commands/add.js +141 -141
  20. package/src/commands/bootstrap.js +96 -96
  21. package/src/commands/build.js +482 -452
  22. package/src/commands/cache.js +189 -189
  23. package/src/commands/clean.js +80 -80
  24. package/src/commands/configure.js +92 -92
  25. package/src/commands/init.js +70 -70
  26. package/src/commands/install-skill.js +115 -115
  27. package/src/commands/install.js +730 -674
  28. package/src/commands/link.js +320 -320
  29. package/src/commands/profile.js +237 -237
  30. package/src/commands/publish.js +584 -555
  31. package/src/commands/show.js +252 -252
  32. package/src/commands/version.js +187 -0
  33. package/src/compat.js +273 -273
  34. package/src/conf/index.js +415 -391
  35. package/src/conf/namespaces.js +94 -94
  36. package/src/context.js +230 -230
  37. package/src/http-fetch.js +53 -53
  38. package/src/ignore.js +118 -118
  39. package/src/logger.js +122 -122
  40. package/src/options.js +303 -303
  41. package/src/settings-overrides.js +152 -152
  42. package/src/toolchain/deps.js +164 -164
  43. package/src/toolchain/index.js +212 -212
  44. package/src/toolchain/presets.js +356 -340
  45. package/src/toolchain/template.cmake +77 -77
  46. package/src/upload-built.js +265 -265
  47. package/src/version-range.js +301 -301
  48. package/src/zip-safe.js +52 -52
  49. package/src/zip-stream.js +126 -0
package/src/zip-safe.js CHANGED
@@ -1,52 +1,52 @@
1
- 'use strict';
2
-
3
- /**
4
- * Defense-in-depth against Zip Slip (CVE-2018-1002200 family). Both
5
- * node-stream-zip and adm-zip claim to handle this upstream, but we
6
- * don't want to take the library's word for it on a supply-chain-
7
- * critical code path. Pre-scan zip entry names before extraction and
8
- * reject anything that could write outside the target directory.
9
- *
10
- * The ZIP spec uses forward slashes only, but Windows-produced archives
11
- * sometimes leak backslashes — normalise both.
12
- *
13
- * @param {string} entryName zip-internal path as reported by the zip library
14
- * @param {string} [context] optional archive identifier for the error message
15
- * @throws {Error} if the entry name is absolute, contains a path-traversal
16
- * segment, or starts with a Windows drive-letter prefix.
17
- */
18
- function assertSafeZipEntryName(entryName, context) {
19
- const where = context ? ` in ${context}` : '';
20
-
21
- if (/^[A-Za-z]:[\\/]/.test(entryName)) {
22
- throw new Error(`unsafe zip entry${where}: drive-letter absolute path ${JSON.stringify(entryName)}`);
23
- }
24
- if (entryName.startsWith('/') || entryName.startsWith('\\')) {
25
- throw new Error(`unsafe zip entry${where}: absolute path ${JSON.stringify(entryName)}`);
26
- }
27
-
28
- const segments = entryName.split(/[\\/]+/);
29
- for (const seg of segments) {
30
- if (seg === '..') {
31
- throw new Error(`unsafe zip entry${where}: path-traversal segment in ${JSON.stringify(entryName)}`);
32
- }
33
- }
34
- }
35
-
36
- /**
37
- * Convenience: validate every name in an iterable. Throws on the first
38
- * offender (fail-fast) rather than collecting all violations.
39
- *
40
- * @param {Iterable<string>} names
41
- * @param {string} [context]
42
- */
43
- function assertAllSafeZipEntryNames(names, context) {
44
- for (const name of names) {
45
- assertSafeZipEntryName(name, context);
46
- }
47
- }
48
-
49
- module.exports = {
50
- assertSafeZipEntryName,
51
- assertAllSafeZipEntryNames,
52
- };
1
+ 'use strict';
2
+
3
+ /**
4
+ * Defense-in-depth against Zip Slip (CVE-2018-1002200 family). Both
5
+ * node-stream-zip and adm-zip claim to handle this upstream, but we
6
+ * don't want to take the library's word for it on a supply-chain-
7
+ * critical code path. Pre-scan zip entry names before extraction and
8
+ * reject anything that could write outside the target directory.
9
+ *
10
+ * The ZIP spec uses forward slashes only, but Windows-produced archives
11
+ * sometimes leak backslashes — normalise both.
12
+ *
13
+ * @param {string} entryName zip-internal path as reported by the zip library
14
+ * @param {string} [context] optional archive identifier for the error message
15
+ * @throws {Error} if the entry name is absolute, contains a path-traversal
16
+ * segment, or starts with a Windows drive-letter prefix.
17
+ */
18
+ function assertSafeZipEntryName(entryName, context) {
19
+ const where = context ? ` in ${context}` : '';
20
+
21
+ if (/^[A-Za-z]:[\\/]/.test(entryName)) {
22
+ throw new Error(`unsafe zip entry${where}: drive-letter absolute path ${JSON.stringify(entryName)}`);
23
+ }
24
+ if (entryName.startsWith('/') || entryName.startsWith('\\')) {
25
+ throw new Error(`unsafe zip entry${where}: absolute path ${JSON.stringify(entryName)}`);
26
+ }
27
+
28
+ const segments = entryName.split(/[\\/]+/);
29
+ for (const seg of segments) {
30
+ if (seg === '..') {
31
+ throw new Error(`unsafe zip entry${where}: path-traversal segment in ${JSON.stringify(entryName)}`);
32
+ }
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Convenience: validate every name in an iterable. Throws on the first
38
+ * offender (fail-fast) rather than collecting all violations.
39
+ *
40
+ * @param {Iterable<string>} names
41
+ * @param {string} [context]
42
+ */
43
+ function assertAllSafeZipEntryNames(names, context) {
44
+ for (const name of names) {
45
+ assertSafeZipEntryName(name, context);
46
+ }
47
+ }
48
+
49
+ module.exports = {
50
+ assertSafeZipEntryName,
51
+ assertAllSafeZipEntryNames,
52
+ };
@@ -0,0 +1,126 @@
1
+ 'use strict';
2
+
3
+ // Streaming zip writer. Replaces adm-zip's load-into-memory model on
4
+ // the publish + source-build write paths so multi-GB files (gRPC
5
+ // static libs, embedded test corpora, …) don't trip Node's
6
+ // `Buffer.byteLength` cap of ~2 GiB inside `fs.readFileSync`.
7
+ //
8
+ // Wraps `archiver` behind an adm-zip-compatible facade
9
+ // (`addLocalFile(fullPath, zipDir)`) so existing call sites stay
10
+ // largely unchanged — the only structural difference is that
11
+ // `finalize()` is async (the file is written progressively as entries
12
+ // are added; closing the underlying stream is what flushes the
13
+ // central directory). Adm-zip's `writeZip()` was sync and required
14
+ // holding the full archive in memory.
15
+ //
16
+ // archiver auto-promotes to ZIP64 when the archive crosses the 4 GB
17
+ // or >65535-entries thresholds, so consumers using `node-stream-zip`
18
+ // (the default extraction path in [src/download.js](download.js))
19
+ // continue to extract correctly without any special handling.
20
+ //
21
+ // adm-zip stays in deps for the consumer-side reading we still do in
22
+ // `install-skill` and the small write of `scripts/repack-skill.js`,
23
+ // where bundle sizes are measured in KB and adm-zip's API is simpler.
24
+
25
+ const fs = require('fs');
26
+ const path = require('path');
27
+ const archiver = require('archiver');
28
+
29
+ class StreamingZipWriter {
30
+ /**
31
+ * @param {string} outPath Output path for the zip file.
32
+ * @param {object} [opts]
33
+ * @param {number} [opts.compressionLevel=6] zlib level 0..9.
34
+ * archiver default is 9 (max compression). 6 is the widely-accepted
35
+ * "balanced" pick — for our artefact mix (mostly already-compressed
36
+ * binaries: .lib/.dll, JPEGs, PNGs in test fixtures), level 9 burns
37
+ * minutes for sub-percent gains over level 6. Override per-call if
38
+ * the artefact is text-heavy.
39
+ */
40
+ constructor(outPath, opts = {}) {
41
+ const { compressionLevel = 6 } = opts;
42
+
43
+ this._outPath = outPath;
44
+ this._out = fs.createWriteStream(outPath);
45
+ this._archive = archiver('zip', { zlib: { level: compressionLevel } });
46
+ this._closed = false;
47
+ this._error = null;
48
+
49
+ // Wire error propagation up front. archiver emits 'warning' for
50
+ // recoverable issues (e.g. ENOENT on a file that vanished between
51
+ // queue and read) — we propagate ALL of them rather than silently
52
+ // dropping content (CLAUDE.md §2 principle 8: silent fallback is a
53
+ // bug). adm-zip's `readFileSync` would have failed loudly in the
54
+ // same scenario; matching that behaviour here means a
55
+ // disappearing file during publish surfaces as an error rather
56
+ // than a silently-incomplete artefact.
57
+ this._archive.on('error', (err) => { this._error = err; });
58
+ this._archive.on('warning', (err) => { this._error = err; });
59
+ this._out.on('error', (err) => { this._error = err; });
60
+
61
+ this._archive.pipe(this._out);
62
+ }
63
+
64
+ /**
65
+ * Stream a file into the archive at `<zipDir>/<basename(fullPath)>`.
66
+ * adm-zip-compatible signature so existing publish/source-build
67
+ * helpers (which were written against `AdmZip#addLocalFile`) work
68
+ * without per-call refactor.
69
+ *
70
+ * No `fs.readFileSync` happens here — archiver opens a read stream
71
+ * lazily during `.finalize()`. Memory usage stays flat regardless of
72
+ * file size.
73
+ *
74
+ * @param {string} fullPath Absolute path on disk.
75
+ * @param {string} zipDir Directory inside the zip (forward
76
+ * slashes); empty string places the file at the zip root.
77
+ */
78
+ addLocalFile(fullPath, zipDir) {
79
+ if (this._error) throw this._error;
80
+ const base = path.basename(fullPath);
81
+ const name = (typeof zipDir === 'string' && zipDir.length > 0)
82
+ ? `${zipDir.replace(/\\/g, '/')}/${base}`
83
+ : base;
84
+ this._archive.file(fullPath, { name });
85
+ }
86
+
87
+ /**
88
+ * Stream a Buffer / string into the archive at the given path. Used
89
+ * for synthesised entries that aren't on disk (the publish flow
90
+ * doesn't hit this today, but it keeps parity with adm-zip's
91
+ * `addFile(path, content)` for future use).
92
+ *
93
+ * @param {string} zipPath
94
+ * @param {Buffer|string} content
95
+ */
96
+ addFile(zipPath, content) {
97
+ if (this._error) throw this._error;
98
+ this._archive.append(content, { name: zipPath.replace(/\\/g, '/') });
99
+ }
100
+
101
+ /**
102
+ * Close the archive and flush bytes to disk. Must be awaited — the
103
+ * file is not fully written until the underlying WriteStream emits
104
+ * `close`.
105
+ *
106
+ * @returns {Promise<void>}
107
+ */
108
+ finalize() {
109
+ if (this._closed) return Promise.resolve();
110
+ this._closed = true;
111
+ return new Promise((resolve, reject) => {
112
+ // Reject if any error already accumulated before finalize was called.
113
+ if (this._error) return reject(this._error);
114
+
115
+ this._out.on('close', () => {
116
+ if (this._error) reject(this._error);
117
+ else resolve();
118
+ });
119
+ this._out.on('error', reject);
120
+ this._archive.on('error', reject);
121
+ this._archive.finalize();
122
+ });
123
+ }
124
+ }
125
+
126
+ module.exports = { StreamingZipWriter };