From 095c5f9323cede85b34218e11407c3deb003595d Mon Sep 17 00:00:00 2001 From: aayank13 Date: Sat, 10 Oct 2026 15:45:58 +0530 Subject: [PATCH] fix: stop recording cline cli prompt recalls that cline drops --- README.md | 8 +++++--- crates/trodden/src/harness/cline.rs | 21 ++++++++++++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e3327f2..a22a990 100644 --- a/README.md +++ b/README.md @@ -91,12 +91,14 @@ trodden backfill # learn from your existing sessions | OpenCode | `opencode` | yes | yes | no | hooks | no | | Kilo Code | `kilo` | yes | yes | no | hooks | no | | Kimi Code | `kimi` | yes | no | yes | hooks | no | -| Cline | `cline` | yes | yes | no | hooks | no | +| Cline | `cline` | extension only | yes | no | hooks | no | "no" means the agent's hooks cannot do it: Cursor cannot add context to a prompt, Kimi Code ignores output after a failed command, and OpenCode, Kilo -Code and Cline cannot continue a finished turn. Agents that learn from hooks -only learn from sessions after they are connected. +Code and Cline cannot continue a finished turn. The Cline CLI cannot add +context to a prompt either, so Cline recalls on a prompt only in its VS Code +and JetBrains extension. Agents that learn from hooks only learn from sessions +after they are connected. A few agents need one step of their own after `trodden connect`: Codex asks you to trust the new hooks the next time it starts, Cline needs its "Enable diff --git a/crates/trodden/src/harness/cline.rs b/crates/trodden/src/harness/cline.rs index c004151..68aae23 100644 --- a/crates/trodden/src/harness/cline.rs +++ b/crates/trodden/src/harness/cline.rs @@ -567,6 +567,7 @@ impl Agent for Cline { fn render(&self, event: &HookEvent, reply: Reply<'_>) -> Option { match (&event.moment, reply) { + (Moment::Prompt(_), Reply::Recall(_)) if event.name != "UserPromptSubmit" => None, (Moment::Prompt(_) | Moment::CommandFailed(_), Reply::Recall(envelope)) => { Some(json!({ "cancel": false, "contextModification": envelope }).to_string()) } @@ -860,7 +861,7 @@ mod tests { #[test] fn replies_inject_context_and_never_continue() { let event = |moment| HookEvent { - name: String::new(), + name: "UserPromptSubmit".to_owned(), session: "s".to_owned(), cwd: PathBuf::from(CWD), transcript: None, @@ -891,6 +892,24 @@ mod tests { ); } + #[test] + fn cli_prompts_are_journaled_but_never_recalled() { + let event = Payload::event(&json!({ + "clineVersion": "3.0.70", "hookName": "prompt_submit", "timestamp": "2026-10-09T10:00:00.000Z", + "taskId": "run_1", "sessionContext": {"rootSessionId": "1791540000000_k3x9q"}, + "workspaceRoots": [CWD], "userId": "me", "agent_id": "lead", "parent_agent_id": null, + "userPromptSubmit": {"prompt": "Fix the paging bug in src/paginate.js"} + })) + .expect("event"); + + assert_eq!( + event.moment, + Moment::Prompt("Fix the paging bug in src/paginate.js".to_owned()) + ); + assert_eq!(event.observed.len(), 1); + assert_eq!(Cline.render(&event, Reply::Recall("")), None); + } + #[test] fn connect_writes_one_script_per_event_and_round_trips() { let scratch = Scratch::new("connect");