zeno-mobile-runner 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/FEATURES.md +1 -1
  3. package/README.md +1 -1
  4. package/build.zig.zon +2 -2
  5. package/clients/kotlin/README.md +1 -1
  6. package/clients/kotlin/build.gradle.kts +1 -1
  7. package/clients/python/pyproject.toml +1 -1
  8. package/clients/rust/Cargo.lock +1 -1
  9. package/clients/rust/Cargo.toml +1 -1
  10. package/clients/typescript/package.json +1 -1
  11. package/docs/protocol-fixtures/core-session.responses.jsonl +1 -1
  12. package/docs/protocol.md +10 -10
  13. package/package.json +3 -1
  14. package/prebuilds/darwin-arm64/zmr +0 -0
  15. package/prebuilds/darwin-x64/zmr +0 -0
  16. package/prebuilds/linux-arm64/zmr +0 -0
  17. package/prebuilds/linux-x64/zmr +0 -0
  18. package/scripts/create-react-native-expo-demo-app.sh +11 -13
  19. package/shims/ios/ZMRShim.swift +40 -12
  20. package/shims/ios/ZMRShimUITestCase.swift +135 -15
  21. package/src/android.zig +10 -9
  22. package/src/android_emulator.zig +22 -11
  23. package/src/android_screen_recording.zig +11 -7
  24. package/src/bundle.zig +10 -9
  25. package/src/bundle_redaction.zig +29 -28
  26. package/src/bundle_tar.zig +15 -12
  27. package/src/cli_devices.zig +7 -3
  28. package/src/cli_discover.zig +7 -3
  29. package/src/cli_doctor.zig +7 -3
  30. package/src/cli_draft.zig +51 -47
  31. package/src/cli_explore.zig +7 -3
  32. package/src/cli_import.zig +8 -4
  33. package/src/cli_info.zig +13 -6
  34. package/src/cli_init.zig +9 -5
  35. package/src/cli_inspect.zig +8 -4
  36. package/src/cli_run.zig +22 -16
  37. package/src/cli_serve.zig +3 -3
  38. package/src/cli_trace.zig +25 -12
  39. package/src/cli_validate.zig +8 -4
  40. package/src/command.zig +81 -99
  41. package/src/config.zig +2 -1
  42. package/src/config_diagnostics.zig +2 -1
  43. package/src/config_paths.zig +2 -1
  44. package/src/doctor.zig +8 -7
  45. package/src/doctor_hints.zig +1 -1
  46. package/src/errors.zig +5 -5
  47. package/src/importer.zig +8 -7
  48. package/src/ios.zig +19 -18
  49. package/src/ios_devices.zig +6 -5
  50. package/src/ios_lifecycle.zig +4 -4
  51. package/src/json_rpc.zig +39 -40
  52. package/src/json_rpc_methods.zig +8 -8
  53. package/src/json_rpc_observation.zig +9 -8
  54. package/src/json_rpc_params.zig +1 -1
  55. package/src/json_rpc_trace.zig +22 -21
  56. package/src/main.zig +19 -10
  57. package/src/mcp.zig +28 -19
  58. package/src/mcp_trace.zig +30 -29
  59. package/src/report.zig +39 -36
  60. package/src/report_html.zig +5 -4
  61. package/src/runner.zig +2 -1
  62. package/src/runner_actions.zig +20 -17
  63. package/src/runner_diagnostics.zig +4 -4
  64. package/src/runner_events.zig +55 -51
  65. package/src/runner_native.zig +21 -19
  66. package/src/runner_waits.zig +46 -41
  67. package/src/scaffold.zig +25 -24
  68. package/src/scenario.zig +4 -3
  69. package/src/stdio.zig +129 -0
  70. package/src/trace.zig +34 -26
  71. package/src/trace_summary.zig +3 -2
  72. package/src/trace_summary_diagnostic.zig +15 -13
  73. package/src/validation.zig +5 -4
  74. package/src/version.zig +1 -1
package/src/cli_trace.zig CHANGED
@@ -1,4 +1,5 @@
1
1
  const std = @import("std");
