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/bin/wyvrn.js CHANGED
@@ -2,12 +2,13 @@
2
2
 
3
3
  'use strict';
4
4
 
5
- const yargs = require('yargs');
6
- const init = require('../src/commands/init');
7
- const install = require('../src/commands/install');
8
- const clean = require('../src/commands/clean');
9
- const publish = require('../src/commands/publish');
5
+ const yargs = require('yargs');
6
+ const init = require('../src/commands/init');
7
+ const install = require('../src/commands/install');
8
+ const clean = require('../src/commands/clean');
9
+ const publish = require('../src/commands/publish');
10
10
  const configure = require('../src/commands/configure');
11
+ const profile = require('../src/commands/profile');
11
12
  const { link, unlink } = require('../src/commands/link');
12
13
 
13
14
  yargs
@@ -21,26 +22,35 @@ yargs
21
22
  description: 'Root directory',
22
23
  default: './',
23
24
  })
25
+
26
+ // ── init ──────────────────────────────────────────────────────────────────
24
27
  .command(
25
28
  'init',
26
29
  'Initialise a new wyvrn.json manifest in the current project',
27
30
  () => {},
28
31
  (argv) => init(argv),
29
32
  )
33
+
34
+ // ── install ───────────────────────────────────────────────────────────────
30
35
  .command(
31
36
  'install',
32
37
  'Resolve and download all dependencies listed in the manifest',
33
- (yargs) => {
34
- yargs
38
+ (y) => {
39
+ y
35
40
  .option('source', {
36
41
  alias: 's',
37
42
  type: 'string',
38
43
  description: 'Base URL of a package source (can be repeated)',
39
44
  array: true,
40
45
  })
46
+ .option('profile', {
47
+ alias: 'p',
48
+ type: 'string',
49
+ description: 'Build profile name to use (default: config.defaultProfile → "default")',
50
+ })
41
51
  .option('platform', {
42
52
  type: 'string',
43
- description: 'Target platform',
53
+ description: 'v1 legacy platform path (used as fallback if v2 not found)',
44
54
  choices: ['win_x64', 'win_x86', 'linux_x64', 'linux_x86', 'osx_x64', 'osx_arm64'],
45
55
  default: 'win_x64',
46
56
  })
@@ -52,32 +62,35 @@ yargs
52
62
  },
53
63
  (argv) => install(argv),
54
64
  )
65
+
66
+ // ── clean ─────────────────────────────────────────────────────────────────
55
67
  .command(
56
68
  'clean',
57
69
  'Remove downloaded packages and lock file',
58
70
  () => {},
59
71
  (argv) => clean(argv),
60
72
  )
73
+
74
+ // ── publish ───────────────────────────────────────────────────────────────
61
75
  .command(
62
76
  'publish',
63
- 'Package and publish the project to a source (S3 or HTTP server)',
64
- (yargs) => {
65
- yargs
77
+ 'Package and publish the project. The active build profile is loaded from the ' +
78
+ 'profiles directory (--profile selects which one).',
79
+ (y) => {
80
+ y
66
81
  .option('source', {
67
82
  alias: 's',
68
83
  type: 'string',
69
- description: 'Publish destination URL/URI or a configured source name (falls back to config)',
84
+ description: 'Publish destination URL/URI or a configured source name',
70
85
  })
71
86
  .option('profile', {
72
87
  alias: 'p',
73
88
  type: 'string',
74
- description: 'AWS SSO profile to use for authentication (S3 only)',
89
+ description: 'Build profile name to publish as (default: config.defaultProfile → "default")',
75
90
  })
76
- .option('platform', {
91
+ .option('aws-profile', {
77
92
  type: 'string',
78
- description: 'Target platform sub-path (e.g. win_x64). Defaults to "common"',
79
- choices: ['win_x64', 'win_x86', 'linux_x64', 'linux_x86', 'osx_x64', 'osx_arm64', 'common'],
80
- default: 'common',
93
+ description: 'AWS SSO profile for S3 authentication (S3 only)',
81
94
  })
82
95
  .option('path', {
83
96
  type: 'string',
@@ -86,139 +99,179 @@ yargs
86
99
  })
87
100
  .option('token', {
88
101
  type: 'string',
89
- description: 'Bearer token for HTTP server authentication (HTTP only)',
102
+ description: 'Bearer token for HTTP server authentication',
90
103
  })
91
104
  .option('force', {
92
105
  alias: 'f',
93
106
  type: 'boolean',
94
107
  description: 'Overwrite an existing published version',
95
108
  default: false,
96
- });
109
+ })
110
+ ;
97
111
  },
98
- (argv) => publish(argv),
112
+ (argv) => publish({ ...argv, awsProfile: argv['aws-profile'] }),
99
113
  )
114
+
115
+ // ── configure ─────────────────────────────────────────────────────────────
100
116
  .command(
101
117
  'configure',
102
- 'Manage wyvrnpm configuration (sources, authentication)',
103
- (yargs) => {
104
- yargs
118
+ 'Manage wyvrnpm configuration (sources, authentication, build profiles)',
119
+ (y) => {
120
+ y
121
+ // --- list ---
105
122
  .command('list', 'List all configured sources', () => {}, () => configure.list())
123
+
124
+ // --- add-source ---
106
125
  .command(
107
126
  'add-source',
108
127
  'Add or update an install/publish source',
109
- (yargs) => {
110
- yargs
111
- .option('kind', {
112
- type: 'string',
113
- description: 'Source kind',
114
- choices: ['install', 'publish'],
115
- demandOption: true,
116
- })
117
- .option('name', {
118
- type: 'string',
119
- description: 'Unique name for this source',
120
- demandOption: true,
121
- })
122
- .option('url', {
123
- type: 'string',
124
- description: 'Source URL or URI (s3://, https://, UNC path, etc.)',
125
- demandOption: true,
126
- })
127
- .option('profile', {
128
- type: 'string',
129
- description: 'AWS SSO profile for this source (S3 only)',
130
- })
131
- .option('token', {
132
- type: 'string',
133
- description: 'Bearer token for this source (HTTP only)',
134
- });
128
+ (y2) => {
129
+ y2
130
+ .option('kind', { type: 'string', choices: ['install', 'publish'], demandOption: true })
131
+ .option('name', { type: 'string', demandOption: true })
132
+ .option('url', { type: 'string', demandOption: true })
133
+ .option('profile', { type: 'string', description: 'AWS SSO profile (S3 only)' })
134
+ .option('token', { type: 'string', description: 'Bearer token (HTTP only)' });
135
135
  },
136
136
  (argv) => configure.addSource(argv),
137
137
  )
138
+
139
+ // --- remove-source ---
138
140
  .command(
139
141
  'remove-source',
140
142
  'Remove a configured source by name',
141
- (yargs) => {
142
- yargs
143
- .option('kind', {
144
- type: 'string',
145
- description: 'Source kind',
146
- choices: ['install', 'publish'],
147
- demandOption: true,
148
- })
149
- .option('name', {
150
- type: 'string',
151
- description: 'Name of the source to remove',
152
- demandOption: true,
153
- });
143
+ (y2) => {
144
+ y2
145
+ .option('kind', { type: 'string', choices: ['install', 'publish'], demandOption: true })
146
+ .option('name', { type: 'string', demandOption: true });
154
147
  },
155
148
  (argv) => configure.removeSource(argv),
156
149
  )
150
+
151
+ // --- profile ---
152
+ .command(
153
+ 'profile',
154
+ 'Manage named build profiles stored in the wyvrnpm profiles directory',
155
+ (y2) => {
156
+ y2
157
+ // list
158
+ .command(
159
+ 'list',
160
+ 'List all saved build profiles',
161
+ () => {},
162
+ () => profile.list(),
163
+ )
164
+ // show
165
+ .command(
166
+ 'show',
167
+ 'Display a named profile',
168
+ (y3) => {
169
+ y3.option('name', {
170
+ alias: 'n',
171
+ type: 'string',
172
+ description: 'Profile name (default: configured default)',
173
+ });
174
+ },
175
+ (argv) => profile.show(argv),
176
+ )
177
+ // detect
178
+ .command(
179
+ 'detect',
180
+ 'Auto-detect the build environment and save as a named profile',
181
+ (y3) => {
182
+ y3
183
+ .option('name', {
184
+ alias: 'n',
185
+ type: 'string',
186
+ description: 'Profile name to save to (default: "default")',
187
+ })
188
+ .option('dry-run', {
189
+ type: 'boolean',
190
+ description: 'Print detected values without saving',
191
+ default: false,
192
+ });
193
+ },
194
+ (argv) => profile.detect(argv),
195
+ )
196
+ // set
197
+ .command(
198
+ 'set',
199
+ 'Manually override fields in a named profile',
200
+ (y3) => {
201
+ y3
202
+ .option('name', { alias: 'n', type: 'string', description: 'Profile name (default: "default")' })
203
+ .option('os', { type: 'string', description: 'OS (Windows | Linux | Macos)' })
204
+ .option('arch', { type: 'string', description: 'Architecture (x86_64 | x86 | armv8 | ...)' })
205
+ .option('compiler', { type: 'string', description: 'Compiler (msvc | gcc | clang | apple-clang)' })
206
+ .option('compiler-version', { type: 'string', description: 'Compiler version (193 | 11 | 14 | ...)' })
207
+ .option('cppstd', { type: 'string', description: 'C++ standard (14 | 17 | 20 | 23)' })
208
+ .option('runtime', { type: 'string', description: 'Runtime linkage (static | dynamic)' });
209
+ },
210
+ (argv) => profile.set({ ...argv, compilerVersion: argv['compiler-version'] }),
211
+ )
212
+ // set-default
213
+ .command(
214
+ 'set-default <name>',
215
+ 'Change which profile is used by default',
216
+ (y3) => {
217
+ y3.positional('name', { type: 'string', demandOption: true });
218
+ },
219
+ (argv) => profile.setDefault(argv),
220
+ )
221
+ // delete
222
+ .command(
223
+ 'delete <name>',
224
+ 'Delete a saved profile',
225
+ (y3) => {
226
+ y3.positional('name', { type: 'string', demandOption: true });
227
+ },
228
+ (argv) => profile.del(argv),
229
+ )
230
+ .demandCommand(1)
231
+ .help();
232
+ },
233
+ () => {},
234
+ )
235
+
157
236
  .demandCommand(1)
158
237
  .help();
159
238
  },
160
239
  () => {},
161
240
  )
241
+
242
+ // ── link ──────────────────────────────────────────────────────────────────
162
243
  .command(
163
244
  'link [name] [path]',
164
245
  'Link a local package for development',
165
- (yargs) => {
166
- yargs
167
- .positional('name', {
168
- type: 'string',
169
- description: 'Package name to link (omit to register current directory)',
170
- })
171
- .positional('path', {
172
- type: 'string',
173
- description: 'Local path to package (optional, uses global registry if omitted)',
174
- })
175
- .option('list', {
176
- type: 'boolean',
177
- description: 'List all globally registered packages',
178
- default: false,
179
- })
180
- .option('subdir', {
181
- type: 'string',
182
- description: 'Subdirectory within the package to link (e.g., "output/install" for CMake packages)',
183
- });
246
+ (y) => {
247
+ y
248
+ .positional('name', { type: 'string', description: 'Package name to link' })
249
+ .positional('path', { type: 'string', description: 'Local path to package' })
250
+ .option('list', { type: 'boolean', description: 'List all globally registered packages', default: false })
251
+ .option('subdir', { type: 'string', description: 'Subdirectory within the package to link' });
184
252
  },
185
253
  (argv) => link(argv),
186
254
  )
255
+
256
+ // ── unlink ────────────────────────────────────────────────────────────────
187
257
  .command(
188
258
  'unlink <name>',
189
259
  'Remove a linked package',
190
- (yargs) => {
191
- yargs
192
- .positional('name', {
193
- type: 'string',
194
- description: 'Package name to unlink',
195
- demandOption: true,
196
- })
197
- .option('restore', {
198
- type: 'boolean',
199
- description: 'Re-download the package from registry after unlinking',
200
- default: false,
201
- })
202
- .option('source', {
203
- alias: 's',
204
- type: 'string',
205
- description: 'Base URL of a package source (for --restore)',
206
- array: true,
207
- })
260
+ (y) => {
261
+ y
262
+ .positional('name', { type: 'string', demandOption: true })
263
+ .option('restore', { type: 'boolean', description: 'Re-download after unlinking', default: false })
264
+ .option('source', { alias: 's', type: 'string', array: true, description: 'Package source URL (for --restore)' })
208
265
  .option('platform', {
209
266
  type: 'string',
210
- description: 'Target platform (for --restore)',
211
267
  choices: ['win_x64', 'win_x86', 'linux_x64', 'linux_x86', 'osx_x64', 'osx_arm64'],
212
268
  default: 'win_x64',
213
269
  })
214
- .option('timeout', {
215
- type: 'number',
216
- description: 'HTTP timeout in seconds (for --restore)',
217
- default: 300,
218
- });
270
+ .option('timeout', { type: 'number', default: 300 });
219
271
  },
220
272
  (argv) => unlink(argv),
221
273
  )
274
+
222
275
  .demandCommand(1)
223
276
  .strict()
224
277
  .help()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wyvrnpm",
3
- "version": "1.3.2",
3
+ "version": "2.0.2",
4
4
  "description": "A simple, static-hosting-compatible C++ package manager",
5
5
  "keywords": [
6
6
  "c++",
@@ -1,40 +1,40 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
-
6
- /**
7
- * Removes the wyvrn_internal/ package cache directory and the wyvrn.lock file.
8
- *
9
- * @param {object} argv - Parsed yargs arguments.
10
- * @param {string} argv.root - Project root directory.
11
- * @param {string} argv.manifest - Path to the manifest file (used to locate wyvrn.lock).
12
- * @returns {Promise<void>}
13
- */
14
- async function clean(argv) {
15
- const rootDir = path.resolve(argv.root);
16
- const razerDir = path.join(rootDir, 'wyvrn_internal');
17
- const lockPath = path.join(path.dirname(path.resolve(argv.manifest)), 'wyvrn.lock');
18
-
19
- let removedAnything = false;
20
-
21
- if (fs.existsSync(razerDir)) {
22
- fs.rmSync(razerDir, { recursive: true, force: true });
23
- console.log(`[wyvrn] Removed ${razerDir}`);
24
- removedAnything = true;
25
- } else {
26
- console.log(`[wyvrn] Nothing to clean at ${razerDir}`);
27
- }
28
-
29
- if (fs.existsSync(lockPath)) {
30
- fs.unlinkSync(lockPath);
31
- console.log(`[wyvrn] Removed ${lockPath}`);
32
- removedAnything = true;
33
- }
34
-
35
- if (!removedAnything) {
36
- console.log('[wyvrn] Nothing to clean.');
37
- }
38
- }
39
-
40
- module.exports = clean;
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ /**
7
+ * Removes the wyvrn_internal/ package cache directory and the wyvrn.lock file.
8
+ *
9
+ * @param {object} argv - Parsed yargs arguments.
10
+ * @param {string} argv.root - Project root directory.
11
+ * @param {string} argv.manifest - Path to the manifest file (used to locate wyvrn.lock).
12
+ * @returns {Promise<void>}
13
+ */
14
+ async function clean(argv) {
15
+ const rootDir = path.resolve(argv.root);
16
+ const razerDir = path.join(rootDir, 'wyvrn_internal');
17
+ const lockPath = path.join(path.dirname(path.resolve(argv.manifest)), 'wyvrn.lock');
18
+
19
+ let removedAnything = false;
20
+
21
+ if (fs.existsSync(razerDir)) {
22
+ fs.rmSync(razerDir, { recursive: true, force: true });
23
+ console.log(`[wyvrn] Removed ${razerDir}`);
24
+ removedAnything = true;
25
+ } else {
26
+ console.log(`[wyvrn] Nothing to clean at ${razerDir}`);
27
+ }
28
+
29
+ if (fs.existsSync(lockPath)) {
30
+ fs.unlinkSync(lockPath);
31
+ console.log(`[wyvrn] Removed ${lockPath}`);
32
+ removedAnything = true;
33
+ }
34
+
35
+ if (!removedAnything) {
36
+ console.log('[wyvrn] Nothing to clean.');
37
+ }
38
+ }
39
+
40
+ module.exports = clean;
@@ -1,80 +1,80 @@
1
- 'use strict';
2
-
3
- const { readConfig, writeConfig, getConfigPath } = require('../config');
4
-
5
- /** wyvrnpm configure list */
6
- function list() {
7
- const config = readConfig();
8
-
9
- console.log(`Config: ${getConfigPath()}\n`);
10
-
11
- printSection('Install Sources', config.installSources);
12
- console.log('');
13
- printSection('Publish Sources', config.publishSources);
14
- }
15
-
16
- function printSection(title, sources) {
17
- console.log(`${title}:`);
18
- if (sources.length === 0) {
19
- console.log(' (none)');
20
- return;
21
- }
22
- for (const src of sources) {
23
- const auth = authLabel(src);
24
- console.log(` ${src.name.padEnd(20)} ${src.url}${auth ? ' ' + auth : ''}`);
25
- }
26
- }
27
-
28
- function authLabel(src) {
29
- if (src.profile) return `[profile: ${src.profile}]`;
30
- if (src.token) return '[token: ***]';
31
- return '';
32
- }
33
-
34
- /**
35
- * wyvrnpm configure add-source --kind install|publish --name <name> --url <url>
36
- * [--profile <profile>] [--token <token>]
37
- */
38
- function addSource(argv) {
39
- const { kind, name, url, profile, token } = argv;
40
- const config = readConfig();
41
- const key = kind === 'install' ? 'installSources' : 'publishSources';
42
-
43
- const entry = { name, url };
44
- if (profile) entry.profile = profile;
45
- if (token) entry.token = token;
46
-
47
- const idx = config[key].findIndex((s) => s.name === name);
48
- if (idx !== -1) {
49
- config[key][idx] = entry;
50
- console.log(`[wyvrn] Updated ${kind} source "${name}"`);
51
- } else {
52
- config[key].push(entry);
53
- console.log(`[wyvrn] Added ${kind} source "${name}"`);
54
- }
55
-
56
- writeConfig(config);
57
- console.log(`[wyvrn] Saved to ${getConfigPath()}`);
58
- }
59
-
60
- /**
61
- * wyvrnpm configure remove-source --kind install|publish --name <name>
62
- */
63
- function removeSource(argv) {
64
- const { kind, name } = argv;
65
- const config = readConfig();
66
- const key = kind === 'install' ? 'installSources' : 'publishSources';
67
-
68
- const before = config[key].length;
69
- config[key] = config[key].filter((s) => s.name !== name);
70
-
71
- if (config[key].length === before) {
72
- console.error(`[wyvrn] Error: No ${kind} source named "${name}"`);
73
- process.exit(1);
74
- }
75
-
76
- writeConfig(config);
77
- console.log(`[wyvrn] Removed ${kind} source "${name}"`);
78
- }
79
-
80
- module.exports = { list, addSource, removeSource };
1
+ 'use strict';
2
+
3
+ const { readConfig, writeConfig, getConfigPath } = require('../config');
4
+
5
+ /** wyvrnpm configure list */
6
+ function list() {
7
+ const config = readConfig();
8
+
9
+ console.log(`Config: ${getConfigPath()}\n`);
10
+
11
+ printSection('Install Sources', config.installSources);
12
+ console.log('');
13
+ printSection('Publish Sources', config.publishSources);
14
+ }
15
+
16
+ function printSection(title, sources) {
17
+ console.log(`${title}:`);
18
+ if (sources.length === 0) {
19
+ console.log(' (none)');
20
+ return;
21
+ }
22
+ for (const src of sources) {
23
+ const auth = authLabel(src);
24
+ console.log(` ${src.name.padEnd(20)} ${src.url}${auth ? ' ' + auth : ''}`);
25
+ }
26
+ }
27
+
28
+ function authLabel(src) {
29
+ if (src.profile) return `[profile: ${src.profile}]`;
30
+ if (src.token) return '[token: ***]';
31
+ return '';
32
+ }
33
+
34
+ /**
35
+ * wyvrnpm configure add-source --kind install|publish --name <name> --url <url>
36
+ * [--profile <profile>] [--token <token>]
37
+ */
38
+ function addSource(argv) {
39
+ const { kind, name, url, profile, token } = argv;
40
+ const config = readConfig();
41
+ const key = kind === 'install' ? 'installSources' : 'publishSources';
42
+
43
+ const entry = { name, url };
44
+ if (profile) entry.profile = profile;
45
+ if (token) entry.token = token;
46
+
47
+ const idx = config[key].findIndex((s) => s.name === name);
48
+ if (idx !== -1) {
49
+ config[key][idx] = entry;
50
+ console.log(`[wyvrn] Updated ${kind} source "${name}"`);
51
+ } else {
52
+ config[key].push(entry);
53
+ console.log(`[wyvrn] Added ${kind} source "${name}"`);
54
+ }
55
+
56
+ writeConfig(config);
57
+ console.log(`[wyvrn] Saved to ${getConfigPath()}`);
58
+ }
59
+
60
+ /**
61
+ * wyvrnpm configure remove-source --kind install|publish --name <name>
62
+ */
63
+ function removeSource(argv) {
64
+ const { kind, name } = argv;
65
+ const config = readConfig();
66
+ const key = kind === 'install' ? 'installSources' : 'publishSources';
67
+
68
+ const before = config[key].length;
69
+ config[key] = config[key].filter((s) => s.name !== name);
70
+
71
+ if (config[key].length === before) {
72
+ console.error(`[wyvrn] Error: No ${kind} source named "${name}"`);
73
+ process.exit(1);
74
+ }
75
+
76
+ writeConfig(config);
77
+ console.log(`[wyvrn] Removed ${kind} source "${name}"`);
78
+ }
79
+
80
+ module.exports = { list, addSource, removeSource };