Skip to content

Commit 3a1e456

Browse files
Enhance permission prompts with diff previews and reasoning stream; update input formatting for better user verification
1 parent 8f4099e commit 3a1e456

2 files changed

Lines changed: 29 additions & 6 deletions

File tree

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -967,3 +967,11 @@ Open the Command Palette (`Cmd+Shift+P` / `Ctrl+Shift+P`) and run:
967967
- **`Codeep: New Session`** — start a fresh session in the chat.
968968

969969
If you already set up keys in the CLI (or via the [codeep.dev](https://codeep.dev/dashboard) dashboard + `codeep account sync`), the extension picks them up automatically on first launch — no welcome prompt.
970+
971+
### Live plan & reasoning stream
972+
973+
The chat sidebar now surfaces two extra ACP signals that previously only the TUI saw:
974+
975+
- **Live plan** — for multi-step tasks the agent's plan appears as a small green card with status icons (`` pending, `` in progress, `` done) that update in place as work progresses.
976+
- **Reasoning stream** — when the model exposes a thinking trace (e.g. Claude extended thinking, GPT-5 reasoning), it shows up in a collapsible "Thinking" card above the answer. Closed by default; click to expand.
977+
- **Diff preview on permission prompts** — manual-mode permission cards now show a `-` / `+` diff for `edit_file`, a content preview for `write_file`, and the full `$ command` + `cwd` for `execute_command`, so users can verify before clicking *Allow*. Payload is truncated (~4 KB per field, 200 lines per file) with a visible marker. Other ACP clients (Zed, etc.) ignore the extra fields silently.

src/acp/server.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,21 +110,36 @@ const LANGUAGE_OPTIONS = [
110110
*/
111111
function formatToolInputForPermission(tool: string, params: Record<string, unknown>): Record<string, string> {
112112
const MAX_LEN = 120;
113+
// Bigger budget for diff/content fields so clients can render an actual preview
114+
// before the user clicks Allow. Truncated with a visible marker so users know
115+
// they're not seeing the full payload.
116+
const MAX_DIFF_LEN = 4000;
117+
const MAX_CONTENT_LINES = 200;
113118
const truncate = (v: unknown): string => {
114119
const s = typeof v === 'string' ? v : JSON.stringify(v);
115120
return s.length > MAX_LEN ? s.slice(0, MAX_LEN) + '…' : s;
116121
};
122+
const truncateDiff = (s: string): string =>
123+
s.length > MAX_DIFF_LEN ? s.slice(0, MAX_DIFF_LEN) + `\n… (truncated, ${s.length - MAX_DIFF_LEN} more chars)` : s;
117124

118125
switch (tool) {
119126
case 'write_file':
120127
case 'edit_file': {
121128
const path = params.path as string ?? '';
122-
const lines = typeof params.content === 'string'
123-
? params.content.split('\n').length + ' lines'
124-
: typeof params.old_string === 'string'
125-
? `replace ${(params.old_string as string).split('\n').length} line(s)`
126-
: '';
127-
return { file: pathBasename(path), path, changes: lines };
129+
const out: Record<string, string> = { file: pathBasename(path), path };
130+
if (typeof params.content === 'string') {
131+
const lines = params.content.split('\n');
132+
out.changes = `${lines.length} lines`;
133+
out.new_content = lines.length > MAX_CONTENT_LINES
134+
? lines.slice(0, MAX_CONTENT_LINES).join('\n') + `\n… (${lines.length - MAX_CONTENT_LINES} more lines)`
135+
: params.content;
136+
}
137+
if (typeof params.old_string === 'string' && typeof params.new_string === 'string') {
138+
out.changes = `replace ${(params.old_string as string).split('\n').length} line(s)`;
139+
out.old_string = truncateDiff(params.old_string as string);
140+
out.new_string = truncateDiff(params.new_string as string);
141+
}
142+
return out;
128143
}
129144
case 'delete_file':
130145
return { file: pathBasename(params.path as string ?? ''), path: params.path as string ?? '' };

0 commit comments

Comments
 (0)