2
+ const stdio = @import("stdio.zig");
2
3
 
3
4
  const bundle = @import("bundle.zig");
4
5
  const report = @import("report.zig");
@@ -36,11 +37,11 @@ pub fn parseReportArgs(args: []const []const u8) !ReportArgs {
36
37
  index += 1;
37
38
  junit_path = if (index < args.len) args[index] else return error.MissingJUnitOutput;
38
39
  } else if (std.mem.startsWith(u8, arg, "--")) {
39
- return error.UnknownFlag;
40
+ return error.unknownFlag;
40
41
  } else if (input_path == null) {
41
42
  input_path = arg;
42
43
  } else {
43
- return error.UnknownFlag;
44
+ return error.unknownFlag;
44
45
  }
45
46
  }
46
47
  if (input_path == null) return error.MissingReportInput;
@@ -60,7 +61,7 @@ pub fn parseExplainArgs(args: []const []const u8) !ExplainArgs {
60
61
  } else if (parsed.trace_dir == null) {
61
62
  parsed.trace_dir = arg;
62
63
  } else {
63
- return error.UnknownFlag;
64
+ return error.unknownFlag;
64
65
  }
65
66
  }
66
67
  if (parsed.trace_dir == null) return error.MissingTraceDir;
@@ -85,11 +86,11 @@ pub fn parseExportArgs(args: []const []const u8) !ExportArgs {
85
86
  redact = true;
86
87
  omit_screenshots = true;
87
88
  } else if (std.mem.startsWith(u8, arg, "--")) {
88
- return error.UnknownFlag;
89
+ return error.unknownFlag;
89
90
  } else if (trace_dir == null) {
90
91
  trace_dir = arg;
91
92
  } else {
92
- return error.UnknownFlag;
93
+ return error.unknownFlag;
93
94
  }
94
95
  }
95
96
  if (trace_dir == null) return error.MissingTraceDir;
@@ -102,32 +103,40 @@ pub fn parseExportArgs(args: []const []const u8) !ExportArgs {
102
103
  };
103
104
  }
104
105
 
