@nemus-cli/nemus 0.11.0 → 0.12.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/CHANGELOG.md +13 -0
- package/README.md +1 -0
- package/dist/commands/version.js +37 -0
- package/dist/program.js +2 -0
- package/dist/utils/version-check.js +15 -0
- package/package.json +1 -1
- package/src/commands/version.test.ts +21 -0
- package/src/commands/version.ts +45 -0
- package/src/program.ts +2 -0
- package/src/utils/version-check.test.ts +28 -1
- package/src/utils/version-check.ts +15 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.12.0] - 2026-09-02
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`nemus version` subcommand** — a companion to the `-V/--version` flag for
|
|
15
|
+
people who type `nemus version`. `--json` additionally reports the Node.js
|
|
16
|
+
version, platform, and arch (handy for bug reports), as a single JSON document
|
|
17
|
+
to stdout. (#74)
|
|
18
|
+
- **`NEMUS_NO_UPDATE_CHECK`** — opt out of the background "update available"
|
|
19
|
+
check entirely (no cache read, no network). Also honors the de-facto
|
|
20
|
+
`NO_UPDATE_NOTIFIER`. An explicit falsey value (`0`/`false`/empty) does not
|
|
21
|
+
disable it. Documented in the README env-var table. (#76)
|
|
22
|
+
|
|
10
23
|
## [0.11.0] - 2026-09-02
|
|
11
24
|
|
|
12
25
|
### Added
|
package/README.md
CHANGED
|
@@ -288,6 +288,7 @@ Everything Nemus reads from the environment (all optional):
|
|
|
288
288
|
| `NEMUS_JUDGE_TIMEOUT_MS` | Timeout for the `reflect` judge call. |
|
|
289
289
|
| `NEMUS_BUG_REPORT_REPO` | Repo that `report-bug` files issues against. |
|
|
290
290
|
| `NEMUS_SKIP_CONFIGURE` | Skip the one-time post-install `configure` prompt. |
|
|
291
|
+
| `NEMUS_NO_UPDATE_CHECK` | Disable the background "update available" check (also honors `NO_UPDATE_NOTIFIER`). |
|
|
291
292
|
| `WORKSPACE_CLONE_TIMEOUT_MS` | Git clone timeout (default 15 min). |
|
|
292
293
|
| `NO_COLOR` / `FORCE_COLOR` | Disable / force ANSI color (see [Global flags](#global-flags)). |
|
|
293
294
|
| `VISUAL` / `EDITOR` | Editor launched by `nemus config edit`. |
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildVersionInfo = buildVersionInfo;
|
|
4
|
+
exports.registerVersionCommand = registerVersionCommand;
|
|
5
|
+
const output_1 = require("../utils/output");
|
|
6
|
+
/**
|
|
7
|
+
* Build the version payload. Pure and process-injectable so the JSON shape is
|
|
8
|
+
* unit-testable without reading the real runtime.
|
|
9
|
+
*/
|
|
10
|
+
function buildVersionInfo(version, proc = process) {
|
|
11
|
+
return {
|
|
12
|
+
version,
|
|
13
|
+
node: proc.versions.node,
|
|
14
|
+
platform: proc.platform,
|
|
15
|
+
arch: proc.arch,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* `nemus version` — a subcommand companion to the `-V/--version` flag, for
|
|
20
|
+
* people who type `nemus version`. `--json` also reports the Node/OS runtime
|
|
21
|
+
* (handy for bug reports), emitting a single JSON document to stdout.
|
|
22
|
+
*/
|
|
23
|
+
function registerVersionCommand(program, version) {
|
|
24
|
+
program
|
|
25
|
+
.command('version')
|
|
26
|
+
.description('Print the Nemus version (with --json for version + runtime info)')
|
|
27
|
+
.option('--json', 'Output version + runtime info as JSON')
|
|
28
|
+
.action((opts) => {
|
|
29
|
+
const info = buildVersionInfo(version);
|
|
30
|
+
if (opts.json) {
|
|
31
|
+
(0, output_1.outputJson)(info);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
process.stdout.write(`nemus ${info.version}\n`);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
package/dist/program.js
CHANGED
|
@@ -40,6 +40,7 @@ const fs = __importStar(require("fs"));
|
|
|
40
40
|
const colors_1 = require("./utils/colors");
|
|
41
41
|
const banner_1 = require("./utils/banner");
|
|
42
42
|
const global_flags_1 = require("./utils/global-flags");
|
|
43
|
+
const version_1 = require("./commands/version");
|
|
43
44
|
// Read version from package.json
|
|
44
45
|
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
45
46
|
// --no-color must be applied BEFORE commander parses so it reaches the help
|
|
@@ -66,6 +67,7 @@ exports.program
|
|
|
66
67
|
// also pre-scanned above.
|
|
67
68
|
exports.program.hook('preAction', () => (0, global_flags_1.applyGlobalFlags)(exports.program.opts()));
|
|
68
69
|
// Register top-level commands
|
|
70
|
+
(0, version_1.registerVersionCommand)(exports.program, pkg.version);
|
|
69
71
|
const create_1 = require("./commands/create");
|
|
70
72
|
const list_1 = require("./commands/list");
|
|
71
73
|
const update_1 = require("./commands/update");
|
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.checkForUpdate = checkForUpdate;
|
|
37
|
+
exports.updateCheckDisabled = updateCheckDisabled;
|
|
37
38
|
const fs = __importStar(require("fs/promises"));
|
|
38
39
|
const path = __importStar(require("path"));
|
|
39
40
|
const child_process_1 = require("child_process");
|
|
@@ -89,6 +90,11 @@ async function fetchLatestVersion() {
|
|
|
89
90
|
* This is designed to be non-blocking and best-effort — failures are silent.
|
|
90
91
|
*/
|
|
91
92
|
async function checkForUpdate() {
|
|
93
|
+
// Opt-out: skip the check entirely (no cache read, no network) when the user
|
|
94
|
+
// asks for it. NEMUS_NO_UPDATE_CHECK is ours; NO_UPDATE_NOTIFIER is the
|
|
95
|
+
// de-facto convention several Node CLIs honor.
|
|
96
|
+
if (updateCheckDisabled(process.env))
|
|
97
|
+
return null;
|
|
92
98
|
try {
|
|
93
99
|
const currentVersion = (0, config_1.getPackageVersion)();
|
|
94
100
|
const cache = await loadCache();
|
|
@@ -116,6 +122,15 @@ async function checkForUpdate() {
|
|
|
116
122
|
return null;
|
|
117
123
|
}
|
|
118
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Whether the update check is opted out via env. A value is "set" unless it is
|
|
127
|
+
* empty or an explicit falsey token (`0`/`false`), so `NEMUS_NO_UPDATE_CHECK=0`
|
|
128
|
+
* does NOT disable the check. Pure + exported for testing.
|
|
129
|
+
*/
|
|
130
|
+
function updateCheckDisabled(env) {
|
|
131
|
+
const isSet = (v) => v !== undefined && v !== '' && v !== '0' && v.toLowerCase() !== 'false';
|
|
132
|
+
return isSet(env.NEMUS_NO_UPDATE_CHECK) || isSet(env.NO_UPDATE_NOTIFIER);
|
|
133
|
+
}
|
|
119
134
|
function formatUpdateMessage(current, latest) {
|
|
120
135
|
return `\x1b[33m[nemus] Update available: ${current} -> ${latest}. Run: npm install -g @nemus-cli/nemus@latest\x1b[0m`;
|
|
121
136
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { buildVersionInfo } from './version';
|
|
3
|
+
|
|
4
|
+
describe('buildVersionInfo', () => {
|
|
5
|
+
it('combines the given version with the injected runtime fields', () => {
|
|
6
|
+
const info = buildVersionInfo('1.2.3', {
|
|
7
|
+
versions: { node: '22.13.0' } as NodeJS.ProcessVersions,
|
|
8
|
+
platform: 'linux',
|
|
9
|
+
arch: 'x64',
|
|
10
|
+
});
|
|
11
|
+
expect(info).toEqual({ version: '1.2.3', node: '22.13.0', platform: 'linux', arch: 'x64' });
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('defaults to the real process runtime', () => {
|
|
15
|
+
const info = buildVersionInfo('9.9.9');
|
|
16
|
+
expect(info.version).toBe('9.9.9');
|
|
17
|
+
expect(info.node).toBe(process.versions.node);
|
|
18
|
+
expect(info.platform).toBe(process.platform);
|
|
19
|
+
expect(info.arch).toBe(process.arch);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { outputJson } from '../utils/output';
|
|
3
|
+
|
|
4
|
+
export interface VersionInfo {
|
|
5
|
+
version: string;
|
|
6
|
+
node: string;
|
|
7
|
+
platform: string;
|
|
8
|
+
arch: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Build the version payload. Pure and process-injectable so the JSON shape is
|
|
13
|
+
* unit-testable without reading the real runtime.
|
|
14
|
+
*/
|
|
15
|
+
export function buildVersionInfo(
|
|
16
|
+
version: string,
|
|
17
|
+
proc: Pick<NodeJS.Process, 'versions' | 'platform' | 'arch'> = process,
|
|
18
|
+
): VersionInfo {
|
|
19
|
+
return {
|
|
20
|
+
version,
|
|
21
|
+
node: proc.versions.node,
|
|
22
|
+
platform: proc.platform,
|
|
23
|
+
arch: proc.arch,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* `nemus version` — a subcommand companion to the `-V/--version` flag, for
|
|
29
|
+
* people who type `nemus version`. `--json` also reports the Node/OS runtime
|
|
30
|
+
* (handy for bug reports), emitting a single JSON document to stdout.
|
|
31
|
+
*/
|
|
32
|
+
export function registerVersionCommand(program: Command, version: string) {
|
|
33
|
+
program
|
|
34
|
+
.command('version')
|
|
35
|
+
.description('Print the Nemus version (with --json for version + runtime info)')
|
|
36
|
+
.option('--json', 'Output version + runtime info as JSON')
|
|
37
|
+
.action((opts: { json?: boolean }) => {
|
|
38
|
+
const info = buildVersionInfo(version);
|
|
39
|
+
if (opts.json) {
|
|
40
|
+
outputJson(info);
|
|
41
|
+
} else {
|
|
42
|
+
process.stdout.write(`nemus ${info.version}\n`);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
package/src/program.ts
CHANGED
|
@@ -4,6 +4,7 @@ import * as fs from 'fs';
|
|
|
4
4
|
import { setColorEnabled } from './utils/colors';
|
|
5
5
|
import { renderHelpBanner } from './utils/banner';
|
|
6
6
|
import { applyGlobalFlags } from './utils/global-flags';
|
|
7
|
+
import { registerVersionCommand } from './commands/version';
|
|
7
8
|
|
|
8
9
|
// Read version from package.json
|
|
9
10
|
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
@@ -35,6 +36,7 @@ program
|
|
|
35
36
|
program.hook('preAction', () => applyGlobalFlags(program.opts()));
|
|
36
37
|
|
|
37
38
|
// Register top-level commands
|
|
39
|
+
registerVersionCommand(program, pkg.version);
|
|
38
40
|
import { registerCreateCommand } from './commands/create';
|
|
39
41
|
import { registerListCommand } from './commands/list';
|
|
40
42
|
import { registerUpdateCommand } from './commands/update';
|
|
@@ -24,14 +24,41 @@ vi.mock('./config', () => ({
|
|
|
24
24
|
getPackageVersion: () => '2.20.0',
|
|
25
25
|
}));
|
|
26
26
|
|
|
27
|
-
import { checkForUpdate } from './version-check';
|
|
27
|
+
import { checkForUpdate, updateCheckDisabled } from './version-check';
|
|
28
28
|
import * as fs from 'fs/promises';
|
|
29
29
|
|
|
30
|
+
describe('updateCheckDisabled', () => {
|
|
31
|
+
it('is true when NEMUS_NO_UPDATE_CHECK is set to a truthy value', () => {
|
|
32
|
+
expect(updateCheckDisabled({ NEMUS_NO_UPDATE_CHECK: '1' })).toBe(true);
|
|
33
|
+
expect(updateCheckDisabled({ NEMUS_NO_UPDATE_CHECK: 'yes' })).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
it('honors the de-facto NO_UPDATE_NOTIFIER', () => {
|
|
36
|
+
expect(updateCheckDisabled({ NO_UPDATE_NOTIFIER: 'true' })).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
it('is false when unset, empty, or an explicit falsey token', () => {
|
|
39
|
+
expect(updateCheckDisabled({})).toBe(false);
|
|
40
|
+
expect(updateCheckDisabled({ NEMUS_NO_UPDATE_CHECK: '' })).toBe(false);
|
|
41
|
+
expect(updateCheckDisabled({ NEMUS_NO_UPDATE_CHECK: '0' })).toBe(false);
|
|
42
|
+
expect(updateCheckDisabled({ NEMUS_NO_UPDATE_CHECK: 'false' })).toBe(false);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
30
46
|
describe('checkForUpdate', () => {
|
|
31
47
|
beforeEach(() => {
|
|
32
48
|
vi.clearAllMocks();
|
|
33
49
|
});
|
|
34
50
|
|
|
51
|
+
it('returns null immediately when opted out via env (no fetch)', async () => {
|
|
52
|
+
process.env.NEMUS_NO_UPDATE_CHECK = '1';
|
|
53
|
+
try {
|
|
54
|
+
const result = await checkForUpdate();
|
|
55
|
+
expect(result).toBeNull();
|
|
56
|
+
expect(mockExecFile).not.toHaveBeenCalled();
|
|
57
|
+
} finally {
|
|
58
|
+
delete process.env.NEMUS_NO_UPDATE_CHECK;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
35
62
|
it('returns null when current version matches latest', async () => {
|
|
36
63
|
// No cached check
|
|
37
64
|
vi.mocked(fs.readFile).mockRejectedValueOnce(new Error('ENOENT'));
|
|
@@ -60,6 +60,10 @@ async function fetchLatestVersion(): Promise<string | null> {
|
|
|
60
60
|
* This is designed to be non-blocking and best-effort — failures are silent.
|
|
61
61
|
*/
|
|
62
62
|
export async function checkForUpdate(): Promise<string | null> {
|
|
63
|
+
// Opt-out: skip the check entirely (no cache read, no network) when the user
|
|
64
|
+
// asks for it. NEMUS_NO_UPDATE_CHECK is ours; NO_UPDATE_NOTIFIER is the
|
|
65
|
+
// de-facto convention several Node CLIs honor.
|
|
66
|
+
if (updateCheckDisabled(process.env)) return null;
|
|
63
67
|
try {
|
|
64
68
|
const currentVersion = getPackageVersion();
|
|
65
69
|
const cache = await loadCache();
|
|
@@ -91,6 +95,17 @@ export async function checkForUpdate(): Promise<string | null> {
|
|
|
91
95
|
}
|
|
92
96
|
}
|
|
93
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Whether the update check is opted out via env. A value is "set" unless it is
|
|
100
|
+
* empty or an explicit falsey token (`0`/`false`), so `NEMUS_NO_UPDATE_CHECK=0`
|
|
101
|
+
* does NOT disable the check. Pure + exported for testing.
|
|
102
|
+
*/
|
|
103
|
+
export function updateCheckDisabled(env: NodeJS.ProcessEnv): boolean {
|
|
104
|
+
const isSet = (v: string | undefined) =>
|
|
105
|
+
v !== undefined && v !== '' && v !== '0' && v.toLowerCase() !== 'false';
|
|
106
|
+
return isSet(env.NEMUS_NO_UPDATE_CHECK) || isSet(env.NO_UPDATE_NOTIFIER);
|
|
107
|
+
}
|
|
108
|
+
|
|
94
109
|
function formatUpdateMessage(current: string, latest: string): string {
|
|
95
110
|
return `\x1b[33m[nemus] Update available: ${current} -> ${latest}. Run: npm install -g @nemus-cli/nemus@latest\x1b[0m`;
|
|
96
111
|
}
|