Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "hermes-code-agent",
"displayName": "Hermes Code Agent",
"description": "VS Code sidebar for the Hermes AI agent. Streams chat, runs tools, manages sessions. Multi-model (Claude, Codex). Communicates over ACP.",
"version": "3.0.3",
"version": "3.0.4",
"publisher": "gitricko",
"author": "gitricko",
"license": "MIT",
Expand Down
27 changes: 27 additions & 0 deletions src/chatPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,33 @@ export class ChatPanelProvider implements vscode.WebviewViewProvider {
this.store = new SessionStore(context);
}

/** Sync sessions from the ACP backend after connection, so the session list survives reloads. */
async syncSessionsFromBackend(): Promise<void> {
try {
const sessions = await this.session.listSessions();
if (!sessions || sessions.length === 0) return;
this.log(`[session] syncing ${sessions.length} backend sessions`);

// Backend returns sessions sorted by updated_at descending (most recent first).
// Reverse so most recent gets pushed last (appears first in reversed view).
let added = 0;
for (const bs of [...sessions].reverse()) {
const exists = this.store.allSessions().some(s => s.acpSessionId === bs.sessionId);
if (!exists) {
const insertPos = Math.max(0, this.store.allSessions().length - 1);
this.store.addBackendSession(bs.sessionId, bs.title || 'Session', bs.updatedAt, insertPos);
added++;
}
}
if (added > 0) {
this.log(`[session] added ${added} backend sessions to store`);
this.broadcastSessions(this.store);
}
} catch (err) {
this.log(`[session] backend sync failed: ${err}`);
}
}

resolveWebviewView(webviewView: vscode.WebviewView): void {
this.view = webviewView;

Expand Down
2 changes: 2 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
await client.start();
outputChannel.appendLine('[acp] connected');
setStatus('connected');
// Sync session list from backend so it survives browser reloads
void panel.syncSessionsFromBackend();
} catch (err) {
outputChannel.appendLine(`[acp] connect failed: ${err}`);
setStatus('disconnected');
Expand Down
7 changes: 7 additions & 0 deletions src/sessionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ export class SessionManager {
return this.sessionId;
}

/** Fetch all ACP sessions from the Hermes backend. */
async listSessions(): Promise<{ sessionId: string; title?: string; updatedAt?: string; cwd?: string }[]> {
const result = await this.client.call('session/list', {});
const response = result as { sessions?: { sessionId: string; title?: string; updatedAt?: string; cwd?: string }[] } | undefined;
return response?.sessions ?? [];
}

async ensureSession(cwd: string): Promise<string> {
if (this.sessionId) {
this.log(`[session] reusing ${this.sessionId}`);
Expand Down
16 changes: 16 additions & 0 deletions src/sessionStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,22 @@ export class SessionStore {
}
}

/** Add a backend session (from ACP list_sessions) to the store without activating it. */
addBackendSession(acpSessionId: string, title: string, updatedAt: string | undefined, insertPos: number): void {
const session: ChatSession = {
id: `acp-${acpSessionId}`,
title,
createdAt: updatedAt ? new Date(updatedAt).getTime() : Date.now(),
messages: [],
acpSessionId,
};
this.sessions.splice(insertPos, 0, session);
if (this.sessions.length > MAX_SESSIONS) {
this.sessions = this.sessions.slice(-MAX_SESSIONS);
}
this.persist();
}

// ── Persistence ────────────────────────────────────

private persist(): void {
Expand Down
Loading