wyvrnpm 1.3.2 → 2.0.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 CHANGED
@@ -1,413 +1,704 @@
1
- # wyvrnpm
2
-
3
- A simple, private C++ package manager that works with any static file hosting provider — Amazon S3, a plain HTTP/HTTPS server, a local directory, or an SMB/UNC network share.
4
-
5
- There is no central registry. You control where packages are hosted.
6
-
7
- ---
8
-
9
- ## Install
10
-
11
- ```bash
12
- npm install -g wyvrnpm
13
- ```
14
-
15
- Requires Node.js >= 18.
16
-
17
- For S3 publishing, also install the AWS SDK:
18
-
19
- ```bash
20
- npm install -g @aws-sdk/client-s3 @aws-sdk/credential-providers
21
- ```
22
-
23
- ---
24
-
25
- ## Quick Start
26
-
27
- ```bash
28
- # 1. Initialise a manifest in your project
29
- wyvrnpm init
30
-
31
- # 2. Configure your package sources once
32
- wyvrnpm configure add-source --kind install --name corp-s3 --url s3://my-bucket/packages --profile my-sso
33
- wyvrnpm configure add-source --kind publish --name default --url s3://my-bucket/packages --profile my-sso
34
-
35
- # 3. Install dependencies (uses configured sources automatically)
36
- wyvrnpm install --platform win_x64
37
-
38
- # 4. Publish your package
39
- wyvrnpm publish --platform win_x64
40
- ```
41
-
42
- ---
43
-
44
- ## Commands
45
-
46
- ### `wyvrnpm init`
47
-
48
- Creates a `wyvrn.json` manifest in the current directory.
49
-
50
- ```bash
51
- wyvrnpm init
52
- wyvrnpm init --root ./my-project
53
- ```
54
-
55
- ---
56
-
57
- ### `wyvrnpm install`
58
-
59
- Resolves the full dependency graph and downloads all packages.
60
-
61
- **Source priority:** CLI `--source` values are used if provided. If omitted, sources are loaded from the [configuration file](#configuration-file).
62
-
63
- ```bash
64
- # Use configured sources (set up via wyvrnpm configure)
65
- wyvrnpm install --platform win_x64
66
-
67
- # Override with explicit sources — ignores config
68
- wyvrnpm install --source https://pkg.example.com/cpp --platform win_x64
69
-
70
- # Multiple sources tried in order, first to respond wins
71
- wyvrnpm install \
72
- --source https://primary.example.com/cpp \
73
- --source https://mirror.example.com/cpp \
74
- --platform linux_x64
75
- ```
76
-
77
- **Options**
78
-
79
- | Option | Default | Description |
80
- |---|---|---|
81
- | `--source` / `-s` | *(config)* | Base URL of a package source. Repeat for multiple. Overrides config when provided. |
82
- | `--platform` | `win_x64` | Target platform: `win_x64` `win_x86` `linux_x64` `linux_x86` `osx_x64` `osx_arm64` |
83
- | `--timeout` | `300` | HTTP request timeout in seconds |
84
- | `--manifest` | `./wyvrn.json` | Path to the manifest file |
85
- | `--root` | `./` | Project root (packages extracted to `{root}/wyvrn_internal/`) |
86
-
87
- Packages are extracted to `wyvrn_internal/{name}/`. A `wyvrn.lock` file is written alongside the manifest recording the exact resolved versions. On subsequent installs the lock file pins all previously resolved versions — only newly added dependencies are resolved fresh.
88
-
89
- ---
90
-
91
- ### `wyvrnpm publish`
92
-
93
- Zips the project directory and uploads `wyvrn.json` + `wyvrn.zip` to the destination source.
94
-
95
- **Source priority:** CLI `--source` is used if provided (as a URL/URI or a configured source name). If omitted, the first configured publish source is used.
96
-
97
- ```bash
98
- # Use the first configured publish source
99
- wyvrnpm publish --platform win_x64
100
-
101
- # Reference a configured source by name
102
- wyvrnpm publish --source default --platform win_x64
103
-
104
- # Explicit destination URL — ignores config
105
- wyvrnpm publish --source s3://my-bucket/packages --profile my-sso --platform win_x64
106
-
107
- # HTTP server with token auth
108
- wyvrnpm publish --source https://pkg.corp.com --token mytoken --platform linux_x64
109
-
110
- # Local directory or SMB share
111
- wyvrnpm publish --source \\fileserver\packages --platform win_x64
112
- wyvrnpm publish --source /mnt/packages --platform linux_x64
113
-
114
- # Publish build artifacts from a specific directory
115
- wyvrnpm publish --path ./dist --platform win_x64
116
- ```
117
-
118
- **Options**
119
-
120
- | Option | Default | Description |
121
- |---|---|---|
122
- | `--source` / `-s` | *(config)* | Destination URL/URI or configured source name. Overrides config when provided. |
123
- | `--profile` / `-p` | *(config)* | AWS SSO profile for S3 authentication. Overrides config when provided. |
124
- | `--token` | *(config)* | Bearer token for HTTP server authentication. Overrides config when provided. |
125
- | `--platform` | `common` | Target platform sub-path: `win_x64` `win_x86` `linux_x64` `linux_x86` `osx_x64` `osx_arm64` `common` |
126
- | `--path` | `.` | Directory to zip and publish |
127
- | `--manifest` | `./wyvrn.json` | Path to the manifest file |
128
-
129
- Files are uploaded to `{source}/{platform}/{name}/{version}/wyvrn.json` and `wyvrn.zip`.
130
-
131
- ---
132
-
133
- ### `wyvrnpm clean`
134
-
135
- Removes the `wyvrn_internal/` package cache and `wyvrn.lock`.
136
-
137
- ```bash
138
- wyvrnpm clean
139
- ```
140
-
141
- ---
142
-
143
- ### `wyvrnpm configure`
144
-
145
- Manages the [configuration file](#configuration-file). All sub-commands read and write `config.json` in the platform config directory.
146
-
147
- #### `wyvrnpm configure list`
148
-
149
- Prints all configured sources.
150
-
151
- ```
152
- Config: C:\Users\you\AppData\Local\wyvrnpm\config.json
153
-
154
- Install Sources:
155
- corp-s3 s3://my-bucket/packages [profile: my-sso]
156
- fallback https://pkg.corp.com [token: ***]
157
-
158
- Publish Sources:
159
- default s3://my-bucket/packages [profile: my-sso]
160
- ```
161
-
162
- #### `wyvrnpm configure add-source`
163
-
164
- Adds a new source or updates an existing one with the same name.
165
-
166
- ```bash
167
- # S3 with AWS SSO profile (install)
168
- wyvrnpm configure add-source \
169
- --kind install \
170
- --name corp-s3 \
171
- --url s3://my-bucket/packages \
172
- --profile my-sso-profile
173
-
174
- # HTTPS server with token auth (install)
175
- wyvrnpm configure add-source \
176
- --kind install \
177
- --name fallback \
178
- --url https://pkg.corp.com \
179
- --token mytoken
180
-
181
- # Local or SMB path (no auth required)
182
- wyvrnpm configure add-source \
183
- --kind install \
184
- --name local \
185
- --url \\fileserver\packages
186
-
187
- # Publish destination
188
- wyvrnpm configure add-source \
189
- --kind publish \
190
- --name default \
191
- --url s3://my-bucket/packages \
192
- --profile my-sso-profile
193
- ```
194
-
195
- **Options**
196
-
197
- | Option | Required | Description |
198
- |---|---|---|
199
- | `--kind` | Yes | `install` or `publish` |
200
- | `--name` | Yes | Unique name for this source |
201
- | `--url` | Yes | Destination URL, URI, or file path |
202
- | `--profile` | No | AWS SSO profile (S3 sources) |
203
- | `--token` | No | Bearer token (HTTP sources) |
204
-
205
- #### `wyvrnpm configure remove-source`
206
-
207
- Removes a source by name.
208
-
209
- ```bash
210
- wyvrnpm configure remove-source --kind install --name fallback
211
- wyvrnpm configure remove-source --kind publish --name default
212
- ```
213
-
214
- ---
215
-
216
- ## Configuration File
217
-
218
- wyvrnpm stores persistent configuration in a `config.json` file:
219
-
220
- | Platform | Path |
221
- |---|---|
222
- | Windows | `%LOCALAPPDATA%\wyvrnpm\config.json` |
223
- | Linux / macOS | `~/.config/wyvrnpm/config.json` |
224
-
225
- **Example config.json**
226
-
227
- ```json
228
- {
229
- "installSources": [
230
- {
231
- "name": "corp-s3",
232
- "url": "s3://my-bucket/packages",
233
- "profile": "my-sso-profile"
234
- },
235
- {
236
- "name": "fallback",
237
- "url": "https://pkg.corp.com",
238
- "token": "mytoken"
239
- }
240
- ],
241
- "publishSources": [
242
- {
243
- "name": "default",
244
- "url": "s3://my-bucket/packages",
245
- "profile": "my-sso-profile"
246
- }
247
- ]
248
- }
249
- ```
250
-
251
- **CLI options always take priority over config.** Config values are only used when the corresponding CLI option is not provided.
252
-
253
- ---
254
-
255
- ## Publish Providers
256
-
257
- wyvrnpm uses a provider architecture to support different destination types. The correct provider is selected automatically based on the source URL format.
258
-
259
- | Provider | Detected from | Auth |
260
- |---|---|---|
261
- | **S3** | `s3://` URI, or S3 HTTPS endpoint | `--profile` (AWS SSO) |
262
- | **HTTP** | `http://` or `https://` | `--token` (Bearer) |
263
- | **File** | Local path or UNC/SMB share | none |
264
-
265
- ### S3 Provider
266
-
267
- Accepts any of these source formats:
268
-
269
- ```
270
- s3://bucket-name/optional/prefix
271
- https://bucket-name.s3.amazonaws.com/prefix
272
- https://bucket-name.s3.us-east-1.amazonaws.com/prefix
273
- https://s3.amazonaws.com/bucket-name/prefix
274
- https://s3.us-east-1.amazonaws.com/bucket-name/prefix
275
- ```
276
-
277
- Authentication uses AWS SSO via `--profile`. If no profile is given, the default AWS credential chain is used.
278
-
279
- ### HTTP Provider
280
-
281
- Accepts `http://` and `https://` URLs. Uploads files via HTTP `PUT`. Optionally authenticates with a Bearer token via `--token`.
282
-
283
- ### File Provider
284
-
285
- Accepts local directory paths and SMB/UNC network shares. Files are copied with no authentication required.
286
-
287
- ```
288
- /absolute/unix/path
289
- ./relative/path
290
- C:\Windows\path
291
- \\server\share\path
292
- //server/share/path
293
- file:///absolute/path
294
- ```
295
-
296
- ### Adding a Custom Provider
297
-
298
- 1. Create `src/providers/myprovider.js` extending `BaseProvider`:
299
-
300
- ```js
301
- 'use strict';
302
- const BaseProvider = require('./base');
303
-
304
- class MyProvider extends BaseProvider {
305
- static canHandle(source) {
306
- return source.startsWith('myscheme://');
307
- }
308
-
309
- static get providerName() { return 'MyProvider'; }
310
-
311
- async publish(files, options) {
312
- // files.manifest — path to wyvrn.json
313
- // files.zip — path to wyvrn.zip
314
- // options.source, options.platform, options.name, options.version
315
- }
316
- }
317
-
318
- module.exports = MyProvider;
319
- ```
320
-
321
- 2. Register it in `src/providers/index.js`:
322
-
323
- ```js
324
- const MyProvider = require('./myprovider');
325
-
326
- const PROVIDERS = [
327
- S3Provider,
328
- HttpProvider,
329
- FileProvider,
330
- MyProvider, // add here
331
- ];
332
- ```
333
-
334
- ---
335
-
336
- ## Registry Layout
337
-
338
- Packages must be hosted at the following path structure relative to the source base:
339
-
340
- ```
341
- {source}/{platform}/{name}/{version}/wyvrn.json <- package manifest
342
- {source}/{platform}/{name}/{version}/wyvrn.zip <- package archive
343
- ```
344
-
345
- The tool also falls back to `razer.json` / `razer.zip` and a `common/` platform path for backwards compatibility.
346
-
347
- **Example (S3):**
348
-
349
- ```
350
- s3://my-bucket/packages/win_x64/OpenSSL/3.0.0.0/wyvrn.json
351
- s3://my-bucket/packages/win_x64/OpenSSL/3.0.0.0/wyvrn.zip
352
- ```
353
-
354
- **Example (HTTP):**
355
-
356
- ```
357
- https://pkg.corp.com/win_x64/OpenSSL/3.0.0.0/wyvrn.json
358
- https://pkg.corp.com/win_x64/OpenSSL/3.0.0.0/wyvrn.zip
359
- ```
360
-
361
- ### Package manifest (wyvrn.json hosted on source)
362
-
363
- ```json
364
- {
365
- "Name": "OpenSSL",
366
- "Version": "3.0.0.0",
367
- "Description": "TLS/SSL toolkit",
368
- "Dependencies": [
369
- { "Name": "zlib", "Version": "1.3.0.0" }
370
- ]
371
- }
372
- ```
373
-
374
- Fields use PascalCase. `Dependencies` is an array — transitive dependencies are resolved automatically.
375
-
376
- ---
377
-
378
- ## Project Manifest (wyvrn.json)
379
-
380
- ```json
381
- {
382
- "name": "my-app",
383
- "version": "1.0.0.0",
384
- "description": "My C++ application",
385
- "kind": "ConsoleApp",
386
- "dependencies": {
387
- "OpenSSL": "3.0.0.0",
388
- "zlib": "1.3.0.0"
389
- }
390
- }
391
- ```
392
-
393
- **`kind` values:** `ConsoleApp`, `StaticLib`, `DynamicLib`, `HeaderOnlyLib`, `WebApp`, `Utility`, `Service`, `TestProject`
394
-
395
- **`dependencies`** maps package names to version strings (`"major.minor.patch.build"`).
396
-
397
- ---
398
-
399
- ## Version Conflict Resolution
400
-
401
- When the dependency graph requires the same package at multiple versions, the highest version wins. If a `wyvrn.lock` exists, locked versions always take priority over any conflicting transitive request. A warning is printed for every conflict detected.
402
-
403
- ---
404
-
405
- ## Ignoring generated files
406
-
407
- Add the following to your `.gitignore`:
408
-
409
- ```
410
- wyvrn_internal/
411
- wyvrn.lock
412
- *.zip
413
- ```
1
+ # wyvrnpm
2
+
3
+ A simple, private C++ package manager that works with any static file hosting provider — Amazon S3, a plain HTTP/HTTPS server, a local directory, or an SMB/UNC network share.
4
+
5
+ There is no central registry. You control where packages are hosted.
6
+
7
+ > **README version: 2.0.1** — Last updated to reflect the v2 build-profile system.
8
+
9
+ ---
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install -g wyvrnpm
15
+ ```
16
+
17
+ Requires Node.js >= 18.
18
+
19
+ For S3 publishing, also install the AWS SDK:
20
+
21
+ ```bash
22
+ npm install -g @aws-sdk/client-s3 @aws-sdk/credential-providers
23
+ ```
24
+
25
+ ---
26
+
27
+ ## Quick Start
28
+
29
+ ```bash
30
+ # 1. Initialise a manifest in your project
31
+ wyvrnpm init
32
+
33
+ # 2. Configure your package sources once
34
+ wyvrnpm configure add-source --kind install --name corp-s3 --url s3://my-bucket/packages --profile my-sso
35
+ wyvrnpm configure add-source --kind publish --name default --url s3://my-bucket/packages --profile my-sso
36
+
37
+ # 3. Detect and save your build environment as the default profile
38
+ wyvrnpm configure profile detect
39
+
40
+ # 4. Install dependencies (resolved against your build profile)
41
+ wyvrnpm install
42
+
43
+ # 5. Publish your package (uses the active profile automatically)
44
+ wyvrnpm publish
45
+
46
+ # 6. (Optional) Link local packages for development
47
+ cd ../my-local-lib && wyvrnpm link
48
+ cd ../my-app && wyvrnpm link my-local-lib
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Build Profiles
54
+
55
+ v2 introduces **build profiles** — named snapshots of your build environment (OS, architecture, compiler, C++ standard, runtime linkage). Each published binary is tagged with a profile hash so installs can resolve the correct prebuilt binary automatically.
56
+
57
+ Profile fields mirror Conan 2.0 settings:
58
+
59
+ | Field | Example values |
60
+ |---|---|
61
+ | `os` | `Windows` `Linux` `Macos` |
62
+ | `arch` | `x86_64` `x86` `armv8` |
63
+ | `compiler` | `msvc` `gcc` `clang` `apple-clang` |
64
+ | `compiler.version` | `193` `13` `17` |
65
+ | `compiler.cppstd` | `14` `17` `20` `23` |
66
+ | `compiler.runtime` | `dynamic` `static` *(MSVC only)* |
67
+
68
+ Profiles are stored in the platform config directory:
69
+
70
+ | Platform | Path |
71
+ |---|---|
72
+ | Windows | `%LOCALAPPDATA%\wyvrnpm\profiles\` |
73
+ | Linux / macOS | `~/.config/wyvrnpm/profiles/` |
74
+
75
+ ### Typical profile workflow
76
+
77
+ ```bash
78
+ # Auto-detect your current environment and save it as "default"
79
+ wyvrnpm configure profile detect
80
+
81
+ # Or save under a specific name (e.g. for a release build with static runtime)
82
+ wyvrnpm configure profile detect --name release
83
+ wyvrnpm configure profile set --name release --runtime static
84
+
85
+ # List all saved profiles (* marks the default)
86
+ wyvrnpm configure profile list
87
+
88
+ # Switch the default profile
89
+ wyvrnpm configure profile set-default release
90
+ ```
91
+
92
+ Once a default profile is saved, `install` and `publish` use it automatically — no flags required.
93
+
94
+ ---
95
+
96
+ ## Commands
97
+
98
+ ### `wyvrnpm init`
99
+
100
+ Creates a `wyvrn.json` manifest in the current directory.
101
+
102
+ ```bash
103
+ wyvrnpm init
104
+ wyvrnpm init --root ./my-project
105
+ ```
106
+
107
+ ---
108
+
109
+ ### `wyvrnpm install`
110
+
111
+ Resolves the full dependency graph and downloads all packages.
112
+
113
+ **Source priority:** CLI `--source` values are used if provided. If omitted, sources are loaded from the [configuration file](#configuration-file).
114
+
115
+ **Profile resolution:** `--profile` selects the named build profile. If omitted, `config.defaultProfile` is used, falling back to `"default"`. v2 binaries are matched first by exact profile hash; if no exact match is found, the tool looks for a compatible build (same OS + arch, any compiler), then falls back to the v1 legacy path.
116
+
117
+ ```bash
118
+ # Use configured sources and the default build profile
119
+ wyvrnpm install
120
+
121
+ # Use a specific named profile
122
+ wyvrnpm install --profile release
123
+
124
+ # Override with explicit sources
125
+ wyvrnpm install --source https://pkg.example.com/cpp
126
+
127
+ # Multiple sources tried in order, first to respond wins
128
+ wyvrnpm install \
129
+ --source https://primary.example.com/cpp \
130
+ --source https://mirror.example.com/cpp
131
+ ```
132
+
133
+ **Options**
134
+
135
+ | Option | Default | Description |
136
+ |---|---|---|
137
+ | `--source` / `-s` | *(config)* | Base URL of a package source. Repeat for multiple. Overrides config when provided. |
138
+ | `--profile` / `-p` | *(config / "default")* | Named build profile to use for v2 binary resolution. |
139
+ | `--platform` | `win_x64` | v1 legacy platform sub-path (used as a fallback when no v2 binary is found). |
140
+ | `--timeout` | `300` | HTTP request timeout in seconds. |
141
+ | `--manifest` | `./wyvrn.json` | Path to the manifest file. |
142
+ | `--root` | `./` | Project root (packages extracted to `{root}/wyvrn_internal/`). |
143
+
144
+ Packages are extracted to `wyvrn_internal/{name}/`. A `wyvrn.lock` file is written alongside the manifest recording the exact resolved versions, profile, and per-package SHA256. On subsequent installs the lock file pins all previously resolved versions — only newly added dependencies are resolved fresh.
145
+
146
+ ---
147
+
148
+ ### `wyvrnpm publish`
149
+
150
+ Zips the project directory and uploads `wyvrn.json` + `wyvrn.zip` to the destination source, tagged with the active build profile.
151
+
152
+ **Source priority:** CLI `--source` is used if provided (as a URL/URI or a configured source name). If omitted, the first configured publish source is used.
153
+
154
+ **Profile:** `--profile` selects the named build profile to publish under. If omitted, `config.defaultProfile` is used, falling back to `"default"`. The profile hash is included in the upload path so multiple builds of the same version (different compilers, runtimes, etc.) can coexist.
155
+
156
+ ```bash
157
+ # Use configured source and default profile
158
+ wyvrnpm publish
159
+
160
+ # Use a specific profile
161
+ wyvrnpm publish --profile release
162
+
163
+ # Reference a configured source by name
164
+ wyvrnpm publish --source default
165
+
166
+ # Explicit destination URL
167
+ wyvrnpm publish --source s3://my-bucket/packages --aws-profile my-sso
168
+
169
+ # HTTP server with token auth
170
+ wyvrnpm publish --source https://pkg.corp.com --token mytoken
171
+
172
+ # Local directory or SMB share
173
+ wyvrnpm publish --source \\fileserver\packages
174
+ wyvrnpm publish --source /mnt/packages
175
+
176
+ # Publish build artifacts from a specific directory
177
+ wyvrnpm publish --path ./dist
178
+
179
+ # Overwrite an existing build (same version + profile hash)
180
+ wyvrnpm publish --force
181
+ ```
182
+
183
+ **Options**
184
+
185
+ | Option | Default | Description |
186
+ |---|---|---|
187
+ | `--source` / `-s` | *(config)* | Destination URL/URI or configured source name. |
188
+ | `--profile` / `-p` | *(config / "default")* | Named build profile to publish under. |
189
+ | `--aws-profile` | *(config)* | AWS SSO profile for S3 authentication. |
190
+ | `--token` | *(config)* | Bearer token for HTTP server authentication. |
191
+ | `--path` | `.` | Directory to zip and publish. |
192
+ | `--manifest` | `./wyvrn.json` | Path to the manifest file. |
193
+ | `--force` / `-f` | `false` | Overwrite an existing published version (same version + profile hash). |
194
+
195
+ During publish the tool also:
196
+ - reads `wyvrn.lock` to pin locked dependency versions into the uploaded manifest
197
+ - captures the current git commit SHA and remote URL as metadata
198
+ - computes a SHA256 of the zip and stores it in the upload metadata
199
+
200
+ ---
201
+
202
+ ### `.wyvrnignore`
203
+
204
+ Place a `.wyvrnignore` file in the directory being published to exclude files from the zip. Uses the same glob syntax as `.gitignore`:
205
+
206
+ ```
207
+ # Build artefacts that shouldn't ship
208
+ build/
209
+ *.obj
210
+ *.pdb
211
+
212
+ # Anchored to root with leading /
213
+ /CMakeCache.txt
214
+ /CMakeFiles/
215
+ ```
216
+
217
+ ---
218
+
219
+ ### `wyvrnpm clean`
220
+
221
+ Removes the `wyvrn_internal/` package cache and `wyvrn.lock`.
222
+
223
+ ```bash
224
+ wyvrnpm clean
225
+ ```
226
+
227
+ ---
228
+
229
+ ### `wyvrnpm link`
230
+
231
+ Links a local package for development, similar to `npm link`. This allows you to test packages from local source directories without publishing to the registry.
232
+
233
+ #### Register a package globally
234
+
235
+ Run `wyvrnpm link` in a package directory to register it for linking:
236
+
237
+ ```bash
238
+ cd C:\Dev\my-library
239
+ wyvrnpm link
240
+ # [wyvrn] Registered "my-library" -> C:\Dev\my-library
241
+ ```
242
+
243
+ For CMake packages where the installable content is in a subdirectory:
244
+
245
+ ```bash
246
+ cd C:\Dev\my-cmake-lib
247
+ wyvrnpm link --subdir output/install
248
+ # [wyvrn] Registered "my-cmake-lib" -> C:\Dev\my-cmake-lib\output\install
249
+ ```
250
+
251
+ #### Link a package into your project
252
+
253
+ Link a globally registered package:
254
+
255
+ ```bash
256
+ cd C:\Projects\my-app
257
+ wyvrnpm link my-library
258
+ # [wyvrn] Linked: my-library -> C:\Dev\my-library
259
+ ```
260
+
261
+ Or link directly from a path (skip global registration):
262
+
263
+ ```bash
264
+ wyvrnpm link my-library C:\Dev\my-library
265
+ wyvrnpm link my-library C:\Dev\my-library --subdir output/install
266
+ ```
267
+
268
+ #### List registered packages
269
+
270
+ ```bash
271
+ wyvrnpm link --list
272
+ # [wyvrn] Globally registered packages:
273
+ # my-library -> C:\Dev\my-library
274
+ # my-cmake-lib -> C:\Dev\my-cmake-lib\output\install [subdir: output/install]
275
+ ```
276
+
277
+ **Options**
278
+
279
+ | Option | Description |
280
+ |---|---|
281
+ | `--list` | List all globally registered packages. |
282
+ | `--subdir` | Subdirectory within the package to link (e.g., `output/install` for CMake packages). |
283
+
284
+ **How it works:**
285
+ - Creates a symlink (Unix) or junction (Windows) in `wyvrn_internal/`
286
+ - Junctions on Windows don't require admin rights
287
+ - Linked packages are recorded in `wyvrn.lock` with a `linked:` prefix
288
+ - `wyvrnpm install` automatically skips downloading linked packages
289
+
290
+ ---
291
+
292
+ ### `wyvrnpm unlink`
293
+
294
+ Removes a linked package from the current project.
295
+
296
+ ```bash
297
+ wyvrnpm unlink my-library
298
+ # [wyvrn] Unlinked: my-library
299
+ ```
300
+
301
+ To unlink and re-download from the registry:
302
+
303
+ ```bash
304
+ wyvrnpm unlink my-library --restore
305
+ # [wyvrn] Unlinked: my-library
306
+ # [wyvrn] Downloading: my-library@1.0.0.0
307
+ ```
308
+
309
+ **Options**
310
+
311
+ | Option | Default | Description |
312
+ |---|---|---|
313
+ | `--restore` | `false` | Re-download the package from registry after unlinking. |
314
+ | `--source` | *(config)* | Package source for `--restore`. |
315
+ | `--platform` | `win_x64` | Target platform for v1 fallback when using `--restore`. |
316
+
317
+ ---
318
+
319
+ ### `wyvrnpm configure`
320
+
321
+ Manages the [configuration file](#configuration-file). All sub-commands read and write `config.json` in the platform config directory.
322
+
323
+ #### `wyvrnpm configure list`
324
+
325
+ Prints all configured sources.
326
+
327
+ ```
328
+ Config: C:\Users\you\AppData\Local\wyvrnpm\config.json
329
+
330
+ Install Sources:
331
+ corp-s3 s3://my-bucket/packages [profile: my-sso]
332
+ fallback https://pkg.corp.com [token: ***]
333
+
334
+ Publish Sources:
335
+ default s3://my-bucket/packages [profile: my-sso]
336
+ ```
337
+
338
+ #### `wyvrnpm configure add-source`
339
+
340
+ Adds a new source or updates an existing one with the same name.
341
+
342
+ ```bash
343
+ # S3 with AWS SSO profile (install)
344
+ wyvrnpm configure add-source \
345
+ --kind install \
346
+ --name corp-s3 \
347
+ --url s3://my-bucket/packages \
348
+ --profile my-sso-profile
349
+
350
+ # HTTPS server with token auth (install)
351
+ wyvrnpm configure add-source \
352
+ --kind install \
353
+ --name fallback \
354
+ --url https://pkg.corp.com \
355
+ --token mytoken
356
+
357
+ # Local or SMB path (no auth required)
358
+ wyvrnpm configure add-source \
359
+ --kind install \
360
+ --name local \
361
+ --url \\fileserver\packages
362
+
363
+ # Publish destination
364
+ wyvrnpm configure add-source \
365
+ --kind publish \
366
+ --name default \
367
+ --url s3://my-bucket/packages \
368
+ --profile my-sso-profile
369
+ ```
370
+
371
+ **Options**
372
+
373
+ | Option | Required | Description |
374
+ |---|---|---|
375
+ | `--kind` | Yes | `install` or `publish`. |
376
+ | `--name` | Yes | Unique name for this source. |
377
+ | `--url` | Yes | Destination URL, URI, or file path. |
378
+ | `--profile` | No | AWS SSO profile (S3 sources). |
379
+ | `--token` | No | Bearer token (HTTP sources). |
380
+
381
+ #### `wyvrnpm configure remove-source`
382
+
383
+ Removes a source by name.
384
+
385
+ ```bash
386
+ wyvrnpm configure remove-source --kind install --name fallback
387
+ wyvrnpm configure remove-source --kind publish --name default
388
+ ```
389
+
390
+ #### `wyvrnpm configure profile`
391
+
392
+ Manages named build profiles stored in the profiles directory.
393
+
394
+ ```bash
395
+ # Auto-detect the current build environment and save it
396
+ wyvrnpm configure profile detect
397
+ wyvrnpm configure profile detect --name msvc_release --dry-run
398
+
399
+ # List all saved profiles (* = default)
400
+ wyvrnpm configure profile list
401
+
402
+ # Show a saved profile
403
+ wyvrnpm configure profile show
404
+ wyvrnpm configure profile show --name msvc_release
405
+
406
+ # Manually set individual fields in a profile
407
+ wyvrnpm configure profile set --name msvc_release --runtime static --cppstd 20
408
+
409
+ # Change which profile is the default
410
+ wyvrnpm configure profile set-default msvc_release
411
+
412
+ # Delete a profile
413
+ wyvrnpm configure profile delete msvc_release
414
+ ```
415
+
416
+ **`configure profile detect` options**
417
+
418
+ | Option | Description |
419
+ |---|---|
420
+ | `--name` / `-n` | Profile name to save to (default: `"default"`). |
421
+ | `--dry-run` | Print detected values without saving. |
422
+
423
+ **`configure profile set` options**
424
+
425
+ | Option | Description |
426
+ |---|---|
427
+ | `--name` / `-n` | Profile name to update (default: `"default"`). |
428
+ | `--os` | OS (`Windows` \| `Linux` \| `Macos`). |
429
+ | `--arch` | Architecture (`x86_64` \| `x86` \| `armv8` \| ...). |
430
+ | `--compiler` | Compiler (`msvc` \| `gcc` \| `clang` \| `apple-clang`). |
431
+ | `--compiler-version` | Compiler version (`193` \| `13` \| `17` \| ...). |
432
+ | `--cppstd` | C++ standard (`14` \| `17` \| `20` \| `23`). |
433
+ | `--runtime` | Runtime linkage (`static` \| `dynamic`). |
434
+
435
+ ---
436
+
437
+ ## Configuration File
438
+
439
+ wyvrnpm stores persistent configuration in a `config.json` file:
440
+
441
+ | Platform | Path |
442
+ |---|---|
443
+ | Windows | `%LOCALAPPDATA%\wyvrnpm\config.json` |
444
+ | Linux / macOS | `~/.config/wyvrnpm/config.json` |
445
+
446
+ **Example config.json**
447
+
448
+ ```json
449
+ {
450
+ "defaultProfile": "default",
451
+ "installSources": [
452
+ {
453
+ "name": "corp-s3",
454
+ "url": "s3://my-bucket/packages",
455
+ "profile": "my-sso-profile"
456
+ },
457
+ {
458
+ "name": "fallback",
459
+ "url": "https://pkg.corp.com",
460
+ "token": "mytoken"
461
+ }
462
+ ],
463
+ "publishSources": [
464
+ {
465
+ "name": "default",
466
+ "url": "s3://my-bucket/packages",
467
+ "profile": "my-sso-profile"
468
+ }
469
+ ],
470
+ "linkedPackages": {
471
+ "my-library": { "path": "C:\\Dev\\my-library" },
472
+ "my-cmake-lib": { "path": "C:\\Dev\\my-cmake-lib", "subdir": "output/install" }
473
+ }
474
+ }
475
+ ```
476
+
477
+ The `defaultProfile` field sets which named build profile is used when `--profile` is not provided on the CLI.
478
+
479
+ The `linkedPackages` field stores globally registered packages for `wyvrnpm link`. Each entry maps a package name to its local path and optional subdirectory.
480
+
481
+ **CLI options always take priority over config.** Config values are only used when the corresponding CLI option is not provided.
482
+
483
+ ---
484
+
485
+ ## Publish Providers
486
+
487
+ wyvrnpm uses a provider architecture to support different destination types. The correct provider is selected automatically based on the source URL format.
488
+
489
+ | Provider | Detected from | Auth |
490
+ |---|---|---|
491
+ | **S3** | `s3://` URI, or S3 HTTPS endpoint | `--aws-profile` (AWS SSO) |
492
+ | **HTTP** | `http://` or `https://` | `--token` (Bearer) |
493
+ | **File** | Local path or UNC/SMB share | none |
494
+
495
+ ### S3 Provider
496
+
497
+ Accepts any of these source formats:
498
+
499
+ ```
500
+ s3://bucket-name/optional/prefix
501
+ https://bucket-name.s3.amazonaws.com/prefix
502
+ https://bucket-name.s3.us-east-1.amazonaws.com/prefix
503
+ https://s3.amazonaws.com/bucket-name/prefix
504
+ https://s3.us-east-1.amazonaws.com/bucket-name/prefix
505
+ ```
506
+
507
+ Authentication uses AWS SSO via `--aws-profile`. If no profile is given, the default AWS credential chain is used.
508
+
509
+ ### HTTP Provider
510
+
511
+ Accepts `http://` and `https://` URLs. Uploads files via HTTP `PUT`. Optionally authenticates with a Bearer token via `--token`.
512
+
513
+ ### File Provider
514
+
515
+ Accepts local directory paths and SMB/UNC network shares. Files are copied with no authentication required.
516
+
517
+ ```
518
+ /absolute/unix/path
519
+ ./relative/path
520
+ C:\Windows\path
521
+ \\server\share\path
522
+ //server/share/path
523
+ file:///absolute/path
524
+ ```
525
+
526
+ ### Adding a Custom Provider
527
+
528
+ 1. Create `src/providers/myprovider.js` extending `BaseProvider`:
529
+
530
+ ```js
531
+ 'use strict';
532
+ const BaseProvider = require('./base');
533
+
534
+ class MyProvider extends BaseProvider {
535
+ static canHandle(source) {
536
+ return source.startsWith('myscheme://');
537
+ }
538
+
539
+ static get providerName() { return 'MyProvider'; }
540
+
541
+ async v2Publish(files, options) {
542
+ // files.manifest — path to wyvrn.json
543
+ // files.zip — path to wyvrn.zip
544
+ // options.source, options.name, options.version, options.profileHash
545
+ // options.contentSha256, options.gitSha, options.gitRepo
546
+ // options.buildSettings, options.lockedDependencies
547
+ }
548
+
549
+ async v2Exists(options) {
550
+ // Return true if this version+profileHash already exists
551
+ return false;
552
+ }
553
+ }
554
+
555
+ module.exports = MyProvider;
556
+ ```
557
+
558
+ 2. Register it in `src/providers/index.js`:
559
+
560
+ ```js
561
+ const MyProvider = require('./myprovider');
562
+
563
+ const PROVIDERS = [
564
+ S3Provider,
565
+ HttpProvider,
566
+ FileProvider,
567
+ MyProvider, // add here
568
+ ];
569
+ ```
570
+
571
+ ---
572
+
573
+ ## Registry Layout
574
+
575
+ ### v2 layout (current)
576
+
577
+ Packages published by v2 tooling are stored under a `v2/` prefix, with the profile hash as a sub-directory:
578
+
579
+ ```
580
+ {source}/v2/{name}/{version}/{profileHash}/wyvrn.json <- package manifest + metadata
581
+ {source}/v2/{name}/{version}/{profileHash}/wyvrn.zip <- package archive
582
+ {source}/v2/{name}/versions.json <- version index
583
+ {source}/v2/{name}/latest.json <- latest version pointer
584
+ ```
585
+
586
+ The profile hash is a 16-character SHA256 prefix computed from the build profile fields. This allows multiple compiler/platform variants of the same version to coexist in the same registry.
587
+
588
+ **Example (S3):**
589
+
590
+ ```
591
+ s3://my-bucket/packages/v2/OpenSSL/3.0.0.0/a1b2c3d4e5f60718/wyvrn.json
592
+ s3://my-bucket/packages/v2/OpenSSL/3.0.0.0/a1b2c3d4e5f60718/wyvrn.zip
593
+ ```
594
+
595
+ ### v1 layout (legacy)
596
+
597
+ v2 tooling also dual-publishes to the v1 path so that older clients can still consume packages:
598
+
599
+ ```
600
+ {source}/{platform}/{name}/{version}/wyvrn.json
601
+ {source}/{platform}/{name}/{version}/wyvrn.zip
602
+ ```
603
+
604
+ **Example (HTTP):**
605
+
606
+ ```
607
+ https://pkg.corp.com/win_x64/OpenSSL/3.0.0.0/wyvrn.json
608
+ https://pkg.corp.com/win_x64/OpenSSL/3.0.0.0/wyvrn.zip
609
+ ```
610
+
611
+ The tool also falls back to `razer.json` / `razer.zip` for legacy compatibility.
612
+
613
+ ### Package manifest (wyvrn.json hosted on source)
614
+
615
+ ```json
616
+ {
617
+ "Name": "OpenSSL",
618
+ "Version": "3.0.0.0",
619
+ "Description": "TLS/SSL toolkit",
620
+ "Dependencies": [
621
+ { "Name": "zlib", "Version": "1.3.0.0" }
622
+ ]
623
+ }
624
+ ```
625
+
626
+ Fields use PascalCase. `Dependencies` is an array — transitive dependencies are resolved automatically.
627
+
628
+ ---
629
+
630
+ ## Project Manifest (wyvrn.json)
631
+
632
+ ```json
633
+ {
634
+ "name": "my-app",
635
+ "version": "1.0.0.0",
636
+ "description": "My C++ application",
637
+ "kind": "ConsoleApp",
638
+ "dependencies": {
639
+ "OpenSSL": "3.0.0.0",
640
+ "zlib": {
641
+ "version": "1.3.0.0",
642
+ "settings": {
643
+ "compiler.runtime": "static"
644
+ }
645
+ }
646
+ }
647
+ }
648
+ ```
649
+
650
+ **`kind` values:** `ConsoleApp`, `StaticLib`, `DynamicLib`, `HeaderOnlyLib`, `WebApp`, `Utility`, `Service`, `TestProject`
651
+
652
+ **`dependencies`** can be either a plain version string (`"major.minor.patch.build"`) or an object with `version` and an optional `settings` map. The `settings` map overrides individual build profile fields for that specific dependency — useful when a dependency must be consumed with a different runtime linkage or C++ standard than your default profile.
653
+
654
+ ---
655
+
656
+ ## Lock File (wyvrn.lock)
657
+
658
+ The v2 lock file records the full build profile alongside the resolved packages:
659
+
660
+ ```json
661
+ {
662
+ "wyvrnVersion": 2,
663
+ "generatedAt": "2025-01-01T00:00:00.000Z",
664
+ "platform": "win_x64",
665
+ "profileName": "default",
666
+ "profile": {
667
+ "os": "Windows",
668
+ "arch": "x86_64",
669
+ "compiler": "msvc",
670
+ "compiler.version": "193",
671
+ "compiler.cppstd": "20",
672
+ "compiler.runtime": "dynamic"
673
+ },
674
+ "profileHash": "a1b2c3d4e5f60718",
675
+ "packages": {
676
+ "OpenSSL": {
677
+ "version": "3.0.0.0",
678
+ "profileHash": "a1b2c3d4e5f60718",
679
+ "contentSha256": "abc123...",
680
+ "gitSha": "def456..."
681
+ }
682
+ }
683
+ }
684
+ ```
685
+
686
+ Locked versions always take priority over transitive requests. A warning is printed for every version conflict detected.
687
+
688
+ ---
689
+
690
+ ## Version Conflict Resolution
691
+
692
+ When the dependency graph requires the same package at multiple versions, the highest version wins. If a `wyvrn.lock` exists, locked versions always take priority over any conflicting transitive request. A warning is printed for every conflict detected.
693
+
694
+ ---
695
+
696
+ ## Ignoring generated files
697
+
698
+ Add the following to your `.gitignore`:
699
+
700
+ ```
701
+ wyvrn_internal/
702
+ wyvrn.lock
703
+ *.zip
704
+ ```