feat(cli): --continue/-c flag forwards to TUI resume path
Other agent: root_tui_passthrough() builds forwarded args, rejects --continue + -p combo (directs to codewhale exec --continue). Tests: parses_top_level_continue, top_level_continue_rejects_one_shot. Session picker: formatting cleanup on test calls.
This commit is contained in:
+56
-15
@@ -102,6 +102,9 @@ struct Cli {
|
||||
/// YOLO mode: auto-approve all tools
|
||||
#[arg(long)]
|
||||
yolo: bool,
|
||||
/// Continue the most recent interactive session for this workspace.
|
||||
#[arg(short = 'c', long = "continue")]
|
||||
continue_session: bool,
|
||||
#[arg(short = 'p', long = "prompt", value_name = "PROMPT")]
|
||||
prompt_flag: Option<String>,
|
||||
#[arg(
|
||||
@@ -555,26 +558,42 @@ fn run() -> Result<()> {
|
||||
Some(Commands::Update) => update::run_update(),
|
||||
None => {
|
||||
let resolved_runtime = resolve_runtime_for_dispatch(&mut store, &runtime_overrides);
|
||||
let mut forwarded = Vec::new();
|
||||
let prompt = cli.prompt_flag.iter().chain(cli.prompt.iter()).fold(
|
||||
String::new(),
|
||||
|mut acc, part| {
|
||||
if !acc.is_empty() {
|
||||
acc.push(' ');
|
||||
}
|
||||
acc.push_str(part);
|
||||
acc
|
||||
},
|
||||
);
|
||||
if !prompt.is_empty() {
|
||||
forwarded.push("--prompt".to_string());
|
||||
forwarded.push(prompt);
|
||||
}
|
||||
let forwarded = root_tui_passthrough(&cli)?;
|
||||
delegate_to_tui(&cli, &resolved_runtime, forwarded)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn root_tui_passthrough(cli: &Cli) -> Result<Vec<String>> {
|
||||
let mut forwarded = Vec::new();
|
||||
if cli.continue_session {
|
||||
forwarded.push("--continue".to_string());
|
||||
}
|
||||
|
||||
let prompt =
|
||||
cli.prompt_flag
|
||||
.iter()
|
||||
.chain(cli.prompt.iter())
|
||||
.fold(String::new(), |mut acc, part| {
|
||||
if !acc.is_empty() {
|
||||
acc.push(' ');
|
||||
}
|
||||
acc.push_str(part);
|
||||
acc
|
||||
});
|
||||
if !prompt.is_empty() {
|
||||
if cli.continue_session {
|
||||
bail!(
|
||||
"`codewhale --continue` resumes the interactive TUI. Use `codewhale exec --continue <PROMPT>` to continue a session non-interactively."
|
||||
);
|
||||
}
|
||||
forwarded.push("--prompt".to_string());
|
||||
forwarded.push(prompt);
|
||||
}
|
||||
|
||||
Ok(forwarded)
|
||||
}
|
||||
|
||||
fn resolve_runtime_for_dispatch(
|
||||
store: &mut ConfigStore,
|
||||
runtime_overrides: &CliRuntimeOverrides,
|
||||
@@ -2651,6 +2670,27 @@ mod tests {
|
||||
assert!(cli.prompt.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_top_level_continue_for_interactive_resume() {
|
||||
let cli = parse_ok(&["codewhale", "--continue"]);
|
||||
|
||||
assert!(cli.continue_session);
|
||||
assert!(cli.prompt_flag.is_none());
|
||||
assert!(cli.prompt.is_empty());
|
||||
assert_eq!(root_tui_passthrough(&cli).unwrap(), vec!["--continue"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn top_level_continue_rejects_one_shot_prompt() {
|
||||
let cli = parse_ok(&["codewhale", "--continue", "-p", "follow up"]);
|
||||
|
||||
let err = root_tui_passthrough(&cli).expect_err("prompted continue should be rejected");
|
||||
assert!(
|
||||
err.to_string()
|
||||
.contains("codewhale exec --continue <PROMPT>")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_split_top_level_prompt_words_for_windows_cmd_shims() {
|
||||
let cli = parse_ok(&["deepseek", "hello", "world"]);
|
||||
@@ -2711,6 +2751,7 @@ mod tests {
|
||||
"--mouse-capture",
|
||||
"--no-mouse-capture",
|
||||
"--skip-onboarding",
|
||||
"--continue",
|
||||
"--prompt",
|
||||
] {
|
||||
assert!(
|
||||
|
||||
@@ -1069,7 +1069,9 @@ mod tests {
|
||||
"A very long title that should be truncated by the list pane width",
|
||||
)];
|
||||
let width = 24;
|
||||
let lines = build_list_lines(&sessions, 0, width, 0, 5, false, "", "recent", false, false, "", None);
|
||||
let lines = build_list_lines(
|
||||
&sessions, 0, width, 0, 5, false, "", "recent", false, false, "", None,
|
||||
);
|
||||
|
||||
for line in lines {
|
||||
let rendered_width: usize = line.spans.iter().map(|span| span.content.width()).sum();
|
||||
@@ -1086,7 +1088,9 @@ mod tests {
|
||||
test_session(1, "first session"),
|
||||
test_session(2, "second session"),
|
||||
];
|
||||
let lines = build_list_lines(&sessions, 1, 80, 0, 5, false, "", "recent", false, false, "", None);
|
||||
let lines = build_list_lines(
|
||||
&sessions, 1, 80, 0, 5, false, "", "recent", false, false, "", None,
|
||||
);
|
||||
|
||||
let selected_line = lines
|
||||
.iter()
|
||||
@@ -1111,7 +1115,20 @@ mod tests {
|
||||
let mut forked = test_session(1, "forked path");
|
||||
forked.parent_session_id = Some("parent-session-abcdef".to_string());
|
||||
forked.forked_from_message_count = Some(3);
|
||||
let lines = build_list_lines(&[forked], 0, 120, 0, 5, false, "", "recent", false, false, "", None);
|
||||
let lines = build_list_lines(
|
||||
&[forked],
|
||||
0,
|
||||
120,
|
||||
0,
|
||||
5,
|
||||
false,
|
||||
"",
|
||||
"recent",
|
||||
false,
|
||||
false,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
|
||||
let rendered = lines
|
||||
.iter()
|
||||
@@ -1128,7 +1145,9 @@ mod tests {
|
||||
test_session(1, "first session"),
|
||||
test_session(2, "second session"),
|
||||
];
|
||||
let lines = build_list_lines(&sessions, 0, 80, 0, 5, false, "", "recent", false, false, "", None);
|
||||
let lines = build_list_lines(
|
||||
&sessions, 0, 80, 0, 5, false, "", "recent", false, false, "", None,
|
||||
);
|
||||
|
||||
let rendered = lines
|
||||
.iter()
|
||||
|
||||
Reference in New Issue
Block a user