- commit
- 87cc98f
- parent
- d12b7cc
- author
- Eric Bower
- date
- 2026-03-03 20:32:47 -0500 EST
fix(run): stdin regression with ZMX_TASK_COMPLETED We were not actually running the command sent into stdin properly. Closes: https://github.com/neurosnap/zmx/issues/71
1 files changed,
+29,
-27
+29,
-27
1@@ -445,18 +445,6 @@ pub fn main() !void {
2 while (args.next()) |arg| {
3 try cmd_args_raw.append(alloc, arg);
4 }
5- var cmd_args = try cmd_args_raw.clone(alloc);
6- defer cmd_args.deinit(alloc);
7-
8- const shell = detectShell();
9- // add a task completed marker so we know when the cmd is finished
10- // we also capture the exit status
11- if (std.mem.eql(u8, std.fs.path.basename(shell), "fish")) {
12- // fish has special handling for capturing exit status
13- try cmd_args.append(alloc, "; echo ZMX_TASK_COMPLETED:$status");
14- } else {
15- try cmd_args.append(alloc, "; echo ZMX_TASK_COMPLETED:$?");
16- }
17 const clients = try std.ArrayList(*Client).initCapacity(alloc, 10);
18
19 var cwd_buf: [std.fs.max_path_bytes]u8 = undefined;
20@@ -480,7 +468,7 @@ pub fn main() !void {
21 };
22 daemon.socket_path = try getSocketPath(alloc, cfg.socket_dir, sesh);
23 std.log.info("socket path={s}", .{daemon.socket_path});
24- return run(&daemon, cmd_args.items);
25+ return run(&daemon, cmd_args_raw.items);
26 } else if (std.mem.eql(u8, cmd, "wait") or std.mem.eql(u8, cmd, "w")) {
27 var args_raw: std.ArrayList([]const u8) = .empty;
28 defer {
29@@ -1055,6 +1043,10 @@ fn run(daemon: *Daemon, command_args: [][]const u8) !void {
30 var buf: [4096]u8 = undefined;
31 var w = std.fs.File.stdout().writer(&buf);
32
33+ var cmd_to_send: ?[]const u8 = null;
34+ var allocated_cmd: ?[]u8 = null;
35+ defer if (allocated_cmd) |cmd| alloc.free(cmd);
36+
37 const result = try ensureSession(daemon);
38 if (result.is_daemon) return;
39
40@@ -1063,9 +1055,16 @@ fn run(daemon: *Daemon, command_args: [][]const u8) !void {
41 try w.interface.flush();
42 }
43
44- var cmd_to_send: ?[]const u8 = null;
45- var allocated_cmd: ?[]u8 = null;
46- defer if (allocated_cmd) |cmd| alloc.free(cmd);
47+ const shell = detectShell();
48+ const shell_basename = std.fs.path.basename(shell);
49+ const inline_task_marker = if (std.mem.eql(u8, shell_basename, "fish"))
50+ "; echo ZMX_TASK_COMPLETED:$status"
51+ else
52+ "; echo ZMX_TASK_COMPLETED:$?";
53+ const stdin_task_marker = if (std.mem.eql(u8, shell_basename, "fish"))
54+ "echo ZMX_TASK_COMPLETED:$status"
55+ else
56+ "echo ZMX_TASK_COMPLETED:$?";
57
58 if (command_args.len > 0) {
59 var parts: std.ArrayList([]const u8) = .empty;
60@@ -1075,11 +1074,8 @@ fn run(daemon: *Daemon, command_args: [][]const u8) !void {
61 }
62
63 var total_len: usize = 0;
64- for (command_args, 0..) |arg, i| {
65- // Last arg is the sentinel (e.g. "; echo ZMX_TASK_COMPLETED:$?")
66- // which must not be quoted so the shell interprets it.
67- const is_last = i == command_args.len - 1;
68- if (!is_last and shellNeedsQuoting(arg)) {
69+ for (command_args) |arg| {
70+ if (shellNeedsQuoting(arg)) {
71 const quoted = try shellQuote(alloc, arg);
72 try parts.append(alloc, quoted);
73 total_len += quoted.len + 1;
74@@ -1090,20 +1086,22 @@ fn run(daemon: *Daemon, command_args: [][]const u8) !void {
75 }
76 }
77
78+ total_len += inline_task_marker.len + 1;
79+
80 const cmd_buf = try alloc.alloc(u8, total_len);
81 allocated_cmd = cmd_buf;
82
83 var offset: usize = 0;
84- for (parts.items, 0..) |part, i| {
85+ for (parts.items) |part| {
86 @memcpy(cmd_buf[offset .. offset + part.len], part);
87 offset += part.len;
88- if (i < parts.items.len - 1) {
89- cmd_buf[offset] = ' ';
90- } else {
91- cmd_buf[offset] = '\n';
92- }
93+ cmd_buf[offset] = ' ';
94 offset += 1;
95 }
96+
97+ @memcpy(cmd_buf[offset .. offset + inline_task_marker.len], inline_task_marker);
98+ offset += inline_task_marker.len;
99+ cmd_buf[offset] = '\n';
100 cmd_to_send = cmd_buf;
101 } else {
102 const stdin_fd = posix.STDIN_FILENO;
103@@ -1126,6 +1124,10 @@ fn run(daemon: *Daemon, command_args: [][]const u8) !void {
104 if (needs_newline) {
105 try stdin_buf.append(alloc, '\n');
106 }
107+
108+ try stdin_buf.appendSlice(alloc, stdin_task_marker);
109+ try stdin_buf.append(alloc, '\n');
110+
111 cmd_to_send = try alloc.dupe(u8, stdin_buf.items);
112 allocated_cmd = @constCast(cmd_to_send.?);
113 }