- commit
- 77d03a5
- parent
- cc33276
- author
- Eric Bower
- date
- 2026-04-02 16:14:24 -0400 EDT
feat(kill): add `--force` flag to remove the socket file If we cannot communicate with the daemon then it could mean a number of things. We don't automatically assume that a communication error means we can never connect to it. So we add a `--force` command for when there is an error the user cannot recover from and we will delete the socket file. Unfortunately, we do not know the pid for the terminal session outside of the daemon so we cannot automatically kill the pid in some cases which means it could linger.
2 files changed,
+23,
-17
+1,
-1
1@@ -73,7 +73,7 @@ Commands:
2 [r]un <name> [command...] Send command without attaching, creating session if needed
3 [d]etach Detach all clients from current session (ctrl+\ for current client)
4 [l]ist [--short] List active sessions
5- [k]ill <name>... Kill a session and all attached clients
6+ [k]ill <name>... [--force] Kill a session and all attached clients
7 [hi]story <name> [--vt|--html] Output session scrollback (--vt or --html for escape sequences)
8 [w]ait <name>... Wait for session tasks to complete
9 [c]ompletions <shell> Completion scripts for shell integration (bash, zsh, or fish)
+22,
-16
1@@ -176,12 +176,16 @@ pub fn main() !void {
2 }
3 args_raw.deinit(alloc);
4 }
5+ var force = false;
6 while (args.next()) |session_name| {
7+ if (std.mem.eql(u8, session_name, "--force")) {
8+ force = true;
9+ continue;
10+ }
11 const sesh = try socket.getSeshName(alloc, session_name);
12 try args_raw.append(alloc, sesh);
13 }
14- // if no args are provided we assume they want to wait for all sessions matching the
15- // prefix.
16+ // if no args are provided we assume they want to kill all sessions matching the prefix.
17 if (args_raw.items.len == 0) {
18 const prefix = socket.getSeshPrefix();
19 if (prefix.len == 0) {
20@@ -196,21 +200,23 @@ pub fn main() !void {
21 }
22 sessions.deinit(alloc);
23 }
24+
25 for (sessions.items) |session| {
26 for (args_raw.items) |prefix| {
27- if (std.mem.startsWith(u8, session.name, prefix)) {
28- kill(&cfg, session.name) catch |err| {
29- try stderr.print(
30- "failed to kill session={s}: {s}\n",
31- .{ session.name, @errorName(err) },
32- );
33- try stderr.flush();
34- };
35- break;
36+ if (!std.mem.startsWith(u8, session.name, prefix)) {
37+ continue;
38 }
39+
40+ kill(&cfg, session.name, force) catch |err| {
41+ try stderr.print(
42+ "failed to kill session={s}: {s}\n",
43+ .{ session.name, @errorName(err) },
44+ );
45+ try stderr.flush();
46+ };
47+ break;
48 }
49 }
50- return;
51 } else if (std.mem.eql(u8, cmd, "wait") or std.mem.eql(u8, cmd, "w")) {
52 var args_raw: std.ArrayList([]const u8) = .empty;
53 defer {
54@@ -803,7 +809,7 @@ fn help() !void {
55 \\ [r]un <name> [command...] Send command without attaching, creating session if needed
56 \\ [d]etach Detach all clients from current session (ctrl+\ for current client)
57 \\ [l]ist [--short] List active sessions
58- \\ [k]ill <name>... Kill a session and all attached clients
59+ \\ [k]ill <name>... [--force] Kill a session and all attached clients
60 \\ [hi]story <name> [--vt|--html] Output session scrollback (--vt or --html for escape sequences)
61 \\ [w]ait <name>... Wait for session tasks to complete
62 \\ [c]ompletions <shell> Completion scripts for shell integration (bash, zsh, or fish)
63@@ -1009,7 +1015,7 @@ fn detachAll(cfg: *Cfg) !void {
64 };
65 }
66
67-fn kill(cfg: *Cfg, session_name: []const u8) !void {
68+fn kill(cfg: *Cfg, session_name: []const u8, force: bool) !void {
69 var gpa = std.heap.GeneralPurposeAllocator(.{}){};
70 defer _ = gpa.deinit();
71 const alloc = gpa.allocator();
72@@ -1035,12 +1041,12 @@ fn kill(cfg: *Cfg, session_name: []const u8) !void {
73 std.log.err("session unresponsive: {s}", .{@errorName(err)});
74 var buf: [4096]u8 = undefined;
75 var w = std.fs.File.stdout().writer(&buf);
76- if (err == error.ConnectionRefused) {
77+ if (force or err == error.ConnectionRefused) {
78 socket.cleanupStaleSocket(dir, session_name);
79 w.interface.print("cleaned up stale session {s}\n", .{session_name}) catch {};
80 } else {
81 w.interface.print(
82- "session {s} is unresponsive ({s}) -- daemon may be busy, try again or kill the process directly\n",
83+ "session {s} is unresponsive ({s})\ndaemon may be busy: try again, add `--force` flag, or kill the process directly\n",
84 .{ session_name, @errorName(err) },
85 ) catch {};
86 }