From b1c9bc97fca091e7cdd7a596b331d08b66cd28db Mon Sep 17 00:00:00 2001 From: Jeremie Fraeys Date: Sat, 21 Feb 2026 17:59:20 -0500 Subject: [PATCH] fix(cli): CLI structure, manifest, and asset fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix commands.zig imports (logs.zig → log.zig, remove missing modules) - Fix manifest.writeManifest to accept allocator param - Add db.Stmt type alias for sqlite3_stmt - Fix rsync placeholder to be valid shell script (#!/bin/sh) --- cli/src/assets/rsync/rsync_placeholder.bin | 3 +- cli/src/commands.zig | 7 +- cli/src/db.zig | 5 +- cli/src/manifest.zig | 93 ++++++++++++++-------- 4 files changed, 68 insertions(+), 40 deletions(-) diff --git a/cli/src/assets/rsync/rsync_placeholder.bin b/cli/src/assets/rsync/rsync_placeholder.bin index 421376d..bd407b7 100755 --- a/cli/src/assets/rsync/rsync_placeholder.bin +++ b/cli/src/assets/rsync/rsync_placeholder.bin @@ -1 +1,2 @@ -dummy +#!/bin/sh +exec /usr/bin/rsync "$@" diff --git a/cli/src/commands.zig b/cli/src/commands.zig index ca122b0..f52dc11 100644 --- a/cli/src/commands.zig +++ b/cli/src/commands.zig @@ -8,13 +8,10 @@ pub const find = @import("commands/find.zig"); pub const info = @import("commands/info.zig"); pub const init = @import("commands/init.zig"); pub const jupyter = @import("commands/jupyter.zig"); -pub const logs = @import("commands/logs.zig"); -pub const monitor = @import("commands/monitor.zig"); -pub const narrative = @import("commands/narrative.zig"); -pub const outcome = @import("commands/outcome.zig"); +pub const logs = @import("commands/log.zig"); pub const prune = @import("commands/prune.zig"); pub const queue = @import("commands/queue.zig"); -pub const requeue = @import("commands/requeue.zig"); +pub const run = @import("commands/run.zig"); pub const status = @import("commands/status.zig"); pub const sync = @import("commands/sync.zig"); pub const validate = @import("commands/validate.zig"); diff --git a/cli/src/db.zig b/cli/src/db.zig index 9eb0f28..9ec27c1 100644 --- a/cli/src/db.zig +++ b/cli/src/db.zig @@ -1,10 +1,13 @@ const std = @import("std"); // SQLite C bindings -const c = @cImport({ +pub const c = @cImport({ @cInclude("sqlite3.h"); }); +// Public type alias for prepared statement +pub const Stmt = ?*c.sqlite3_stmt; + // SQLITE_TRANSIENT constant - use C wrapper to avoid Zig 0.15 C translation issue extern fn fetchml_sqlite_transient() c.sqlite3_destructor_type; fn sqliteTransient() c.sqlite3_destructor_type { diff --git a/cli/src/manifest.zig b/cli/src/manifest.zig index 56a0960..2df9d95 100644 --- a/cli/src/manifest.zig +++ b/cli/src/manifest.zig @@ -59,82 +59,109 @@ pub const RunManifest = struct { }; /// Write manifest to JSON file -pub fn writeManifest(manifest: RunManifest, path: []const u8) !void { +pub fn writeManifest(manifest: RunManifest, path: []const u8, allocator: std.mem.Allocator) !void { var file = try std.fs.cwd().createFile(path, .{}); defer file.close(); - const writer = file.writer(); - // Write JSON manually to avoid std.json complexity with hash maps - try writer.writeAll("{\n"); + try file.writeAll("{\n"); - try writer.print(" \"run_id\": \"{s}\",\n", .{manifest.run_id}); - try writer.print(" \"experiment\": \"{s}\",\n", .{manifest.experiment}); - try writer.print(" \"command\": \"{s}\",\n", .{manifest.command}); + const line1 = try std.fmt.allocPrint(allocator, " \"run_id\": \"{s}\",\n", .{manifest.run_id}); + defer allocator.free(line1); + try file.writeAll(line1); + + const line2 = try std.fmt.allocPrint(allocator, " \"experiment\": \"{s}\",\n", .{manifest.experiment}); + defer allocator.free(line2); + try file.writeAll(line2); + + const line3 = try std.fmt.allocPrint(allocator, " \"command\": \"{s}\",\n", .{manifest.command}); + defer allocator.free(line3); + try file.writeAll(line3); // Args array - try writer.writeAll(" \"args\": ["); + try file.writeAll(" \"args\": ["); for (manifest.args, 0..) |arg, i| { - if (i > 0) try writer.writeAll(", "); - try writer.print("\"{s}\"", .{arg}); + if (i > 0) try file.writeAll(", "); + const arg_str = try std.fmt.allocPrint(allocator, "\"{s}\"", .{arg}); + defer allocator.free(arg_str); + try file.writeAll(arg_str); } - try writer.writeAll("],\n"); + try file.writeAll("],\n"); // Commit ID (optional) if (manifest.commit_id) |cid| { - try writer.print(" \"commit_id\": \"{s}\",\n", .{cid}); + const cid_str = try std.fmt.allocPrint(allocator, " \"commit_id\": \"{s}\",\n", .{cid}); + defer allocator.free(cid_str); + try file.writeAll(cid_str); } else { - try writer.writeAll(" \"commit_id\": null,\n"); + try file.writeAll(" \"commit_id\": null,\n"); } - try writer.print(" \"started_at\": \"{s}\",\n", .{manifest.started_at}); + const started_str = try std.fmt.allocPrint(allocator, " \"started_at\": \"{s}\",\n", .{manifest.started_at}); + defer allocator.free(started_str); + try file.writeAll(started_str); // Ended at (optional) if (manifest.ended_at) |ended| { - try writer.print(" \"ended_at\": \"{s}\",\n", .{ended}); + const ended_str = try std.fmt.allocPrint(allocator, " \"ended_at\": \"{s}\",\n", .{ended}); + defer allocator.free(ended_str); + try file.writeAll(ended_str); } else { - try writer.writeAll(" \"ended_at\": null,\n"); + try file.writeAll(" \"ended_at\": null,\n"); } - try writer.print(" \"status\": \"{s}\",\n", .{manifest.status}); + const status_str = try std.fmt.allocPrint(allocator, " \"status\": \"{s}\",\n", .{manifest.status}); + defer allocator.free(status_str); + try file.writeAll(status_str); // Exit code (optional) if (manifest.exit_code) |code| { - try writer.print(" \"exit_code\": {d},\n", .{code}); + const exit_str = try std.fmt.allocPrint(allocator, " \"exit_code\": {d},\n", .{code}); + defer allocator.free(exit_str); + try file.writeAll(exit_str); } else { - try writer.writeAll(" \"exit_code\": null,\n"); + try file.writeAll(" \"exit_code\": null,\n"); } // Params object - try writer.writeAll(" \"params\": {"); + try file.writeAll(" \"params\": {"); var params_first = true; var params_iter = manifest.params.iterator(); while (params_iter.next()) |entry| { - if (!params_first) try writer.writeAll(", "); + if (!params_first) try file.writeAll(", "); params_first = false; - try writer.print("\"{s}\": \"{s}\"", .{ entry.key_ptr.*, entry.value_ptr.* }); + const param_str = try std.fmt.allocPrint(allocator, "\"{s}\": \"{s}\"", .{ entry.key_ptr.*, entry.value_ptr.* }); + defer allocator.free(param_str); + try file.writeAll(param_str); } - try writer.writeAll("},\n"); + try file.writeAll("},\n"); // Metrics summary (optional) if (manifest.metrics_summary) |summary| { - try writer.writeAll(" \"metrics_summary\": {"); + try file.writeAll(" \"metrics_summary\": {"); var summary_first = true; var summary_iter = summary.iterator(); while (summary_iter.next()) |entry| { - if (!summary_first) try writer.writeAll(", "); + if (!summary_first) try file.writeAll(", "); summary_first = false; - try writer.print("\"{s}\": {d:.4}", .{ entry.key_ptr.*, entry.value_ptr.* }); + const metric_str = try std.fmt.allocPrint(allocator, "\"{s}\": {d:.4}", .{ entry.key_ptr.*, entry.value_ptr.* }); + defer allocator.free(metric_str); + try file.writeAll(metric_str); } - try writer.writeAll("},\n"); + try file.writeAll("},\n"); } else { - try writer.writeAll(" \"metrics_summary\": null,\n"); + try file.writeAll(" \"metrics_summary\": null,\n"); } - try writer.print(" \"artifact_path\": \"{s}\",\n", .{manifest.artifact_path}); - try writer.print(" \"synced\": {}", .{manifest.synced}); + const artifact_str = try std.fmt.allocPrint(allocator, " \"artifact_path\": \"{s}\",\n", .{manifest.artifact_path}); + defer allocator.free(artifact_str); + try file.writeAll(artifact_str); - try writer.writeAll("\n}\n"); + const synced_str = try std.fmt.allocPrint(allocator, " \"synced\": {}", .{manifest.synced}); + defer allocator.free(synced_str); + try file.writeAll(synced_str); + + try file.writeAll("\n}\n"); } /// Read manifest from JSON file @@ -265,7 +292,7 @@ pub fn updateManifestStatus(path: []const u8, status: []const u8, exit_code: ?i3 manifest.ended_at = try allocator.dupe(u8, timestamp); - try writeManifest(manifest, path); + try writeManifest(manifest, path, allocator); } /// Mark manifest as synced @@ -274,7 +301,7 @@ pub fn markManifestSynced(path: []const u8, allocator: std.mem.Allocator) !void defer manifest.deinit(allocator); manifest.synced = true; - try writeManifest(manifest, path); + try writeManifest(manifest, path, allocator); } /// Build manifest path from experiment and run_id