shell-logo 0.1.0 → 0.1.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/package.json +1 -1
- package/src/config.js +63 -46
- package/src/generate.js +44 -6
- package/src/index.js +25 -46
- package/src/paths.js +44 -0
- package/src/themes.js +12 -1
- package/src/ui.js +62 -18
package/package.json
CHANGED
package/src/config.js
CHANGED
|
@@ -1,22 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config loading with XDG-first resolution and legacy migration.
|
|
3
|
+
*
|
|
4
|
+
* Load order:
|
|
5
|
+
* 1. XDG path (~/.config/shell-logo/folders/<hash>/config.json)
|
|
6
|
+
* 2. Legacy path (.shell-logo.json in the working directory)
|
|
7
|
+
*
|
|
8
|
+
* If a legacy config is found but no XDG config exists, the legacy config
|
|
9
|
+
* is automatically copied to XDG (the legacy file is left untouched).
|
|
10
|
+
*/
|
|
11
|
+
|
|
1
12
|
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
13
|
import chalk from 'chalk';
|
|
14
|
+
import { configPath, legacyConfigPath } from './paths.js';
|
|
15
|
+
import { writeConfig } from './generate.js';
|
|
4
16
|
|
|
5
17
|
export const DEFAULTS = {
|
|
6
18
|
colors: ['#ff6b6b', '#feca57', '#48dbfb'],
|
|
7
19
|
font: 'Standard',
|
|
8
20
|
};
|
|
9
21
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} catch {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Parse a JSON string and validate it as a shell-logo config.
|
|
24
|
+
* Requires a non-empty `text` field. Colors must be an array of 2+ if present.
|
|
25
|
+
* Returns a normalized config object, or null if invalid.
|
|
26
|
+
*/
|
|
27
|
+
function parseAndValidate(raw) {
|
|
20
28
|
let config;
|
|
21
29
|
try {
|
|
22
30
|
config = JSON.parse(raw);
|
|
@@ -41,51 +49,60 @@ export function tryLoadConfig() {
|
|
|
41
49
|
};
|
|
42
50
|
}
|
|
43
51
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Try to load config for `cwd`. Returns the parsed config or null.
|
|
54
|
+
* Checks XDG first, then falls back to legacy .shell-logo.json.
|
|
55
|
+
* Auto-migrates legacy configs to XDG on first load.
|
|
56
|
+
*/
|
|
57
|
+
export function tryLoadConfig(cwd) {
|
|
58
|
+
// 1. Try XDG path
|
|
48
59
|
try {
|
|
49
|
-
raw = readFileSync(configPath, 'utf-8');
|
|
60
|
+
const raw = readFileSync(configPath(cwd), 'utf-8');
|
|
61
|
+
const config = parseAndValidate(raw);
|
|
62
|
+
if (config) return config;
|
|
50
63
|
} catch {
|
|
51
|
-
|
|
52
|
-
chalk.red('Error: ') +
|
|
53
|
-
'No .shell-logo.json found in the current directory.\n\n' +
|
|
54
|
-
'Create one with at least:\n\n' +
|
|
55
|
-
' { "text": "HELLO" }\n\n' +
|
|
56
|
-
'Or copy an example:\n\n' +
|
|
57
|
-
' cp node_modules/shell-logo/examples/.shell-logo.json .'
|
|
58
|
-
);
|
|
59
|
-
process.exit(1);
|
|
64
|
+
// Not found or unreadable — fall through to legacy
|
|
60
65
|
}
|
|
61
66
|
|
|
62
|
-
|
|
67
|
+
// 2. Try legacy .shell-logo.json in the working directory
|
|
68
|
+
let raw;
|
|
63
69
|
try {
|
|
64
|
-
|
|
70
|
+
raw = readFileSync(legacyConfigPath(cwd), 'utf-8');
|
|
65
71
|
} catch {
|
|
66
|
-
|
|
67
|
-
process.exit(1);
|
|
72
|
+
return null;
|
|
68
73
|
}
|
|
69
74
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
const config = parseAndValidate(raw);
|
|
76
|
+
if (!config) return null;
|
|
77
|
+
|
|
78
|
+
// 3. Auto-migrate legacy config to XDG (legacy file is left untouched)
|
|
79
|
+
try {
|
|
80
|
+
writeConfig(config, cwd);
|
|
81
|
+
const xdgPath = configPath(cwd);
|
|
82
|
+
console.log(
|
|
83
|
+
chalk.dim(`Migrated config from .shell-logo.json → ${xdgPath}`)
|
|
73
84
|
);
|
|
74
|
-
|
|
85
|
+
} catch {
|
|
86
|
+
// Migration failed — still usable from the legacy path
|
|
75
87
|
}
|
|
76
88
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
console.error(
|
|
80
|
-
chalk.red('Error: ') + '"colors" must be an array of at least 2 color strings.'
|
|
81
|
-
);
|
|
82
|
-
process.exit(1);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
89
|
+
return config;
|
|
90
|
+
}
|
|
85
91
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Load config for `cwd`, or exit with an error if none is found.
|
|
94
|
+
* Same resolution as tryLoadConfig but treats missing config as fatal.
|
|
95
|
+
*/
|
|
96
|
+
export function loadConfig(cwd) {
|
|
97
|
+
const config = tryLoadConfig(cwd);
|
|
98
|
+
if (config) return config;
|
|
99
|
+
|
|
100
|
+
const xdg = configPath(cwd);
|
|
101
|
+
console.error(
|
|
102
|
+
chalk.red('Error: ') +
|
|
103
|
+
`No config found for this folder.\n\n` +
|
|
104
|
+
`Expected at: ${xdg}\n\n` +
|
|
105
|
+
'Run shell-logo and choose "Generate" to create one.'
|
|
106
|
+
);
|
|
107
|
+
process.exit(1);
|
|
91
108
|
}
|
package/src/generate.js
CHANGED
|
@@ -1,8 +1,46 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Config persistence — writes config to the XDG folder structure.
|
|
3
|
+
*
|
|
4
|
+
* Uses atomic writes (write to tmp file, then rename) to prevent corruption
|
|
5
|
+
* if two terminals write to the same folder config simultaneously.
|
|
6
|
+
*/
|
|
3
7
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
import { writeFileSync, renameSync, mkdirSync } from 'node:fs';
|
|
9
|
+
import { resolve, join, dirname } from 'node:path';
|
|
10
|
+
import { randomBytes } from 'node:crypto';
|
|
11
|
+
import { configPath, folderConfigDir, metaPath } from './paths.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Write data to a file atomically: write to a temp file in the same
|
|
15
|
+
* directory, then rename. This avoids partial reads if another process
|
|
16
|
+
* is reading the file at the same time.
|
|
17
|
+
*/
|
|
18
|
+
function atomicWriteSync(targetPath, data) {
|
|
19
|
+
const dir = dirname(targetPath);
|
|
20
|
+
const tmpPath = join(dir, `.tmp.${randomBytes(6).toString('hex')}`);
|
|
21
|
+
writeFileSync(tmpPath, data);
|
|
22
|
+
renameSync(tmpPath, targetPath);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Persist a config object to the XDG folder for `cwd`.
|
|
27
|
+
* Creates the directory tree if it doesn't exist yet.
|
|
28
|
+
* Also writes a meta.json with the original folder path (best-effort).
|
|
29
|
+
* Returns the path the config was written to.
|
|
30
|
+
*/
|
|
31
|
+
export function writeConfig(config, cwd = process.cwd()) {
|
|
32
|
+
const dir = folderConfigDir(cwd);
|
|
33
|
+
mkdirSync(dir, { recursive: true });
|
|
34
|
+
|
|
35
|
+
atomicWriteSync(configPath(cwd), JSON.stringify(config, null, 2) + '\n');
|
|
36
|
+
|
|
37
|
+
// meta.json stores the original folder path so humans can identify
|
|
38
|
+
// which hash directory belongs to which project.
|
|
39
|
+
try {
|
|
40
|
+
atomicWriteSync(metaPath(cwd), JSON.stringify({ path: resolve(cwd) }, null, 2) + '\n');
|
|
41
|
+
} catch {
|
|
42
|
+
// Best-effort — not critical if this fails
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return configPath(cwd);
|
|
8
46
|
}
|
package/src/index.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Entry point for shell-logo.
|
|
5
|
+
*
|
|
6
|
+
* 1. Run the interactive UI to get a config + session mode (persistent or temporary).
|
|
7
|
+
* 2. If the user chose "Generate", persist the new config to disk.
|
|
8
|
+
* 3. Start the fullscreen render loop with arrow-key theme/font cycling.
|
|
9
|
+
*/
|
|
10
|
+
|
|
5
11
|
import { runInteractiveUI } from './ui.js';
|
|
6
12
|
import { writeConfig } from './generate.js';
|
|
7
13
|
import { render } from './renderer.js';
|
|
@@ -10,56 +16,26 @@ import { THEMES, FONTS } from './themes.js';
|
|
|
10
16
|
import chalk from 'chalk';
|
|
11
17
|
import * as p from '@clack/prompts';
|
|
12
18
|
|
|
13
|
-
const { action, config } = await runInteractiveUI();
|
|
19
|
+
const { action, config, persistent } = await runInteractiveUI();
|
|
14
20
|
|
|
15
21
|
if (action === 'generate') {
|
|
16
22
|
const s = p.spinner();
|
|
17
|
-
s.start('
|
|
23
|
+
s.start('Saving config...');
|
|
18
24
|
writeConfig(config);
|
|
19
25
|
s.stop('Config saved!');
|
|
20
|
-
|
|
21
|
-
const isGitRepo = existsSync(join(process.cwd(), '.git'));
|
|
22
|
-
const gitignorePath = join(process.cwd(), '.gitignore');
|
|
23
|
-
let shouldPrompt = isGitRepo;
|
|
24
|
-
|
|
25
|
-
if (existsSync(gitignorePath)) {
|
|
26
|
-
const content = readFileSync(gitignorePath, 'utf-8');
|
|
27
|
-
const lines = content.split('\n').map(l => l.trim());
|
|
28
|
-
if (lines.includes('.shell-logo.json')) {
|
|
29
|
-
shouldPrompt = false;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (shouldPrompt) {
|
|
34
|
-
const addToGitignore = await p.select({
|
|
35
|
-
message: 'Add .shell-logo.json to .gitignore?',
|
|
36
|
-
options: [
|
|
37
|
-
{ value: true, label: 'Yes (recommended)' },
|
|
38
|
-
{ value: false, label: 'No' },
|
|
39
|
-
],
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
if (p.isCancel(addToGitignore)) {
|
|
43
|
-
p.cancel('Cancelled.');
|
|
44
|
-
process.exit(0);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (addToGitignore) {
|
|
48
|
-
if (existsSync(gitignorePath)) {
|
|
49
|
-
const existing = readFileSync(gitignorePath, 'utf-8');
|
|
50
|
-
const separator = existing.endsWith('\n') ? '' : '\n';
|
|
51
|
-
writeFileSync(gitignorePath, existing + separator + '.shell-logo.json\n');
|
|
52
|
-
} else {
|
|
53
|
-
writeFileSync(gitignorePath, '.shell-logo.json\n');
|
|
54
|
-
}
|
|
55
|
-
p.log.success('.gitignore updated.');
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
26
|
}
|
|
59
27
|
|
|
60
|
-
startRenderLoop(config);
|
|
61
|
-
|
|
62
|
-
|
|
28
|
+
startRenderLoop(config, persistent);
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Fullscreen render loop. Draws the logo centered in the terminal and
|
|
32
|
+
* listens for arrow keys to cycle themes (up/down) and fonts (left/right).
|
|
33
|
+
*
|
|
34
|
+
* @param {object} config - Logo config: { text, colors, font }
|
|
35
|
+
* @param {boolean} persistent - When true, arrow key changes are saved to disk.
|
|
36
|
+
* When false (temporary session), changes are in-memory only.
|
|
37
|
+
*/
|
|
38
|
+
function startRenderLoop(config, persistent) {
|
|
63
39
|
let resizeTimer;
|
|
64
40
|
|
|
65
41
|
// Find the current theme index by matching colors
|
|
@@ -85,6 +61,7 @@ function startRenderLoop(config) {
|
|
|
85
61
|
}
|
|
86
62
|
}
|
|
87
63
|
|
|
64
|
+
/** Briefly show the status bar (theme name, font, controls) for 2 seconds. */
|
|
88
65
|
function flashStatus() {
|
|
89
66
|
showStatus = true;
|
|
90
67
|
clearTimeout(statusTimer);
|
|
@@ -94,6 +71,7 @@ function startRenderLoop(config) {
|
|
|
94
71
|
}, 2000);
|
|
95
72
|
}
|
|
96
73
|
|
|
74
|
+
/** Debounce re-renders on terminal resize to avoid flickering. */
|
|
97
75
|
function debouncedRender() {
|
|
98
76
|
clearTimeout(resizeTimer);
|
|
99
77
|
resizeTimer = setTimeout(renderLoop, 50);
|
|
@@ -140,7 +118,8 @@ function startRenderLoop(config) {
|
|
|
140
118
|
} else {
|
|
141
119
|
return;
|
|
142
120
|
}
|
|
143
|
-
|
|
121
|
+
// Only persist theme/font changes in a persistent (non-temporary) session
|
|
122
|
+
if (persistent) writeConfig(config);
|
|
144
123
|
flashStatus();
|
|
145
124
|
renderLoop();
|
|
146
125
|
}
|
package/src/paths.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path resolution for XDG-based config storage.
|
|
3
|
+
*
|
|
4
|
+
* Configs are stored per-folder under:
|
|
5
|
+
* $XDG_CONFIG_HOME/shell-logo/folders/<hash>/config.json
|
|
6
|
+
*
|
|
7
|
+
* where <hash> is the first 16 hex chars of SHA-256(absolute CWD).
|
|
8
|
+
* Falls back to ~/.config/shell-logo/ when XDG_CONFIG_HOME is unset.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { createHash } from 'node:crypto';
|
|
12
|
+
import { resolve, join } from 'node:path';
|
|
13
|
+
import { homedir } from 'node:os';
|
|
14
|
+
|
|
15
|
+
/** Root directory for all shell-logo config: $XDG_CONFIG_HOME/shell-logo/ */
|
|
16
|
+
export function configRoot() {
|
|
17
|
+
const base = process.env.XDG_CONFIG_HOME || join(homedir(), '.config');
|
|
18
|
+
return join(base, 'shell-logo');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Deterministic 16-char hex hash of the absolute path for `cwd`. */
|
|
22
|
+
export function folderHash(cwd = process.cwd()) {
|
|
23
|
+
return createHash('sha256').update(resolve(cwd)).digest('hex').slice(0, 16);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Per-folder config directory: <configRoot>/folders/<hash>/ */
|
|
27
|
+
export function folderConfigDir(cwd = process.cwd()) {
|
|
28
|
+
return join(configRoot(), 'folders', folderHash(cwd));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Path to the per-folder config file (text, colors, font). */
|
|
32
|
+
export function configPath(cwd = process.cwd()) {
|
|
33
|
+
return join(folderConfigDir(cwd), 'config.json');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Path to the per-folder meta file (stores original absolute path for debugging). */
|
|
37
|
+
export function metaPath(cwd = process.cwd()) {
|
|
38
|
+
return join(folderConfigDir(cwd), 'meta.json');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Path to the legacy config file (.shell-logo.json in the working directory). */
|
|
42
|
+
export function legacyConfigPath(cwd = process.cwd()) {
|
|
43
|
+
return join(resolve(cwd), '.shell-logo.json');
|
|
44
|
+
}
|
package/src/themes.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
export const FONTS = [
|
|
1
|
+
export const FONTS = [
|
|
2
|
+
'Standard', 'Big', 'ANSI Shadow', 'Slant', 'Small',
|
|
3
|
+
'ANSI Regular', 'Bloody', 'DOS Rebel', 'Graffiti', 'Larry 3D',
|
|
4
|
+
'Star Wars', 'Doh', 'Ghost', 'Fraktur', 'Fire Font-k',
|
|
5
|
+
];
|
|
2
6
|
|
|
3
7
|
export const THEMES = [
|
|
4
8
|
{ name: 'Sunset', colors: ['#ff6b6b', '#ff9f43', '#feca57'] },
|
|
@@ -9,4 +13,11 @@ export const THEMES = [
|
|
|
9
13
|
{ name: 'Fire', colors: ['#ff4757', '#ff6348', '#ffdd59'] },
|
|
10
14
|
{ name: 'Pastel', colors: ['#fd79a8', '#feca57', '#48dbfb'] },
|
|
11
15
|
{ name: 'Monochrome', colors: ['#ffffff', '#54a0ff', '#5f27cd'] },
|
|
16
|
+
{ name: 'Aurora', colors: ['#00d2ff', '#3a7bd5', '#7b2ff7'] },
|
|
17
|
+
{ name: 'Cherry', colors: ['#eb3349', '#f45c43', '#ff8a80'] },
|
|
18
|
+
{ name: 'Cyberpunk', colors: ['#f72585', '#7209b7', '#4cc9f0'] },
|
|
19
|
+
{ name: 'Arctic', colors: ['#e0eafc', '#cfdef3', '#74b9ff'] },
|
|
20
|
+
{ name: 'Emerald', colors: ['#11998e', '#38ef7d', '#b8ff96'] },
|
|
21
|
+
{ name: 'Midnight', colors: ['#0f0c29', '#302b63', '#24c6dc'] },
|
|
22
|
+
{ name: 'Rose Gold', colors: ['#f4c4f3', '#fc5c7d', '#fda085'] },
|
|
12
23
|
];
|
package/src/ui.js
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive CLI prompts for shell-logo.
|
|
3
|
+
*
|
|
4
|
+
* When a config already exists for the current folder, presents three options:
|
|
5
|
+
* - Run — display the logo, arrow key changes persist to disk
|
|
6
|
+
* - New session — display the logo, changes are in-memory only (temporary)
|
|
7
|
+
* - Generate — walk through the setup wizard to create a new config
|
|
8
|
+
*
|
|
9
|
+
* When no config exists, only the Generate option is shown.
|
|
10
|
+
*
|
|
11
|
+
* Returns { action, config, persistent } where `persistent` controls
|
|
12
|
+
* whether arrow key theme/font changes are saved back to disk.
|
|
13
|
+
*/
|
|
14
|
+
|
|
1
15
|
import * as p from '@clack/prompts';
|
|
2
16
|
import chalk from 'chalk';
|
|
3
17
|
import { tryLoadConfig } from './config.js';
|
|
@@ -27,8 +41,19 @@ const FONT_OPTIONS = [
|
|
|
27
41
|
{ value: 'ANSI Shadow', label: 'ANSI Shadow' },
|
|
28
42
|
{ value: 'Slant', label: 'Slant' },
|
|
29
43
|
{ value: 'Small', label: 'Small' },
|
|
44
|
+
{ value: 'ANSI Regular', label: 'ANSI Regular' },
|
|
45
|
+
{ value: 'Bloody', label: 'Bloody' },
|
|
46
|
+
{ value: 'DOS Rebel', label: 'DOS Rebel' },
|
|
47
|
+
{ value: 'Graffiti', label: 'Graffiti' },
|
|
48
|
+
{ value: 'Larry 3D', label: 'Larry 3D' },
|
|
49
|
+
{ value: 'Star Wars', label: 'Star Wars' },
|
|
50
|
+
{ value: 'Doh', label: 'Doh' },
|
|
51
|
+
{ value: 'Ghost', label: 'Ghost' },
|
|
52
|
+
{ value: 'Fraktur', label: 'Fraktur' },
|
|
53
|
+
{ value: 'Fire Font-k', label: 'Fire Font-k' },
|
|
30
54
|
];
|
|
31
55
|
|
|
56
|
+
/** Exit gracefully if the user presses Ctrl+C / Escape during a prompt. */
|
|
32
57
|
function handleCancel(value) {
|
|
33
58
|
if (p.isCancel(value)) {
|
|
34
59
|
p.cancel('Cancelled.');
|
|
@@ -37,6 +62,7 @@ function handleCancel(value) {
|
|
|
37
62
|
return value;
|
|
38
63
|
}
|
|
39
64
|
|
|
65
|
+
/** Walk the user through the Generate wizard: text, colors, font. */
|
|
40
66
|
async function promptGenerate() {
|
|
41
67
|
const text = handleCancel(
|
|
42
68
|
await p.text({
|
|
@@ -77,21 +103,53 @@ async function promptGenerate() {
|
|
|
77
103
|
return {
|
|
78
104
|
action: 'generate',
|
|
79
105
|
config: { text: text.trim(), colors, font },
|
|
106
|
+
persistent: true,
|
|
80
107
|
};
|
|
81
108
|
}
|
|
82
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Main entry point for the interactive CLI.
|
|
112
|
+
* Returns { action: 'generate'|'run', config, persistent }.
|
|
113
|
+
*/
|
|
83
114
|
export async function runInteractiveUI() {
|
|
84
115
|
p.intro(chalk.bold('terminal-logo'));
|
|
85
116
|
|
|
86
|
-
const
|
|
117
|
+
const existingConfig = tryLoadConfig();
|
|
118
|
+
|
|
119
|
+
if (existingConfig) {
|
|
120
|
+
const action = handleCancel(
|
|
121
|
+
await p.select({
|
|
122
|
+
message: 'What would you like to do?',
|
|
123
|
+
initialValue: 'run',
|
|
124
|
+
options: [
|
|
125
|
+
{ value: 'run', label: 'Run', hint: 'use saved config' },
|
|
126
|
+
{ value: 'temp', label: 'New session', hint: "temporary, changes won't be saved" },
|
|
127
|
+
{ value: 'generate', label: 'Generate', hint: 'create a new logo config' },
|
|
128
|
+
],
|
|
129
|
+
})
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
if (action === 'generate') {
|
|
133
|
+
return promptGenerate();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (action === 'temp') {
|
|
137
|
+
p.outro('Launching logo (temporary session)...');
|
|
138
|
+
return { action: 'run', config: existingConfig, persistent: false };
|
|
139
|
+
}
|
|
87
140
|
|
|
141
|
+
// action === 'run'
|
|
142
|
+
p.outro('Launching logo...');
|
|
143
|
+
return { action: 'run', config: existingConfig, persistent: true };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// No existing config — only offer Generate
|
|
88
147
|
const action = handleCancel(
|
|
89
148
|
await p.select({
|
|
90
149
|
message: 'What would you like to do?',
|
|
91
|
-
initialValue:
|
|
150
|
+
initialValue: 'generate',
|
|
92
151
|
options: [
|
|
93
|
-
{ value: 'generate', label: 'Generate', hint: 'create
|
|
94
|
-
{ value: 'run', label: 'Run', hint: 'display current logo' },
|
|
152
|
+
{ value: 'generate', label: 'Generate', hint: 'create a new logo config' },
|
|
95
153
|
],
|
|
96
154
|
})
|
|
97
155
|
);
|
|
@@ -99,18 +157,4 @@ export async function runInteractiveUI() {
|
|
|
99
157
|
if (action === 'generate') {
|
|
100
158
|
return promptGenerate();
|
|
101
159
|
}
|
|
102
|
-
|
|
103
|
-
// action === 'run'
|
|
104
|
-
const config = tryLoadConfig();
|
|
105
|
-
if (!config) {
|
|
106
|
-
p.log.error(
|
|
107
|
-
'No valid .shell-logo.json found in the current directory.\n' +
|
|
108
|
-
' Run again and choose "Generate" to create one.'
|
|
109
|
-
);
|
|
110
|
-
p.outro('Done');
|
|
111
|
-
process.exit(1);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
p.outro('Launching logo...');
|
|
115
|
-
return { action: 'run', config };
|
|
116
160
|
}
|