cli: validate conflicting flags and add security warning

Adds validation logic to catch conflicting or missing CLI flags, such as
preventing `--task` with positional scripts and requiring a script for
`--self-heal`. Also adds a security warning to the help text regarding
arbitrary JavaScript execution in `.lp` files.
This commit is contained in:
Adrià Arrufat
2026-05-13 09:58:26 +02:00
parent 3293977f58
commit dbd0197576
2 changed files with 27 additions and 0 deletions

View File

@@ -836,6 +836,9 @@ pub fn printUsageAndExit(self: *const Config, success: bool) void {
\\ With -i: replays if present, then enters the REPL and
\\ appends any new commands to the file (creating it if
\\ it does not yet exist).
\\ Caution: .lp files can contain EVAL blocks that run
\\ arbitrary JavaScript in the page. Only replay scripts
\\ you trust, the same way you would a shell script.
\\
\\Options:
\\--provider The AI provider: anthropic, openai, gemini, or ollama.

View File

@@ -123,6 +123,22 @@ one_shot_attachments: ?[]const []const u8,
slash_schemas: []const SlashCommand.SchemaInfo,
pub fn init(allocator: std.mem.Allocator, app: *App, opts: Config.Agent) !*Self {
if (opts.task != null and opts.script_file != null) {
log.fatal(.app, "conflicting flags", .{
.hint = "--task runs a one-shot turn; drop the positional script or drop --task",
});
return error.ConflictingFlags;
}
if (opts.self_heal and opts.script_file == null) {
log.fatal(.app, "self-heal needs a script", .{
.hint = "--self-heal rewrites a recorded .lp on drift; pass a script path",
});
return error.ConflictingFlags;
}
if (opts.no_llm and opts.provider != null) {
log.warn(.app, "ignoring --provider", .{ .reason = "--no-llm takes precedence" });
}
const is_one_shot = opts.task != null;
const will_repl = !is_one_shot and (opts.interactive or opts.script_file == null);
const needs_llm = will_repl or is_one_shot;
@@ -1089,6 +1105,14 @@ pub fn listModels(allocator: std.mem.Allocator, opts: Config.Agent) !void {
});
return error.ConflictingFlags;
}
if (opts.task != null or opts.self_heal or opts.interactive or
opts.script_file != null or opts.pick_model)
{
log.fatal(.app, "list-models is exclusive", .{
.hint = "--list-models only takes --provider/--model/--base-url",
});
return error.ConflictingFlags;
}
const provider = opts.provider orelse (try autoDetectProvider()) orelse {
log.fatal(.app, "list-models needs LLM", .{
.hint = "set ANTHROPIC_API_KEY (or OPENAI_API_KEY / GOOGLE_API_KEY) or pass --provider",