Skip to content

Commit 4a6f569

Browse files
committed
feat: improve session manager disposal and cleanup logic
1 parent 891bfcb commit 4a6f569

6 files changed

Lines changed: 57 additions & 2 deletions

File tree

src/cli.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,22 @@ async function main(): Promise<void> {
6464
const restartRef: { current: (() => void) | null } = { current: null };
6565

6666
function startApp(): void {
67+
let restarting = false;
6768
const inkInstance = render(
6869
<App projectRoot={projectRoot} version={packageInfo.version} onRestart={() => restartRef.current?.()} />,
6970
{ exitOnCtrlC: false }
7071
);
7172

7273
restartRef.current = () => {
74+
restarting = true;
7375
process.stdout.write("\u001B[2J\u001B[3J\u001B[H");
7476
inkInstance.unmount();
7577
startApp();
7678
};
7779

7880
inkInstance.waitUntilExit().then(() => {
79-
if (!restartRef.current) {
81+
if (!restarting) {
82+
restartRef.current = null;
8083
process.exit(0);
8184
}
8285
});

src/session.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ export class SessionManager {
205205
return this.mcpManager.getStatus();
206206
}
207207

208+
dispose(): void {
209+
this.mcpManager.disconnect();
210+
}
211+
208212
private estimateStreamTokens(text: string): number {
209213
let tokens = 0;
210214
for (const char of text) {

src/tests/session.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,46 @@ test("SessionManager lists project skills from .agents with legacy .deepcode com
322322
assert.equal(sharedSkill?.description, "Project .agents skill");
323323
});
324324

325+
test("SessionManager dispose disconnects MCP servers", async () => {
326+
const workspace = createTempDir("deepcode-mcp-dispose-workspace-");
327+
const serverPath = path.join(workspace, "mcp-server.cjs");
328+
fs.writeFileSync(
329+
serverPath,
330+
`
331+
const readline = require("readline");
332+
const rl = readline.createInterface({ input: process.stdin, crlfDelay: Infinity });
333+
function send(message) {
334+
process.stdout.write(JSON.stringify(message) + "\\n");
335+
}
336+
rl.on("line", (line) => {
337+
const request = JSON.parse(line);
338+
if (!("id" in request)) {
339+
return;
340+
}
341+
if (request.method === "initialize") {
342+
send({ jsonrpc: "2.0", id: request.id, result: { protocolVersion: "2024-11-05", capabilities: { tools: {} } } });
343+
return;
344+
}
345+
if (request.method === "tools/list") {
346+
send({ jsonrpc: "2.0", id: request.id, result: { tools: [{ name: "echo", inputSchema: { type: "object", properties: {} } }] } });
347+
return;
348+
}
349+
send({ jsonrpc: "2.0", id: request.id, result: { content: [] } });
350+
});
351+
`,
352+
"utf8"
353+
);
354+
355+
const manager = createSessionManager(workspace, "machine-id-mcp-dispose");
356+
await manager.initMcpServers({ smoke: { command: process.execPath, args: [serverPath] } });
357+
358+
assert.deepEqual(manager.getMcpStatus(), [{ name: "smoke", connected: true, toolCount: 1, tools: ["echo"] }]);
359+
360+
manager.dispose();
361+
362+
assert.deepEqual(manager.getMcpStatus(), []);
363+
});
364+
325365
test("createSession stores /init and sends the active .deepcode project AGENTS path to the LLM", async () => {
326366
const workspace = createTempDir("deepcode-init-deepcode-workspace-");
327367
const home = createTempDir("deepcode-init-deepcode-home-");

src/tools/mcp-client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export class McpClient {
8888
});
8989

9090
if (this.process.stderr) {
91-
this.process.stderr.on("data", (data: Buffer) => {
91+
this.process.stderr.on("data", (_data: Buffer) => {
9292
// MCP servers log to stderr; we ignore for now
9393
});
9494
}

src/tools/mcp-manager.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ export class McpManager {
140140
}
141141
this.clients = [];
142142
this.tools = [];
143+
this.serverStatuses = [];
143144
this.initialized = false;
144145
}
145146
}

src/ui/App.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,12 @@ export function App({ projectRoot, version = "", onRestart }: AppProps): React.R
131131
void sessionManager.initMcpServers(settings.mcpServers);
132132
}, [sessionManager]);
133133

134+
useEffect(() => {
135+
return () => {
136+
sessionManager.dispose();
137+
};
138+
}, [sessionManager]);
139+
134140
const writeRef = useRef(write);
135141
writeRef.current = write;
136142
const handlePrompt = useCallback(
@@ -150,6 +156,7 @@ export function App({ projectRoot, version = "", onRestart }: AppProps): React.R
150156
process.stdout.write("\n\n");
151157
process.stdout.write(summary);
152158
process.stdout.write("\n\n");
159+
sessionManager.dispose();
153160
exit();
154161
}, 0);
155162
return;

0 commit comments

Comments
 (0)