- commit
- 1dbbe3d
- parent
- e17899d
- author
- Eric Bower
- date
- 2026-01-23 09:45:09 -0500 EST
feat(list): show `started_in` directory and original `cmd` if provided
2 files changed,
+71,
-2
+8,
-1
1@@ -25,9 +25,16 @@ pub const Resize = packed struct {
2 cols: u16,
3 };
4
5-pub const Info = packed struct {
6+pub const MAX_CMD_LEN = 256;
7+pub const MAX_CWD_LEN = 256;
8+
9+pub const Info = extern struct {
10 clients_len: usize,
11 pid: i32,
12+ cmd_len: u16,
13+ cwd_len: u16,
14+ cmd: [MAX_CMD_LEN]u8,
15+ cwd: [MAX_CWD_LEN]u8,
16 };
17
18 pub fn expectedLength(data: []const u8) ?usize {
+63,
-1
1@@ -128,6 +128,7 @@ const Daemon = struct {
2 running: bool,
3 pid: i32,
4 command: ?[]const []const u8 = null,
5+ cwd: []const u8 = "",
6 has_pty_output: bool = false,
7 has_had_client: bool = false,
8
9@@ -258,9 +259,37 @@ const Daemon = struct {
10
11 pub fn handleInfo(self: *Daemon, client: *Client) !void {
12 const clients_len = self.clients.items.len - 1;
13+
14+ // Build command string from args
15+ var cmd_buf: [ipc.MAX_CMD_LEN]u8 = undefined;
16+ var cmd_len: u16 = 0;
17+ if (self.command) |args| {
18+ for (args, 0..) |arg, i| {
19+ if (i > 0) {
20+ if (cmd_len < ipc.MAX_CMD_LEN) {
21+ cmd_buf[cmd_len] = ' ';
22+ cmd_len += 1;
23+ }
24+ }
25+ const remaining = ipc.MAX_CMD_LEN - cmd_len;
26+ const copy_len: u16 = @intCast(@min(arg.len, remaining));
27+ @memcpy(cmd_buf[cmd_len..][0..copy_len], arg[0..copy_len]);
28+ cmd_len += copy_len;
29+ }
30+ }
31+
32+ // Copy cwd
33+ var cwd_buf: [ipc.MAX_CWD_LEN]u8 = undefined;
34+ const cwd_len: u16 = @intCast(@min(self.cwd.len, ipc.MAX_CWD_LEN));
35+ @memcpy(cwd_buf[0..cwd_len], self.cwd[0..cwd_len]);
36+
37 const info = ipc.Info{
38 .clients_len = clients_len,
39 .pid = self.pid,
40+ .cmd_len = cmd_len,
41+ .cwd_len = cwd_len,
42+ .cmd = cmd_buf,
43+ .cwd = cwd_buf,
44 };
45 try ipc.appendMessage(self.alloc, &client.write_buf, .Info, std.mem.asBytes(&info));
46 client.has_pending_output = true;
47@@ -357,6 +386,10 @@ pub fn main() !void {
48 if (command_args.items.len > 0) {
49 command = command_args.items;
50 }
51+
52+ var cwd_buf: [std.fs.max_path_bytes]u8 = undefined;
53+ const cwd = std.posix.getcwd(&cwd_buf) catch "";
54+
55 var daemon = Daemon{
56 .running = true,
57 .cfg = &cfg,
58@@ -366,6 +399,7 @@ pub fn main() !void {
59 .socket_path = undefined,
60 .pid = undefined,
61 .command = command,
62+ .cwd = cwd,
63 };
64 daemon.socket_path = try getSocketPath(alloc, cfg.socket_dir, session_name);
65 std.log.info("socket path={s}", .{daemon.socket_path});
66@@ -382,6 +416,10 @@ pub fn main() !void {
67 }
68
69 const clients = try std.ArrayList(*Client).initCapacity(alloc, 10);
70+
71+ var cwd_buf: [std.fs.max_path_bytes]u8 = undefined;
72+ const cwd = std.posix.getcwd(&cwd_buf) catch "";
73+
74 var daemon = Daemon{
75 .running = true,
76 .cfg = &cfg,
77@@ -391,6 +429,7 @@ pub fn main() !void {
78 .socket_path = undefined,
79 .pid = undefined,
80 .command = null,
81+ .cwd = cwd,
82 };
83 daemon.socket_path = try getSocketPath(alloc, cfg.socket_dir, session_name);
84 std.log.info("socket path={s}", .{daemon.socket_path});
85@@ -436,6 +475,8 @@ const SessionEntry = struct {
86 clients_len: ?usize,
87 is_error: bool,
88 error_name: ?[]const u8,
89+ cmd: ?[]const u8 = null,
90+ cwd: ?[]const u8 = null,
91
92 fn lessThan(_: void, a: SessionEntry, b: SessionEntry) bool {
93 return std.mem.order(u8, a.name, b.name) == .lt;
94@@ -457,6 +498,8 @@ fn list(cfg: *Cfg) !void {
95 defer {
96 for (sessions.items) |session| {
97 alloc.free(session.name);
98+ if (session.cmd) |cmd| alloc.free(cmd);
99+ if (session.cwd) |cwd| alloc.free(cwd);
100 }
101 sessions.deinit(alloc);
102 }
103@@ -483,12 +526,24 @@ fn list(cfg: *Cfg) !void {
104 };
105 posix.close(result.fd);
106
107+ // Extract cmd and cwd from the fixed-size arrays
108+ const cmd: ?[]const u8 = if (result.info.cmd_len > 0)
109+ alloc.dupe(u8, result.info.cmd[0..result.info.cmd_len]) catch null
110+ else
111+ null;
112+ const cwd: ?[]const u8 = if (result.info.cwd_len > 0)
113+ alloc.dupe(u8, result.info.cwd[0..result.info.cwd_len]) catch null
114+ else
115+ null;
116+
117 try sessions.append(alloc, .{
118 .name = name,
119 .pid = result.info.pid,
120 .clients_len = result.info.clients_len,
121 .is_error = false,
122 .error_name = null,
123+ .cmd = cmd,
124+ .cwd = cwd,
125 });
126 }
127 }
128@@ -505,7 +560,14 @@ fn list(cfg: *Cfg) !void {
129 if (session.is_error) {
130 try w.interface.print("session_name={s}\tstatus={s}\t(cleaning up)\n", .{ session.name, session.error_name.? });
131 } else {
132- try w.interface.print("session_name={s}\tpid={d}\tclients={d}\n", .{ session.name, session.pid.?, session.clients_len.? });
133+ try w.interface.print("session_name={s}\tpid={d}\tclients={d}", .{ session.name, session.pid.?, session.clients_len.? });
134+ if (session.cwd) |cwd| {
135+ try w.interface.print("\tstarted_in={s}", .{cwd});
136+ }
137+ if (session.cmd) |cmd| {
138+ try w.interface.print("\tcmd={s}", .{cmd});
139+ }
140+ try w.interface.print("\n", .{});
141 }
142 try w.interface.flush();
143 }