This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

--ephemeral to auto-cleanup after exit, rm to rm, kill now only kills

Nathan Herald (Apr 3, 2026, 11:00 AM +0200) a90b5b95 7d41f52f

+64 -18
+48 -14
src/cli.ts
··· 89 89 // Parse flags before the -- separator 90 90 let detach = false; 91 91 let attachExisting = false; 92 + let ephemeral = false; 92 93 let name: string | null = null; 93 94 let i = 1; 94 95 while (i < args.length && args[i] !== "--") { 95 96 if (args[i] === "-d" || args[i] === "--detach") { detach = true; i++; } 96 97 else if (args[i] === "-a" || args[i] === "--attach") { attachExisting = true; i++; } 98 + else if (args[i] === "-e" || args[i] === "--ephemeral") { ephemeral = true; i++; } 97 99 else if (args[i] === "--name" && i + 1 < args.length) { name = args[i + 1]; i += 2; } 98 100 else break; 99 101 // Note: unknown flags or positional args before -- break the loop ··· 166 168 process.exit(1); 167 169 } 168 170 169 - await cmdRun(name, cmd, cmdArgs, detach, attachExisting, displayCmd); 171 + await cmdRun(name, cmd, cmdArgs, detach, attachExisting, displayCmd, ephemeral); 170 172 break; 171 173 } 172 174 ··· 321 323 break; 322 324 } 323 325 326 + case "rm": 327 + case "remove": { 328 + if (args.length < 2) { 329 + console.error("Usage: pty rm <name>"); 330 + process.exit(1); 331 + } 332 + try { 333 + validateName(args[1]); 334 + } catch (e: any) { 335 + console.error(e.message); 336 + process.exit(1); 337 + } 338 + await cmdRm(args[1]); 339 + break; 340 + } 341 + 324 342 case "wrap": { 325 343 if (args[1] === "--list" || args[1] === "-l") { 326 344 cmdWrapList(); ··· 368 386 args: string[], 369 387 detach = false, 370 388 attachExisting = false, 371 - displayCommand: string 389 + displayCommand: string, 390 + ephemeral = false, 372 391 ): Promise<void> { 373 392 const session = await getSession(name); 374 393 if (session?.status === "running") { ··· 398 417 } 399 418 400 419 try { 401 - await spawnDaemon(name, command, args, displayCommand, previousCwd); 420 + await spawnDaemon(name, command, args, displayCommand, previousCwd, ephemeral); 402 421 } finally { 403 422 releaseLock(name); 404 423 } ··· 693 712 process.exit(1); 694 713 } 695 714 696 - if (session.status === "running" && session.pid) { 697 - try { 698 - process.kill(session.pid, "SIGTERM"); 699 - console.log(`Session "${name}" killed.`); 700 - } catch { 701 - console.error(`Failed to kill session "${name}".`); 702 - } 703 - cleanupSocket(name); 715 + if (session.status !== "running" || !session.pid) { 716 + console.error(`Session "${name}" is not running. Use "pty rm ${name}" to remove it.`); 717 + process.exit(1); 718 + } 719 + 720 + try { 721 + process.kill(session.pid, "SIGTERM"); 722 + console.log(`Session "${name}" killed.`); 723 + } catch { 724 + console.error(`Failed to kill session "${name}".`); 725 + } 726 + cleanupSocket(name); 727 + } 728 + 729 + async function cmdRm(name: string): Promise<void> { 730 + const session = await getSession(name); 731 + 732 + if (!session) { 733 + console.error(`Session "${name}" not found.`); 734 + process.exit(1); 735 + } 736 + 737 + if (session.status === "running") { 738 + console.error(`Session "${name}" is still running. Use "pty kill ${name}" first.`); 739 + process.exit(1); 704 740 } 705 741 706 742 cleanupAll(name); 707 - if (session.status === "exited") { 708 - console.log(`Session "${name}" removed.`); 709 - } 743 + console.log(`Session "${name}" removed.`); 710 744 } 711 745 712 746 async function cmdRestart(name: string, force = false): Promise<void> {
+13 -3
src/server.ts
··· 21 21 getPidPath, 22 22 ensureSessionDir, 23 23 cleanup, 24 + cleanupAll, 24 25 writeMetadata, 25 26 readMetadata, 26 27 type SessionMetadata, ··· 479 480 process.exit(1); 480 481 } 481 482 483 + const isEphemeral = config.ephemeral === true; 484 + 485 + function cleanShutdown(code: number): Promise<never> { 486 + return server.close().then(() => { 487 + if (isEphemeral) cleanupAll(config.name); 488 + process.exit(code); 489 + }); 490 + } 491 + 482 492 const server = new PtyServer({ 483 493 name: config.name, 484 494 command: config.command, ··· 489 499 cols: config.cols ?? 80, 490 500 onExit: (code) => { 491 501 // Give clients a moment to receive the exit message, then shut down 492 - setTimeout(() => server.close().then(() => process.exit(code)), 500); 502 + setTimeout(() => cleanShutdown(code), 500); 493 503 }, 494 504 }); 495 505 496 - process.on("SIGTERM", () => server.close().then(() => process.exit(0))); 497 - process.on("SIGINT", () => server.close().then(() => process.exit(0))); 506 + process.on("SIGTERM", () => cleanShutdown(0)); 507 + process.on("SIGINT", () => cleanShutdown(0)); 498 508 }
+3 -1
src/spawn.ts
··· 12 12 command: string, 13 13 args: string[], 14 14 displayCommand: string, 15 - cwd?: string 15 + cwd?: string, 16 + ephemeral = false, 16 17 ): Promise<void> { 17 18 const stdout = process.stdout as tty.WriteStream; 18 19 const rows = stdout.rows ?? 24; ··· 27 28 cwd: cwd ?? process.cwd(), 28 29 rows, 29 30 cols, 31 + ephemeral, 30 32 }); 31 33 32 34 const child = spawn(process.execPath, [serverModule], {