Compare commits

..

2 Commits

Author SHA1 Message Date
7ef479639a feat(booterm): add PTY session registry + listing endpoint
In-memory SessionMeta registry tracks active terminal sessions with
paneId, sessionId, projectPath, title, createdAt, lastActivityAt.
GET /api/term/sessions returns all active sessions as JSON array.
Registry is updated on WS attach and cleaned up on disconnect.
2026-06-07 22:40:27 +00:00
89a6ffe8a0 feat(mcp): add type-inject MCP server for TypeScript type recovery
Registers @nick-vi/type-inject-mcp as a stdio MCP server via npx.
Provides lookup_type and list_types tools for TypeScript type
recovery — solves the 0% TS type recovery gap in codecontext.
2026-06-07 22:40:27 +00:00
5 changed files with 74 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ import { loadConfig } from './config.js';
import { getPool, closeDb } from './db.js'; import { getPool, closeDb } from './db.js';
import { registerHealthRoutes } from './routes/health.js'; import { registerHealthRoutes } from './routes/health.js';
import { registerTerminalRoutes } from './routes/terminals.js'; import { registerTerminalRoutes } from './routes/terminals.js';
import { registerSessionRoutes } from './routes/sessions.js';
import { registerWsAttachRoute } from './ws/attach.js'; import { registerWsAttachRoute } from './ws/attach.js';
async function main(): Promise<void> { async function main(): Promise<void> {
@@ -33,6 +34,7 @@ async function main(): Promise<void> {
registerHealthRoutes(app); registerHealthRoutes(app);
registerTerminalRoutes(app, config.TMUX_CONF_PATH); registerTerminalRoutes(app, config.TMUX_CONF_PATH);
registerSessionRoutes(app);
registerWsAttachRoute(app, config.TMUX_CONF_PATH); registerWsAttachRoute(app, config.TMUX_CONF_PATH);
const shutdown = async (signal: string) => { const shutdown = async (signal: string) => {

View File

@@ -0,0 +1,44 @@
export interface SessionMeta {
paneId: string;
sessionId: string;
projectPath: string;
title?: string;
createdAt: Date;
lastActivityAt: Date;
}
const sessions = new Map<string, SessionMeta>();
export function register(
sessionId: string,
paneId: string,
projectPath: string,
title?: string,
): void {
const now = new Date();
const existing = sessions.get(paneId);
if (existing) {
existing.lastActivityAt = now;
return;
}
sessions.set(paneId, {
paneId,
sessionId,
projectPath,
title,
createdAt: now,
lastActivityAt: now,
});
}
export function unregister(paneId: string): void {
sessions.delete(paneId);
}
export function list(): SessionMeta[] {
return Array.from(sessions.values());
}
export function get(paneId: string): SessionMeta | undefined {
return sessions.get(paneId);
}

View File

@@ -0,0 +1,18 @@
import type { FastifyInstance } from 'fastify';
import { list } from '../pty/registry.js';
export function registerSessionRoutes(app: FastifyInstance): void {
app.get('/api/term/sessions', async (_req, reply) => {
const active = list();
return reply.code(200).send({
sessions: active.map((s) => ({
paneId: s.paneId,
sessionId: s.sessionId,
projectPath: s.projectPath,
title: s.title ?? null,
createdAt: s.createdAt.toISOString(),
lastActivityAt: s.lastActivityAt.toISOString(),
})),
});
});
}

View File

@@ -9,6 +9,7 @@ import {
} from '../pty/manager.js'; } from '../pty/manager.js';
import { attachPty } from '../pty/pty.js'; import { attachPty } from '../pty/pty.js';
import { getUser } from '../auth.js'; import { getUser } from '../auth.js';
import { register, unregister } from '../pty/registry.js';
export function registerWsAttachRoute(app: FastifyInstance, tmuxConfPath: string): void { export function registerWsAttachRoute(app: FastifyInstance, tmuxConfPath: string): void {
app.get<{ app.get<{
@@ -57,6 +58,8 @@ export function registerWsAttachRoute(app: FastifyInstance, tmuxConfPath: string
return; return;
} }
register(sid, pid, session.project_path);
let handle: IPty; let handle: IPty;
try { try {
handle = attachPty({ handle = attachPty({
@@ -157,6 +160,7 @@ export function registerWsAttachRoute(app: FastifyInstance, tmuxConfPath: string
// teardown happens via the /kill route called from the frontend when the // teardown happens via the /kill route called from the frontend when the
// user closes the pane. // user closes the pane.
socket.on('close', () => { socket.on('close', () => {
unregister(pid);
try { try {
handle.kill(); handle.kill();
} catch { } catch {

View File

@@ -7,6 +7,12 @@
"CONTEXT7_API_KEY": "{env:CONTEXT7_API_KEY}" "CONTEXT7_API_KEY": "{env:CONTEXT7_API_KEY}"
}, },
"enabled": false "enabled": false
},
"type-inject": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@nick-vi/type-inject-mcp"],
"enabled": true
} }
} }
} }