project-compass 3.2.1 → 3.3.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 +31 -25
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -152,7 +152,7 @@ const TaskManager = memo(({tasks, activeTaskId, renameMode, renameInput, renameC
|
|
|
152
152
|
Box,
|
|
153
153
|
{flexDirection: 'column', borderStyle: 'round', borderColor: 'yellow', padding: 1},
|
|
154
154
|
create(Text, {bold: true, color: 'yellow'}, '🛰️ Task Manager | Background Processes'),
|
|
155
|
-
create(Text, {dimColor: true, marginBottom: 1}, 'Up/Down: focus, Shift+K: Kill
|
|
155
|
+
create(Text, {dimColor: true, marginBottom: 1}, 'Up/Down: focus, Shift+K: Force Kill, Shift+R: Rename'),
|
|
156
156
|
...tasks.map(t => create(
|
|
157
157
|
Box,
|
|
158
158
|
{key: t.id, marginBottom: 0, flexDirection: 'column'},
|
|
@@ -225,22 +225,27 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
225
225
|
const [stdinBuffer, setStdinBuffer] = useState('');
|
|
226
226
|
const [stdinCursor, setStdinCursor] = useState(0);
|
|
227
227
|
const [showHelp, setShowHelp] = useState(false);
|
|
228
|
-
const selectedProject = projects[selectedIndex] || null;
|
|
229
228
|
const runningProcessMap = useRef(new Map());
|
|
230
229
|
const lastCommandRef = useRef(null);
|
|
231
230
|
|
|
232
231
|
const activeTask = useMemo(() => tasks.find(t => t.id === activeTaskId), [tasks, activeTaskId]);
|
|
233
232
|
const running = activeTask?.status === 'running';
|
|
234
233
|
const hasRunningTasks = useMemo(() => tasks.some(t => t.status === 'running'), [tasks]);
|
|
234
|
+
const selectedProject = useMemo(() => projects[selectedIndex] || null, [projects, selectedIndex]);
|
|
235
235
|
|
|
236
236
|
const addLogToTask = useCallback((taskId, line) => {
|
|
237
|
-
setTasks(prev =>
|
|
238
|
-
|
|
237
|
+
setTasks(prev => {
|
|
238
|
+
const idx = prev.findIndex(t => t.id === taskId);
|
|
239
|
+
if (idx === -1) return prev;
|
|
240
|
+
const t = prev[idx];
|
|
239
241
|
const normalized = typeof line === 'string' ? line : JSON.stringify(line);
|
|
240
|
-
const
|
|
241
|
-
const nextLogs = [...t.logs, ...
|
|
242
|
-
|
|
243
|
-
|
|
242
|
+
const newLines = normalized.split(/\r?\n/).filter(l => l.trim().length > 0);
|
|
243
|
+
const nextLogs = [...t.logs, ...newLines];
|
|
244
|
+
const updatedTask = { ...t, logs: nextLogs.length > 500 ? nextLogs.slice(-500) : nextLogs };
|
|
245
|
+
const nextTasks = [...prev];
|
|
246
|
+
nextTasks[idx] = updatedTask;
|
|
247
|
+
return nextTasks;
|
|
248
|
+
});
|
|
244
249
|
}, []);
|
|
245
250
|
|
|
246
251
|
const detailedIndexed = useMemo(() => buildDetailCommands(selectedProject, config).map((command, index) => ({
|
|
@@ -256,7 +261,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
256
261
|
|
|
257
262
|
const killAllTasks = useCallback(() => {
|
|
258
263
|
runningProcessMap.current.forEach((proc) => {
|
|
259
|
-
try { proc.kill('
|
|
264
|
+
try { proc.kill('SIGKILL'); } catch { /* ignore */ }
|
|
260
265
|
});
|
|
261
266
|
runningProcessMap.current.clear();
|
|
262
267
|
}, []);
|
|
@@ -284,7 +289,8 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
284
289
|
const subprocess = execa(commandMeta.command[0], commandMeta.command.slice(1), {
|
|
285
290
|
cwd: project.path,
|
|
286
291
|
env: process.env,
|
|
287
|
-
stdin: 'pipe'
|
|
292
|
+
stdin: 'pipe',
|
|
293
|
+
cleanup: true
|
|
288
294
|
});
|
|
289
295
|
runningProcessMap.current.set(taskId, subprocess);
|
|
290
296
|
|
|
@@ -295,9 +301,9 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
295
301
|
setTasks(prev => prev.map(t => t.id === taskId ? {...t, status: 'finished'} : t));
|
|
296
302
|
addLogToTask(taskId, kleur.green(`✓ ${commandLabel} finished`));
|
|
297
303
|
} catch (error) {
|
|
298
|
-
if (error.isCanceled || error.killed) {
|
|
304
|
+
if (error.isCanceled || error.killed || error.signal === 'SIGKILL' || error.signal === 'SIGINT') {
|
|
299
305
|
setTasks(prev => prev.map(t => t.id === taskId ? {...t, status: 'killed'} : t));
|
|
300
|
-
addLogToTask(taskId, kleur.yellow(`! Task killed
|
|
306
|
+
addLogToTask(taskId, kleur.yellow(`! Task killed forcefully`));
|
|
301
307
|
} else {
|
|
302
308
|
setTasks(prev => prev.map(t => t.id === taskId ? {...t, status: 'failed'} : t));
|
|
303
309
|
addLogToTask(taskId, kleur.red(`✗ ${commandLabel} failed: ${error.shortMessage || error.message}`));
|
|
@@ -310,7 +316,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
310
316
|
const handleKillTask = useCallback((taskId) => {
|
|
311
317
|
const proc = runningProcessMap.current.get(taskId);
|
|
312
318
|
if (proc) {
|
|
313
|
-
proc.kill('
|
|
319
|
+
proc.kill('SIGKILL');
|
|
314
320
|
} else {
|
|
315
321
|
setTasks(prev => prev.filter(t => t.id !== taskId));
|
|
316
322
|
if (activeTaskId === taskId) setActiveTaskId(null);
|
|
@@ -318,15 +324,16 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
318
324
|
}, [activeTaskId]);
|
|
319
325
|
|
|
320
326
|
const exportLogs = useCallback(() => {
|
|
321
|
-
|
|
327
|
+
const taskToExport = tasks.find(t => t.id === activeTaskId);
|
|
328
|
+
if (!taskToExport || !taskToExport.logs.length) return;
|
|
322
329
|
try {
|
|
323
|
-
const exportPath = path.resolve(process.cwd(), `compass-${
|
|
324
|
-
fs.writeFileSync(exportPath,
|
|
330
|
+
const exportPath = path.resolve(process.cwd(), `compass-${taskToExport.id}.txt`);
|
|
331
|
+
fs.writeFileSync(exportPath, taskToExport.logs.join('\n'));
|
|
325
332
|
addLogToTask(activeTaskId, kleur.green(`✓ Logs exported to ${exportPath}`));
|
|
326
333
|
} catch {
|
|
327
334
|
addLogToTask(activeTaskId, kleur.red('✗ Export failed'));
|
|
328
335
|
}
|
|
329
|
-
}, [
|
|
336
|
+
}, [tasks, activeTaskId, addLogToTask]);
|
|
330
337
|
|
|
331
338
|
useInput((input, key) => {
|
|
332
339
|
if (quitConfirm) {
|
|
@@ -338,13 +345,14 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
338
345
|
if (customMode) {
|
|
339
346
|
if (key.return) {
|
|
340
347
|
const raw = customInput.trim();
|
|
341
|
-
|
|
348
|
+
const selProj = selectedProject;
|
|
349
|
+
if (selProj && raw) {
|
|
342
350
|
const [labelPart, commandPart] = raw.split('|');
|
|
343
351
|
const commandTokens = (commandPart || labelPart).trim().split(/\s+/).filter(Boolean);
|
|
344
352
|
if (commandTokens.length) {
|
|
345
|
-
const label = commandPart ? labelPart.trim() : `Custom ${
|
|
353
|
+
const label = commandPart ? labelPart.trim() : `Custom ${selProj.name}`;
|
|
346
354
|
setConfig((prev) => {
|
|
347
|
-
const projectKey =
|
|
355
|
+
const projectKey = selProj.path;
|
|
348
356
|
const existing = prev.customCommands?.[projectKey] || [];
|
|
349
357
|
const nextConfig = { ...prev, customCommands: { ...prev.customCommands, [projectKey]: [...existing, {label, command: commandTokens}] } };
|
|
350
358
|
saveConfig(nextConfig);
|
|
@@ -448,11 +456,9 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
448
456
|
if (tasks.length > 0) {
|
|
449
457
|
if (key.upArrow) { setActiveTaskId(prev => tasks[(tasks.findIndex(t => t.id === prev) - 1 + tasks.length) % tasks.length]?.id); return; }
|
|
450
458
|
if (key.downArrow) { setActiveTaskId(prev => tasks[(tasks.findIndex(t => t.id === prev) + 1) % tasks.length]?.id); return; }
|
|
451
|
-
if (shiftCombo('k') && activeTaskId) {
|
|
452
|
-
handleKillTask(activeTaskId);
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
459
|
+
if (shiftCombo('k') && activeTaskId) { handleKillTask(activeTaskId); return; }
|
|
455
460
|
if (shiftCombo('r') && activeTaskId) { setRenameMode(true); setRenameInput(activeTask.name); setRenameCursor(activeTask.name.length); return; }
|
|
461
|
+
if (key.ctrl && input === 'c') { handleKillTask(activeTaskId); return; }
|
|
456
462
|
}
|
|
457
463
|
if (key.return) { setMainView('navigator'); return; }
|
|
458
464
|
return;
|
|
@@ -460,7 +466,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
460
466
|
|
|
461
467
|
if (running && activeTaskId && runningProcessMap.current.has(activeTaskId)) {
|
|
462
468
|
const proc = runningProcessMap.current.get(activeTaskId);
|
|
463
|
-
if (key.ctrl && input === 'c') { proc.kill('
|
|
469
|
+
if (key.ctrl && input === 'c') { proc.kill('SIGKILL'); setStdinBuffer(''); setStdinCursor(0); return; }
|
|
464
470
|
if (key.return) { proc.stdin?.write(stdinBuffer + '\n'); setStdinBuffer(''); setStdinCursor(0); return; }
|
|
465
471
|
if (key.backspace || key.delete) {
|
|
466
472
|
if (stdinCursor > 0) {
|