105
- pub fn runReport(allocator: std.mem.Allocator, args: *std.process.ArgIterator) !void {
106
+ pub fn runReport(allocator: std.mem.Allocator, args: *std.process.Args.Iterator) !void {
106
107
  var raw_args = std.ArrayList([]const u8).empty;
107
108
  defer raw_args.deinit(allocator);
108
109
  while (args.next()) |arg| try raw_args.append(allocator, arg);
109
110
 
110
111
  const parsed = try parseReportArgs(raw_args.items);
112
+ var stdout_io: stdio.Output = .{};
113
+ stdout_io.init(.stdout());
114
+ defer stdout_io.deinit();
115
+ const stdout = stdout_io.writer();
116
+
111
117
  try report.writeHtmlReport(allocator, parsed.input_path, parsed.out_path.?);
112
- try std.fs.File.stdout().deprecatedWriter().print("wrote {s}\n", .{parsed.out_path.?});
118
+ try stdout.print("wrote {s}\n", .{parsed.out_path.?});
113
119
  if (parsed.junit_path) |junit_path| {
114
120
  try report.writeJUnitReport(allocator, parsed.input_path, junit_path);
115
- try std.fs.File.stdout().deprecatedWriter().print("wrote {s}\n", .{junit_path});
121
+ try stdout.print("wrote {s}\n", .{junit_path});
116
122
  }
117
123
  }
118
124
 
119
- pub fn runExplain(allocator: std.mem.Allocator, args: *std.process.ArgIterator) !void {
125
+ pub fn runExplain(allocator: std.mem.Allocator, args: *std.process.Args.Iterator) !void {
120
126
  var raw_args = std.ArrayList([]const u8).empty;
121
127
  defer raw_args.deinit(allocator);
122
128
  while (args.next()) |arg| try raw_args.append(allocator, arg);
123
129
 
124
130
  const parsed = try parseExplainArgs(raw_args.items);
125
- const stdout = std.fs.File.stdout().deprecatedWriter();
131
+ var stdout_io: stdio.Output = .{};
132
+ stdout_io.init(.stdout());
133
+ defer stdout_io.deinit();
134
+ const stdout = stdout_io.writer();
126
135
  if (parsed.json) return try report.writeTraceExplanationJson(allocator, parsed.trace_dir.?, stdout);
127
136
  try report.writeTraceExplanation(allocator, parsed.trace_dir.?, stdout);
128
137
  }
129
138
 
130
- pub fn runExport(allocator: std.mem.Allocator, args: *std.process.ArgIterator) !void {
139
+ pub fn runExport(allocator: std.mem.Allocator, args: *std.process.Args.Iterator) !void {
131
140
  var raw_args = std.ArrayList([]const u8).empty;
132
141
  defer raw_args.deinit(allocator);
133
142
  while (args.next()) |arg| try raw_args.append(allocator, arg);
@@ -137,5 +146,9 @@ pub fn runExport(allocator: std.mem.Allocator, args: *std.process.ArgIterator) !
137
146
  .redact = parsed.redact,
138
147
  .omit_screenshots = parsed.omit_screenshots,
139
148
  });
140
- try std.fs.File.stdout().deprecatedWriter().print("wrote {s}\n", .{parsed.out_path.?});
149
+ var stdout_io: stdio.Output = .{};
150
+ stdout_io.init(.stdout());
151
+ defer stdout_io.deinit();
152
+ const stdout = stdout_io.writer();
153
+ try stdout.print("wrote {s}\n", .{parsed.out_path.?});
141
154
  }
@@ -1,4 +1,5 @@
1
1
  const std = @import("std");
2
+ const stdio = @import("stdio.zig");
2
3
 
3
4
  const cli_output = @import("cli_output.zig");
4
5
  const validation = @import("validation.zig");
@@ -15,11 +16,11 @@ pub fn parseArgs(args: []const []const u8) !ParsedArgs {
15
16
  if (std.mem.eql(u8, arg, "--json")) {
16
17
  json = true;
17
18
  } else if (std.mem.startsWith(u8, arg, "--")) {
18
- return error.UnknownFlag;
19
+ return error.unknownFlag;
19
20
  } else if (path == null) {
20
21
  path = arg;
21
22
  } else {
22
- return error.UnknownFlag;
23
+ return error.unknownFlag;
23
24
  }
24
25
  }
25
26
  return ParsedArgs{
@@ -28,7 +29,7 @@ pub fn parseArgs(args: []const []const u8) !ParsedArgs {
28
29
  };
29
30
  }
30
31
 
31
- pub fn run(allocator: std.mem.Allocator, args: *std.process.ArgIterator) !void {
32
+ pub fn run(allocator: std.mem.Allocator, args: *std.process.Args.Iterator) !void {
32
33
  var raw_args = std.ArrayList([]const u8).empty;
33
34
  defer raw_args.deinit(allocator);
34
35
  while (args.next()) |arg| try raw_args.append(allocator, arg);
@@ -37,7 +38,10 @@ pub fn run(allocator: std.mem.Allocator, args: *std.process.ArgIterator) !void {
37
38
  const result = try validation.validateFile(allocator, parsed.path);
38
39
  defer result.deinit(allocator);
39
40
 
40
- const stdout = std.fs.File.stdout().deprecatedWriter();
41
+ var stdout_io: stdio.Output = .{};
42
+ stdout_io.init(.stdout());
43
+ defer stdout_io.deinit();
44
+ const stdout = stdout_io.writer();
41
45
  if (parsed.json) {
42
46
  try cli_output.writeValidationJson(stdout, parsed.path, result);
43
47
  } else {
package/src/command.zig CHANGED
@@ -1,5 +1,5 @@
1
1
  const std = @import("std");
2
- const builtin = @import("builtin");
2
+ const stdio = @import("stdio.zig");
3
3
 
4
4
  pub const ExecResult = struct {
5
5
  stdout: []u8,
@@ -15,7 +15,7 @@ pub const ExecResult = struct {
15
15
  pub fn ensureSuccess(self: ExecResult) !void {
16
16
  if (self.timed_out) return error.CommandTimedOut;
17
17
  switch (self.term) {
18
- .Exited => |code| if (code == 0) return,
18
+ .exited => |code| if (code == 0) return,
19
19
  else => {},
20
20
  }
21
21
  return error.CommandFailed;
@@ -27,10 +27,10 @@ pub fn run(
27
27
  argv: []const []const u8,
28
28
  max_output_bytes: usize,
29
29
  ) !ExecResult {
30
- const result = try std.process.Child.run(.{
31
- .allocator = allocator,
30
+ const result = try std.process.run(allocator, stdio.io(), .{
32
31
  .argv = argv,
33
- .max_output_bytes = max_output_bytes,
32
+ .stdout_limit = .limited(max_output_bytes),
33
+ .stderr_limit = .limited(max_output_bytes),
34
34
  });
35
35
  return .{
36
36
  .stdout = result.stdout,
@@ -56,59 +56,24 @@ pub fn runWithInputTimeout(
56
56
  max_output_bytes: usize,
57
57
  timeout_ms: u64,
58
58
  ) !ExecResult {
59
- var child = std.process.Child.init(argv, allocator);
60
- child.stdin_behavior = .Pipe;
61
- child.stdout_behavior = .Pipe;
62
- child.stderr_behavior = .Pipe;
63
-
64
- var stdout = std.ArrayList(u8).empty;
65
- defer stdout.deinit(allocator);
66
- var stderr = std.ArrayList(u8).empty;
67
- defer stderr.deinit(allocator);
68
-
69
- try child.spawn();
70
- errdefer _ = child.kill() catch {};
71
-
72
- var done = std.Thread.ResetEvent{};
73
- var timed_out = std.atomic.Value(bool).init(false);
74
- const use_timeout = timeout_ms > 0;
75
- const killer = if (use_timeout)
76
- try std.Thread.spawn(.{}, timeoutKiller, .{
77
- child.id,
78
- &done,
79
- &timed_out,
80
- std.math.mul(u64, timeout_ms, std.time.ns_per_ms) catch std.math.maxInt(u64),
81
- })
82
- else
83
- null;
59
+ var child = try std.process.spawn(stdio.io(), .{
60
+ .argv = argv,
61
+ .stdin = .pipe,
62
+ .stdout = .pipe,
63
+ .stderr = .pipe,
64
+ });
65
+ defer if (child.id != null) child.kill(stdio.io());
84
66
 
85
67
  if (child.stdin) |stdin_file| {
86
- try stdin_file.writeAll(stdin);
87
- stdin_file.close();
68
+ var stdin_buffer: [8192]u8 = undefined;
69
+ var stdin_writer = stdin_file.writerStreaming(stdio.io(), &stdin_buffer);
70
+ try stdin_writer.interface.writeAll(stdin);
71
+ try stdin_writer.interface.flush();
72
+ stdin_file.close(stdio.io());
88
73
  child.stdin = null;
89
74
  }
90
75
 
91
- child.collectOutput(allocator, &stdout, &stderr, max_output_bytes) catch |err| {
92
- _ = child.kill() catch {};
93
- done.set();
94
- if (killer) |thread| thread.join();
95
- return err;
96
- };
97
-
98
- const term = child.wait() catch |err| {
99
- done.set();
100
- if (killer) |thread| thread.join();
101
- return err;
102
- };
103
- done.set();
104
- if (killer) |thread| thread.join();
105
-
106
- return .{
107
- .stdout = try stdout.toOwnedSlice(allocator),
108
- .stderr = try stderr.toOwnedSlice(allocator),
109
- .term = term,
110
- .timed_out = timed_out.load(.acquire),
111
- };
76
+ return try collectSpawnedOutput(allocator, &child, max_output_bytes, timeoutForMs(timeout_ms));
112
77
  }
113
78
 
114
79
  pub fn runWithTimeout(
@@ -119,64 +84,81 @@ pub fn runWithTimeout(
119
84
  ) !ExecResult {
120
85
  if (timeout_ms == 0) return run(allocator, argv, max_output_bytes);
121
86
 
122
- var child = std.process.Child.init(argv, allocator);
123
- child.stdin_behavior = .Ignore;
124
- child.stdout_behavior = .Pipe;
125
- child.stderr_behavior = .Pipe;
126
-
127
- var stdout = std.ArrayList(u8).empty;
128
- defer stdout.deinit(allocator);
129
- var stderr = std.ArrayList(u8).empty;
130
- defer stderr.deinit(allocator);
131
-
132
- try child.spawn();
133
- errdefer _ = child.kill() catch {};
87
+ const result = std.process.run(allocator, stdio.io(), .{
88
+ .argv = argv,
89
+ .stdout_limit = .limited(max_output_bytes),
90
+ .stderr_limit = .limited(max_output_bytes),
91
+ .timeout = timeoutForMs(timeout_ms),
92
+ }) catch |err| switch (err) {
93
+ error.Timeout => return timedOutResult(allocator),
94
+ else => |actual| return actual,
95
+ };
96
+ return .{
97
+ .stdout = result.stdout,
98
+ .stderr = result.stderr,
99
+ .term = result.term,
100
+ .timed_out = false,
101
+ };
102
+ }
134
103
 
135
- var done = std.Thread.ResetEvent{};
136
- var timed_out = std.atomic.Value(bool).init(false);
137
- const timeout_ns = std.math.mul(u64, timeout_ms, std.time.ns_per_ms) catch std.math.maxInt(u64);
138
- const killer = try std.Thread.spawn(.{}, timeoutKiller, .{ child.id, &done, &timed_out, timeout_ns });
104
+ fn collectSpawnedOutput(
105
+ allocator: std.mem.Allocator,
106
+ child: *std.process.Child,
107
+ max_output_bytes: usize,
108
+ timeout: std.Io.Timeout,
109
+ ) !ExecResult {
110
+ var multi_reader_buffer: std.Io.File.MultiReader.Buffer(2) = undefined;
111
+ var multi_reader: std.Io.File.MultiReader = undefined;
112
+ multi_reader.init(allocator, stdio.io(), multi_reader_buffer.toStreams(), &.{ child.stdout.?, child.stderr.? });
113
+ defer multi_reader.deinit();
114
+
115
+ const stdout_reader = multi_reader.reader(0);
116
+ const stderr_reader = multi_reader.reader(1);
117
+
118
+ while (multi_reader.fill(64, timeout)) |_| {
119
+ if (stdout_reader.buffered().len > max_output_bytes) return error.StreamTooLong;
120
+ if (stderr_reader.buffered().len > max_output_bytes) return error.StreamTooLong;
121
+ } else |err| switch (err) {
122
+ error.EndOfStream => {},
123
+ error.Timeout => {
124
+ child.kill(stdio.io());
125
+ return timedOutResult(allocator);
126
+ },
127
+ else => |actual| return actual,
128
+ }
139
129
 
140
- child.collectOutput(allocator, &stdout, &stderr, max_output_bytes) catch |err| {
141
- _ = child.kill() catch {};
142
- done.set();
143
- killer.join();
144
- return err;
145
- };
130
+ try multi_reader.checkAnyError();
131
+ const term = try child.wait(stdio.io());
146
132
 
147
- const term = child.wait() catch |err| {
148
- done.set();
149
- killer.join();
150
- return err;
151
- };
152
- done.set();
153
- killer.join();
133
+ const stdout_slice = try multi_reader.toOwnedSlice(0);
134
+ errdefer allocator.free(stdout_slice);
135
+ const stderr_slice = try multi_reader.toOwnedSlice(1);
136
+ errdefer allocator.free(stderr_slice);
154
137
 
155
138
  return .{
156
- .stdout = try stdout.toOwnedSlice(allocator),
157
- .stderr = try stderr.toOwnedSlice(allocator),
139
+ .stdout = stdout_slice,
140
+ .stderr = stderr_slice,
158
141
  .term = term,
159
- .timed_out = timed_out.load(.acquire),
142
+ .timed_out = false,
160
143
  };
161
144
  }
162
145
 
163
- fn timeoutKiller(
164
- child_id: std.process.Child.Id,
165
- done: *std.Thread.ResetEvent,
166
- timed_out: *std.atomic.Value(bool),
167
- timeout_ns: u64,
168
- ) void {
169
- done.timedWait(timeout_ns) catch {
170
- timed_out.store(true, .release);
171
- killChildId(child_id);
146
+ fn timedOutResult(allocator: std.mem.Allocator) !ExecResult {
147
+ return .{
148
+ .stdout = try allocator.dupe(u8, ""),
149
+ .stderr = try allocator.dupe(u8, ""),
150
+ .term = .{ .unknown = 0 },
151
+ .timed_out = true,
172
152
  };
173
153
  }
174
154
 
175
- fn killChildId(child_id: std.process.Child.Id) void {
176
- switch (builtin.os.tag) {
177
- .windows => {},
178
- else => std.posix.kill(child_id, std.posix.SIG.TERM) catch {},
179
- }
155
+ fn timeoutForMs(timeout_ms: u64) std.Io.Timeout {
156
+ if (timeout_ms == 0) return .none;
157
+ const timeout_ns = std.math.mul(u64, timeout_ms, std.time.ns_per_ms) catch std.math.maxInt(u64);
158
+ return .{ .duration = .{
159
+ .raw = std.Io.Duration.fromNanoseconds(@intCast(timeout_ns)),
160
+ .clock = .awake,
161
+ } };
180
162
  }
181
163
 
182
164
  pub fn escapeAdbInputText(allocator: std.mem.Allocator, text: []const u8) ![]const u8 {
package/src/config.zig CHANGED
@@ -1,4 +1,5 @@
1
1
  const std = @import("std");
2
+ const stdio = @import("stdio.zig");
2
3
  const config_diagnostics = @import("config_diagnostics.zig");
3
4
 
4
5
  pub const PlatformConfig = struct {
@@ -92,7 +93,7 @@ pub const Config = struct {
92
93
  };
93
94
 
94
95
  pub fn parseFile(allocator: std.mem.Allocator, path: []const u8) !Config {
95
- const content = try std.fs.cwd().readFileAlloc(allocator, path, 1024 * 1024);
96
+ const content = try stdio.readFileAlloc(allocator, path, 1024 * 1024);
96
97
  defer allocator.free(content);
97
98
  return try parseSlice(allocator, content);
98
99
  }
@@ -1,7 +1,8 @@
1
1
  const std = @import("std");
2
+ const stdio = @import("stdio.zig");
2
3
 
3
4
  pub fn errorFieldPathForFile(allocator: std.mem.Allocator, path: []const u8, err: anyerror) !?[]const u8 {
4
- const content = std.fs.cwd().readFileAlloc(allocator, path, 1024 * 1024) catch return null;
5
+ const content = stdio.readFileAlloc(allocator, path, 1024 * 1024) catch return null;
5
6
  defer allocator.free(content);
6
7
  return try errorFieldPathForSlice(allocator, content, err);
7
8
  }
@@ -1,11 +1,12 @@
1
1
  const std = @import("std");
2
+ const stdio = @import("stdio.zig");
2
3
  const config = @import("config.zig");
3
4
 
4
5
  pub const default_path = ".zmr/config.json";
5
6
 
6
7
  pub fn loadIfPresent(allocator: std.mem.Allocator, explicit_path: ?[]const u8) !?config.Config {
7
8
  if (explicit_path) |path| return try config.parseFile(allocator, path);
8
- std.fs.cwd().access(default_path, .{}) catch |err| switch (err) {
9
+ stdio.access(default_path) catch |err| switch (err) {
9
10
  error.FileNotFound => return null,
10
11
  else => return err,
11
12
  };
package/src/doctor.zig CHANGED
@@ -1,4 +1,5 @@
1
1
  const std = @import("std");
2
+ const stdio = @import("stdio.zig");
2
3
  const android = @import("android.zig");
3
4
  const command = @import("command.zig");
4
5
  const config = @import("config.zig");
@@ -137,7 +138,7 @@ pub fn run(allocator: std.mem.Allocator, options: Options) ![]Check {
137
138
  }
138
139
 
139
140
  fn checkPath(allocator: std.mem.Allocator, name: []const u8, path: []const u8) !Check {
140
- std.fs.cwd().access(path, .{ .mode = .read_only }) catch |err| {
141
+ stdio.accessWithOptions(path, .{ .read = true }) catch |err| {
141
142
  return .{
142
143
  .name = try allocator.dupe(u8, name),
143
144
  .status = .missing,
@@ -347,9 +348,9 @@ fn physicalStateBreakdown(allocator: std.mem.Allocator, devices: []const types.D
347
348
  }
348
349
  }
349
350
 
350
- var parts = std.ArrayList(u8).empty;
351
- defer parts.deinit(allocator);
352
- const writer = parts.writer(allocator);
351
+ var parts: std.Io.Writer.Allocating = .init(allocator);
352
+ defer parts.deinit();
353
+ const writer = &parts.writer;
353
354
  var wrote = false;
354
355
  if (disconnected > 0) {
355
356
  try writer.print("disconnected={d}", .{disconnected});
@@ -372,7 +373,7 @@ fn physicalStateBreakdown(allocator: std.mem.Allocator, devices: []const types.D
372
373
  }
373
374
 
374
375
  if (!wrote) return try allocator.dupe(u8, "");
375
- return try std.fmt.allocPrint(allocator, " ({s})", .{parts.items});
376
+ return try std.fmt.allocPrint(allocator, " ({s})", .{parts.writer.buffered()});
376
377
  }
377
378
 
378
379
  pub fn checkCommand(allocator: std.mem.Allocator, name: []const u8, argv: []const []const u8) !Check {
@@ -387,7 +388,7 @@ pub fn checkCommand(allocator: std.mem.Allocator, name: []const u8, argv: []cons
387
388
  };
388
389
  defer result.deinit(allocator);
389
390
 
390
- if (result.term == .Exited and result.term.Exited == 0) {
391
+ if (result.term == .exited and result.term.exited == 0) {
391
392
  return .{
392
393
  .name = try allocator.dupe(u8, name),
393
394
  .status = .ok,
@@ -395,7 +396,7 @@ pub fn checkCommand(allocator: std.mem.Allocator, name: []const u8, argv: []cons
395
396
  };
396
397
  }
397
398
 
398
- const code = if (result.term == .Exited) result.term.Exited else 255;
399
+ const code = if (result.term == .exited) result.term.exited else 255;
399
400
  return .{
400
401
  .name = try allocator.dupe(u8, name),
401
402
  .status = .warning,
@@ -19,7 +19,7 @@ pub fn hintForCheck(allocator: std.mem.Allocator, name: []const u8, status: Stat
19
19
  if (status == .ok) return null;
20
20
  const hint =
21
21
  if (std.mem.eql(u8, name, "zig"))
22
- "Install Zig 0.15.2 or newer, ensure it is on PATH, then run zmr doctor again."
22
+ "Install Zig 0.16.0 or newer, ensure it is on PATH, then run zmr doctor again."
23
23
  else if (std.mem.eql(u8, name, "adb"))
24
24
  "Install Android SDK Platform Tools, ensure adb is on PATH, then run adb devices."
25
25
  else if (std.mem.eql(u8, name, "android-devices"))
package/src/errors.zig CHANGED
@@ -21,8 +21,8 @@ pub fn classify(err: anyerror) PublicError {
21
21
  error.MissingXcrunPath => .{ .code = "cli.missing_xcrun_path", .message = "missing xcrun path" },
22
22
  error.MissingZigPath => .{ .code = "cli.missing_zig_path", .message = "missing zig path" },
23
23
  error.MissingPlatform => .{ .code = "cli.missing_platform", .message = "missing platform" },
24
- error.UnknownCommand => .{ .code = "cli.unknown_command", .message = "unknown command" },
25
- error.UnknownFlag => .{ .code = "cli.unknown_flag", .message = "unknown flag" },
24
+ error.unknownCommand => .{ .code = "cli.unknown_command", .message = "unknown command" },
25
+ error.unknownFlag => .{ .code = "cli.unknown_flag", .message = "unknown flag" },
26
26
  error.MissingParam => .{ .code = "cli.missing_param", .message = "missing parameter" },
27
27
  error.FileNotFound => .{ .code = "scenario.file_not_found", .message = "scenario file was not found" },
28
28
  error.SemanticSnapshotMissing => .{ .code = "draft.no_snapshot", .message = "no semantic snapshot was found in the trace" },
@@ -36,9 +36,9 @@ pub fn classify(err: anyerror) PublicError {
36
36
  error.StepMustBeObject,
37
37
  error.StepMissingAction,
38
38
  error.StepActionMustBeString,
39
- error.UnknownAction,
40
- error.UnknownScenarioAction,
41
- error.UnknownScrollDirection,
39
+ error.unknownAction,
40
+ error.unknownScenarioAction,
41
+ error.unknownScrollDirection,
42
42
  error.StepMissingUrl,
43
43
  error.StepMissingText,
44
44
  error.StepMissingX1,
package/src/importer.zig CHANGED
@@ -1,4 +1,5 @@
1
1
  const std = @import("std");
2
+ const stdio = @import("stdio.zig");
2
3
  const importer_json = @import("importer_json.zig");
3
4
  const model = @import("importer_model.zig");
4
5
 
@@ -13,20 +14,20 @@ pub fn importFlowYamlFile(
13
14
  ) !ImportResult {
14
15
  if (!options.force and fileExists(out_path)) return error.ImportOutputExists;
15
16
 
16
- const content = try std.fs.cwd().readFileAlloc(allocator, source_path, 4 * 1024 * 1024);
17
+ const content = try stdio.readFileAlloc(allocator, source_path, 4 * 1024 * 1024);
17
18
  defer allocator.free(content);
18
19
 
19
20
  var imported = try parseFlowYamlSlice(allocator, content, options);
20
21
  defer imported.deinit(allocator);
21
22
 
22
23
  if (std.fs.path.dirname(out_path)) |dir| {
23
- if (dir.len > 0) try std.fs.cwd().makePath(dir);
24
+ if (dir.len > 0) try std.Io.Dir.cwd().createDirPath(stdio.io(), dir);
24
25
  }
25
26
 
26
- var file = try std.fs.cwd().createFile(out_path, .{ .truncate = true });
27
- defer file.close();
27
+ var file = try std.Io.Dir.cwd().createFile(stdio.io(), out_path, .{ .truncate = true });
28
+ defer file.close(stdio.io());
28
29
  var write_buffer: [8192]u8 = undefined;
29
- var file_writer = file.writer(&write_buffer);
30
+ var file_writer = file.writerStreaming(stdio.io(), &write_buffer);
30
31
  try importer_json.writeScenarioJson(&file_writer.interface, imported);
31
32
  try file_writer.interface.flush();
32
33
 
@@ -39,7 +40,7 @@ pub fn importFlowYamlFile(
39
40
  }
40
41
 
41
42
  fn fileExists(path: []const u8) bool {
42
- std.fs.cwd().access(path, .{}) catch return false;
43
+ stdio.access(path) catch return false;
43
44
  return true;
44
45
  }
45
46
 
@@ -59,7 +60,7 @@ fn parseFlowYamlSlice(allocator: std.mem.Allocator, content: []const u8, options
59
60
  defer lines.deinit(allocator);
60
61
  var split = std.mem.splitScalar(u8, content, '\n');
61
62
  while (split.next()) |line| {
62
- try lines.append(allocator, std.mem.trimRight(u8, line, "\r"));
63
+ try lines.append(allocator, std.mem.trimEnd(u8, line, "\r"));
63
64
  }
64
65
 
65
66
  var in_commands = false;