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
@@ -1,252 +1,252 @@
1
- 'use strict';
2
-
3
- const { getProvider } = require('../providers');
4
- const { buildContext } = require('../context');
5
- const log = require('../logger');
6
-
7
- /**
8
- * `wyvrnpm show <pkg>` — surface registry metadata for a package.
9
- *
10
- * Accepts:
11
- * name → list every published version + profile.
12
- * name@version → list every profile for that version,
13
- * fetch full metadata for each, highlight
14
- * consumer (`uploadedBy`) vs author builds.
15
- * name@version@profileHash → dump full metadata for one build.
16
- *
17
- * Sources: CLI `--source` overrides config.installSources. First source
18
- * that returns data wins (same first-match policy as `install`).
19
- *
20
- * Added for PLAN-UPLOAD-BUILT phase 3 so maintainers can spot-check which
21
- * profileHashes were uploaded by consumers vs published by an author. The
22
- * `uploadedBy` block is the signal; its absence means "author publish"
23
- * by convention.
24
- *
25
- * @param {object} argv
26
- * @param {string} argv.pkg e.g. "zlib", "zlib@1.3.0.0", "zlib@1.3.0.0@a1b2..."
27
- * @param {string[]} [argv.source] source URLs
28
- * @param {string} [argv.awsProfile]
29
- * @param {string} [argv.token]
30
- * @returns {Promise<void>}
31
- */
32
- async function show(argv) {
33
- const { name, version, profileHash } = parseSpec(argv.pkg);
34
- if (!name) {
35
- log.error('Usage: wyvrnpm show <name>[@<version>[@<profileHash>]]');
36
- process.exit(1);
37
- }
38
-
39
- // Shared per-invocation state (config, auth, JSON-mode toggle). `show`
40
- // never reads the manifest, which is why ctx.manifest is lazy. See
41
- // src/context.js + claude/PLAN-COMMAND-CONTEXT.md.
42
- let ctx;
43
- try {
44
- ctx = buildContext(argv);
45
- } catch (err) {
46
- log.error(err.message);
47
- process.exit(1);
48
- }
49
- const jsonOut = ctx.flags.format === 'json';
50
-
51
- const { sources, awsProfile, token } = resolveSources(argv, ctx);
52
- if (sources.length === 0) {
53
- log.error(
54
- 'no sources configured. ' +
55
- 'Pass --source <url> or run: wyvrnpm configure add-source --kind install ...',
56
- );
57
- process.exit(1);
58
- }
59
-
60
- for (const source of sources) {
61
- let provider;
62
- try { provider = getProvider(source); } catch { continue; }
63
-
64
- const idx = await provider.v2GetVersionsIndex({ source, name, awsProfile, token });
65
- if (!idx?.versions) continue;
66
-
67
- const versionKeys = version
68
- ? (idx.versions[version] ? [version] : [])
69
- : Object.keys(idx.versions).sort();
70
-
71
- if (version && versionKeys.length === 0) {
72
- log.error(`Version ${version} not found on ${source}`);
73
- process.exit(1);
74
- }
75
-
76
- // Collect a single structured result as we walk. Text rendering happens
77
- // inline in the legacy path; JSON mode emits the whole object at the
78
- // end of the first source that answered.
79
- const result = {
80
- command: 'show',
81
- wyvrnpmVersion: require('../../package.json').version,
82
- source,
83
- package: name,
84
- latest: idx.latest ?? null,
85
- versions: {},
86
- };
87
-
88
- if (!jsonOut) {
89
- console.log(`${name} (source: ${source})`);
90
- if (idx.latest) console.log(` latest: ${idx.latest}`);
91
- }
92
-
93
- for (const v of versionKeys) {
94
- const ventry = idx.versions[v];
95
- const profiles = ventry?.profiles ?? {};
96
- const profileKeys = profileHash
97
- ? (profiles[profileHash] ? [profileHash] : [])
98
- : Object.keys(profiles).sort();
99
-
100
- if (profileHash && profileKeys.length === 0) {
101
- log.error(`ProfileHash ${profileHash} not found for ${name}@${v}`);
102
- process.exit(1);
103
- }
104
-
105
- if (!jsonOut) {
106
- console.log(`\n ${name}@${v} (${profileKeys.length} profile${profileKeys.length === 1 ? '' : 's'})`);
107
- if (ventry.source?.gitSha) {
108
- console.log(` git: ${ventry.source.gitRepo ?? '?'} @ ${ventry.source.gitSha}`);
109
- }
110
- }
111
-
112
- // For bare `name` queries we'd fetch O(M×N) manifests (versions ×
113
- // profiles) — too noisy. Only deep-fetch when the user has narrowed
114
- // to a specific version.
115
- const deepFetch = Boolean(version);
116
-
117
- const profileArr = [];
118
- for (const hash of profileKeys) {
119
- const entry = profiles[hash];
120
- if (!jsonOut) {
121
- console.log(`\n [${hash}]`);
122
- if (entry.buildSettings) {
123
- console.log(` profile : ${formatBuildSettings(entry.buildSettings)}`);
124
- if (entry.buildSettings.options && Object.keys(entry.buildSettings.options).length > 0) {
125
- console.log(` options : ${formatOptions(entry.buildSettings.options)}`);
126
- }
127
- }
128
- console.log(` sha256 : ${entry.contentSha256 ?? '?'}`);
129
- if (entry.publishedAt) console.log(` published: ${entry.publishedAt}`);
130
- }
131
-
132
- let meta = null;
133
- if (deepFetch) {
134
- meta = await provider.v2GetMeta({
135
- source, name, version: v, profileHash: hash, awsProfile, token,
136
- });
137
- if (!jsonOut) {
138
- if (meta?.uploadedBy) {
139
- console.log(` origin : consumer upload (${meta.uploadedBy.kind})`);
140
- console.log(` uploadedAt : ${meta.uploadedBy.uploadedAt}`);
141
- console.log(` wyvrnpmVersion : ${meta.uploadedBy.wyvrnpmVersion ?? '?'}`);
142
- if (meta.uploadedBy.builtFromGit) {
143
- console.log(` builtFromGit : ${meta.uploadedBy.builtFromGit}`);
144
- }
145
- if (meta.uploadedBy.builtFromSha) {
146
- console.log(` builtFromSha : ${meta.uploadedBy.builtFromSha}`);
147
- }
148
- } else if (meta) {
149
- console.log(` origin : author publish`);
150
- }
151
- if (meta?.compatibility) {
152
- console.log(` compat : ${JSON.stringify(meta.compatibility)}`);
153
- }
154
- if (meta?.options && Object.keys(meta.options).length > 0) {
155
- console.log(` declared: ${formatDeclaredOptions(meta.options)}`);
156
- }
157
- // PLAN-CONF.md §4.6 — surface publisher's publishedConf.
158
- // Informational only; absent for pre-2.6.0 author publishes.
159
- if (meta?.publishedConf && Object.keys(meta.publishedConf).length > 0) {
160
- console.log(` conf : ${JSON.stringify(meta.publishedConf)}`);
161
- }
162
- }
163
- }
164
-
165
- profileArr.push({
166
- profileHash: hash,
167
- contentSha256: entry.contentSha256 ?? null,
168
- publishedAt: entry.publishedAt ?? null,
169
- buildSettings: entry.buildSettings ?? null,
170
- origin: meta?.uploadedBy ? 'consumer-source-build' : (meta ? 'author-publish' : null),
171
- uploadedBy: meta?.uploadedBy ?? null,
172
- compatibility: meta?.compatibility ?? null,
173
- declaredOptions: meta?.options ?? null,
174
- publishedConf: meta?.publishedConf ?? null,
175
- });
176
- }
177
-
178
- result.versions[v] = {
179
- source: ventry.source ?? null,
180
- profiles: profileArr,
181
- };
182
- }
183
-
184
- if (jsonOut) {
185
- process.stdout.write(JSON.stringify(result, null, 2) + '\n');
186
- }
187
- return;
188
- }
189
-
190
- log.error(`Package ${name} not found in any configured source`);
191
- process.exit(1);
192
- }
193
-
194
- /**
195
- * Parse a package spec "name[@version[@profileHash]]".
196
- * @param {string} spec
197
- * @returns {{ name?: string, version?: string, profileHash?: string }}
198
- */
199
- function parseSpec(spec) {
200
- if (!spec || typeof spec !== 'string') return {};
201
- const parts = spec.split('@');
202
- const [name, version, profileHash] = parts;
203
- return {
204
- name: name || undefined,
205
- version: version || undefined,
206
- profileHash: profileHash || undefined,
207
- };
208
- }
209
-
210
- function resolveSources(argv, ctx) {
211
- const { config } = ctx;
212
- const sources = (argv.source && argv.source.length > 0)
213
- ? argv.source
214
- : config.installSources.map((s) => s.url);
215
-
216
- const firstConfig = config.installSources?.[0];
217
- return {
218
- sources,
219
- awsProfile: argv.awsProfile ?? firstConfig?.profile,
220
- token: ctx.auth.for(firstConfig).token,
221
- };
222
- }
223
-
224
- function formatBuildSettings(bs) {
225
- const parts = [
226
- `${bs.os}/${bs.arch}`,
227
- `${bs.compiler} ${bs['compiler.version']}`,
228
- `C++${bs['compiler.cppstd']}`,
229
- ];
230
- if (bs['compiler.runtime']) parts.push(`[${bs['compiler.runtime']}]`);
231
- return parts.join(' ');
232
- }
233
-
234
- function formatOptions(options) {
235
- return Object.entries(options)
236
- .sort(([a], [b]) => a.localeCompare(b))
237
- .map(([k, v]) => `${k}=${typeof v === 'string' ? v : String(v)}`)
238
- .join(', ');
239
- }
240
-
241
- function formatDeclaredOptions(declared) {
242
- return Object.entries(declared)
243
- .sort(([a], [b]) => a.localeCompare(b))
244
- .map(([name, spec]) => {
245
- const allowed = Array.isArray(spec?.allowed) ? spec.allowed : [];
246
- return `${name} (default=${String(spec?.default)}, allowed=${allowed.map(String).join('|')})`;
247
- })
248
- .join('; ');
249
- }
250
-
251
- module.exports = show;
252
- module.exports.parseSpec = parseSpec;
1
+ 'use strict';
2
+
3
+ const { getProvider } = require('../providers');
4
+ const { buildContext } = require('../context');
5
+ const log = require('../logger');
6
+
7
+ /**
8
+ * `wyvrnpm show <pkg>` — surface registry metadata for a package.
9
+ *
10
+ * Accepts:
11
+ * name → list every published version + profile.
12
+ * name@version → list every profile for that version,
13
+ * fetch full metadata for each, highlight
14
+ * consumer (`uploadedBy`) vs author builds.
15
+ * name@version@profileHash → dump full metadata for one build.
16
+ *
17
+ * Sources: CLI `--source` overrides config.installSources. First source
18
+ * that returns data wins (same first-match policy as `install`).
19
+ *
20
+ * Added for PLAN-UPLOAD-BUILT phase 3 so maintainers can spot-check which
21
+ * profileHashes were uploaded by consumers vs published by an author. The
22
+ * `uploadedBy` block is the signal; its absence means "author publish"
23
+ * by convention.
24
+ *
25
+ * @param {object} argv
26
+ * @param {string} argv.pkg e.g. "zlib", "zlib@1.3.0.0", "zlib@1.3.0.0@a1b2..."
27
+ * @param {string[]} [argv.source] source URLs
28
+ * @param {string} [argv.awsProfile]
29
+ * @param {string} [argv.token]
30
+ * @returns {Promise<void>}
31
+ */
32
+ async function show(argv) {
33
+ const { name, version, profileHash } = parseSpec(argv.pkg);
34
+ if (!name) {
35
+ log.error('Usage: wyvrnpm show <name>[@<version>[@<profileHash>]]');
36
+ process.exit(1);
37
+ }
38
+
39
+ // Shared per-invocation state (config, auth, JSON-mode toggle). `show`
40
+ // never reads the manifest, which is why ctx.manifest is lazy. See
41
+ // src/context.js + claude/PLAN-COMMAND-CONTEXT.md.
42
+ let ctx;
43
+ try {
44
+ ctx = buildContext(argv);
45
+ } catch (err) {
46
+ log.error(err.message);
47
+ process.exit(1);
48
+ }
49
+ const jsonOut = ctx.flags.format === 'json';
50
+
51
+ const { sources, awsProfile, token } = resolveSources(argv, ctx);
52
+ if (sources.length === 0) {
53
+ log.error(
54
+ 'no sources configured. ' +
55
+ 'Pass --source <url> or run: wyvrnpm configure add-source --kind install ...',
56
+ );
57
+ process.exit(1);
58
+ }
59
+
60
+ for (const source of sources) {
61
+ let provider;
62
+ try { provider = getProvider(source); } catch { continue; }
63
+
64
+ const idx = await provider.v2GetVersionsIndex({ source, name, awsProfile, token });
65
+ if (!idx?.versions) continue;
66
+
67
+ const versionKeys = version
68
+ ? (idx.versions[version] ? [version] : [])
69
+ : Object.keys(idx.versions).sort();
70
+
71
+ if (version && versionKeys.length === 0) {
72
+ log.error(`Version ${version} not found on ${source}`);
73
+ process.exit(1);
74
+ }
75
+
76
+ // Collect a single structured result as we walk. Text rendering happens
77
+ // inline in the legacy path; JSON mode emits the whole object at the
78
+ // end of the first source that answered.
79
+ const result = {
80
+ command: 'show',
81
+ wyvrnpmVersion: require('../../package.json').version,
82
+ source,
83
+ package: name,
84
+ latest: idx.latest ?? null,
85
+ versions: {},
86
+ };
87
+
88
+ if (!jsonOut) {
89
+ console.log(`${name} (source: ${source})`);
90
+ if (idx.latest) console.log(` latest: ${idx.latest}`);
91
+ }
92
+
93
+ for (const v of versionKeys) {
94
+ const ventry = idx.versions[v];
95
+ const profiles = ventry?.profiles ?? {};
96
+ const profileKeys = profileHash
97
+ ? (profiles[profileHash] ? [profileHash] : [])
98
+ : Object.keys(profiles).sort();
99
+
100
+ if (profileHash && profileKeys.length === 0) {
101
+ log.error(`ProfileHash ${profileHash} not found for ${name}@${v}`);
102
+ process.exit(1);
103
+ }
104
+
105
+ if (!jsonOut) {
106
+ console.log(`\n ${name}@${v} (${profileKeys.length} profile${profileKeys.length === 1 ? '' : 's'})`);
107
+ if (ventry.source?.gitSha) {
108
+ console.log(` git: ${ventry.source.gitRepo ?? '?'} @ ${ventry.source.gitSha}`);
109
+ }
110
+ }
111
+
112
+ // For bare `name` queries we'd fetch O(M×N) manifests (versions ×
113
+ // profiles) — too noisy. Only deep-fetch when the user has narrowed
114
+ // to a specific version.
115
+ const deepFetch = Boolean(version);
116
+
117
+ const profileArr = [];
118
+ for (const hash of profileKeys) {
119
+ const entry = profiles[hash];
120
+ if (!jsonOut) {
121
+ console.log(`\n [${hash}]`);
122
+ if (entry.buildSettings) {
123
+ console.log(` profile : ${formatBuildSettings(entry.buildSettings)}`);
124
+ if (entry.buildSettings.options && Object.keys(entry.buildSettings.options).length > 0) {
125
+ console.log(` options : ${formatOptions(entry.buildSettings.options)}`);
126
+ }
127
+ }
128
+ console.log(` sha256 : ${entry.contentSha256 ?? '?'}`);
129
+ if (entry.publishedAt) console.log(` published: ${entry.publishedAt}`);
130
+ }
131
+
132
+ let meta = null;
133
+ if (deepFetch) {
134
+ meta = await provider.v2GetMeta({
135
+ source, name, version: v, profileHash: hash, awsProfile, token,
136
+ });
137
+ if (!jsonOut) {
138
+ if (meta?.uploadedBy) {
139
+ console.log(` origin : consumer upload (${meta.uploadedBy.kind})`);
140
+ console.log(` uploadedAt : ${meta.uploadedBy.uploadedAt}`);
141
+ console.log(` wyvrnpmVersion : ${meta.uploadedBy.wyvrnpmVersion ?? '?'}`);
142
+ if (meta.uploadedBy.builtFromGit) {
143
+ console.log(` builtFromGit : ${meta.uploadedBy.builtFromGit}`);
144
+ }
145
+ if (meta.uploadedBy.builtFromSha) {
146
+ console.log(` builtFromSha : ${meta.uploadedBy.builtFromSha}`);
147
+ }
148
+ } else if (meta) {
149
+ console.log(` origin : author publish`);
150
+ }
151
+ if (meta?.compatibility) {
152
+ console.log(` compat : ${JSON.stringify(meta.compatibility)}`);
153
+ }
154
+ if (meta?.options && Object.keys(meta.options).length > 0) {
155
+ console.log(` declared: ${formatDeclaredOptions(meta.options)}`);
156
+ }
157
+ // PLAN-CONF.md §4.6 — surface publisher's publishedConf.
158
+ // Informational only; absent for pre-2.6.0 author publishes.
159
+ if (meta?.publishedConf && Object.keys(meta.publishedConf).length > 0) {
160
+ console.log(` conf : ${JSON.stringify(meta.publishedConf)}`);
161
+ }
162
+ }
163
+ }
164
+
165
+ profileArr.push({
166
+ profileHash: hash,
167
+ contentSha256: entry.contentSha256 ?? null,
168
+ publishedAt: entry.publishedAt ?? null,
169
+ buildSettings: entry.buildSettings ?? null,
170
+ origin: meta?.uploadedBy ? 'consumer-source-build' : (meta ? 'author-publish' : null),
171
+ uploadedBy: meta?.uploadedBy ?? null,
172
+ compatibility: meta?.compatibility ?? null,
173
+ declaredOptions: meta?.options ?? null,
174
+ publishedConf: meta?.publishedConf ?? null,
175
+ });
176
+ }
177
+
178
+ result.versions[v] = {
179
+ source: ventry.source ?? null,
180
+ profiles: profileArr,
181
+ };
182
+ }
183
+
184
+ if (jsonOut) {
185
+ process.stdout.write(JSON.stringify(result, null, 2) + '\n');
186
+ }
187
+ return;
188
+ }
189
+
190
+ log.error(`Package ${name} not found in any configured source`);
191
+ process.exit(1);
192
+ }
193
+
194
+ /**
195
+ * Parse a package spec "name[@version[@profileHash]]".
196
+ * @param {string} spec
197
+ * @returns {{ name?: string, version?: string, profileHash?: string }}
198
+ */
199
+ function parseSpec(spec) {
200
+ if (!spec || typeof spec !== 'string') return {};
201
+ const parts = spec.split('@');
202
+ const [name, version, profileHash] = parts;
203
+ return {
204
+ name: name || undefined,
205
+ version: version || undefined,
206
+ profileHash: profileHash || undefined,
207
+ };
208
+ }
209
+
210
+ function resolveSources(argv, ctx) {
211
+ const { config } = ctx;
212
+ const sources = (argv.source && argv.source.length > 0)
213
+ ? argv.source
214
+ : config.installSources.map((s) => s.url);
215
+
216
+ const firstConfig = config.installSources?.[0];
217
+ return {
218
+ sources,
219
+ awsProfile: argv.awsProfile ?? firstConfig?.profile,
220
+ token: ctx.auth.for(firstConfig).token,
221
+ };
222
+ }
223
+
224
+ function formatBuildSettings(bs) {
225
+ const parts = [
226
+ `${bs.os}/${bs.arch}`,
227
+ `${bs.compiler} ${bs['compiler.version']}`,
228
+ `C++${bs['compiler.cppstd']}`,
229
+ ];
230
+ if (bs['compiler.runtime']) parts.push(`[${bs['compiler.runtime']}]`);
231
+ return parts.join(' ');
232
+ }
233
+
234
+ function formatOptions(options) {
235
+ return Object.entries(options)
236
+ .sort(([a], [b]) => a.localeCompare(b))
237
+ .map(([k, v]) => `${k}=${typeof v === 'string' ? v : String(v)}`)
238
+ .join(', ');
239
+ }
240
+
241
+ function formatDeclaredOptions(declared) {
242
+ return Object.entries(declared)
243
+ .sort(([a], [b]) => a.localeCompare(b))
244
+ .map(([name, spec]) => {
245
+ const allowed = Array.isArray(spec?.allowed) ? spec.allowed : [];
246
+ return `${name} (default=${String(spec?.default)}, allowed=${allowed.map(String).join('|')})`;
247
+ })
248
+ .join('; ');
249
+ }
250
+
251
+ module.exports = show;
252
+ module.exports.parseSpec = parseSpec;