fetch_ml/cli/src/main.zig
Jeremie Fraeys 5ae997ceb3
feat(cli): add groups and tasks commands with visibility controls
New Zig CLI commands for lab management:

- groups.zig: Lab group management commands
  * create-group: Create new lab groups with metadata
  * list-groups: Show all groups with member counts
  * add-member: Add users with role assignment (admin/member/viewer)
  * remove-member: Remove users from groups
  * group-info: Display group details and membership

- tasks.zig: Task operations with visibility integration
  * create-task: New tasks with visibility flag (private/lab/institution/open)
  * list-tasks: Filter by visibility level and group membership
  * share-task: Generate access tokens for external sharing
  * clone-task: Copy tasks with public clone tokens
  * task-visibility: Change visibility and cascade to experiments

- run.zig: Updated experiment runner
  * Integrate with new task visibility system
  * Group-scoped experiment execution
  * Token-based access for shared experiments

- main.zig: Command registration updates
  * Wire up new groups and tasks commands
  * Updated help text and command discovery
2026-03-08 13:03:10 -04:00

126 lines
6.2 KiB
Zig

const std = @import("std");
// Handle unknown command - prints error and exits
fn handleUnknownCommand(cmd: []const u8) noreturn {
std.debug.print("Error: Unknown command: {s}\n", .{cmd});
printUsage();
std.process.exit(1);
}
pub fn main() !void {
// Use c_allocator for better performance on Linux
const allocator = std.heap.c_allocator;
const args = std.process.argsAlloc(allocator) catch |err| {
std.debug.print("Failed to allocate args: {}\n", .{err});
return;
};
defer std.process.argsFree(allocator, args);
const command = args[1];
// Handle help flags as valid commands
if (std.mem.eql(u8, command, "--help") or std.mem.eql(u8, command, "-h") or args.len < 2) {
printUsage();
return;
}
// Fast dispatch using switch on first character
switch (command[0]) {
'j' => if (std.mem.eql(u8, command, "jupyter")) {
try @import("commands/jupyter.zig").run(allocator, args[2..]);
} else handleUnknownCommand(command),
'i' => if (std.mem.eql(u8, command, "init")) {
try @import("commands/init.zig").run(allocator, args[2..]);
} else if (std.mem.eql(u8, command, "info")) {
try @import("commands/info.zig").run(allocator, args[2..]);
} else handleUnknownCommand(command),
'a' => if (std.mem.eql(u8, command, "annotate")) {
try @import("commands/annotate.zig").execute(allocator, args[2..]);
} else handleUnknownCommand(command),
'e' => if (std.mem.eql(u8, command, "experiment")) {
try @import("commands/experiment.zig").execute(allocator, args[2..]);
} else if (std.mem.eql(u8, command, "export")) {
try @import("commands/export_cmd.zig").run(allocator, args[2..]);
} else handleUnknownCommand(command),
's' => if (std.mem.eql(u8, command, "sync")) {
try @import("commands/sync.zig").run(allocator, args[2..]);
} else if (std.mem.eql(u8, command, "status")) {
try @import("commands/status.zig").run(allocator, args[2..]);
} else handleUnknownCommand(command),
'r' => if (std.mem.eql(u8, command, "run")) {
try @import("commands/run.zig").execute(allocator, args[2..]);
} else handleUnknownCommand(command),
't' => if (std.mem.eql(u8, command, "tasks")) {
try @import("commands/tasks.zig").execute(allocator, args[2..]);
} else handleUnknownCommand(command),
'g' => if (std.mem.eql(u8, command, "groups")) {
try @import("commands/groups.zig").execute(allocator, args[2..]);
} else handleUnknownCommand(command),
'd' => if (std.mem.eql(u8, command, "dataset")) {
try @import("commands/dataset.zig").run(allocator, args[2..]);
} else handleUnknownCommand(command),
'x' => if (std.mem.eql(u8, command, "export")) {
try @import("commands/export_cmd.zig").run(allocator, args[2..]);
} else handleUnknownCommand(command),
'c' => if (std.mem.eql(u8, command, "cancel")) {
try @import("commands/cancel.zig").run(allocator, args[2..]);
} else if (std.mem.eql(u8, command, "compare")) {
try @import("commands/compare.zig").run(allocator, args[2..]);
} else handleUnknownCommand(command),
'f' => if (std.mem.eql(u8, command, "find")) {
try @import("commands/find.zig").run(allocator, args[2..]);
} else handleUnknownCommand(command),
'v' => if (std.mem.eql(u8, command, "validate")) {
try @import("commands/validate.zig").run(allocator, args[2..]);
} else handleUnknownCommand(command),
'l' => if (std.mem.eql(u8, command, "logs")) {
try @import("commands/log.zig").run(allocator, args[2..]);
} else if (std.mem.eql(u8, command, "log")) {
try @import("commands/log.zig").run(allocator, args[2..]);
} else handleUnknownCommand(command),
'w' => if (std.mem.eql(u8, command, "watch")) {
try @import("commands/watch.zig").run(allocator, args[2..]);
} else handleUnknownCommand(command),
else => {
std.debug.print("Error: Unknown command: {s}\n", .{args[1]});
printUsage();
return error.InvalidCommand;
},
}
}
// Optimized usage printer
fn printUsage() void {
std.debug.print("ML Experiment Manager\n\n", .{});
std.debug.print("Usage: ml <command> [options]\n\n", .{});
std.debug.print("Commands:\n", .{});
std.debug.print(" run <job> Execute job (auto local/remote)\n", .{});
std.debug.print(" tasks Task management (share, open-link, visibility)\n", .{});
std.debug.print(" groups Manage lab groups (create, invite, list)\n", .{});
std.debug.print(" init Initialize project with config\n", .{});
std.debug.print(" annotate <id> Add metadata annotations\n", .{});
std.debug.print(" experiment Manage experiments (create, list, show)\n", .{});
std.debug.print(" logs <id> Fetch or stream run logs\n", .{});
std.debug.print(" sync [id] Push local runs to server\n", .{});
std.debug.print(" cancel <id> Cancel local run\n", .{});
std.debug.print(" watch [--sync] Watch directory with optional auto-sync\n", .{});
std.debug.print(" status Get system status\n", .{});
std.debug.print(" dataset Manage datasets\n", .{});
std.debug.print(" export <id> Export experiment bundle\n", .{});
std.debug.print(" validate Validate provenance and integrity\n", .{});
std.debug.print(" compare <a> <b> Compare two runs\n", .{});
std.debug.print(" find [query] Search experiments\n", .{});
std.debug.print(" jupyter Jupyter workspace management\n", .{});
std.debug.print(" info <id> Show run info\n", .{});
std.debug.print("\nUse 'ml <command> --help' for detailed help.\n", .{});
}
test {
_ = @import("commands/info.zig");
_ = @import("commands/compare.zig");
_ = @import("commands/find.zig");
_ = @import("commands/export_cmd.zig");
_ = @import("commands/log.zig");
_ = @import("commands/annotate.zig");
_ = @import("commands/experiment.zig");
}