Skip to content

Commit 7f493f0

Browse files
committed
fix: implement proper signal-based process termination handling in executor
- Replace simple Exited==0 check with switch statement on Child.Term - Handle all termination cases: Exited, Signal, Stopped, Unknown - Log appropriate error messages for non-zero exits and signals - Add deinit() method to Executor for proper cleanup - Fix session_id memory management using allocPrint instead of bufPrint - Pass --session flag to opencode CLI for session continuity - Call executor.deinit() in main.zig for resource cleanup Signed-off-by: leocavalcante <[email protected]>
1 parent c081b90 commit 7f493f0

File tree

2 files changed

+34
-8
lines changed

2 files changed

+34
-8
lines changed

src/executor.zig

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ pub const Executor = struct {
3333
};
3434
}
3535

36+
/// Cleanup executor resources
37+
pub fn deinit(self: *Executor) void {
38+
if (self.session_id) |sid| {
39+
self.allocator.free(sid);
40+
}
41+
}
42+
3643
/// Run planning phase
3744
pub fn runPlanning(self: *Executor, cycle: u32) !ExecutionResult {
3845
self.log.statusFmt("[Cycle {d}] Planning...", .{cycle});
@@ -47,7 +54,7 @@ pub const Executor = struct {
4754

4855
if (result == .success) {
4956
// Reset session for new cycle
50-
self.session_id = null;
57+
self.resetSession();
5158
}
5259

5360
return result;
@@ -67,10 +74,8 @@ pub const Executor = struct {
6774
const result = try self.runWithRetry(self.cfg.execution_model, title, prompt, continue_session);
6875

6976
if (result == .success and self.session_id == null) {
70-
// Set session ID after first successful task
71-
var sid_buf: [32]u8 = undefined;
72-
const sid = std.fmt.bufPrint(&sid_buf, "cycle_{d}", .{cycle}) catch "session";
73-
self.session_id = sid;
77+
// Set session ID after first successful task (allocate owned memory)
78+
self.session_id = try std.fmt.allocPrint(self.allocator, "cycle_{d}", .{cycle});
7479
}
7580

7681
return result;
@@ -122,6 +127,9 @@ pub const Executor = struct {
122127

123128
/// Reset session for new cycle
124129
pub fn resetSession(self: *Executor) void {
130+
if (self.session_id) |sid| {
131+
self.allocator.free(sid);
132+
}
125133
self.session_id = null;
126134
}
127135

@@ -166,7 +174,10 @@ pub const Executor = struct {
166174
try args.append(self.allocator, title);
167175

168176
if (continue_session) {
169-
try args.append(self.allocator, "--continue");
177+
if (self.session_id) |sid| {
178+
try args.append(self.allocator, "--session");
179+
try args.append(self.allocator, sid);
180+
}
170181
}
171182

172183
try args.append(self.allocator, prompt);
@@ -197,8 +208,22 @@ pub const Executor = struct {
197208

198209
const term = try child.wait();
199210

200-
if (term.Exited == 0) {
201-
return stdout_list.toOwnedSlice(self.allocator);
211+
switch (term) {
212+
.Exited => |code| {
213+
if (code == 0) {
214+
return stdout_list.toOwnedSlice(self.allocator);
215+
}
216+
self.log.logErrorFmt("opencode exited with code {d}", .{code});
217+
},
218+
.Signal => |sig| {
219+
self.log.logErrorFmt("opencode terminated by signal {d}", .{sig});
220+
},
221+
.Stopped => |sig| {
222+
self.log.logErrorFmt("opencode stopped by signal {d}", .{sig});
223+
},
224+
.Unknown => |status| {
225+
self.log.logErrorFmt("opencode terminated with unknown status {d}", .{status});
226+
},
202227
}
203228

204229
stdout_list.deinit(self.allocator);

src/main.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ fn runOpencoder(cfg: config.Config, allocator: std.mem.Allocator) !void {
9999

100100
// Initialize executor
101101
var executor = Executor.init(&cfg, &log, allocator);
102+
defer executor.deinit();
102103

103104
// Run main loop
104105
var main_loop = loop.Loop.init(&cfg, &st, &paths, &log, &executor, allocator);

0 commit comments

Comments
 (0)