repos / zmx

session persistence for terminal processes
git clone https://github.com/neurosnap/zmx.git

commit
e2ddda3
parent
83c8c35
author
Eric Bower
date
2025-10-16 14:11:42 -0400 EDT
feat: attach will start in the cwd of client
3 files changed,  +16, -5
M src/attach.zig
+5, -0
 1@@ -115,10 +115,15 @@ pub fn main(config: config_mod.Config, iter: *std.process.ArgIterator) !void {
 2     const rows: u16 = if (result == 0) ws.ws_row else 24;
 3     const cols: u16 = if (result == 0) ws.ws_col else 80;
 4 
 5+    const cwd_buf = try allocator.alloc(u8, std.fs.max_path_bytes);
 6+    defer allocator.free(cwd_buf);
 7+    const cwd = try std.posix.getcwd(cwd_buf);
 8+
 9     const request_payload = protocol.AttachSessionRequest{
10         .session_name = session_name,
11         .rows = rows,
12         .cols = cols,
13+        .cwd = cwd,
14     };
15     var out: std.io.Writer.Allocating = .init(allocator);
16     defer out.deinit();
M src/daemon.zig
+10, -5
 1@@ -517,8 +517,8 @@ fn handleMessage(client: *Client, data: []const u8) !void {
 2         .attach_session_request => {
 3             const parsed = try protocol.parseMessage(protocol.AttachSessionRequest, client.allocator, data);
 4             defer parsed.deinit();
 5-            std.debug.print("Handling attach request for session: {s} ({}x{})\n", .{ parsed.value.payload.session_name, parsed.value.payload.cols, parsed.value.payload.rows });
 6-            try handleAttachSession(client.server_ctx, client, parsed.value.payload.session_name, parsed.value.payload.rows, parsed.value.payload.cols);
 7+            std.debug.print("Handling attach request for session: {s} ({}x{}) cwd={s}\n", .{ parsed.value.payload.session_name, parsed.value.payload.cols, parsed.value.payload.rows, parsed.value.payload.cwd });
 8+            try handleAttachSession(client.server_ctx, client, parsed.value.payload.session_name, parsed.value.payload.rows, parsed.value.payload.cols, parsed.value.payload.cwd);
 9         },
10         .detach_session_request => {
11             const parsed = try protocol.parseMessage(protocol.DetachSessionRequest, client.allocator, data);
12@@ -745,7 +745,7 @@ fn handleListSessions(ctx: *ServerContext, client: *Client) !void {
13     _ = written;
14 }
15 
16-fn handleAttachSession(ctx: *ServerContext, client: *Client, session_name: []const u8, rows: u16, cols: u16) !void {
17+fn handleAttachSession(ctx: *ServerContext, client: *Client, session_name: []const u8, rows: u16, cols: u16, cwd: []const u8) !void {
18     // Check if session already exists
19     const is_reattach = ctx.sessions.contains(session_name);
20     const session = if (is_reattach) blk: {
21@@ -754,7 +754,7 @@ fn handleAttachSession(ctx: *ServerContext, client: *Client, session_name: []con
22     } else blk: {
23         // Create new session with forkpty
24         std.debug.print("Creating new session: {s}\n", .{session_name});
25-        const new_session = try createSession(ctx.allocator, session_name);
26+        const new_session = try createSession(ctx.allocator, session_name, cwd);
27         try ctx.sessions.put(new_session.name, new_session);
28         break :blk new_session;
29     };
30@@ -1298,7 +1298,7 @@ fn execShellWithPrompt(allocator: std.mem.Allocator, session_name: []const u8, s
31     }
32 }
33 
34-fn createSession(allocator: std.mem.Allocator, session_name: []const u8) !*Session {
35+fn createSession(allocator: std.mem.Allocator, session_name: []const u8, cwd: []const u8) !*Session {
36     var master_fd: c_int = undefined;
37 
38     // Fork and create PTY
39@@ -1310,6 +1310,11 @@ fn createSession(allocator: std.mem.Allocator, session_name: []const u8) !*Sessi
40     if (pid == 0) {
41         // Child process - set environment and execute shell with prompt
42 
43+        // Change to client's working directory
44+        std.posix.chdir(cwd) catch {
45+            std.posix.exit(1);
46+        };
47+
48         // Set ZMX_SESSION to identify the session
49         const zmx_session_var = std.fmt.allocPrint(allocator, "ZMX_SESSION={s}\x00", .{session_name}) catch {
50             std.posix.exit(1);
M src/protocol.zig
+1, -0
1@@ -59,6 +59,7 @@ pub const AttachSessionRequest = struct {
2     session_name: []const u8,
3     rows: u16,
4     cols: u16,
5+    cwd: []const u8,
6 };
7 
8 pub const DetachSessionRequest = struct {