project-compass 2.8.1 → 2.9.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/package.json +1 -1
- package/src/cli.js +121 -69
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -78,9 +78,7 @@ function useScanner(rootPath) {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
function buildDetailCommands(project, config) {
|
|
81
|
-
if (!project)
|
|
82
|
-
return [];
|
|
83
|
-
}
|
|
81
|
+
if (!project) return [];
|
|
84
82
|
const builtins = Object.entries(project.commands || {}).map(([key, command]) => ({
|
|
85
83
|
label: command.label || key,
|
|
86
84
|
command: command.command,
|
|
@@ -177,6 +175,11 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
177
175
|
const [customMode, setCustomMode] = useState(false);
|
|
178
176
|
const [customInput, setCustomInput] = useState('');
|
|
179
177
|
const [customCursor, setCustomCursor] = useState(0);
|
|
178
|
+
const [renameMode, setRenameMode] = useState(false);
|
|
179
|
+
const [renameInput, setRenameInput] = useState('');
|
|
180
|
+
const [renameCursor, setRenameCursor] = useState(0);
|
|
181
|
+
const [quitConfirm, setQuitConfirm] = useState(false);
|
|
182
|
+
const [showArtBoard, setShowArtBoard] = useState(true);
|
|
180
183
|
const [config, setConfig] = useState(() => loadConfig());
|
|
181
184
|
const [showHelpCards, setShowHelpCards] = useState(false);
|
|
182
185
|
const [showStructureGuide, setShowStructureGuide] = useState(false);
|
|
@@ -189,6 +192,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
189
192
|
|
|
190
193
|
const activeTask = useMemo(() => tasks.find(t => t.id === activeTaskId), [tasks, activeTaskId]);
|
|
191
194
|
const running = activeTask?.status === 'running';
|
|
195
|
+
const hasRunningTasks = useMemo(() => tasks.some(t => t.status === 'running'), [tasks]);
|
|
192
196
|
|
|
193
197
|
const addLogToTask = useCallback((taskId, line) => {
|
|
194
198
|
setTasks(prev => prev.map(t => {
|
|
@@ -200,11 +204,11 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
200
204
|
}));
|
|
201
205
|
}, []);
|
|
202
206
|
|
|
203
|
-
const
|
|
204
|
-
const detailedIndexed = useMemo(() => detailCommands.map((command, index) => ({
|
|
207
|
+
const detailedIndexed = useMemo(() => buildDetailCommands(selectedProject, config).map((command, index) => ({
|
|
205
208
|
...command,
|
|
206
209
|
shortcut: `${index + 1}`
|
|
207
|
-
})), [
|
|
210
|
+
})), [selectedProject, config]);
|
|
211
|
+
|
|
208
212
|
const detailShortcutMap = useMemo(() => {
|
|
209
213
|
const map = new Map();
|
|
210
214
|
detailedIndexed.forEach((cmd) => map.set(cmd.shortcut, cmd));
|
|
@@ -245,52 +249,27 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
245
249
|
setTasks(prev => prev.map(t => t.id === taskId ? {...t, status: 'finished'} : t));
|
|
246
250
|
addLogToTask(taskId, kleur.green(`✓ ${commandLabel} finished`));
|
|
247
251
|
} catch (error) {
|
|
248
|
-
|
|
249
|
-
|
|
252
|
+
if (error.isCanceled) {
|
|
253
|
+
setTasks(prev => prev.map(t => t.id === taskId ? {...t, status: 'killed'} : t));
|
|
254
|
+
addLogToTask(taskId, kleur.yellow(`! Task killed by user`));
|
|
255
|
+
} else {
|
|
256
|
+
setTasks(prev => prev.map(t => t.id === taskId ? {...t, status: 'failed'} : t));
|
|
257
|
+
addLogToTask(taskId, kleur.red(`✗ ${commandLabel} failed: ${error.shortMessage || error.message}`));
|
|
258
|
+
}
|
|
250
259
|
} finally {
|
|
251
260
|
runningProcessMap.current.delete(taskId);
|
|
252
261
|
}
|
|
253
262
|
}, [addLogToTask, selectedProject]);
|
|
254
263
|
|
|
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;
|
|
279
|
-
}
|
|
280
|
-
const [labelPart, commandPart] = raw.split('|');
|
|
281
|
-
const commandTokens = (commandPart || labelPart).trim().split(/\s+/).filter(Boolean);
|
|
282
|
-
if (!commandTokens.length) {
|
|
283
|
-
setCustomMode(false);
|
|
284
|
-
setCustomInput('');
|
|
285
|
-
setCustomCursor(0);
|
|
286
|
-
return;
|
|
264
|
+
const handleKillTask = useCallback((taskId) => {
|
|
265
|
+
const proc = runningProcessMap.current.get(taskId);
|
|
266
|
+
if (proc) {
|
|
267
|
+
proc.kill('SIGINT');
|
|
268
|
+
} else {
|
|
269
|
+
setTasks(prev => prev.filter(t => t.id !== taskId));
|
|
270
|
+
if (activeTaskId === taskId) setActiveTaskId(null);
|
|
287
271
|
}
|
|
288
|
-
|
|
289
|
-
handleAddCustomCommand(label, commandTokens);
|
|
290
|
-
setCustomMode(false);
|
|
291
|
-
setCustomInput('');
|
|
292
|
-
setCustomCursor(0);
|
|
293
|
-
}, [customInput, selectedProject, handleAddCustomCommand]);
|
|
272
|
+
}, [activeTaskId]);
|
|
294
273
|
|
|
295
274
|
const exportLogs = useCallback(() => {
|
|
296
275
|
if (!activeTask || !activeTask.logs.length) return;
|
|
@@ -304,8 +283,32 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
304
283
|
}, [activeTask, activeTaskId, addLogToTask]);
|
|
305
284
|
|
|
306
285
|
useInput((input, key) => {
|
|
286
|
+
if (quitConfirm) {
|
|
287
|
+
if (input?.toLowerCase() === 'y') exit();
|
|
288
|
+
if (input?.toLowerCase() === 'n' || key.escape) setQuitConfirm(false);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
307
292
|
if (customMode) {
|
|
308
|
-
if (key.return) {
|
|
293
|
+
if (key.return) {
|
|
294
|
+
const raw = customInput.trim();
|
|
295
|
+
if (selectedProject && raw) {
|
|
296
|
+
const [labelPart, commandPart] = raw.split('|');
|
|
297
|
+
const commandTokens = (commandPart || labelPart).trim().split(/\s+/).filter(Boolean);
|
|
298
|
+
if (commandTokens.length) {
|
|
299
|
+
const label = commandPart ? labelPart.trim() : `Custom ${selectedProject.name}`;
|
|
300
|
+
setConfig((prev) => {
|
|
301
|
+
const projectKey = selectedProject.path;
|
|
302
|
+
const existing = prev.customCommands?.[projectKey] || [];
|
|
303
|
+
const nextConfig = { ...prev, customCommands: { ...prev.customCommands, [projectKey]: [...existing, {label, command: commandTokens}] } };
|
|
304
|
+
saveConfig(nextConfig);
|
|
305
|
+
return nextConfig;
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
setCustomMode(false); setCustomInput(''); setCustomCursor(0);
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
309
312
|
if (key.escape) { setCustomMode(false); setCustomInput(''); setCustomCursor(0); return; }
|
|
310
313
|
if (key.backspace || key.delete) {
|
|
311
314
|
if (customCursor > 0) {
|
|
@@ -323,6 +326,29 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
323
326
|
return;
|
|
324
327
|
}
|
|
325
328
|
|
|
329
|
+
if (renameMode) {
|
|
330
|
+
if (key.return) {
|
|
331
|
+
setTasks(prev => prev.map(t => t.id === activeTaskId ? {...t, name: renameInput} : t));
|
|
332
|
+
setRenameMode(false); setRenameInput(''); setRenameCursor(0);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
if (key.escape) { setRenameMode(false); setRenameInput(''); setRenameCursor(0); return; }
|
|
336
|
+
if (key.backspace || key.delete) {
|
|
337
|
+
if (renameCursor > 0) {
|
|
338
|
+
setRenameInput((prev) => prev.slice(0, renameCursor - 1) + prev.slice(renameCursor));
|
|
339
|
+
setRenameCursor(c => Math.max(0, c - 1));
|
|
340
|
+
}
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
if (key.leftArrow) { setRenameCursor(c => Math.max(0, c - 1)); return; }
|
|
344
|
+
if (key.rightArrow) { setRenameCursor(c => Math.min(renameInput.length, c + 1)); return; }
|
|
345
|
+
if (input) {
|
|
346
|
+
setRenameInput((prev) => prev.slice(0, renameCursor) + input + prev.slice(renameCursor));
|
|
347
|
+
setRenameCursor(c => c + input.length);
|
|
348
|
+
}
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
|
|
326
352
|
const normalizedInput = input?.toLowerCase();
|
|
327
353
|
const shiftCombo = (char) => key.shift && normalizedInput === char;
|
|
328
354
|
|
|
@@ -332,7 +358,16 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
332
358
|
if (shiftCombo('x')) { setTasks(prev => prev.map(t => t.id === activeTaskId ? {...t, logs: []} : t)); setLogOffset(0); return; }
|
|
333
359
|
if (shiftCombo('e')) { exportLogs(); return; }
|
|
334
360
|
if (shiftCombo('d')) { setActiveTaskId(null); return; }
|
|
335
|
-
if (shiftCombo('
|
|
361
|
+
if (shiftCombo('b')) { setShowArtBoard(prev => !prev); return; }
|
|
362
|
+
|
|
363
|
+
if (shiftCombo('t')) {
|
|
364
|
+
setMainView((prev) => {
|
|
365
|
+
if (prev === 'tasks') return 'navigator';
|
|
366
|
+
if (tasks.length > 0 && !activeTaskId) setActiveTaskId(tasks[0].id);
|
|
367
|
+
return 'tasks';
|
|
368
|
+
});
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
336
371
|
|
|
337
372
|
const scrollLogs = (delta) => {
|
|
338
373
|
setLogOffset((prev) => {
|
|
@@ -342,6 +377,20 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
342
377
|
});
|
|
343
378
|
};
|
|
344
379
|
|
|
380
|
+
if (mainView === 'tasks') {
|
|
381
|
+
if (tasks.length > 0) {
|
|
382
|
+
if (key.upArrow) { setActiveTaskId(prev => tasks[(tasks.findIndex(t => t.id === prev) - 1 + tasks.length) % tasks.length]?.id); return; }
|
|
383
|
+
if (key.downArrow) { setActiveTaskId(prev => tasks[(tasks.findIndex(t => t.id === prev) + 1) % tasks.length]?.id); return; }
|
|
384
|
+
if (shiftCombo('k') && activeTaskId) {
|
|
385
|
+
handleKillTask(activeTaskId);
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
if (shiftCombo('r') && activeTaskId) { setRenameMode(true); setRenameInput(activeTask.name); setRenameCursor(activeTask.name.length); return; }
|
|
389
|
+
}
|
|
390
|
+
if (key.return) { setMainView('navigator'); return; }
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
|
|
345
394
|
if (running && activeTaskId && runningProcessMap.current.has(activeTaskId)) {
|
|
346
395
|
const proc = runningProcessMap.current.get(activeTaskId);
|
|
347
396
|
if (key.ctrl && input === 'c') { proc.kill('SIGINT'); setStdinBuffer(''); setStdinCursor(0); return; }
|
|
@@ -368,13 +417,6 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
368
417
|
if (normalizedInput === '?') { setShowHelp((prev) => !prev); return; }
|
|
369
418
|
if (shiftCombo('l') && lastCommandRef.current) { runProjectCommand(lastCommandRef.current.commandMeta, lastCommandRef.current.project); return; }
|
|
370
419
|
|
|
371
|
-
if (mainView === 'tasks') {
|
|
372
|
-
if (key.upArrow) { setActiveTaskId(prev => tasks[(tasks.findIndex(t => t.id === prev) - 1 + tasks.length) % tasks.length]?.id); return; }
|
|
373
|
-
if (key.downArrow) { setActiveTaskId(prev => tasks[(tasks.findIndex(t => t.id === prev) + 1) % tasks.length]?.id); return; }
|
|
374
|
-
if (key.return || shiftCombo('t')) { setMainView('navigator'); return; }
|
|
375
|
-
return;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
420
|
if (key.upArrow && !key.shift && projects.length > 0) { setSelectedIndex((prev) => (prev - 1 + projects.length) % projects.length); return; }
|
|
379
421
|
if (key.downArrow && !key.shift && projects.length > 0) { setSelectedIndex((prev) => (prev + 1) % projects.length); return; }
|
|
380
422
|
if (key.return) {
|
|
@@ -382,7 +424,10 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
382
424
|
setViewMode((prev) => (prev === 'detail' ? 'list' : 'detail'));
|
|
383
425
|
return;
|
|
384
426
|
}
|
|
385
|
-
if (shiftCombo('q')) {
|
|
427
|
+
if (shiftCombo('q')) {
|
|
428
|
+
if (hasRunningTasks) setQuitConfirm(true); else exit();
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
386
431
|
if (shiftCombo('c') && viewMode === 'detail' && selectedProject) { setCustomMode(true); setCustomInput(''); setCustomCursor(0); return; }
|
|
387
432
|
|
|
388
433
|
const actionKey = normalizedInput && ACTION_MAP[normalizedInput];
|
|
@@ -398,6 +443,10 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
398
443
|
|
|
399
444
|
const projectCountLabel = `${projects.length} project${projects.length === 1 ? '' : 's'}`;
|
|
400
445
|
|
|
446
|
+
if (quitConfirm) {
|
|
447
|
+
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'));
|
|
448
|
+
}
|
|
449
|
+
|
|
401
450
|
if (mainView === 'studio') return create(Studio);
|
|
402
451
|
|
|
403
452
|
if (mainView === 'tasks') {
|
|
@@ -405,14 +454,16 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
405
454
|
Box,
|
|
406
455
|
{flexDirection: 'column', borderStyle: 'round', borderColor: 'yellow', padding: 1},
|
|
407
456
|
create(Text, {bold: true, color: 'yellow'}, '🛰️ Task Manager | Background Processes'),
|
|
408
|
-
create(Text, {dimColor: true, marginBottom: 1}, '
|
|
457
|
+
create(Text, {dimColor: true, marginBottom: 1}, 'Up/Down: focus, Shift+K: Kill/Delete, Shift+R: Rename'),
|
|
409
458
|
...tasks.map(t => create(
|
|
410
459
|
Box,
|
|
411
|
-
{key: t.id, marginBottom: 0},
|
|
412
|
-
|
|
460
|
+
{key: t.id, marginBottom: 0, flexDirection: 'column'},
|
|
461
|
+
t.id === activeTaskId && renameMode
|
|
462
|
+
? create(Box, {flexDirection: 'row'}, create(Text, {color: 'cyan'}, '→ Rename to: '), create(CursorText, {value: renameInput, cursorIndex: renameCursor}))
|
|
463
|
+
: create(Text, {color: t.id === activeTaskId ? 'cyan' : 'white', bold: t.id === activeTaskId}, `${t.id === activeTaskId ? '→' : ' '} [${t.status.toUpperCase()}] ${t.name}`)
|
|
413
464
|
)),
|
|
414
465
|
!tasks.length && create(Text, {dimColor: true}, 'No active or background tasks.'),
|
|
415
|
-
create(Text, {marginTop: 1, dimColor: true}, 'Press Enter
|
|
466
|
+
create(Text, {marginTop: 1, dimColor: true}, 'Press Enter or Shift+T to return to Navigator.')
|
|
416
467
|
);
|
|
417
468
|
}
|
|
418
469
|
|
|
@@ -476,10 +527,6 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
476
527
|
detailContent.push(create(Text, {key: 'e-h', dimColor: true}, 'Press Enter on a project to reveal details.'));
|
|
477
528
|
}
|
|
478
529
|
|
|
479
|
-
if (customMode) {
|
|
480
|
-
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})));
|
|
481
|
-
}
|
|
482
|
-
|
|
483
530
|
const artTileNodes = [
|
|
484
531
|
{label: 'Pulse', detail: projectCountLabel, accent: 'magenta', icon: '●', subtext: `Workspace · ${path.basename(rootPath) || rootPath}`},
|
|
485
532
|
{label: 'Focus', detail: selectedProject?.name || 'Selection', accent: 'cyan', icon: '◆', subtext: `${selectedProject?.type || 'Stack'}`},
|
|
@@ -490,11 +537,11 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
490
537
|
create(Text, {dimColor: true}, tile.subtext)
|
|
491
538
|
));
|
|
492
539
|
|
|
493
|
-
const artBoard = create(Box, {flexDirection: 'column', marginTop: 1, borderStyle: 'round', borderColor: 'gray', padding: 1},
|
|
540
|
+
const artBoard = showArtBoard ? create(Box, {flexDirection: 'column', marginTop: 1, borderStyle: 'round', borderColor: 'gray', padding: 1},
|
|
494
541
|
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')),
|
|
495
542
|
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)))),
|
|
496
543
|
create(Box, {flexDirection: 'row', marginTop: 1}, ...artTileNodes)
|
|
497
|
-
);
|
|
544
|
+
) : null;
|
|
498
545
|
|
|
499
546
|
const logs = activeTask?.logs || [];
|
|
500
547
|
const logWindowStart = Math.max(0, logs.length - OUTPUT_WINDOW_SIZE - logOffset);
|
|
@@ -505,7 +552,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
505
552
|
const helpCards = [
|
|
506
553
|
{label: 'Navigation', color: 'magenta', body: ['↑ / ↓ move focus, Enter: details', 'Shift+↑ / ↓ scroll output', 'Shift+H toggle help cards', 'Shift+D detach from task']},
|
|
507
554
|
{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']},
|
|
508
|
-
{label: 'Orbit & Studio', color: 'yellow', body: ['Shift+T task manager', 'Shift+A
|
|
555
|
+
{label: 'Orbit & Studio', color: 'yellow', body: ['Shift+T task manager', 'Shift+A studio / Shift+B art', 'Shift+C custom / Shift+Q quit']}
|
|
509
556
|
];
|
|
510
557
|
|
|
511
558
|
const toggleHint = showHelpCards ? 'Shift+H hide help' : 'Shift+H show help';
|
|
@@ -527,7 +574,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
527
574
|
),
|
|
528
575
|
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))))),
|
|
529
576
|
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(', ')}`))),
|
|
530
|
-
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.'))
|
|
577
|
+
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.'))
|
|
531
578
|
);
|
|
532
579
|
}
|
|
533
580
|
|
|
@@ -564,10 +611,15 @@ async function main() {
|
|
|
564
611
|
console.log(' Shift+A Switch to Omni-Studio (Environment Health)');
|
|
565
612
|
console.log(' Shift+T Open Orbit Task Manager (Manage background processes)');
|
|
566
613
|
console.log(' Shift+D Detach from active task (Keep it running in background)');
|
|
614
|
+
console.log(' Shift+B Toggle Art Board visibility');
|
|
567
615
|
console.log(' Shift+X Clear active task output log');
|
|
568
616
|
console.log(' Shift+E Export current logs to a .txt file');
|
|
569
617
|
console.log(' Shift+↑ / ↓ Scroll the output logs');
|
|
570
|
-
console.log(' Shift+Q Quit application');
|
|
618
|
+
console.log(' Shift+Q Quit application (with confirmation if tasks run)');
|
|
619
|
+
console.log('');
|
|
620
|
+
console.log(kleur.bold('Task Manager (Shift+T):'));
|
|
621
|
+
console.log(' Shift+K Kill active/selected task');
|
|
622
|
+
console.log(' Shift+R Rename selected task');
|
|
571
623
|
console.log('');
|
|
572
624
|
console.log(kleur.bold('Execution shortcuts:'));
|
|
573
625
|
console.log(' B / T / R Quick run: Build / Test / Run');
|