Skip to content

Commit 3f06b7c

Browse files
committed
fix(agent): cross-compile macOS x64, harden Windows source, tighten matrix
- release/ci matrix: drop retired macos-13; cross-compile darwin-x64 from the macos-14 runner via -Dtarget=x86_64-macos. Skip zig build test for non-native matrix entries. - Drop windows-x64 from the matrix for now: napi_* symbols need a delay-load stub (node.lib / /DELAYLOAD:node.exe) to resolve at link time on Windows, which requires more build.zig plumbing than we want to take on here. Re-enable once that's in. - Replace std.posix.getenv (compile-error on Windows, env strings are WTF-16) with std.process.getEnvVarOwned in src/http/client.zig. Guard swarm backend registry's posix.getenv lookups behind a comptime `os.tag != .windows` check — iTerm2/tmux backends don't exist on Windows anyway. - build.zig: link ws2_32 on Windows targets so std.net's WSASend / WSARecv / WSAGetOverlappedResult resolve — the prerequisite for the eventual Windows re-enable.
1 parent 30c5d6e commit 3f06b7c

5 files changed

Lines changed: 56 additions & 27 deletions

File tree

.github/workflows/ci.yml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,16 @@ jobs:
3434
- os: macos
3535
arch: arm64
3636
runner: macos-14
37+
zig_target: aarch64-macos
3738
- os: macos
3839
arch: x64
39-
runner: macos-13
40+
runner: macos-14 # cross-compile from arm64; macos-13 is retired
41+
zig_target: x86_64-macos
4042
- os: linux
4143
arch: x64
4244
runner: ubuntu-latest
43-
- os: windows
44-
arch: x64
45-
runner: windows-latest
45+
zig_target: x86_64-linux
46+
# windows-x64: see release.yml for why it is omitted.
4647
steps:
4748
- uses: actions/checkout@v4
4849

@@ -52,7 +53,7 @@ jobs:
5253
version: 0.15.2
5354

5455
- name: Build NAPI addon
55-
run: zig build napi -Doptimize=ReleaseFast
56+
run: zig build napi -Doptimize=ReleaseFast -Dtarget=${{ matrix.zig_target }}
5657

5758
- name: Upload artifact
5859
uses: actions/upload-artifact@v4

.github/workflows/release.yml

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,24 @@ jobs:
1919
- os: macos
2020
arch: arm64
2121
runner: macos-14
22+
zig_target: aarch64-macos
23+
native: true
2224
- os: macos
2325
arch: x64
24-
runner: macos-13
26+
# macos-13 runners are retired — cross-compile from the arm64
27+
# runner; zig's cross toolchain handles the Mach-O x64 target.
28+
runner: macos-14
29+
zig_target: x86_64-macos
30+
native: false
2531
- os: linux
2632
arch: x64
2733
runner: ubuntu-latest
28-
- os: windows
29-
arch: x64
30-
runner: windows-latest
34+
zig_target: x86_64-linux
35+
native: true
36+
# windows-x64 is intentionally omitted: NAPI on Windows needs a
37+
# delay-load stub (node.lib / /DELAYLOAD:node.exe) to satisfy the
38+
# napi_* symbols at link time, which requires more build.zig
39+
# plumbing than we have here. Re-add once that's in place.
3140
steps:
3241
- uses: actions/checkout@v4
3342

@@ -37,10 +46,11 @@ jobs:
3746
version: 0.15.2
3847

3948
- name: Run tests
49+
if: matrix.native
4050
run: zig build test
4151

4252
- name: Build NAPI addon
43-
run: zig build napi -Doptimize=ReleaseFast
53+
run: zig build napi -Doptimize=ReleaseFast -Dtarget=${{ matrix.zig_target }}
4454

4555
- name: Rename artifact
4656
shell: bash

build.zig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ pub fn build(b: *std.Build) void {
3939
.optimize = optimize,
4040
});
4141
c_api_static_module.link_libc = true;
42+
// std.net on Windows pulls in Winsock — link ws2_32 so WSASend/WSARecv/
43+
// WSAGetOverlappedResult resolve at link time instead of failing at load.
44+
if (target.result.os.tag == .windows) {
45+
c_api_static_module.linkSystemLibrary("ws2_32", .{});
46+
}
4247
const static_lib = b.addLibrary(.{
4348
.name = "agent_static",
4449
.root_module = c_api_static_module,
@@ -51,6 +56,9 @@ pub fn build(b: *std.Build) void {
5156
});
5257
bridge_module.linkLibrary(static_lib);
5358
bridge_module.link_libc = true;
59+
if (target.result.os.tag == .windows) {
60+
bridge_module.linkSystemLibrary("ws2_32", .{});
61+
}
5462
const napi_lib = b.addLibrary(.{
5563
.name = "agent_napi",
5664
.root_module = bridge_module,

src/http/client.zig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,12 @@ pub const HttpClient = struct {
158158
// Do NOT read the response body — response.reader() panics
159159
// on some providers that send responses without proper
160160
// transfer encoding.
161+
// std.posix.getenv is a compile error on Windows (env strings are
162+
// WTF-16); use getEnvVarOwned instead and skip the opt-in on hosts
163+
// that can't satisfy the lookup.
161164
const log_body_enabled = blk: {
162-
const env = std.posix.getenv("OPENPENCIL_HTTP_LOG_REQUEST_BODY") orelse break :blk false;
165+
const env = std.process.getEnvVarOwned(self.allocator, "OPENPENCIL_HTTP_LOG_REQUEST_BODY") catch break :blk false;
166+
defer self.allocator.free(env);
163167
break :blk env.len > 0 and env[0] != '0';
164168
};
165169
const should_log_body =

src/swarm/backends/registry.zig

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,28 @@ pub const BackendRegistry = struct {
1818
pub fn detect(self: *BackendRegistry) BackendType {
1919
if (self.cached) |c| return c;
2020

21-
// iTerm2 — highest priority.
22-
if (std.posix.getenv("ITERM_SESSION_ID") != null) {
23-
self.cached = .iterm2;
24-
return .iterm2;
25-
}
26-
27-
// tmux — check env variable first.
28-
if (std.posix.getenv("TMUX") != null) {
29-
self.cached = .tmux;
30-
return .tmux;
31-
}
32-
33-
// tmux — check if binary is on PATH.
34-
if (tmuxBinaryExists()) {
35-
self.cached = .tmux;
36-
return .tmux;
21+
// Terminal multiplexer backends (iTerm2, tmux) only exist on
22+
// Unix-like hosts. std.posix.getenv is also a compile error on
23+
// Windows (env strings are WTF-16), so gate the whole lookup behind
24+
// a comptime OS check.
25+
if (comptime @import("builtin").os.tag != .windows) {
26+
// iTerm2 — highest priority.
27+
if (std.posix.getenv("ITERM_SESSION_ID") != null) {
28+
self.cached = .iterm2;
29+
return .iterm2;
30+
}
31+
32+
// tmux — check env variable first.
33+
if (std.posix.getenv("TMUX") != null) {
34+
self.cached = .tmux;
35+
return .tmux;
36+
}
37+
38+
// tmux — check if binary is on PATH.
39+
if (tmuxBinaryExists()) {
40+
self.cached = .tmux;
41+
return .tmux;
42+
}
3743
}
3844

3945
// Fallback — always available.

0 commit comments

Comments
 (0)