Add features & update project

This commit is contained in:
Gabriel Brown
2026-06-23 01:46:08 -04:00
parent 930fbf5965
commit fe72fc2957
39 changed files with 3106 additions and 178 deletions
+54 -9
View File
@@ -1,12 +1,19 @@
import { createServer } from 'node:http';
import type { IncomingMessage, ServerResponse } from 'node:http';
import type { Id } from '@spoon/backend/convex/_generated/dataModel.js';
import { env } from './env';
import {
abortWorkspaceAgent,
cleanupOrphanedWorkspaces,
getWorkerHealth,
getWorkspaceAgentStatus,
getWorkspaceDiff,
listWorkspaceTree,
openWorkspacePullRequest,
readWorkspaceFile,
replyToInteraction,
runWorkspaceCommand,
sendWorkspaceMessage,
stopWorkspace,
@@ -43,7 +50,7 @@ const requireAuth = (request: IncomingMessage) => {
};
const jobRoute = (pathname: string) => {
const match = /^\/jobs\/([^/]+)\/([^/]+)$/.exec(pathname);
const match = /^\/jobs\/([^/]+)\/(.+)$/.exec(pathname);
if (!match?.[1] || !match[2]) return null;
return { jobId: decodeURIComponent(match[1]), action: match[2] };
};
@@ -57,8 +64,12 @@ export const startWorkerServer = () => {
request.url ?? '/',
`http://localhost:${env.httpPort}`,
);
if (url.pathname === '/health') {
sendJson(response, 200, { ok: true, workerId: env.workerId });
if (url.pathname === '/health' && request.method === 'GET') {
sendJson(response, 200, await getWorkerHealth());
return;
}
if (url.pathname === '/cleanup' && request.method === 'POST') {
sendJson(response, 200, await cleanupOrphanedWorkspaces());
return;
}
const route = jobRoute(url.pathname);
@@ -108,6 +119,34 @@ export const startWorkerServer = () => {
sendJson(response, 200, { success: true });
return;
}
if (request.method === 'GET' && route.action === 'agent/status') {
sendJson(response, 200, getWorkspaceAgentStatus(route.jobId));
return;
}
if (request.method === 'POST' && route.action === 'agent/abort') {
sendJson(response, 200, await abortWorkspaceAgent(route.jobId));
return;
}
const interactionMatch =
/^interactions\/([^/]+)\/reply$/.exec(route.action);
if (request.method === 'POST' && interactionMatch?.[1]) {
const body = await parseJson<{
externalRequestId?: string;
response?: string;
}>(request);
sendJson(
response,
200,
await replyToInteraction(route.jobId, {
interactionId: decodeURIComponent(
interactionMatch[1],
) as Id<'agentInteractionRequests'>,
externalRequestId: body.externalRequestId ?? '',
response: body.response ?? 'once',
}),
);
return;
}
if (request.method === 'POST' && route.action === 'run-command') {
const body = await parseJson<{ command?: string }>(request);
sendJson(
@@ -126,12 +165,18 @@ export const startWorkerServer = () => {
return;
}
sendJson(response, 404, { error: 'Not found' });
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
sendJson(response, message === 'Unauthorized' ? 401 : 500, {
error: message,
});
}
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
const status =
message === 'Unauthorized'
? 401
: message.includes('not supported')
? 409
: 500;
sendJson(response, status, {
error: message,
});
}
})();
});
server.listen(env.httpPort, () => {