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.
- package/README.md +1914 -1860
- package/bin/{wyvrn.js → wyvrnpm.js} +66 -0
- package/cmake/cpp.cmake +9 -9
- package/cmake/functions.cmake +224 -224
- package/cmake/macros.cmake +284 -284
- package/package.json +3 -2
- package/src/auth.js +66 -66
- package/src/binary-dir.js +95 -0
- package/src/bootstrap/cookbook.js +196 -196
- package/src/bootstrap/detect.js +150 -150
- package/src/bootstrap/index.js +220 -220
- package/src/bootstrap/version.js +72 -72
- package/src/build/cache.js +344 -344
- package/src/build/clone.js +170 -170
- package/src/build/cmake.js +342 -342
- package/src/build/index.js +299 -297
- package/src/build/msvc-env.js +260 -260
- package/src/build/recipe.js +188 -188
- package/src/commands/add.js +141 -141
- package/src/commands/bootstrap.js +96 -96
- package/src/commands/build.js +482 -452
- package/src/commands/cache.js +189 -189
- package/src/commands/clean.js +80 -80
- package/src/commands/configure.js +92 -92
- package/src/commands/init.js +70 -70
- package/src/commands/install-skill.js +115 -115
- package/src/commands/install.js +730 -674
- package/src/commands/link.js +320 -320
- package/src/commands/profile.js +237 -237
- package/src/commands/publish.js +584 -555
- package/src/commands/show.js +252 -252
- package/src/commands/version.js +187 -0
- package/src/compat.js +273 -273
- package/src/conf/index.js +415 -391
- package/src/conf/namespaces.js +94 -94
- package/src/context.js +230 -230
- package/src/http-fetch.js +53 -53
- package/src/ignore.js +118 -118
- package/src/logger.js +122 -122
- package/src/options.js +303 -303
- package/src/settings-overrides.js +152 -152
- package/src/toolchain/deps.js +164 -164
- package/src/toolchain/index.js +212 -212
- package/src/toolchain/presets.js +356 -340
- package/src/toolchain/template.cmake +77 -77
- package/src/upload-built.js +265 -265
- package/src/version-range.js +301 -301
- package/src/zip-safe.js +52 -52
- package/src/zip-stream.js +126 -0
package/src/build/clone.js
CHANGED
|
@@ -1,170 +1,170 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const { spawn } = require('child_process');
|
|
6
|
-
|
|
7
|
-
const log = require('../logger');
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Spawn a command with inherited stdio, resolve on exit 0, reject otherwise.
|
|
11
|
-
*
|
|
12
|
-
* @param {string} cmd
|
|
13
|
-
* @param {string[]} args
|
|
14
|
-
* @param {{ cwd?: string }} [opts]
|
|
15
|
-
* @returns {Promise<void>}
|
|
16
|
-
*/
|
|
17
|
-
function run(cmd, args, opts = {}) {
|
|
18
|
-
return new Promise((resolve, reject) => {
|
|
19
|
-
const proc = spawn(cmd, args, { stdio: 'inherit', ...opts });
|
|
20
|
-
proc.on('error', (err) => reject(new Error(
|
|
21
|
-
`Failed to spawn ${cmd}: ${err.message} (is it installed and on PATH?)`,
|
|
22
|
-
)));
|
|
23
|
-
proc.on('close', (code) => {
|
|
24
|
-
if (code === 0) resolve();
|
|
25
|
-
else reject(new Error(`${cmd} ${args.join(' ')} exited ${code}`));
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Ensure `gitRepo` is cloned into `destDir` at commit `gitSha`.
|
|
32
|
-
*
|
|
33
|
-
* Semantics:
|
|
34
|
-
* - If destDir does not exist → fresh clone + checkout gitSha.
|
|
35
|
-
* - If destDir exists and the HEAD commit already matches gitSha → no-op.
|
|
36
|
-
* - If destDir exists with a different HEAD → fetch + checkout the right
|
|
37
|
-
* SHA, reusing already-downloaded git objects.
|
|
38
|
-
* - If reuse fails for any reason (corrupted cache, unreachable SHA),
|
|
39
|
-
* blow away the cache and fresh-clone.
|
|
40
|
-
*
|
|
41
|
-
* Each path tries a fast shallow fetch by SHA first, then falls back to a
|
|
42
|
-
* full fetch. Some git servers disable `uploadpack.allowReachableSHA1InWant`
|
|
43
|
-
* (notably older Bitbucket Server installs), which makes direct SHA fetches
|
|
44
|
-
* fail with "upload-pack: not our ref"; the full-fetch fallback handles it.
|
|
45
|
-
*
|
|
46
|
-
* Credentials are delegated entirely to the user's ambient git config
|
|
47
|
-
* (SSH keys, credential helpers). We do NOT manage auth.
|
|
48
|
-
*
|
|
49
|
-
* @param {{ gitRepo: string, gitSha: string, destDir: string }} args
|
|
50
|
-
* @returns {Promise<void>}
|
|
51
|
-
*/
|
|
52
|
-
async function cloneAtSha({ gitRepo, gitSha, destDir }) {
|
|
53
|
-
if (!gitRepo) throw new Error('cloneAtSha: gitRepo is required');
|
|
54
|
-
if (!gitSha) throw new Error('cloneAtSha: gitSha is required');
|
|
55
|
-
|
|
56
|
-
// Reuse existing clone if possible.
|
|
57
|
-
if (fs.existsSync(path.join(destDir, '.git'))) {
|
|
58
|
-
try {
|
|
59
|
-
await reuseExistingClone({ destDir, gitSha, gitRepo });
|
|
60
|
-
return;
|
|
61
|
-
} catch (err) {
|
|
62
|
-
// An unreachable-commit error is fatal and won't be helped by rebuilding.
|
|
63
|
-
if (/not reachable/.test(err.message)) throw err;
|
|
64
|
-
log.warn(` cached clone unusable (${err.message}); rebuilding`);
|
|
65
|
-
fs.rmSync(destDir, { recursive: true, force: true });
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
await freshClone({ gitRepo, gitSha, destDir });
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Verify that `gitSha` is present and reachable in `destDir`. Throws with an
|
|
74
|
-
* actionable error message when it isn't — the common root cause is an
|
|
75
|
-
* unpushed publisher-side commit or a feature branch that was deleted after
|
|
76
|
-
* publish, leaving the commit dangling on origin.
|
|
77
|
-
*/
|
|
78
|
-
async function verifyShaPresent({ destDir, gitSha, gitRepo }) {
|
|
79
|
-
try {
|
|
80
|
-
await run('git', ['cat-file', '-e', `${gitSha}^{commit}`], { cwd: destDir });
|
|
81
|
-
} catch {
|
|
82
|
-
throw new Error(
|
|
83
|
-
`commit ${gitSha.slice(0, 12)} is not reachable from any branch or tag on ${gitRepo}. ` +
|
|
84
|
-
`Likely cause: the publisher's HEAD was not pushed, OR the commit was on a ` +
|
|
85
|
-
`feature branch that was deleted/squash-merged after publish. ` +
|
|
86
|
-
`Fix: the package maintainer should republish from a commit that is pushed ` +
|
|
87
|
-
`and reachable from a remote branch or tag.`,
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Checkout `gitSha` in an existing clone. Tries shallow-SHA fetch first,
|
|
94
|
-
* then full fetch (+ tags), then verifies reachability before checkout.
|
|
95
|
-
*/
|
|
96
|
-
async function reuseExistingClone({ destDir, gitSha, gitRepo }) {
|
|
97
|
-
const current = await getHeadSha(destDir);
|
|
98
|
-
if (current === gitSha) return;
|
|
99
|
-
|
|
100
|
-
log.info(` reusing existing clone, switching to ${gitSha.slice(0, 12)}`);
|
|
101
|
-
try {
|
|
102
|
-
// Fast path: shallow fetch the specific SHA directly.
|
|
103
|
-
await run('git', ['fetch', '--depth', '1', 'origin', gitSha], { cwd: destDir });
|
|
104
|
-
} catch {
|
|
105
|
-
// Fallback: full fetch + tags. Fetching tags catches commits that live
|
|
106
|
-
// only under `refs/tags/*` — e.g. a release commit whose branch was
|
|
107
|
-
// deleted but whose tag remains.
|
|
108
|
-
log.info(' shallow SHA fetch unsupported by server; fetching all refs + tags (slower)');
|
|
109
|
-
await run('git', ['fetch', '--tags', 'origin'], { cwd: destDir });
|
|
110
|
-
}
|
|
111
|
-
await verifyShaPresent({ destDir, gitSha, gitRepo });
|
|
112
|
-
await run('git', ['checkout', '--detach', gitSha], { cwd: destDir });
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Fresh clone. Tries `init + remote add + shallow-fetch <sha>` first, falls
|
|
117
|
-
* back to a full `git clone --tags` if the server refuses direct-SHA
|
|
118
|
-
* fetches. Verifies the commit is reachable before attempting checkout so
|
|
119
|
-
* the failure mode is a clear error rather than a cryptic `unable to read
|
|
120
|
-
* tree`.
|
|
121
|
-
*/
|
|
122
|
-
async function freshClone({ gitRepo, gitSha, destDir }) {
|
|
123
|
-
fs.mkdirSync(destDir, { recursive: true });
|
|
124
|
-
log.info(` cloning ${gitRepo} at ${gitSha.slice(0, 12)} → ${destDir}`);
|
|
125
|
-
try {
|
|
126
|
-
await run('git', ['init', '--quiet'], { cwd: destDir });
|
|
127
|
-
await run('git', ['remote', 'add', 'origin', gitRepo], { cwd: destDir });
|
|
128
|
-
await run('git', ['fetch', '--depth', '1', 'origin', gitSha], { cwd: destDir });
|
|
129
|
-
await verifyShaPresent({ destDir, gitSha, gitRepo });
|
|
130
|
-
await run('git', ['checkout', '--detach', gitSha], { cwd: destDir });
|
|
131
|
-
} catch (err) {
|
|
132
|
-
// If the shallow-SHA fetch itself failed (server refuses it), fall
|
|
133
|
-
// through to a full clone. If instead the SHA-reachability check failed,
|
|
134
|
-
// re-throw with the actionable message — a full clone wouldn't help.
|
|
135
|
-
if (/not reachable/.test(err.message)) throw err;
|
|
136
|
-
|
|
137
|
-
log.warn(` shallow fetch by SHA failed (${err.message}); falling back to full clone`);
|
|
138
|
-
fs.rmSync(destDir, { recursive: true, force: true });
|
|
139
|
-
fs.mkdirSync(destDir, { recursive: true });
|
|
140
|
-
// `--tags` brings down tag refs in the same round-trip so tag-only
|
|
141
|
-
// commits are reachable too.
|
|
142
|
-
await run('git', ['clone', '--quiet', '--tags', gitRepo, '.'], { cwd: destDir });
|
|
143
|
-
await verifyShaPresent({ destDir, gitSha, gitRepo });
|
|
144
|
-
await run('git', ['checkout', '--detach', gitSha], { cwd: destDir });
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Return the current HEAD commit SHA of a git working tree, or null on error.
|
|
150
|
-
* @param {string} dir
|
|
151
|
-
* @returns {Promise<string|null>}
|
|
152
|
-
*/
|
|
153
|
-
function getHeadSha(dir) {
|
|
154
|
-
return new Promise((resolve) => {
|
|
155
|
-
const proc = spawn('git', ['rev-parse', 'HEAD'], {
|
|
156
|
-
cwd: dir,
|
|
157
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
158
|
-
});
|
|
159
|
-
let out = '';
|
|
160
|
-
proc.stdout.on('data', (c) => { out += c.toString(); });
|
|
161
|
-
proc.on('error', () => resolve(null));
|
|
162
|
-
proc.on('close', (code) => {
|
|
163
|
-
if (code !== 0) return resolve(null);
|
|
164
|
-
const sha = out.trim();
|
|
165
|
-
resolve(/^[0-9a-f]{40}$/i.test(sha) ? sha : null);
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
module.exports = { cloneAtSha, getHeadSha };
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { spawn } = require('child_process');
|
|
6
|
+
|
|
7
|
+
const log = require('../logger');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Spawn a command with inherited stdio, resolve on exit 0, reject otherwise.
|
|
11
|
+
*
|
|
12
|
+
* @param {string} cmd
|
|
13
|
+
* @param {string[]} args
|
|
14
|
+
* @param {{ cwd?: string }} [opts]
|
|
15
|
+
* @returns {Promise<void>}
|
|
16
|
+
*/
|
|
17
|
+
function run(cmd, args, opts = {}) {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
const proc = spawn(cmd, args, { stdio: 'inherit', ...opts });
|
|
20
|
+
proc.on('error', (err) => reject(new Error(
|
|
21
|
+
`Failed to spawn ${cmd}: ${err.message} (is it installed and on PATH?)`,
|
|
22
|
+
)));
|
|
23
|
+
proc.on('close', (code) => {
|
|
24
|
+
if (code === 0) resolve();
|
|
25
|
+
else reject(new Error(`${cmd} ${args.join(' ')} exited ${code}`));
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Ensure `gitRepo` is cloned into `destDir` at commit `gitSha`.
|
|
32
|
+
*
|
|
33
|
+
* Semantics:
|
|
34
|
+
* - If destDir does not exist → fresh clone + checkout gitSha.
|
|
35
|
+
* - If destDir exists and the HEAD commit already matches gitSha → no-op.
|
|
36
|
+
* - If destDir exists with a different HEAD → fetch + checkout the right
|
|
37
|
+
* SHA, reusing already-downloaded git objects.
|
|
38
|
+
* - If reuse fails for any reason (corrupted cache, unreachable SHA),
|
|
39
|
+
* blow away the cache and fresh-clone.
|
|
40
|
+
*
|
|
41
|
+
* Each path tries a fast shallow fetch by SHA first, then falls back to a
|
|
42
|
+
* full fetch. Some git servers disable `uploadpack.allowReachableSHA1InWant`
|
|
43
|
+
* (notably older Bitbucket Server installs), which makes direct SHA fetches
|
|
44
|
+
* fail with "upload-pack: not our ref"; the full-fetch fallback handles it.
|
|
45
|
+
*
|
|
46
|
+
* Credentials are delegated entirely to the user's ambient git config
|
|
47
|
+
* (SSH keys, credential helpers). We do NOT manage auth.
|
|
48
|
+
*
|
|
49
|
+
* @param {{ gitRepo: string, gitSha: string, destDir: string }} args
|
|
50
|
+
* @returns {Promise<void>}
|
|
51
|
+
*/
|
|
52
|
+
async function cloneAtSha({ gitRepo, gitSha, destDir }) {
|
|
53
|
+
if (!gitRepo) throw new Error('cloneAtSha: gitRepo is required');
|
|
54
|
+
if (!gitSha) throw new Error('cloneAtSha: gitSha is required');
|
|
55
|
+
|
|
56
|
+
// Reuse existing clone if possible.
|
|
57
|
+
if (fs.existsSync(path.join(destDir, '.git'))) {
|
|
58
|
+
try {
|
|
59
|
+
await reuseExistingClone({ destDir, gitSha, gitRepo });
|
|
60
|
+
return;
|
|
61
|
+
} catch (err) {
|
|
62
|
+
// An unreachable-commit error is fatal and won't be helped by rebuilding.
|
|
63
|
+
if (/not reachable/.test(err.message)) throw err;
|
|
64
|
+
log.warn(` cached clone unusable (${err.message}); rebuilding`);
|
|
65
|
+
fs.rmSync(destDir, { recursive: true, force: true });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
await freshClone({ gitRepo, gitSha, destDir });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Verify that `gitSha` is present and reachable in `destDir`. Throws with an
|
|
74
|
+
* actionable error message when it isn't — the common root cause is an
|
|
75
|
+
* unpushed publisher-side commit or a feature branch that was deleted after
|
|
76
|
+
* publish, leaving the commit dangling on origin.
|
|
77
|
+
*/
|
|
78
|
+
async function verifyShaPresent({ destDir, gitSha, gitRepo }) {
|
|
79
|
+
try {
|
|
80
|
+
await run('git', ['cat-file', '-e', `${gitSha}^{commit}`], { cwd: destDir });
|
|
81
|
+
} catch {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`commit ${gitSha.slice(0, 12)} is not reachable from any branch or tag on ${gitRepo}. ` +
|
|
84
|
+
`Likely cause: the publisher's HEAD was not pushed, OR the commit was on a ` +
|
|
85
|
+
`feature branch that was deleted/squash-merged after publish. ` +
|
|
86
|
+
`Fix: the package maintainer should republish from a commit that is pushed ` +
|
|
87
|
+
`and reachable from a remote branch or tag.`,
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Checkout `gitSha` in an existing clone. Tries shallow-SHA fetch first,
|
|
94
|
+
* then full fetch (+ tags), then verifies reachability before checkout.
|
|
95
|
+
*/
|
|
96
|
+
async function reuseExistingClone({ destDir, gitSha, gitRepo }) {
|
|
97
|
+
const current = await getHeadSha(destDir);
|
|
98
|
+
if (current === gitSha) return;
|
|
99
|
+
|
|
100
|
+
log.info(` reusing existing clone, switching to ${gitSha.slice(0, 12)}`);
|
|
101
|
+
try {
|
|
102
|
+
// Fast path: shallow fetch the specific SHA directly.
|
|
103
|
+
await run('git', ['fetch', '--depth', '1', 'origin', gitSha], { cwd: destDir });
|
|
104
|
+
} catch {
|
|
105
|
+
// Fallback: full fetch + tags. Fetching tags catches commits that live
|
|
106
|
+
// only under `refs/tags/*` — e.g. a release commit whose branch was
|
|
107
|
+
// deleted but whose tag remains.
|
|
108
|
+
log.info(' shallow SHA fetch unsupported by server; fetching all refs + tags (slower)');
|
|
109
|
+
await run('git', ['fetch', '--tags', 'origin'], { cwd: destDir });
|
|
110
|
+
}
|
|
111
|
+
await verifyShaPresent({ destDir, gitSha, gitRepo });
|
|
112
|
+
await run('git', ['checkout', '--detach', gitSha], { cwd: destDir });
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Fresh clone. Tries `init + remote add + shallow-fetch <sha>` first, falls
|
|
117
|
+
* back to a full `git clone --tags` if the server refuses direct-SHA
|
|
118
|
+
* fetches. Verifies the commit is reachable before attempting checkout so
|
|
119
|
+
* the failure mode is a clear error rather than a cryptic `unable to read
|
|
120
|
+
* tree`.
|
|
121
|
+
*/
|
|
122
|
+
async function freshClone({ gitRepo, gitSha, destDir }) {
|
|
123
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
124
|
+
log.info(` cloning ${gitRepo} at ${gitSha.slice(0, 12)} → ${destDir}`);
|
|
125
|
+
try {
|
|
126
|
+
await run('git', ['init', '--quiet'], { cwd: destDir });
|
|
127
|
+
await run('git', ['remote', 'add', 'origin', gitRepo], { cwd: destDir });
|
|
128
|
+
await run('git', ['fetch', '--depth', '1', 'origin', gitSha], { cwd: destDir });
|
|
129
|
+
await verifyShaPresent({ destDir, gitSha, gitRepo });
|
|
130
|
+
await run('git', ['checkout', '--detach', gitSha], { cwd: destDir });
|
|
131
|
+
} catch (err) {
|
|
132
|
+
// If the shallow-SHA fetch itself failed (server refuses it), fall
|
|
133
|
+
// through to a full clone. If instead the SHA-reachability check failed,
|
|
134
|
+
// re-throw with the actionable message — a full clone wouldn't help.
|
|
135
|
+
if (/not reachable/.test(err.message)) throw err;
|
|
136
|
+
|
|
137
|
+
log.warn(` shallow fetch by SHA failed (${err.message}); falling back to full clone`);
|
|
138
|
+
fs.rmSync(destDir, { recursive: true, force: true });
|
|
139
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
140
|
+
// `--tags` brings down tag refs in the same round-trip so tag-only
|
|
141
|
+
// commits are reachable too.
|
|
142
|
+
await run('git', ['clone', '--quiet', '--tags', gitRepo, '.'], { cwd: destDir });
|
|
143
|
+
await verifyShaPresent({ destDir, gitSha, gitRepo });
|
|
144
|
+
await run('git', ['checkout', '--detach', gitSha], { cwd: destDir });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Return the current HEAD commit SHA of a git working tree, or null on error.
|
|
150
|
+
* @param {string} dir
|
|
151
|
+
* @returns {Promise<string|null>}
|
|
152
|
+
*/
|
|
153
|
+
function getHeadSha(dir) {
|
|
154
|
+
return new Promise((resolve) => {
|
|
155
|
+
const proc = spawn('git', ['rev-parse', 'HEAD'], {
|
|
156
|
+
cwd: dir,
|
|
157
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
158
|
+
});
|
|
159
|
+
let out = '';
|
|
160
|
+
proc.stdout.on('data', (c) => { out += c.toString(); });
|
|
161
|
+
proc.on('error', () => resolve(null));
|
|
162
|
+
proc.on('close', (code) => {
|
|
163
|
+
if (code !== 0) return resolve(null);
|
|
164
|
+
const sha = out.trim();
|
|
165
|
+
resolve(/^[0-9a-f]{40}$/i.test(sha) ? sha : null);
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
module.exports = { cloneAtSha, getHeadSha };
|