feat(chat): Comments and review in VS Code, like the OpenChamber desktop app (#1724)

* feat(chat): render code comments as cards instead of fenced text

* fix(vscode): route Add Comment to the active session editor panel

* fix(chat): persist queued inline comments and tighten file-chip path matching

* feat(vscode): comment on code from the editor

* fix(chat): keep attached context in the message and broadcast comment removal

* fix(vscode): hold every pending comment and gate both entry points on the workspace

* fix(vscode): let only the owning surface decide its comment threads

* fix(vscode): drop a comment removed while its delivery was still in flight

* test(vscode): cover the in-flight comment removal guard

* test(vscode): cover comment removal reaching every chat surface

* fix(vscode): give up on a comment the chat never confirmed holding

* fix(vscode): retract a comment everywhere before reporting it discarded

* fix(chat): preserve queued comment cards

* fix: preserve inline comment context across send paths

* fix(chat): preserve command routing with context

* fix(chat): keep unavailable actions on normal send path

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
Felipe Gené
2026-09-05 12:28:17 +03:00
committed by GitHub
co-authored by Bohdan Triapitsyn
parent d323b51a0a
commit a12b9be443
35 changed files with 2192 additions and 131 deletions
+36
View File
@@ -9,6 +9,7 @@ import { openSseProxy } from './sseProxy';
import { resolveWebviewDevServerUrl } from './webviewDevServer';
import { normalizeWindowsDriveLetter } from './pathUtils';
import { resolveWorkspaceFolders, type WorkspaceFolderCandidate } from './workspaceResolver';
import { SIDEBAR_SURFACE_ID } from './InlineCommentThreads';
type ActiveEditorFilePayload = {
filePath: string;
@@ -150,6 +151,19 @@ export class ChatViewProvider implements vscode.WebviewViewProvider {
return;
}
// Editor comment threads mirror the composer's drafts, so the webview
// reports every change. Handled before the id check because this is a
// one-way notification, not a bridge request awaiting a response.
if (message.type === 'inlineComments:sync') {
// Tagged with the sidebar's identity: a snapshot only speaks for the
// store that produced it, and each session panel has its own.
void vscode.commands.executeCommand('openchamber.internal.inlineCommentsSync', {
snapshot: message.payload,
surfaceId: SIDEBAR_SURFACE_ID,
});
return;
}
if (!('id' in message) || typeof message.id !== 'string') {
return;
}
@@ -249,6 +263,28 @@ export class ChatViewProvider implements vscode.WebviewViewProvider {
});
}
public addLineComment(payload: { draftId?: string; filePath: string; relativePath: string; source: 'diff' | 'file'; side?: 'original' | 'modified'; startLine: number; endLine: number; code: string; language: string; comment: string }) {
if (!this._view) return;
// Bring the chat into view like the other capture flows do, so the chip the
// comment becomes is visible rather than waiting behind a collapsed panel.
this._view.show(true);
this._view.webview.postMessage({
type: 'command',
command: 'addLineComment',
payload,
});
}
/** Drops a draft the user removed from its editor thread. */
public removeLineComment(draftId: string) {
if (!this._view) return;
this._view.webview.postMessage({
type: 'command',
command: 'removeLineComment',
payload: { draftId },
});
}
public addFileAttachments(files: Array<{ filePath: string; fileName: string; fileSize: number | null }>) {
if (!this._view) {
return;