wyvrnpm 2.8.1 → 2.9.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 +19 -4
- package/bin/wyvrn.js +15 -2
- package/claude/skills/wyvrnpm.skill +0 -0
- package/package.json +1 -1
- package/src/build/index.js +3 -2
- package/src/commands/add.js +2 -1
- package/src/commands/build.js +109 -44
- package/src/commands/install.js +674 -665
- package/src/commands/link.js +320 -319
- package/src/commands/profile.js +237 -237
- package/src/commands/publish.js +435 -420
- package/src/commands/show.js +18 -13
- package/src/context.js +230 -0
- package/src/http-fetch.js +53 -0
- package/src/providers/file.js +5 -19
- package/src/providers/http.js +26 -26
- package/src/providers/s3.js +29 -25
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ A simple, private C++ package manager that works with any static file hosting pr
|
|
|
4
4
|
|
|
5
5
|
There is no central registry. You control where packages are hosted.
|
|
6
6
|
|
|
7
|
-
> **README version: 2.8.
|
|
7
|
+
> **README version: 2.8.3** — Highlights since 2.4.0: non-ABI build-time `conf` block (CMake cache variables via recipe / team profile / `wyvrn.local.json` / CLI `--conf`), per-package `source` pin for multi-source defense, profile inheritance via `extends`, pattern-based `settingsOverrides` (`boost*: {...}`), `wyvrnpm cache list` / `cache prune` for selective source-build-cache cleanup, `install --dry-run` (JSON plan without side effects), `install --build=always` to force source-rebuild, `--token-env` for CI credentials, CloudFront/WAF-compatible HTTP provider (sends `User-Agent`, surfaces non-404 errors), publish preserves dependency ranges verbatim with lock snapshot moved to informational `publishedLock`, and a raft of security hardening (Zip Slip, MSVC arch allow-list). Full list in `claude/EVALUATION.md`.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -285,6 +285,13 @@ wyvrnpm build
|
|
|
285
285
|
# Build Debug, verbose compiler output
|
|
286
286
|
wyvrnpm build --config Debug --verbose
|
|
287
287
|
|
|
288
|
+
# Build multiple configs in one go — configure runs once, build loops per config
|
|
289
|
+
wyvrnpm build --config Debug,Release --install
|
|
290
|
+
|
|
291
|
+
# Build every config the recipe declares (recipe's build.configs, or all four
|
|
292
|
+
# canonical configs if no recipe is present). Pairs naturally with --install.
|
|
293
|
+
wyvrnpm build --all-configs --install
|
|
294
|
+
|
|
288
295
|
# Use a specific profile's preset
|
|
289
296
|
wyvrnpm build --profile release
|
|
290
297
|
|
|
@@ -318,7 +325,8 @@ wyvrnpm build -- -j 8
|
|
|
318
325
|
|---|---|---|
|
|
319
326
|
| `--preset` / `-P` | `wyvrn-<profile>` | CMake configure preset name. |
|
|
320
327
|
| `--profile` / `-p` | *(config / "default")* | Build profile — determines the default preset name. |
|
|
321
|
-
| `--config` / `-c` | `Release` | Build configuration (`Debug` \| `Release` \| `RelWithDebInfo` \| `MinSizeRel`). |
|
|
328
|
+
| `--config` / `-c` | `Release` | Build configuration (`Debug` \| `Release` \| `RelWithDebInfo` \| `MinSizeRel`). Comma-separated to build multiple in one invocation (e.g. `Debug,Release`) — configure runs once, build (+ `--install`) loops per config. |
|
|
329
|
+
| `--all-configs` | `false` | Build every config from the recipe's `build.configs` (or all four canonical configs when no recipe is present). Takes precedence over `--config`. |
|
|
322
330
|
| `--target` / `-t` | *(all)* | Specific CMake target to build. |
|
|
323
331
|
| `--verbose` / `-v` | `false` | Pass `--verbose` to `cmake --build`. |
|
|
324
332
|
| `--clean` | `false` | Remove the build directory before configuring. |
|
|
@@ -546,8 +554,6 @@ You only need this if you want Claude Code to pick up the skill. The CLI itself
|
|
|
546
554
|
| `--force` | `false` | Overwrite an existing skill install. Without it, the command refuses to clobber. |
|
|
547
555
|
| `--dry-run` | `false` | Print the destination paths and intended actions without writing. |
|
|
548
556
|
|
|
549
|
-
**CLAUDE.md §9 note for contributors:** the tested path for deploying a locally-edited skill is `node scripts/repack-skill.js && node bin/wyvrn.js install-skill --claude --force` — never `rm -rf` + `cp -r`.
|
|
550
|
-
|
|
551
557
|
---
|
|
552
558
|
|
|
553
559
|
### `wyvrnpm link`
|
|
@@ -1736,6 +1742,15 @@ wyvrnpm build --install --install-prefix C:\out\stage
|
|
|
1736
1742
|
|
|
1737
1743
|
# Install a specific config
|
|
1738
1744
|
wyvrnpm build --install --config Debug
|
|
1745
|
+
|
|
1746
|
+
# Install multiple configs in one invocation — configure runs once,
|
|
1747
|
+
# build + install loops per config. Before 2.9.0 this required two
|
|
1748
|
+
# separate `wyvrnpm build --install ...` invocations.
|
|
1749
|
+
wyvrnpm build --install --config Debug,Release
|
|
1750
|
+
|
|
1751
|
+
# Install every config declared in the recipe's build.configs
|
|
1752
|
+
# (or all four canonical configs when no recipe is present).
|
|
1753
|
+
wyvrnpm build --install --all-configs
|
|
1739
1754
|
```
|
|
1740
1755
|
|
|
1741
1756
|
### What it does, in order
|
package/bin/wyvrn.js
CHANGED
|
@@ -191,9 +191,21 @@ yargs
|
|
|
191
191
|
.option('config', {
|
|
192
192
|
alias: 'c',
|
|
193
193
|
type: 'string',
|
|
194
|
-
choices: ['Debug', 'Release', 'RelWithDebInfo', 'MinSizeRel'],
|
|
195
194
|
default: 'Release',
|
|
196
|
-
description:
|
|
195
|
+
description:
|
|
196
|
+
'Build configuration. Accepts a single value (Release) or a ' +
|
|
197
|
+
'comma-separated list (Debug,Release) to build multiple configs ' +
|
|
198
|
+
'in one invocation — configure runs once, build (+ --install) ' +
|
|
199
|
+
'loops per config. Valid: Debug | Release | RelWithDebInfo | MinSizeRel.',
|
|
200
|
+
})
|
|
201
|
+
.option('all-configs', {
|
|
202
|
+
type: 'boolean',
|
|
203
|
+
default: false,
|
|
204
|
+
description:
|
|
205
|
+
'Build every config declared in the recipe\'s build.configs ' +
|
|
206
|
+
'(falls back to all four canonical configs when no recipe is ' +
|
|
207
|
+
'present). Equivalent to spelling out --config Debug,Release,... ' +
|
|
208
|
+
'by hand. Pairs naturally with --install.',
|
|
197
209
|
})
|
|
198
210
|
.option('target', {
|
|
199
211
|
alias: 't',
|
|
@@ -262,6 +274,7 @@ yargs
|
|
|
262
274
|
...argv,
|
|
263
275
|
autoInstall: argv['auto-install'],
|
|
264
276
|
installPrefix: argv['install-prefix'],
|
|
277
|
+
allConfigs: argv['all-configs'],
|
|
265
278
|
}),
|
|
266
279
|
)
|
|
267
280
|
|
|
Binary file
|
package/package.json
CHANGED
package/src/build/index.js
CHANGED
|
@@ -15,6 +15,7 @@ const { hashProfile, mergeProfile, sha256Of } = require('../profile');
|
|
|
15
15
|
const { generateToolchain } = require('../toolchain');
|
|
16
16
|
const { normalizeOptionsDeclaration, resolveEffectiveOptions } = require('../options');
|
|
17
17
|
const { readRecipeConf, cmakeCacheVariables } = require('../conf');
|
|
18
|
+
const { wyvrnFetch } = require('../http-fetch');
|
|
18
19
|
const log = require('../logger');
|
|
19
20
|
|
|
20
21
|
/**
|
|
@@ -195,7 +196,7 @@ async function buildFromSource(args) {
|
|
|
195
196
|
log.info(` resolving ${Object.keys(depsForResolution).length} transitive dep(s)`);
|
|
196
197
|
const transitiveManifests = new Map();
|
|
197
198
|
const resolvedDeps = await resolveDependencies(
|
|
198
|
-
depsForResolution, packageSources, platform,
|
|
199
|
+
depsForResolution, packageSources, platform, wyvrnFetch, new Map(),
|
|
199
200
|
transitiveManifests,
|
|
200
201
|
);
|
|
201
202
|
|
|
@@ -231,7 +232,7 @@ async function buildFromSource(args) {
|
|
|
231
232
|
if (enrichedDeps.size > 0) {
|
|
232
233
|
await downloadDependencies(
|
|
233
234
|
enrichedDeps, packageSources, platform, paths.internal,
|
|
234
|
-
|
|
235
|
+
wyvrnFetch, Math.max(30, Math.round(timeoutMs / 1000)),
|
|
235
236
|
{ ...authOptions, buildMode },
|
|
236
237
|
);
|
|
237
238
|
} else {
|
package/src/commands/add.js
CHANGED
|
@@ -5,6 +5,7 @@ const path = require('path');
|
|
|
5
5
|
const { readManifest, writeManifest } = require('../manifest');
|
|
6
6
|
const { resolveLatestVersion } = require('../resolve');
|
|
7
7
|
const { readConfig } = require('../config');
|
|
8
|
+
const { wyvrnFetch } = require('../http-fetch');
|
|
8
9
|
const log = require('../logger');
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -99,7 +100,7 @@ async function add(argv) {
|
|
|
99
100
|
versionToWrite = spec.version;
|
|
100
101
|
log.info(`${spec.name}: writing "${versionToWrite}" (as given)`);
|
|
101
102
|
} else {
|
|
102
|
-
const latest = await resolveLatestVersion(spec.name, packageSources, argv.platform,
|
|
103
|
+
const latest = await resolveLatestVersion(spec.name, packageSources, argv.platform, wyvrnFetch);
|
|
103
104
|
versionToWrite = `^${latest}`;
|
|
104
105
|
log.info(`${spec.name}: latest is ${latest} → writing "${versionToWrite}"`);
|
|
105
106
|
}
|
package/src/commands/build.js
CHANGED
|
@@ -4,14 +4,11 @@ const fs = require('fs');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const { spawn } = require('child_process');
|
|
6
6
|
|
|
7
|
-
const {
|
|
8
|
-
const { loadProfile } = require('../profile');
|
|
9
|
-
const { readManifest } = require('../manifest');
|
|
10
|
-
const { normalizeRecipe, hasBuildRecipe } = require('../build/recipe');
|
|
7
|
+
const { normalizeRecipe, hasBuildRecipe, VALID_CMAKE_CONFIGS, DEFAULT_RECIPE } = require('../build/recipe');
|
|
11
8
|
const { loadMsvcEnv } = require('../build/msvc-env');
|
|
12
9
|
const { archToVsPlatform, isVisualStudioGenerator } = require('../toolchain');
|
|
13
|
-
const { parseCliConf } = require('../conf');
|
|
14
10
|
const { LOCAL_OVERLAY_FILENAME } = require('../conf');
|
|
11
|
+
const { buildContext } = require('../context');
|
|
15
12
|
const install = require('./install');
|
|
16
13
|
const log = require('../logger');
|
|
17
14
|
|
|
@@ -141,6 +138,51 @@ function buildConfigureArgs({
|
|
|
141
138
|
return args;
|
|
142
139
|
}
|
|
143
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Resolve the list of CMake configs to build (and optionally install).
|
|
143
|
+
*
|
|
144
|
+
* Precedence:
|
|
145
|
+
* 1. `--all-configs` → recipe.configs (falls back to all four canonical
|
|
146
|
+
* configs when no recipe declares any).
|
|
147
|
+
* 2. `--config` → comma-separated list, validated against
|
|
148
|
+
* VALID_CMAKE_CONFIGS. Order preserved. Duplicates removed.
|
|
149
|
+
* 3. default → `['Release']`.
|
|
150
|
+
*
|
|
151
|
+
* Configure runs once per `wyvrnpm build` invocation regardless — multi-
|
|
152
|
+
* config generators (VS, Xcode, Ninja Multi-Config) produce all configs
|
|
153
|
+
* from one configure step. Single-config generators (plain Ninja, Make)
|
|
154
|
+
* bake CMAKE_BUILD_TYPE into the cache, so `cmake --build --config X`
|
|
155
|
+
* effectively ignores X for them; building two configs against a single-
|
|
156
|
+
* config generator rebuilds the same binary twice. That's wasteful but
|
|
157
|
+
* correct; fixing it properly requires per-config build dirs, which is
|
|
158
|
+
* out of scope for this helper.
|
|
159
|
+
*
|
|
160
|
+
* @param {{ argv: object, recipeConfigs?: string[] }} args
|
|
161
|
+
* @returns {string[]}
|
|
162
|
+
*/
|
|
163
|
+
function resolveConfigList({ argv, recipeConfigs = null }) {
|
|
164
|
+
if (argv.allConfigs) {
|
|
165
|
+
const fromRecipe = (recipeConfigs ?? []).filter((c) => VALID_CMAKE_CONFIGS.has(c));
|
|
166
|
+
return fromRecipe.length > 0 ? [...fromRecipe] : [...DEFAULT_RECIPE.configs];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const raw = typeof argv.config === 'string' && argv.config.trim() ? argv.config : 'Release';
|
|
170
|
+
const list = raw.split(',').map((s) => s.trim()).filter(Boolean);
|
|
171
|
+
|
|
172
|
+
const invalid = list.filter((c) => !VALID_CMAKE_CONFIGS.has(c));
|
|
173
|
+
if (invalid.length > 0) {
|
|
174
|
+
const valid = [...VALID_CMAKE_CONFIGS].join(' | ');
|
|
175
|
+
throw new Error(`invalid --config "${invalid.join(', ')}" — expected ${valid}`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const seen = new Set();
|
|
179
|
+
const deduped = [];
|
|
180
|
+
for (const c of list) {
|
|
181
|
+
if (!seen.has(c)) { seen.add(c); deduped.push(c); }
|
|
182
|
+
}
|
|
183
|
+
return deduped.length > 0 ? deduped : ['Release'];
|
|
184
|
+
}
|
|
185
|
+
|
|
144
186
|
/**
|
|
145
187
|
* Args passed to `cmake` for the build step.
|
|
146
188
|
*
|
|
@@ -225,13 +267,34 @@ function runCmake(args, env = null) {
|
|
|
225
267
|
* @param {object} argv
|
|
226
268
|
*/
|
|
227
269
|
async function build(argv) {
|
|
228
|
-
|
|
229
|
-
|
|
270
|
+
// Shared per-invocation state. See src/context.js +
|
|
271
|
+
// claude/PLAN-COMMAND-CONTEXT.md. Parses --conf up front so a malformed
|
|
272
|
+
// flag fails here instead of after cmake's already configured.
|
|
273
|
+
let ctx;
|
|
274
|
+
try {
|
|
275
|
+
ctx = buildContext(argv);
|
|
276
|
+
} catch (err) {
|
|
277
|
+
log.error(err.message);
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
230
280
|
|
|
231
|
-
const
|
|
232
|
-
const profileName
|
|
281
|
+
const { rootDir, manifestPath } = ctx;
|
|
282
|
+
const { name: profileName, profile: activeProfile } = ctx.profiles.host;
|
|
233
283
|
const presetName = resolvePresetName({ presetOverride: argv.preset, profileName });
|
|
234
|
-
|
|
284
|
+
|
|
285
|
+
// Resolve the list of configs up front so a malformed --config fails
|
|
286
|
+
// before auto-install kicks off. `--all-configs` consults the recipe
|
|
287
|
+
// (if any); otherwise comma-separated --config, defaulting to Release.
|
|
288
|
+
let configList;
|
|
289
|
+
try {
|
|
290
|
+
const recipe = hasBuildRecipe(ctx.manifest)
|
|
291
|
+
? (() => { try { return normalizeRecipe(ctx.manifest.build, null); } catch { return null; } })()
|
|
292
|
+
: null;
|
|
293
|
+
configList = resolveConfigList({ argv, recipeConfigs: recipe?.configs ?? null });
|
|
294
|
+
} catch (err) {
|
|
295
|
+
log.error(err.message);
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
235
298
|
|
|
236
299
|
// ── Stale check / auto-install ────────────────────────────────────────────
|
|
237
300
|
// `--auto-install` gates the "run `wyvrnpm install` first when the
|
|
@@ -278,13 +341,12 @@ async function build(argv) {
|
|
|
278
341
|
let effectiveGenerator = argv.generator ?? null;
|
|
279
342
|
let effectiveProfile = null;
|
|
280
343
|
try {
|
|
281
|
-
const { profile: activeProfile } = loadProfile(profileName);
|
|
282
344
|
effectiveProfile = activeProfile;
|
|
283
345
|
// Which generator will the preset actually use? Read it from the
|
|
284
346
|
// project's own recipe if one exists. If not, default to null and let
|
|
285
347
|
// cmake/CMakePresets decide — in which case MSVC env activation is
|
|
286
348
|
// skipped (because VS is usually the default on Windows).
|
|
287
|
-
const manifest =
|
|
349
|
+
const manifest = ctx.manifest;
|
|
288
350
|
let presetGenerator = null;
|
|
289
351
|
if (hasBuildRecipe(manifest)) {
|
|
290
352
|
try {
|
|
@@ -321,16 +383,10 @@ async function build(argv) {
|
|
|
321
383
|
// CLI --conf → -D / -U passthrough (PLAN-CONF.md §7). The preset's
|
|
322
384
|
// baked-in cacheVariables (from the last install) already reflect the
|
|
323
385
|
// recipe + local-overlay layers; CLI conf layers on top for this
|
|
324
|
-
// invocation only.
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
cliConfSets = cli.sets;
|
|
329
|
-
cliConfUnsets = cli.unsets;
|
|
330
|
-
} catch (err) {
|
|
331
|
-
log.error(`--conf parse error: ${err.message}`);
|
|
332
|
-
process.exit(1);
|
|
333
|
-
}
|
|
386
|
+
// invocation only. ctx.cliConf is pre-parsed by buildContext; malformed
|
|
387
|
+
// values already threw above.
|
|
388
|
+
const cliConfSets = ctx.cliConf.sets;
|
|
389
|
+
const cliConfUnsets = ctx.cliConf.unsets;
|
|
334
390
|
|
|
335
391
|
const configureArgs = buildConfigureArgs({
|
|
336
392
|
presetName,
|
|
@@ -342,35 +398,43 @@ async function build(argv) {
|
|
|
342
398
|
log.info(`cmake ${configureArgs.join(' ')}`);
|
|
343
399
|
await runCmake(configureArgs, cmakeEnv);
|
|
344
400
|
|
|
345
|
-
// ── Build
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
// defaults to whatever was baked into the cache at configure time; pass
|
|
359
|
-
// `--install-prefix` to override without reconfiguring.
|
|
360
|
-
if (argv.install) {
|
|
361
|
-
const installArgs = buildInstallArgs({
|
|
401
|
+
// ── Build (+ optional install) per config ─────────────────────────────────
|
|
402
|
+
// Configure ran once above. Multi-config generators (VS, Xcode, Ninja
|
|
403
|
+
// Multi-Config) produce every config from that one configure step; for
|
|
404
|
+
// single-config generators each iteration simply re-`cmake --build`s the
|
|
405
|
+
// same baked CMAKE_BUILD_TYPE (harmless duplication). `--install` runs
|
|
406
|
+
// per config too — the usual reason to want multi-config is so that a
|
|
407
|
+
// downstream `find_package()` can pick whichever it needs.
|
|
408
|
+
if (configList.length > 1) {
|
|
409
|
+
log.info(`Building ${configList.length} configs: ${configList.join(', ')}`);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
for (const config of configList) {
|
|
413
|
+
const buildArgs = buildBuildArgs({
|
|
362
414
|
binaryDir,
|
|
363
|
-
config
|
|
364
|
-
|
|
415
|
+
config,
|
|
416
|
+
target: argv.target,
|
|
417
|
+
verbose: argv.verbose,
|
|
418
|
+
passthru: argv['--'] ?? [],
|
|
365
419
|
});
|
|
366
|
-
log.info(`cmake ${
|
|
367
|
-
await runCmake(
|
|
420
|
+
log.info(`cmake ${buildArgs.join(' ')}`);
|
|
421
|
+
await runCmake(buildArgs, cmakeEnv);
|
|
422
|
+
|
|
423
|
+
if (argv.install) {
|
|
424
|
+
const installArgs = buildInstallArgs({
|
|
425
|
+
binaryDir,
|
|
426
|
+
config,
|
|
427
|
+
prefix: argv.installPrefix,
|
|
428
|
+
});
|
|
429
|
+
log.info(`cmake ${installArgs.join(' ')}`);
|
|
430
|
+
await runCmake(installArgs, cmakeEnv);
|
|
431
|
+
}
|
|
368
432
|
}
|
|
369
433
|
|
|
370
434
|
const suffix = argv.install
|
|
371
435
|
? ` + installed${argv.installPrefix ? ` to ${argv.installPrefix}` : ''}`
|
|
372
436
|
: '';
|
|
373
|
-
log.success(`Build complete: ${binaryDir} (${
|
|
437
|
+
log.success(`Build complete: ${binaryDir} (${configList.join(', ')})${suffix}`);
|
|
374
438
|
}
|
|
375
439
|
|
|
376
440
|
module.exports = build;
|
|
@@ -381,6 +445,7 @@ module.exports._helpers = {
|
|
|
381
445
|
isToolchainStale,
|
|
382
446
|
resolvePresetName,
|
|
383
447
|
resolveBinaryDir,
|
|
448
|
+
resolveConfigList,
|
|
384
449
|
buildConfigureArgs,
|
|
385
450
|
buildBuildArgs,
|
|
386
451
|
buildInstallArgs,
|