@jacebenson/jsn 4.3.13-dev.104.1 → 4.3.13-dev.106.1
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 +6 -2
- package/package.json +1 -1
- package/src/cli.js +2 -0
- package/src/command-audience.js +1 -1
- package/src/commands/upgrade.js +69 -0
- package/src/commands/version.js +2 -2
package/README.md
CHANGED
|
@@ -23,8 +23,12 @@ npm install -g @jacebenson/jsn@dev
|
|
|
23
23
|
|
|
24
24
|
Dev builds check the dev channel for updates during normal use, at most once
|
|
25
25
|
per day. Run `jsn version --check` to check immediately. To install the newest
|
|
26
|
-
dev build, run `
|
|
27
|
-
|
|
26
|
+
dev build, run `jsn upgrade` (alias: `jsn update`). It preserves your installed
|
|
27
|
+
channel and skips installation when no newer version is available. Use
|
|
28
|
+
`--dry-run` to print the npm command without network access or installation,
|
|
29
|
+
`--force` to reinstall, or `--channel dev|latest` to switch channels explicitly.
|
|
30
|
+
For example, `jsn upgrade --channel latest` returns to stable. npm installation
|
|
31
|
+
permissions still apply; the command does not elevate privileges automatically.
|
|
28
32
|
|
|
29
33
|
Pushes to `main` promote the commit to `dev` and publish a tested prerelease
|
|
30
34
|
under npm's `dev` tag. Versions include the workflow run number and attempt
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -39,6 +39,7 @@ import { transactionsCmd } from './commands/transactions.js';
|
|
|
39
39
|
import { platformCmd } from './commands/platform.js';
|
|
40
40
|
import { codesearchCmd } from './commands/codesearch.js';
|
|
41
41
|
import { versionCmd } from './commands/version.js';
|
|
42
|
+
import { upgradeCmd } from './commands/upgrade.js';
|
|
42
43
|
import { skillCmd, checkSkill } from './commands/skill.js';
|
|
43
44
|
import { getVersion, checkLatest, getReleaseChannel, getInstallCommand } from './commands/version.js';
|
|
44
45
|
import { docsCmd } from './commands/docs/docs.js';
|
|
@@ -438,6 +439,7 @@ export function buildCLI() {
|
|
|
438
439
|
.command(skillCmd(wrap))
|
|
439
440
|
.command(docsCmd(wrap))
|
|
440
441
|
.command(versionCmd(wrap))
|
|
442
|
+
.command(upgradeCmd(wrap))
|
|
441
443
|
.command(discoverCmd(wrap, (argv) => visibleCommandRegistry(cliInstance.commandRegistry(), app.config, argv)))
|
|
442
444
|
.demandCommand(1, 'You must specify a command')
|
|
443
445
|
// Completion plumbing under a hidden command name, so the explicit
|
package/src/command-audience.js
CHANGED
|
@@ -5,7 +5,7 @@ const BASIC_COMMANDS = new Set([
|
|
|
5
5
|
'knowledge',
|
|
6
6
|
'groups', 'groupmembers', 'grouproles', 'users', 'setup', 'auth', 'skill',
|
|
7
7
|
'cmdb',
|
|
8
|
-
'version', 'docs', 'history', 'discover', 'completion',
|
|
8
|
+
'version', 'upgrade', 'docs', 'history', 'discover', 'completion',
|
|
9
9
|
'catalogitems',
|
|
10
10
|
]);
|
|
11
11
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { declareCapabilities } from '../capabilities.js';
|
|
3
|
+
import { AppError, CodeAPI, CodeNetwork } from '../errors.js';
|
|
4
|
+
import { checkLatest, getReleaseChannel, getVersion } from './version.js';
|
|
5
|
+
|
|
6
|
+
for (const name of ['upgrade', 'update']) {
|
|
7
|
+
declareCapabilities(name, { noInstance: true, skipDailyChecks: true });
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function installPackage(args, { structured }) {
|
|
11
|
+
const result = spawnSync('npm', args, { stdio: structured ? 'pipe' : 'inherit', encoding: 'utf8' });
|
|
12
|
+
if (result.error || result.status !== 0) {
|
|
13
|
+
throw new AppError(CodeAPI, 'npm could not upgrade jsn.', 'Check npm installation permissions and connectivity, then retry.');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function isNewer(candidate, installed) {
|
|
18
|
+
const parse = (value) => {
|
|
19
|
+
const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(value);
|
|
20
|
+
if (!match) throw new AppError(CodeAPI, 'The registry returned an invalid package version.');
|
|
21
|
+
return { core: match.slice(1, 4).map(Number), pre: match[4]?.split('.') };
|
|
22
|
+
};
|
|
23
|
+
const a = parse(candidate), b = parse(installed);
|
|
24
|
+
for (let i = 0; i < 3; i++) {
|
|
25
|
+
if (a.core[i] !== b.core[i]) return a.core[i] > b.core[i];
|
|
26
|
+
}
|
|
27
|
+
if (!a.pre || !b.pre) return !a.pre && Boolean(b.pre);
|
|
28
|
+
for (let i = 0; i < Math.max(a.pre.length, b.pre.length); i++) {
|
|
29
|
+
if (a.pre[i] === b.pre[i]) continue;
|
|
30
|
+
if (a.pre[i] === undefined) return false;
|
|
31
|
+
if (b.pre[i] === undefined) return true;
|
|
32
|
+
const an = /^\d+$/.test(a.pre[i]), bn = /^\d+$/.test(b.pre[i]);
|
|
33
|
+
if (an && bn) return Number(a.pre[i]) > Number(b.pre[i]);
|
|
34
|
+
if (an !== bn) return !an;
|
|
35
|
+
return a.pre[i] > b.pre[i];
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function upgradeCmd(wrap, { version = getVersion, check = checkLatest, install = installPackage } = {}) {
|
|
41
|
+
return {
|
|
42
|
+
command: 'upgrade',
|
|
43
|
+
aliases: ['update'],
|
|
44
|
+
describe: 'Upgrade jsn through npm (preserves the installed release channel)',
|
|
45
|
+
builder: (y) => y
|
|
46
|
+
.option('channel', { type: 'string', choices: ['dev', 'latest'], describe: 'Choose the npm release channel' })
|
|
47
|
+
.option('dry-run', { type: 'boolean', describe: 'Show the install command without installing' })
|
|
48
|
+
.option('force', { type: 'boolean', describe: 'Reinstall even when the selected version is not newer' }),
|
|
49
|
+
handler: wrap(async (argv, app) => {
|
|
50
|
+
const current = version();
|
|
51
|
+
const channel = argv.channel || getReleaseChannel(current);
|
|
52
|
+
const args = ['install', '-g', `@jacebenson/jsn@${channel}`];
|
|
53
|
+
const command = `npm ${args.join(' ')}`;
|
|
54
|
+
if (argv.dryRun || argv['dry-run']) {
|
|
55
|
+
app.ok({ version: current, channel, dryRun: true, installCmd: command }, { summary: command });
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const latest = await check({ version: current, channel });
|
|
59
|
+
if (!latest) throw new AppError(CodeNetwork, 'Could not check the npm release channel.', 'Check connectivity and retry; use --dry-run to inspect the command.');
|
|
60
|
+
const switching = argv.channel && channel !== getReleaseChannel(current);
|
|
61
|
+
if (!argv.force && !switching && !isNewer(latest, current)) {
|
|
62
|
+
app.ok({ version: current, latest, channel, upToDate: true }, { summary: `jsn ${current} — no newer version available` });
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
await install(args, { structured: Boolean(!process.stdout.isTTY || argv.json || argv.get || argv.format === 'json') });
|
|
66
|
+
app.ok({ previousVersion: current, version: latest, channel, upgraded: true }, { summary: `Installed jsn from the ${channel} channel (registry version ${latest})` });
|
|
67
|
+
}),
|
|
68
|
+
};
|
|
69
|
+
}
|
package/src/commands/version.js
CHANGED
|
@@ -32,13 +32,13 @@ export function cancelBackgroundChecks() {
|
|
|
32
32
|
backgroundChecks.clear();
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export async function checkLatest({ timeout = 1500, background = false, version = getVersion() } = {}) {
|
|
35
|
+
export async function checkLatest({ timeout = 1500, background = false, version = getVersion(), channel = getReleaseChannel(version) } = {}) {
|
|
36
36
|
const controller = new AbortController();
|
|
37
37
|
const timer = setTimeout(() => controller.abort(), timeout);
|
|
38
38
|
timer.unref();
|
|
39
39
|
if (background) backgroundChecks.add(controller);
|
|
40
40
|
try {
|
|
41
|
-
const res = await fetch(`https://registry.npmjs.org/${NPM_PKG}/${
|
|
41
|
+
const res = await fetch(`https://registry.npmjs.org/${NPM_PKG}/${channel}`, { signal: controller.signal });
|
|
42
42
|
if (!res.ok) return null;
|
|
43
43
|
const data = await res.json();
|
|
44
44
|
return typeof data.version === 'string' ? data.version : null;
|