diff --git a/build.zig b/build.zig index e46f6ab..d53de2e 100644 --- a/build.zig +++ b/build.zig @@ -1,21 +1,84 @@ const std = @import("std"); +const Profile = struct { + name: []const u8, + exe_name: []const u8, + local_socket: bool, + remote_transport: bool, + plugin_host: bool, + bundled_pi: bool, + background_agent: bool, + tool_mutation: []const u8, +}; + pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); - const mod = b.createModule(.{ - .root_source_file = b.path("src/main.zig"), - .target = target, - .optimize = optimize, - }); + const profiles = [_]Profile{ + .{ + .name = "dev-local", + .exe_name = "mim", + .local_socket = true, + .remote_transport = false, + .plugin_host = false, + .bundled_pi = false, + .background_agent = false, + .tool_mutation = "protocol_logged", + }, + .{ + .name = "minimal", + .exe_name = "mim-min", + .local_socket = false, + .remote_transport = false, + .plugin_host = false, + .bundled_pi = false, + .background_agent = false, + .tool_mutation = "not_built", + }, + .{ + .name = "coding", + .exe_name = "mim-code", + .local_socket = true, + .remote_transport = false, + .plugin_host = false, + .bundled_pi = false, + .background_agent = false, + .tool_mutation = "protocol_logged", + }, + .{ + .name = "full-local", + .exe_name = "mim-full", + .local_socket = true, + .remote_transport = false, + .plugin_host = false, + .bundled_pi = false, + .background_agent = false, + .tool_mutation = "protocol_logged", + }, + }; + const main_mod = profileModule(b, target, optimize, profiles[0]); const exe = b.addExecutable(.{ - .name = "mim", - .root_module = mod, + .name = profiles[0].exe_name, + .root_module = main_mod, }); b.installArtifact(exe); + inline for (profiles[1..]) |profile| { + const profile_exe = b.addExecutable(.{ + .name = profile.exe_name, + .root_module = profileModule(b, target, optimize, profile), + }); + b.installArtifact(profile_exe); + const run_profile = b.addRunArtifact(profile_exe); + run_profile.step.dependOn(b.getInstallStep()); + if (b.args) |args| run_profile.addArgs(args); + const step_name = if (std.mem.eql(u8, profile.exe_name, "mim-min")) "run-min" else if (std.mem.eql(u8, profile.exe_name, "mim-code")) "run-code" else "run-full"; + const run_profile_step = b.step(step_name, "Run profile variant"); + run_profile_step.dependOn(&run_profile.step); + } + const run_cmd = b.addRunArtifact(exe); run_cmd.step.dependOn(b.getInstallStep()); if (b.args) |args| { @@ -25,13 +88,28 @@ pub fn build(b: *std.Build) void { run_step.dependOn(&run_cmd.step); const tests = b.addTest(.{ - .root_module = b.createModule(.{ - .root_source_file = b.path("src/main.zig"), - .target = target, - .optimize = optimize, - }), + .root_module = profileModule(b, target, optimize, profiles[0]), }); const test_cmd = b.addRunArtifact(tests); const test_step = b.step("test", "Run unit tests"); test_step.dependOn(&test_cmd.step); } + +fn profileModule(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, profile: Profile) *std.Build.Module { + const options = b.addOptions(); + options.addOption([]const u8, "active_profile", profile.name); + options.addOption(bool, "local_socket", profile.local_socket); + options.addOption(bool, "remote_transport_built", profile.remote_transport); + options.addOption(bool, "plugin_host_built", profile.plugin_host); + options.addOption(bool, "bundled_pi_built", profile.bundled_pi); + options.addOption(bool, "background_agent_built", profile.background_agent); + options.addOption([]const u8, "tool_mutation", profile.tool_mutation); + + const mod = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + mod.addOptions("build_options", options); + return mod; +} diff --git a/src/main.zig b/src/main.zig index d82c223..e93aacb 100644 --- a/src/main.zig +++ b/src/main.zig @@ -82,6 +82,10 @@ pub fn main(init: std.process.Init) !u8 { return 69; } if (std.mem.eql(u8, arg, "mimctl")) { + if (!profile.local_socket) { + try printProfileStub(init.io, stderr, "mimctl"); + return 69; + } const sub = args.next() orelse { try stderr.writeStreamingAll(init.io, "mim: mimctl requires a subcommand\n"); return 64; @@ -101,6 +105,10 @@ pub fn main(init: std.process.Init) !u8 { } if (std.mem.eql(u8, arg, "--mimctl")) { + if (!profile.local_socket) { + try printProfileStub(init.io, stderr, "mimctl"); + return 69; + } const socket_path = args.next() orelse { try stderr.writeStreamingAll(init.io, "mim: --mimctl requires a socket path\n"); return 64; @@ -152,6 +160,7 @@ fn printProfile(allocator: std.mem.Allocator, io: std.Io, stdout: std.Io.File) ! fn isProfileStub(arg: []const u8) bool { return std.mem.eql(u8, arg, "remote") or + std.mem.eql(u8, arg, "mimctl") or std.mem.eql(u8, arg, "plugin") or std.mem.eql(u8, arg, "plugins") or std.mem.eql(u8, arg, "background-agent") or @@ -243,6 +252,7 @@ test "regular: help text names the binary and smoke boundary" { test "regular: excluded profile capabilities have explicit stubs" { try std.testing.expect(isProfileStub("remote")); + try std.testing.expect(isProfileStub("mimctl")); try std.testing.expect(isProfileStub("plugin")); try std.testing.expect(isProfileStub("background-agent")); try std.testing.expect(!isProfileStub("context")); diff --git a/src/profile.zig b/src/profile.zig index 3dc5840..7bc13ab 100644 --- a/src/profile.zig +++ b/src/profile.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const build_options = @import("build_options"); // Explicit v1 build/profile fences. // req: governance/002, governance/003, testing/001, testing/002 @@ -7,12 +8,12 @@ test { _ = statusAlloc; } -pub const active_profile = "dev-local"; -pub const local_socket = true; -pub const remote_transport_built = false; -pub const plugin_host_built = false; -pub const bundled_pi_built = false; -pub const background_agent_built = false; +pub const active_profile = build_options.active_profile; +pub const local_socket = build_options.local_socket; +pub const remote_transport_built = build_options.remote_transport_built; +pub const plugin_host_built = build_options.plugin_host_built; +pub const bundled_pi_built = build_options.bundled_pi_built; +pub const background_agent_built = build_options.background_agent_built; pub fn statusAlloc(allocator: std.mem.Allocator) ![]u8 { var out = std.ArrayList(u8).empty; @@ -24,7 +25,7 @@ pub fn statusAlloc(allocator: std.mem.Allocator) ![]u8 { try appendKV(allocator, &out, "plugin_host", if (plugin_host_built) "built" else "not_built"); try appendKV(allocator, &out, "bundled_pi", if (bundled_pi_built) "built" else "not_built"); try appendKV(allocator, &out, "background_agent", if (background_agent_built) "built" else "not_built"); - try appendKV(allocator, &out, "tool_mutation", "protocol_logged"); + try appendKV(allocator, &out, "tool_mutation", build_options.tool_mutation); return out.toOwnedSlice(allocator); }