jamdesk 1.1.101 → 1.1.103
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/dist/__tests__/unit/first-run-banner.test.d.ts +2 -0
- package/dist/__tests__/unit/first-run-banner.test.d.ts.map +1 -0
- package/dist/__tests__/unit/first-run-banner.test.js +84 -0
- package/dist/__tests__/unit/first-run-banner.test.js.map +1 -0
- package/dist/__tests__/unit/install-banner-gating.test.d.ts +2 -0
- package/dist/__tests__/unit/install-banner-gating.test.d.ts.map +1 -0
- package/dist/__tests__/unit/install-banner-gating.test.js +54 -0
- package/dist/__tests__/unit/install-banner-gating.test.js.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/first-run-banner.d.ts +7 -0
- package/dist/lib/first-run-banner.d.ts.map +1 -0
- package/dist/lib/first-run-banner.js +79 -0
- package/dist/lib/first-run-banner.js.map +1 -0
- package/package.json +1 -1
- package/scripts/install-banner.js +9 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"first-run-banner.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/first-run-banner.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* First-run banner contract (src/lib/first-run-banner.ts).
|
|
3
|
+
*
|
|
4
|
+
* The npm postinstall banner is undeliverable for `npm i -g` (npm swallows
|
|
5
|
+
* global postinstall stdout — see install-banner-gating.test.ts). This
|
|
6
|
+
* first-run banner is the replacement; these tests pin its gating so it
|
|
7
|
+
* shows exactly once, on the first real command, in a real terminal only.
|
|
8
|
+
*/
|
|
9
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
10
|
+
import fs from 'fs';
|
|
11
|
+
import os from 'os';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import { maybeShowFirstRunBanner } from '../../lib/first-run-banner.js';
|
|
14
|
+
let tmp;
|
|
15
|
+
let writeSpy;
|
|
16
|
+
const savedTTY = Object.getOwnPropertyDescriptor(process.stdout, 'isTTY');
|
|
17
|
+
const savedEnv = { CI: process.env.CI, JAMDESK_INSTALLER: process.env.JAMDESK_INSTALLER };
|
|
18
|
+
function out() {
|
|
19
|
+
return writeSpy.mock.calls.map((c) => String(c[0])).join('');
|
|
20
|
+
}
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'jd-firstrun-'));
|
|
23
|
+
writeSpy = vi.spyOn(process.stdout, 'write').mockReturnValue(true);
|
|
24
|
+
// A real interactive terminal is a TTY; vitest's stdout is not.
|
|
25
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });
|
|
26
|
+
delete process.env.CI;
|
|
27
|
+
delete process.env.JAMDESK_INSTALLER;
|
|
28
|
+
});
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
writeSpy.mockRestore();
|
|
31
|
+
if (savedTTY)
|
|
32
|
+
Object.defineProperty(process.stdout, 'isTTY', savedTTY);
|
|
33
|
+
for (const [k, v] of Object.entries(savedEnv)) {
|
|
34
|
+
if (v === undefined)
|
|
35
|
+
delete process.env[k];
|
|
36
|
+
else
|
|
37
|
+
process.env[k] = v;
|
|
38
|
+
}
|
|
39
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
40
|
+
});
|
|
41
|
+
describe('maybeShowFirstRunBanner', () => {
|
|
42
|
+
it('shows the art once on the first real command, then writes the sentinel', () => {
|
|
43
|
+
maybeShowFirstRunBanner({ argv: ['dev'], jamdeskDir: tmp });
|
|
44
|
+
const text = out();
|
|
45
|
+
expect(text).toContain('| | __ _ _ __ ___ __| | ___ ___| | __'); // art line
|
|
46
|
+
expect(text).toContain('Get started:');
|
|
47
|
+
expect(text).toContain('jamdesk init');
|
|
48
|
+
expect(fs.existsSync(path.join(tmp, '.welcomed'))).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
it('stays silent once the sentinel exists (shows exactly once)', () => {
|
|
51
|
+
fs.writeFileSync(path.join(tmp, '.welcomed'), 'x\n');
|
|
52
|
+
maybeShowFirstRunBanner({ argv: ['dev'], jamdeskDir: tmp });
|
|
53
|
+
expect(out()).toBe('');
|
|
54
|
+
});
|
|
55
|
+
it('does not show OR consume first-run for --version', () => {
|
|
56
|
+
maybeShowFirstRunBanner({ argv: ['--version'], jamdeskDir: tmp });
|
|
57
|
+
expect(out()).toBe('');
|
|
58
|
+
expect(fs.existsSync(path.join(tmp, '.welcomed'))).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
it('does not show for bare `jamdesk` (help) or --json', () => {
|
|
61
|
+
maybeShowFirstRunBanner({ argv: [], jamdeskDir: tmp });
|
|
62
|
+
maybeShowFirstRunBanner({ argv: ['doctor', '--json'], jamdeskDir: tmp });
|
|
63
|
+
expect(out()).toBe('');
|
|
64
|
+
expect(fs.existsSync(path.join(tmp, '.welcomed'))).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
it('stays silent in CI', () => {
|
|
67
|
+
process.env.CI = 'true';
|
|
68
|
+
maybeShowFirstRunBanner({ argv: ['dev'], jamdeskDir: tmp });
|
|
69
|
+
expect(out()).toBe('');
|
|
70
|
+
});
|
|
71
|
+
it('stays silent when stdout is not a TTY (piped / scripted)', () => {
|
|
72
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: false, configurable: true });
|
|
73
|
+
maybeShowFirstRunBanner({ argv: ['dev'], jamdeskDir: tmp });
|
|
74
|
+
expect(out()).toBe('');
|
|
75
|
+
});
|
|
76
|
+
it('still prints (and never throws) if the sentinel write fails', () => {
|
|
77
|
+
// jamdeskDir points at a file → mkdir/write fail, banner must still show.
|
|
78
|
+
const asFile = path.join(tmp, 'not-a-dir');
|
|
79
|
+
fs.writeFileSync(asFile, 'x');
|
|
80
|
+
expect(() => maybeShowFirstRunBanner({ argv: ['dev'], jamdeskDir: asFile })).not.toThrow();
|
|
81
|
+
expect(out()).toContain('Get started:');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=first-run-banner.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"first-run-banner.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/first-run-banner.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-banner-gating.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/install-banner-gating.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gating contract for the npm postinstall banner (scripts/install-banner.js).
|
|
3
|
+
*
|
|
4
|
+
* Regression guard for the 1.1.101 ship bug: the script gated on
|
|
5
|
+
* `process.stdout.isTTY`, but npm >=7 runs `postinstall` with stdout PIPED
|
|
6
|
+
* (never a TTY) unless the user passes `--foreground-scripts`. That gate
|
|
7
|
+
* therefore suppressed the banner on every normal `npm i -g jamdesk` — the
|
|
8
|
+
* feature was dead on arrival and no test caught it.
|
|
9
|
+
*
|
|
10
|
+
* These tests run the REAL shipped script as a child process with stdout
|
|
11
|
+
* piped — i.e. exactly npm's postinstall condition (child.stdout.isTTY is
|
|
12
|
+
* undefined). A correctly-gated banner MUST still print here. The script is
|
|
13
|
+
* un-exported and side-effecting by design (zero-dep, must never fail an
|
|
14
|
+
* install), so we assert through its observable output, not internals.
|
|
15
|
+
*/
|
|
16
|
+
import { describe, it, expect } from 'vitest';
|
|
17
|
+
import { spawnSync } from 'node:child_process';
|
|
18
|
+
import path from 'node:path';
|
|
19
|
+
import { fileURLToPath } from 'node:url';
|
|
20
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
21
|
+
const script = path.join(here, '../../../scripts/install-banner.js');
|
|
22
|
+
// A clean global-install env: only what node needs + npm's global marker.
|
|
23
|
+
// Built from scratch (not spreading process.env) so the host's CI=… or a
|
|
24
|
+
// stray npm_config_* can't leak in and flip the gate under test.
|
|
25
|
+
function run(env) {
|
|
26
|
+
return spawnSync(process.execPath, [script], {
|
|
27
|
+
env: { PATH: process.env.PATH ?? '', NO_COLOR: '1', ...env },
|
|
28
|
+
encoding: 'utf8',
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
const GLOBAL_INSTALL = { npm_config_global: 'true' };
|
|
32
|
+
describe('install-banner postinstall gating', () => {
|
|
33
|
+
it('prints the banner on a normal global install with PIPED stdout (npm postinstall reality)', () => {
|
|
34
|
+
const { stdout, status } = run(GLOBAL_INSTALL);
|
|
35
|
+
// The exact regression: child stdout is a pipe here, never a TTY.
|
|
36
|
+
expect(stdout).toContain('Jamdesk CLI installed:');
|
|
37
|
+
expect(stdout).toContain('jamdesk init');
|
|
38
|
+
// Cosmetic — must never fail the install.
|
|
39
|
+
expect(status).toBe(0);
|
|
40
|
+
});
|
|
41
|
+
it('stays silent for a non-global install (npm i / npm ci of deps)', () => {
|
|
42
|
+
expect(run({}).stdout).toBe('');
|
|
43
|
+
});
|
|
44
|
+
it('stays silent in CI', () => {
|
|
45
|
+
expect(run({ ...GLOBAL_INSTALL, CI: 'true' }).stdout).toBe('');
|
|
46
|
+
});
|
|
47
|
+
it('stays silent when the bootstrap installer already showed a banner', () => {
|
|
48
|
+
expect(run({ ...GLOBAL_INSTALL, JAMDESK_INSTALLER: '1' }).stdout).toBe('');
|
|
49
|
+
});
|
|
50
|
+
it('stays silent at a quiet loglevel (npm i -g --silent / Docker)', () => {
|
|
51
|
+
expect(run({ ...GLOBAL_INSTALL, npm_config_loglevel: 'silent' }).stdout).toBe('');
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
//# sourceMappingURL=install-banner-gating.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-banner-gating.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/install-banner-gating.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,oCAAoC,CAAC,CAAC;AAErE,0EAA0E;AAC1E,yEAAyE;AACzE,iEAAiE;AACjE,SAAS,GAAG,CAAC,GAA2B;IACtC,OAAO,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE;QAC3C,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE;QAC5D,QAAQ,EAAE,MAAM;KACjB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,cAAc,GAAG,EAAE,iBAAiB,EAAE,MAAM,EAAE,CAAC;AAErD,QAAQ,CAAC,mCAAmC,EAAE,GAAG,EAAE;IACjD,EAAE,CAAC,0FAA0F,EAAE,GAAG,EAAE;QAClG,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,cAAc,CAAC,CAAC;QAC/C,kEAAkE;QAClE,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QACzC,0CAA0C;QAC1C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAC5B,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,cAAc,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,cAAc,EAAE,iBAAiB,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,cAAc,EAAE,mBAAmB,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import { loadConfig } from './lib/config.js';
|
|
|
11
11
|
import { createRequire } from 'module';
|
|
12
12
|
import { isUserError } from './lib/errors.js';
|
|
13
13
|
import { output } from './lib/output.js';
|
|
14
|
+
import { maybeShowFirstRunBanner } from './lib/first-run-banner.js';
|
|
14
15
|
const require = createRequire(import.meta.url);
|
|
15
16
|
const pkg = require('../package.json');
|
|
16
17
|
// Detect local dev: published package doesn't include src/
|
|
@@ -399,6 +400,11 @@ Supported targets:
|
|
|
399
400
|
process.exit(1);
|
|
400
401
|
}
|
|
401
402
|
});
|
|
403
|
+
// One-time welcome banner, synchronously before command dispatch so it
|
|
404
|
+
// lands strictly before any command output. Self-gating, never throws —
|
|
405
|
+
// npm can't deliver an install-time banner for `npm i -g`
|
|
406
|
+
// (install-banner-gating.test.ts), so first run is where users see it.
|
|
407
|
+
maybeShowFirstRunBanner();
|
|
402
408
|
try {
|
|
403
409
|
await program.parseAsync();
|
|
404
410
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface FirstRunBannerOptions {
|
|
2
|
+
argv?: string[];
|
|
3
|
+
/** ~/.jamdesk by default; injectable for tests (mirrors clean.ts ctx). */
|
|
4
|
+
jamdeskDir?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function maybeShowFirstRunBanner({ argv, jamdeskDir, }?: FirstRunBannerOptions): void;
|
|
7
|
+
//# sourceMappingURL=first-run-banner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"first-run-banner.d.ts","sourceRoot":"","sources":["../../src/lib/first-run-banner.ts"],"names":[],"mappings":"AAsCA,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD,wBAAgB,uBAAuB,CAAC,EACtC,IAA4B,EAC5B,UAA6C,GAC9C,GAAE,qBAA0B,GAAG,IAAI,CAoCnC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* First-run welcome banner.
|
|
3
|
+
*
|
|
4
|
+
* Shows the ASCII "Jamdesk" art once — the first time the user runs a real
|
|
5
|
+
* command after install. npm swallows successful global `postinstall` stdout
|
|
6
|
+
* for `npm i -g` (verified on npm 11; see install-banner-gating.test.ts), so
|
|
7
|
+
* an install-time banner can never reach those users. A first-run banner is
|
|
8
|
+
* the reliable delivery path and behaves the same across npm/pnpm/yarn/bun.
|
|
9
|
+
*
|
|
10
|
+
* Cosmetic and defensive: it never throws and never blocks the CLI. Worst
|
|
11
|
+
* case it shows twice (the sentinel write failed) — harmless.
|
|
12
|
+
*/
|
|
13
|
+
import fs from 'fs';
|
|
14
|
+
import path from 'path';
|
|
15
|
+
import { homedir } from 'os';
|
|
16
|
+
import { fileURLToPath } from 'url';
|
|
17
|
+
import chalk from 'chalk';
|
|
18
|
+
// Args that aren't a real command invocation. We skip the banner AND leave
|
|
19
|
+
// first-run unconsumed, so the user still gets it on their first real
|
|
20
|
+
// command. `--json` is excluded too — banner text would corrupt machine
|
|
21
|
+
// output (e.g. `jamdesk doctor --json`).
|
|
22
|
+
const SKIP_ARGS = new Set(['-v', '-V', '--version', '-h', '--help', '--json']);
|
|
23
|
+
function shouldSkip(argv) {
|
|
24
|
+
if (process.env.CI)
|
|
25
|
+
return true;
|
|
26
|
+
if (process.env.JAMDESK_INSTALLER)
|
|
27
|
+
return true;
|
|
28
|
+
// A real interactive terminal IS a TTY here — unlike an npm postinstall,
|
|
29
|
+
// which npm always pipes. This is the correct place for an isTTY gate.
|
|
30
|
+
// It's also the real guard against corrupting piped/scripted/JSON output:
|
|
31
|
+
// SKIP_ARGS only catches a literal `--json`, but anything consuming the
|
|
32
|
+
// CLI's output programmatically isn't a TTY, so it's excluded here. Don't
|
|
33
|
+
// weaken this to "only skip when --json".
|
|
34
|
+
if (!process.stdout.isTTY)
|
|
35
|
+
return true;
|
|
36
|
+
if (argv.length === 0)
|
|
37
|
+
return true; // bare `jamdesk` just prints help
|
|
38
|
+
return argv.some((a) => SKIP_ARGS.has(a));
|
|
39
|
+
}
|
|
40
|
+
// Synchronous on purpose: only sync fs is used, and index.ts calls this
|
|
41
|
+
// before `program.parseAsync()` — staying sync makes "the banner lands
|
|
42
|
+
// strictly before any command output" an unconditional guarantee rather
|
|
43
|
+
// than one that depends on microtask ordering.
|
|
44
|
+
export function maybeShowFirstRunBanner({ argv = process.argv.slice(2), jamdeskDir = path.join(homedir(), '.jamdesk'), } = {}) {
|
|
45
|
+
try {
|
|
46
|
+
if (shouldSkip(argv))
|
|
47
|
+
return;
|
|
48
|
+
const sentinel = path.join(jamdeskDir, '.welcomed');
|
|
49
|
+
if (fs.existsSync(sentinel))
|
|
50
|
+
return;
|
|
51
|
+
// banner.txt is shipped (package.json "files") and is the single
|
|
52
|
+
// drift-guarded source of the art (banner-art-sync.test.ts). From
|
|
53
|
+
// dist/lib/first-run-banner.js the package root is ../../.
|
|
54
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
55
|
+
const art = fs
|
|
56
|
+
.readFileSync(path.join(here, '..', '..', 'scripts', 'banner.txt'), 'utf8')
|
|
57
|
+
.replace(/\n$/, '');
|
|
58
|
+
// chalk respects NO_COLOR / non-TTY itself, so no manual color gate.
|
|
59
|
+
process.stdout.write(`\n${chalk.blue(art)}\n\n` +
|
|
60
|
+
'Welcome to Jamdesk — build docs sites from MDX.\n\n' +
|
|
61
|
+
'Get started:\n' +
|
|
62
|
+
' jamdesk init # Create a new docs project\n' +
|
|
63
|
+
' jamdesk dev # Start the dev server\n' +
|
|
64
|
+
' jamdesk --help # See all commands\n\n');
|
|
65
|
+
// Best-effort: mark welcomed so it shows exactly once. If this fails the
|
|
66
|
+
// banner just shows again next run — never worth failing a command over.
|
|
67
|
+
try {
|
|
68
|
+
fs.mkdirSync(jamdeskDir, { recursive: true });
|
|
69
|
+
fs.writeFileSync(sentinel, `${new Date().toISOString()}\n`);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
/* non-fatal */
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Cosmetic only — a missing/garbled banner must never break the CLI.
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=first-run-banner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"first-run-banner.js","sourceRoot":"","sources":["../../src/lib/first-run-banner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,2EAA2E;AAC3E,sEAAsE;AACtE,wEAAwE;AACxE,yCAAyC;AACzC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;AAE/E,SAAS,UAAU,CAAC,IAAc;IAChC,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IAChC,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAAE,OAAO,IAAI,CAAC;IAC/C,yEAAyE;IACzE,uEAAuE;IACvE,0EAA0E;IAC1E,wEAAwE;IACxE,0EAA0E;IAC1E,0CAA0C;IAC1C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,kCAAkC;IACtE,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,CAAC;AAQD,wEAAwE;AACxE,uEAAuE;AACvE,wEAAwE;AACxE,+CAA+C;AAC/C,MAAM,UAAU,uBAAuB,CAAC,EACtC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAC5B,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,MACpB,EAAE;IAC3B,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO;QAE7B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QACpD,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,OAAO;QAEpC,iEAAiE;QACjE,kEAAkE;QAClE,2DAA2D;QAC3D,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1D,MAAM,GAAG,GAAG,EAAE;aACX,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC;aAC1E,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAEtB,qEAAqE;QACrE,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM;YACxB,qDAAqD;YACrD,gBAAgB;YAChB,mDAAmD;YACnD,8CAA8C;YAC9C,4CAA4C,CAC/C,CAAC;QAEF,yEAAyE;QACzE,yEAAyE;QACzE,IAAI,CAAC;YACH,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9C,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QAC9D,CAAC;QAAC,MAAM,CAAC;YACP,eAAe;QACjB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,qEAAqE;IACvE,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jamdesk",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.103",
|
|
4
4
|
"description": "CLI for Jamdesk — build, preview, and deploy documentation sites from MDX. Dev server with hot reload, 50+ components, OpenAPI support, AI search, and Mintlify migration",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jamdesk",
|
|
@@ -14,10 +14,17 @@
|
|
|
14
14
|
* precedent as the sibling scripts/patch-openapi-schemas.js — do not "DRY"
|
|
15
15
|
* this against src/lib/output.ts; it would break `npm install`.
|
|
16
16
|
*
|
|
17
|
-
* It deliberately stays quiet unless this is
|
|
17
|
+
* It deliberately stays quiet unless this is a user-initiated global install:
|
|
18
18
|
* - JAMDESK_INSTALLER set → the bootstrap installer already showed a banner
|
|
19
19
|
* - not a global install → don't spam dependency installs / `npm ci`
|
|
20
|
-
* - CI /
|
|
20
|
+
* - CI / quiet loglevel → no banner in pipelines, Docker layers, logs
|
|
21
|
+
*
|
|
22
|
+
* Deliberately NOT gated on `process.stdout.isTTY`: npm >=7 runs postinstall
|
|
23
|
+
* with stdout PIPED, never a TTY, unless the user passes --foreground-scripts.
|
|
24
|
+
* A TTY gate here suppressed the banner on every real `npm i -g` (shipped
|
|
25
|
+
* dead in 1.1.101). The CI / loglevel / global gates already keep it out of
|
|
26
|
+
* pipelines and Docker. Do not re-add an isTTY check — see
|
|
27
|
+
* install-banner-gating.test.ts.
|
|
21
28
|
*/
|
|
22
29
|
import { readFileSync } from 'node:fs';
|
|
23
30
|
import { fileURLToPath } from 'node:url';
|
|
@@ -34,7 +41,6 @@ function shouldShow() {
|
|
|
34
41
|
if (process.env.npm_config_global !== 'true') return false;
|
|
35
42
|
if (process.env.CI) return false;
|
|
36
43
|
if (QUIET_LOGLEVELS.includes(process.env.npm_config_loglevel)) return false;
|
|
37
|
-
if (!process.stdout.isTTY) return false;
|
|
38
44
|
return true;
|
|
39
45
|
}
|
|
40
46
|
|