project-compass 2.8.2 → 2.9.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/package.json +1 -1
- package/src/cli.js +120 -69
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -9,7 +9,6 @@ import {discoverProjects, SCHEMA_GUIDE, checkBinary} from './projectDetection.js
|
|
|
9
9
|
import {CONFIG_PATH, ensureConfigDir} from './configPaths.js';
|
|
10
10
|
|
|
11
11
|
const create = React.createElement;
|
|
12
|
-
const DEFAULT_CONFIG = {customCommands: {}};
|
|
13
12
|
const ART_CHARS = ['▁', '▃', '▄', '▅', '▇'];
|
|
14
13
|
const ART_COLORS = ['magenta', 'blue', 'cyan', 'yellow', 'red'];
|
|
15
14
|
const OUTPUT_WINDOW_SIZE = 8;
|
|
@@ -38,18 +37,15 @@ function loadConfig() {
|
|
|
38
37
|
const payload = fs.readFileSync(CONFIG_PATH, 'utf-8');
|
|
39
38
|
const parsed = JSON.parse(payload || '{}');
|
|
40
39
|
return {
|
|
41
|
-
|
|
40
|
+
customCommands: {},
|
|
41
|
+
showArtBoard: true,
|
|
42
42
|
...parsed,
|
|
43
|
-
customCommands: {
|
|
44
|
-
...DEFAULT_CONFIG.customCommands,
|
|
45
|
-
...(parsed.customCommands || {})
|
|
46
|
-
}
|
|
47
43
|
};
|
|
48
44
|
}
|
|
49
45
|
} catch (error) {
|
|
50
46
|
console.error(`Ignoring corrupt config: ${error.message}`);
|
|
51
47
|
}
|
|
52
|
-
return {
|
|
48
|
+
return {customCommands: {}, showArtBoard: true};
|
|
53
49
|
}
|
|
54
50
|
|
|
55
51
|
function useScanner(rootPath) {
|
|
@@ -78,9 +74,7 @@ function useScanner(rootPath) {
|
|
|
78
74
|
}
|
|
79
75
|
|
|
80
76
|
function buildDetailCommands(project, config) {
|
|
81
|
-
if (!project)
|
|
82
|
-
return [];
|
|
83
|
-
}
|
|
77
|
+
if (!project) return [];
|
|
84
78
|
const builtins = Object.entries(project.commands || {}).map(([key, command]) => ({
|
|
85
79
|
label: command.label || key,
|
|
86
80
|
command: command.command,
|
|
@@ -177,6 +171,10 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
177
171
|
const [customMode, setCustomMode] = useState(false);
|
|
178
172
|
const [customInput, setCustomInput] = useState('');
|
|
179
173
|
const [customCursor, setCustomCursor] = useState(0);
|
|
174
|
+
const [renameMode, setRenameMode] = useState(false);
|
|
175
|
+
const [renameInput, setRenameInput] = useState('');
|
|
176
|
+
const [renameCursor, setRenameCursor] = useState(0);
|
|
177
|
+
const [quitConfirm, setQuitConfirm] = useState(false);
|
|
180
178
|
const [config, setConfig] = useState(() => loadConfig());
|
|
181
179
|
const [showHelpCards, setShowHelpCards] = useState(false);
|
|
182
180
|
const [showStructureGuide, setShowStructureGuide] = useState(false);
|
|
@@ -189,6 +187,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
189
187
|
|
|
190
188
|
const activeTask = useMemo(() => tasks.find(t => t.id === activeTaskId), [tasks, activeTaskId]);
|
|
191
189
|
const running = activeTask?.status === 'running';
|
|
190
|
+
const hasRunningTasks = useMemo(() => tasks.some(t => t.status === 'running'), [tasks]);
|
|
192
191
|
|
|
193
192
|
const addLogToTask = useCallback((taskId, line) => {
|
|
194
193
|
setTasks(prev => prev.map(t => {
|
|
@@ -200,17 +199,24 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
200
199
|
}));
|
|
201
200
|
}, []);
|
|
202
201
|
|
|
203
|
-
const
|
|
204
|
-
const detailedIndexed = useMemo(() => detailCommands.map((command, index) => ({
|
|
202
|
+
const detailedIndexed = useMemo(() => buildDetailCommands(selectedProject, config).map((command, index) => ({
|
|
205
203
|
...command,
|
|
206
204
|
shortcut: `${index + 1}`
|
|
207
|
-
})), [
|
|
205
|
+
})), [selectedProject, config]);
|
|
206
|
+
|
|
208
207
|
const detailShortcutMap = useMemo(() => {
|
|
209
208
|
const map = new Map();
|
|
210
209
|
detailedIndexed.forEach((cmd) => map.set(cmd.shortcut, cmd));
|
|
211
210
|
return map;
|
|
212
211
|
}, [detailedIndexed]);
|
|
213
212
|
|
|
213
|
+
const killAllTasks = useCallback(() => {
|
|
214
|
+
runningProcessMap.current.forEach((proc) => {
|
|
215
|
+
try { proc.kill('SIGINT'); } catch { /* ignore */ }
|
|
216
|
+
});
|
|
217
|
+
runningProcessMap.current.clear();
|
|
218
|
+
}, []);
|
|
219
|
+
|
|
214
220
|
const runProjectCommand = useCallback(async (commandMeta, targetProject = selectedProject) => {
|
|
215
221
|
const project = targetProject || selectedProject;
|
|
216
222
|
if (!project) return;
|
|
@@ -245,52 +251,27 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
245
251
|
setTasks(prev => prev.map(t => t.id === taskId ? {...t, status: 'finished'} : t));
|
|
246
252
|
addLogToTask(taskId, kleur.green(`✓ ${commandLabel} finished`));
|
|
247
253
|
} catch (error) {
|
|
248
|
-
|
|
249
|
-
|
|
254
|
+
if (error.isCanceled || error.killed) {
|
|
255
|
+
setTasks(prev => prev.map(t => t.id === taskId ? {...t, status: 'killed'} : t));
|
|
256
|
+
addLogToTask(taskId, kleur.yellow(`! Task killed by user`));
|
|
257
|
+
} else {
|
|
258
|
+
setTasks(prev => prev.map(t => t.id === taskId ? {...t, status: 'failed'} : t));
|
|
259
|
+
addLogToTask(taskId, kleur.red(`✗ ${commandLabel} failed: ${error.shortMessage || error.message}`));
|
|
260
|
+
}
|
|
250
261
|
} finally {
|
|
251
262
|
runningProcessMap.current.delete(taskId);
|
|
252
263
|
}
|
|
253
264
|
}, [addLogToTask, selectedProject]);
|
|
254
265
|
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
customCommands: {
|
|
263
|
-
...prev.customCommands,
|
|
264
|
-
[projectKey]: [...existing, {label, command: commandTokens}]
|
|
265
|
-
}
|
|
266
|
-
};
|
|
267
|
-
saveConfig(nextConfig);
|
|
268
|
-
return nextConfig;
|
|
269
|
-
});
|
|
270
|
-
}, [selectedProject]);
|
|
271
|
-
|
|
272
|
-
const handleCustomSubmit = useCallback(() => {
|
|
273
|
-
const raw = customInput.trim();
|
|
274
|
-
if (!selectedProject || !raw) {
|
|
275
|
-
setCustomMode(false);
|
|
276
|
-
setCustomInput('');
|
|
277
|
-
setCustomCursor(0);
|
|
278
|
-
return;
|
|
266
|
+
const handleKillTask = useCallback((taskId) => {
|
|
267
|
+
const proc = runningProcessMap.current.get(taskId);
|
|
268
|
+
if (proc) {
|
|
269
|
+
proc.kill('SIGINT');
|
|
270
|
+
} else {
|
|
271
|
+
setTasks(prev => prev.filter(t => t.id !== taskId));
|
|
272
|
+
if (activeTaskId === taskId) setActiveTaskId(null);
|
|
279
273
|
}
|
|
280
|
-
|
|
281
|
-
const commandTokens = (commandPart || labelPart).trim().split(/\s+/).filter(Boolean);
|
|
282
|
-
if (!commandTokens.length) {
|
|
283
|
-
setCustomMode(false);
|
|
284
|
-
setCustomInput('');
|
|
285
|
-
setCustomCursor(0);
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
const label = commandPart ? labelPart.trim() : `Custom ${selectedProject.name}`;
|
|
289
|
-
handleAddCustomCommand(label, commandTokens);
|
|
290
|
-
setCustomMode(false);
|
|
291
|
-
setCustomInput('');
|
|
292
|
-
setCustomCursor(0);
|
|
293
|
-
}, [customInput, selectedProject, handleAddCustomCommand]);
|
|
274
|
+
}, [activeTaskId]);
|
|
294
275
|
|
|
295
276
|
const exportLogs = useCallback(() => {
|
|
296
277
|
if (!activeTask || !activeTask.logs.length) return;
|
|
@@ -304,8 +285,32 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
304
285
|
}, [activeTask, activeTaskId, addLogToTask]);
|
|
305
286
|
|
|
306
287
|
useInput((input, key) => {
|
|
288
|
+
if (quitConfirm) {
|
|
289
|
+
if (input?.toLowerCase() === 'y') { killAllTasks(); exit(); return; }
|
|
290
|
+
if (input?.toLowerCase() === 'n' || key.escape) { setQuitConfirm(false); return; }
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
307
294
|
if (customMode) {
|
|
308
|
-
if (key.return) {
|
|
295
|
+
if (key.return) {
|
|
296
|
+
const raw = customInput.trim();
|
|
297
|
+
if (selectedProject && raw) {
|
|
298
|
+
const [labelPart, commandPart] = raw.split('|');
|
|
299
|
+
const commandTokens = (commandPart || labelPart).trim().split(/\s+/).filter(Boolean);
|
|
300
|
+
if (commandTokens.length) {
|
|
301
|
+
const label = commandPart ? labelPart.trim() : `Custom ${selectedProject.name}`;
|
|
302
|
+
setConfig((prev) => {
|
|
303
|
+
const projectKey = selectedProject.path;
|
|
304
|
+
const existing = prev.customCommands?.[projectKey] || [];
|
|
305
|
+
const nextConfig = { ...prev, customCommands: { ...prev.customCommands, [projectKey]: [...existing, {label, command: commandTokens}] } };
|
|
306
|
+
saveConfig(nextConfig);
|
|
307
|
+
return nextConfig;
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
setCustomMode(false); setCustomInput(''); setCustomCursor(0);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
309
314
|
if (key.escape) { setCustomMode(false); setCustomInput(''); setCustomCursor(0); return; }
|
|
310
315
|
if (key.backspace || key.delete) {
|
|
311
316
|
if (customCursor > 0) {
|
|
@@ -323,6 +328,29 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
323
328
|
return;
|
|
324
329
|
}
|
|
325
330
|
|
|
331
|
+
if (renameMode) {
|
|
332
|
+
if (key.return) {
|
|
333
|
+
setTasks(prev => prev.map(t => t.id === activeTaskId ? {...t, name: renameInput} : t));
|
|
334
|
+
setRenameMode(false); setRenameInput(''); setRenameCursor(0);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (key.escape) { setRenameMode(false); setRenameInput(''); setRenameCursor(0); return; }
|
|
338
|
+
if (key.backspace || key.delete) {
|
|
339
|
+
if (renameCursor > 0) {
|
|
340
|
+
setRenameInput((prev) => prev.slice(0, renameCursor - 1) + prev.slice(renameCursor));
|
|
341
|
+
setRenameCursor(c => Math.max(0, c - 1));
|
|
342
|
+
}
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
if (key.leftArrow) { setRenameCursor(c => Math.max(0, c - 1)); return; }
|
|
346
|
+
if (key.rightArrow) { setRenameCursor(c => Math.min(renameInput.length, c + 1)); return; }
|
|
347
|
+
if (input) {
|
|
348
|
+
setRenameInput((prev) => prev.slice(0, renameCursor) + input + prev.slice(renameCursor));
|
|
349
|
+
setRenameCursor(c => c + input.length);
|
|
350
|
+
}
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
|
|
326
354
|
const normalizedInput = input?.toLowerCase();
|
|
327
355
|
const shiftCombo = (char) => key.shift && normalizedInput === char;
|
|
328
356
|
|
|
@@ -332,6 +360,14 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
332
360
|
if (shiftCombo('x')) { setTasks(prev => prev.map(t => t.id === activeTaskId ? {...t, logs: []} : t)); setLogOffset(0); return; }
|
|
333
361
|
if (shiftCombo('e')) { exportLogs(); return; }
|
|
334
362
|
if (shiftCombo('d')) { setActiveTaskId(null); return; }
|
|
363
|
+
if (shiftCombo('b')) {
|
|
364
|
+
setConfig(prev => {
|
|
365
|
+
const next = {...prev, showArtBoard: !prev.showArtBoard};
|
|
366
|
+
saveConfig(next);
|
|
367
|
+
return next;
|
|
368
|
+
});
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
335
371
|
|
|
336
372
|
if (shiftCombo('t')) {
|
|
337
373
|
setMainView((prev) => {
|
|
@@ -354,6 +390,11 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
354
390
|
if (tasks.length > 0) {
|
|
355
391
|
if (key.upArrow) { setActiveTaskId(prev => tasks[(tasks.findIndex(t => t.id === prev) - 1 + tasks.length) % tasks.length]?.id); return; }
|
|
356
392
|
if (key.downArrow) { setActiveTaskId(prev => tasks[(tasks.findIndex(t => t.id === prev) + 1) % tasks.length]?.id); return; }
|
|
393
|
+
if (shiftCombo('k') && activeTaskId) {
|
|
394
|
+
handleKillTask(activeTaskId);
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
if (shiftCombo('r') && activeTaskId) { setRenameMode(true); setRenameInput(activeTask.name); setRenameCursor(activeTask.name.length); return; }
|
|
357
398
|
}
|
|
358
399
|
if (key.return) { setMainView('navigator'); return; }
|
|
359
400
|
return;
|
|
@@ -392,7 +433,10 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
392
433
|
setViewMode((prev) => (prev === 'detail' ? 'list' : 'detail'));
|
|
393
434
|
return;
|
|
394
435
|
}
|
|
395
|
-
if (shiftCombo('q')) {
|
|
436
|
+
if (shiftCombo('q')) {
|
|
437
|
+
if (hasRunningTasks) setQuitConfirm(true); else exit();
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
396
440
|
if (shiftCombo('c') && viewMode === 'detail' && selectedProject) { setCustomMode(true); setCustomInput(''); setCustomCursor(0); return; }
|
|
397
441
|
|
|
398
442
|
const actionKey = normalizedInput && ACTION_MAP[normalizedInput];
|
|
@@ -408,6 +452,10 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
408
452
|
|
|
409
453
|
const projectCountLabel = `${projects.length} project${projects.length === 1 ? '' : 's'}`;
|
|
410
454
|
|
|
455
|
+
if (quitConfirm) {
|
|
456
|
+
return create(Box, {flexDirection: 'column', borderStyle: 'round', borderColor: 'red', padding: 1}, create(Text, {bold: true, color: 'red'}, '⚠️ Confirm Exit'), create(Text, null, `There are ${tasks.filter(t=>t.status==='running').length} tasks still running in the background.`), create(Text, null, 'Are you sure you want to quit and stop all processes?'), create(Text, {marginTop: 1}, kleur.bold('Y') + ' to Quit, ' + kleur.bold('N') + ' to Cancel'));
|
|
457
|
+
}
|
|
458
|
+
|
|
411
459
|
if (mainView === 'studio') return create(Studio);
|
|
412
460
|
|
|
413
461
|
if (mainView === 'tasks') {
|
|
@@ -415,14 +463,16 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
415
463
|
Box,
|
|
416
464
|
{flexDirection: 'column', borderStyle: 'round', borderColor: 'yellow', padding: 1},
|
|
417
465
|
create(Text, {bold: true, color: 'yellow'}, '🛰️ Task Manager | Background Processes'),
|
|
418
|
-
create(Text, {dimColor: true, marginBottom: 1}, '
|
|
466
|
+
create(Text, {dimColor: true, marginBottom: 1}, 'Up/Down: focus, Shift+K: Kill/Delete, Shift+R: Rename'),
|
|
419
467
|
...tasks.map(t => create(
|
|
420
468
|
Box,
|
|
421
|
-
{key: t.id, marginBottom: 0},
|
|
422
|
-
|
|
469
|
+
{key: t.id, marginBottom: 0, flexDirection: 'column'},
|
|
470
|
+
t.id === activeTaskId && renameMode
|
|
471
|
+
? create(Box, {flexDirection: 'row'}, create(Text, {color: 'cyan'}, '→ Rename to: '), create(CursorText, {value: renameInput, cursorIndex: renameCursor}))
|
|
472
|
+
: create(Text, {color: t.id === activeTaskId ? 'cyan' : 'white', bold: t.id === activeTaskId}, `${t.id === activeTaskId ? '→' : ' '} [${t.status.toUpperCase()}] ${t.name}`)
|
|
423
473
|
)),
|
|
424
474
|
!tasks.length && create(Text, {dimColor: true}, 'No active or background tasks.'),
|
|
425
|
-
create(Text, {marginTop: 1, dimColor: true}, 'Press Enter or Shift+T to return to Navigator
|
|
475
|
+
create(Text, {marginTop: 1, dimColor: true}, 'Press Enter or Shift+T to return to Navigator.')
|
|
426
476
|
);
|
|
427
477
|
}
|
|
428
478
|
|
|
@@ -486,10 +536,6 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
486
536
|
detailContent.push(create(Text, {key: 'e-h', dimColor: true}, 'Press Enter on a project to reveal details.'));
|
|
487
537
|
}
|
|
488
538
|
|
|
489
|
-
if (customMode) {
|
|
490
|
-
detailContent.push(create(Box, {key: 'ci-box', flexDirection: 'row'}, create(Text, {color: 'cyan'}, 'Type label|cmd (Enter: save, Esc: cancel): '), create(CursorText, {value: customInput, cursorIndex: customCursor})));
|
|
491
|
-
}
|
|
492
|
-
|
|
493
539
|
const artTileNodes = [
|
|
494
540
|
{label: 'Pulse', detail: projectCountLabel, accent: 'magenta', icon: '●', subtext: `Workspace · ${path.basename(rootPath) || rootPath}`},
|
|
495
541
|
{label: 'Focus', detail: selectedProject?.name || 'Selection', accent: 'cyan', icon: '◆', subtext: `${selectedProject?.type || 'Stack'}`},
|
|
@@ -500,11 +546,11 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
500
546
|
create(Text, {dimColor: true}, tile.subtext)
|
|
501
547
|
));
|
|
502
548
|
|
|
503
|
-
const artBoard = create(Box, {flexDirection: 'column', marginTop: 1, borderStyle: 'round', borderColor: 'gray', padding: 1},
|
|
549
|
+
const artBoard = config.showArtBoard ? create(Box, {flexDirection: 'column', marginTop: 1, borderStyle: 'round', borderColor: 'gray', padding: 1},
|
|
504
550
|
create(Box, {flexDirection: 'row', justifyContent: 'space-between'}, create(Text, {color: 'magenta', bold: true}, 'Art-coded build atlas'), create(Text, {dimColor: true}, 'press ? for overlay help')),
|
|
505
551
|
create(Box, {flexDirection: 'row', marginTop: 1}, ...ART_CHARS.map((char, i) => create(Text, {key: i, color: ART_COLORS[i % ART_COLORS.length]}, char.repeat(2)))),
|
|
506
552
|
create(Box, {flexDirection: 'row', marginTop: 1}, ...artTileNodes)
|
|
507
|
-
);
|
|
553
|
+
) : null;
|
|
508
554
|
|
|
509
555
|
const logs = activeTask?.logs || [];
|
|
510
556
|
const logWindowStart = Math.max(0, logs.length - OUTPUT_WINDOW_SIZE - logOffset);
|
|
@@ -515,7 +561,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
515
561
|
const helpCards = [
|
|
516
562
|
{label: 'Navigation', color: 'magenta', body: ['↑ / ↓ move focus, Enter: details', 'Shift+↑ / ↓ scroll output', 'Shift+H toggle help cards', 'Shift+D detach from task']},
|
|
517
563
|
{label: 'Commands', color: 'cyan', body: ['B / T / R build/test/run', '1-9 run detail commands', 'Shift+L rerun last command', 'Shift+X clear / Shift+E export']},
|
|
518
|
-
{label: 'Orbit & Studio', color: 'yellow', body: ['Shift+T task manager', 'Shift+A
|
|
564
|
+
{label: 'Orbit & Studio', color: 'yellow', body: ['Shift+T task manager', 'Shift+A studio / Shift+B art', 'Shift+C custom / Shift+Q quit']}
|
|
519
565
|
];
|
|
520
566
|
|
|
521
567
|
const toggleHint = showHelpCards ? 'Shift+H hide help' : 'Shift+H show help';
|
|
@@ -533,11 +579,11 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
533
579
|
create(Box, {flexDirection: 'row', justifyContent: 'space-between'}, create(Text, {bold: true, color: 'yellow'}, `Output: ${activeTask?.name || 'None'}`), create(Text, {dimColor: true}, logOffset ? `Scrolled ${logOffset} lines` : 'Live log view')),
|
|
534
580
|
create(Box, {flexDirection: 'column', borderStyle: 'round', borderColor: 'yellow', padding: 1, minHeight: OUTPUT_WINDOW_HEIGHT, maxHeight: OUTPUT_WINDOW_HEIGHT, height: OUTPUT_WINDOW_HEIGHT, overflow: 'hidden'}, ...logNodes),
|
|
535
581
|
create(Box, {marginTop: 1, flexDirection: 'row', justifyContent: 'space-between'}, create(Text, {dimColor: true}, running ? 'Type to feed stdin; Enter: submit, Ctrl+C: abort.' : 'Run a command or press Shift+T to switch tasks.'), create(Text, {dimColor: true}, `${toggleHint}, Shift+S: Structure Guide`)),
|
|
536
|
-
create(Box, {marginTop: 1, flexDirection: 'row', borderStyle: 'round', borderColor: running ? 'green' : 'gray', paddingX: 1}, create(Text, {bold: true, color: 'green'}, running ? ' Stdin buffer ' : ' Input ready '), create(Box, {marginLeft: 1}, create(CursorText, {value: stdinBuffer || (running ? '' : 'Start a command to feed stdin'), cursorIndex: stdinCursor, active: running})))
|
|
582
|
+
create(Box, {marginTop: 1, flexDirection: 'row', borderStyle: 'round', borderColor: running ? 'green' : 'gray', paddingX: 1}, create(Text, {bold: true, color: running ? 'green' : 'white'}, running ? ' Stdin buffer ' : ' Input ready '), create(Box, {marginLeft: 1}, create(CursorText, {value: stdinBuffer || (running ? '' : 'Start a command to feed stdin'), cursorIndex: stdinCursor, active: running})))
|
|
537
583
|
),
|
|
538
584
|
showHelpCards && create(Box, {marginTop: 1, flexDirection: 'row', justifyContent: 'space-between', flexWrap: 'wrap'}, ...helpCards.map((card, idx) => create(Box, {key: card.label, flexGrow: 1, flexBasis: 0, minWidth: HELP_CARD_MIN_WIDTH, marginRight: idx < 2 ? 1 : 0, marginBottom: 1, borderStyle: 'round', borderColor: card.color, padding: 1, flexDirection: 'column'}, create(Text, {color: card.color, bold: true, marginBottom: 1}, card.label), ...card.body.map((line, lidx) => create(Text, {key: lidx, dimColor: card.color === 'yellow'}, line))))),
|
|
539
585
|
showStructureGuide && create(Box, {flexDirection: 'column', borderStyle: 'round', borderColor: 'blue', marginTop: 1, padding: 1}, create(Text, {color: 'cyan', bold: true}, 'Structure guide · press Shift+S to hide'), ...SCHEMA_GUIDE.map(e => create(Text, {key: e.type, dimColor: true}, `• ${e.icon} ${e.label}: ${e.files.join(', ')}`))),
|
|
540
|
-
showHelp && create(Box, {flexDirection: 'column', borderStyle: 'double', borderColor: 'cyan', marginTop: 1, padding: 1}, create(Text, {color: 'cyan', bold: true}, 'Help overlay'), create(Text, null, 'Shift+↑/↓ scrolls logs; Shift+X clears; Shift+E exports; Shift+A Studio; Shift+T Tasks; Shift+D Detach.'))
|
|
586
|
+
showHelp && create(Box, {flexDirection: 'column', borderStyle: 'double', borderColor: 'cyan', marginTop: 1, padding: 1}, create(Text, {color: 'cyan', bold: true}, 'Help overlay'), create(Text, null, 'Shift+↑/↓ scrolls logs; Shift+X clears; Shift+E exports; Shift+A Studio; Shift+T Tasks; Shift+D Detach; Shift+B Toggle Art.'))
|
|
541
587
|
);
|
|
542
588
|
}
|
|
543
589
|
|
|
@@ -574,10 +620,15 @@ async function main() {
|
|
|
574
620
|
console.log(' Shift+A Switch to Omni-Studio (Environment Health)');
|
|
575
621
|
console.log(' Shift+T Open Orbit Task Manager (Manage background processes)');
|
|
576
622
|
console.log(' Shift+D Detach from active task (Keep it running in background)');
|
|
623
|
+
console.log(' Shift+B Toggle Art Board visibility');
|
|
577
624
|
console.log(' Shift+X Clear active task output log');
|
|
578
625
|
console.log(' Shift+E Export current logs to a .txt file');
|
|
579
626
|
console.log(' Shift+↑ / ↓ Scroll the output logs');
|
|
580
|
-
console.log(' Shift+Q Quit application');
|
|
627
|
+
console.log(' Shift+Q Quit application (with confirmation if tasks run)');
|
|
628
|
+
console.log('');
|
|
629
|
+
console.log(kleur.bold('Task Manager (Shift+T):'));
|
|
630
|
+
console.log(' Shift+K Kill active/selected task');
|
|
631
|
+
console.log(' Shift+R Rename selected task');
|
|
581
632
|
console.log('');
|
|
582
633
|
console.log(kleur.bold('Execution shortcuts:'));
|
|
583
634
|
console.log(' B / T / R Quick run: Build / Test / Run');
|