feat(cli): flow-debug run-script — run a site script by name through the flow debugger

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
This commit is contained in:
Joseph Doherty
2026-09-08 01:13:15 -04:00
parent 001123d930
commit 067a858ce9
3 changed files with 127 additions and 12 deletions
@@ -32,6 +32,7 @@ public static class FlowDebugCommands
var command = new Command("flow-debug") { Description = "Flow Debugger: trace an inbound API method or value-change flow end to end, or replay a past one" };
command.Add(BuildRunMethod(urlOption, formatOption, usernameOption, passwordOption));
command.Add(BuildRunScript(urlOption, formatOption, usernameOption, passwordOption));
command.Add(BuildRunValueChange(urlOption, formatOption, usernameOption, passwordOption));
command.Add(BuildReplay(urlOption, formatOption, usernameOption, passwordOption));
@@ -82,13 +83,77 @@ public static class FlowDebugCommands
return cmd;
}
private static Command BuildRunScript(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
{
var instanceIdOption = new Option<int>("--instance-id") { Description = "Instance ID", Required = true };
var scriptOption = new Option<string>("--script")
{
Description = "Canonical script name, as shown by the Flow Debugger picker / the flattened configuration (e.g. Manual or Module.Script)",
Required = true,
};
var paramsOption = new Option<string?>("--params") { Description = "Flat JSON object of parameters for a Call/Interval/Expression/no-trigger script (validated against the script's ParameterDefinitions)" };
var valueOption = new Option<string?>("--value") { Description = "Value to write to the trigger attribute of a ValueChange/Conditional script (canonical string form)" };
var waitOption = new Option<int>("--wait-seconds") { Description = "Write kinds: how long to wait for the triggered run before NO_TRIGGER_WITHIN_WINDOW", DefaultValueFactory = _ => 45 };
var timeoutOption = new Option<int>("--timeout-seconds")
{
Description = "Client-side wait for the run; raise above the script's ExecutionTimeoutSeconds + 25 for a long script",
DefaultValueFactory = _ => 120,
};
var cmd = new Command("run-script") { Description = "Run one site script with tracing — a ValueChange/Conditional script is fired by writing its trigger attribute (--value); any other script is called directly (--params)" };
cmd.Add(instanceIdOption);
cmd.Add(scriptOption);
cmd.Add(paramsOption);
cmd.Add(valueOption);
cmd.Add(waitOption);
cmd.Add(timeoutOption);
cmd.SetAction(async (ParseResult result) =>
{
var waitSeconds = result.GetValue(waitOption);
var timeoutSeconds = result.GetValue(timeoutOption);
if (waitSeconds <= 0)
{
OutputFormatter.WriteError("--wait-seconds must be greater than zero.", "INVALID_ARGUMENT");
return 1;
}
if (timeoutSeconds <= 0)
{
OutputFormatter.WriteError("--timeout-seconds must be greater than zero.", "INVALID_ARGUMENT");
return 1;
}
JsonElement? parameters;
try
{
parameters = ParseParameters(result.GetValue(paramsOption));
}
catch (JsonException ex)
{
OutputFormatter.WriteError($"--params is not valid JSON: {ex.Message}", "INVALID_PARAMS");
return 1;
}
return await CommandHelpers.ExecuteCommandAsync(
result, urlOption, formatOption, usernameOption, passwordOption,
new FlowDebugRunScriptCommand(
result.GetValue(instanceIdOption),
result.GetValue(scriptOption)!,
parameters,
result.GetValue(valueOption),
waitSeconds),
timeout: TimeSpan.FromSeconds(Math.Max(timeoutSeconds, waitSeconds + ClientSlackSeconds)),
tableProjector: FlowDebugTableProjection.ProjectEvents);
});
return cmd;
}
private static Command BuildRunValueChange(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
{
var instanceIdOption = new Option<int>("--instance-id") { Description = "Instance ID", Required = true };
var attributeOption = new Option<string>("--attribute") { Description = "Canonical attribute name to write", Required = true };
var valueOption = new Option<string>("--value") { Description = "Value to write (canonical string form)", Required = true };
var waitOption = new Option<int>("--wait-seconds") { Description = "How long to wait for a triggered script run before reporting NO_TRIGGER_WITHIN_WINDOW", DefaultValueFactory = _ => 45 };
var cmd = new Command("run-value-change") { Description = "Write an attribute through the traced path and capture the script run(s) the change triggers" };
var cmd = new Command("run-value-change") { Description = "Write an attribute through the traced path and capture the script run(s) the change triggers — the attribute-level path (also fires Expression triggers); prefer run-script to run a named script" };
cmd.Add(instanceIdOption);
cmd.Add(attributeOption);
cmd.Add(valueOption);