feat: freeze legacy code queue entry

This commit is contained in:
Codex
2026-06-09 01:14:23 +00:00
parent 7306000ac1
commit 987f41d258
9 changed files with 389 additions and 103 deletions
@@ -4859,6 +4859,48 @@ function readOnlyRejectResponse(method: string, targetPath: string): Response {
}, 405);
}
function legacyQueueFrozenResponse(method: string, targetPath: string, action: string): Response {
return jsonResponse({
ok: false,
frozen: true,
mutation: false,
error: "Legacy UniDesk Code Queue is frozen for new task and execution mutations; use AgentRun Queue for new commander work.",
reason: "legacy-code-queue-frozen",
serviceRole: config.serviceRole,
method,
path: targetPath,
action,
replacement: {
queueCommander: "bun scripts/cli.ts agentrun v01 queue commander --reader-id cli",
queueSubmit: "bun scripts/cli.ts agentrun v01 queue submit --json-file <task.json>",
queueDispatch: "bun scripts/cli.ts agentrun v01 queue dispatch <taskId> --json-file <dispatch.json>",
sessionsTrace: "bun scripts/cli.ts agentrun v01 sessions trace <sessionId> --after-seq 0 --limit 100",
sessionsOutput: "bun scripts/cli.ts agentrun v01 sessions output <sessionId> --after-seq 0 --limit 100",
sessionsSteer: "bun scripts/cli.ts agentrun v01 sessions steer <sessionId> --prompt-file <path>",
sessionsRead: "bun scripts/cli.ts agentrun v01 sessions read <sessionId> --reader-id cli",
queueCancel: "bun scripts/cli.ts agentrun v01 queue cancel <taskId> --reason <text>",
},
legacy: {
retainedFor: "historical archive/read-only troubleshooting",
allowedReadPaths: [
"GET /api/tasks",
"GET /api/tasks/overview",
"GET /api/tasks/:id",
"GET /api/tasks/:id/output",
"GET /api/tasks/:id/trace-summary",
"GET /api/tasks/:id/trace-steps",
"GET /api/queues",
],
cancellationPath: "POST /api/tasks/:id/interrupt remains available only to stop residual old runs",
noDoubleWrite: true,
},
}, 410);
}
function legacyQueueWritesFrozen(): boolean {
return true;
}
function databaseNotReadyResponse(method: string, targetPath: string): Response {
return jsonResponse({
ok: false,
@@ -4918,6 +4960,7 @@ async function listWorkdirs(url: URL): Promise<Response> {
}
async function createWorkdir(req: Request): Promise<Response> {
if (legacyQueueWritesFrozen()) return legacyQueueFrozenResponse(req.method, "/api/workdirs", "workdir-create");
const notReady = requireDatabaseReadyForWrite(req.method, "/api/workdirs");
if (notReady !== null) return notReady;
const body = await readJson(req);
@@ -4948,6 +4991,7 @@ async function createWorkdir(req: Request): Promise<Response> {
}
async function deleteWorkdir(providerIdValue: string, executionModeValue: string, pathValue: string): Promise<Response> {
if (legacyQueueWritesFrozen()) return legacyQueueFrozenResponse("DELETE", `/api/workdirs/${providerIdValue}/${executionModeValue}/${pathValue}`, "workdir-delete");
const notReady = requireDatabaseReadyForWrite("DELETE", `/api/workdirs/${providerIdValue}/${executionModeValue}/${pathValue}`);
if (notReady !== null) return notReady;
const providerId = normalizeTaskProviderId(providerIdValue);
@@ -4970,6 +5014,7 @@ async function deleteWorkdir(providerIdValue: string, executionModeValue: string
}
async function createTasks(req: Request): Promise<Response> {
if (legacyQueueWritesFrozen()) return legacyQueueFrozenResponse(req.method, "/api/tasks", "task-submit");
if (!serviceRoleAllowsWrite(config.serviceRole)) return readOnlyRejectResponse(req.method, "/api/tasks");
const notReady = requireDatabaseReadyForWrite(req.method, "/api/tasks");
if (notReady !== null) return notReady;
@@ -4998,6 +5043,7 @@ async function createTasks(req: Request): Promise<Response> {
}
async function steerTask(task: QueueTask, req: Request): Promise<Response> {
if (legacyQueueWritesFrozen()) return legacyQueueFrozenResponse(req.method, `/api/tasks/${task.id}/steer`, "task-steer");
if (!serviceRoleAllowsScheduler(config.serviceRole)) return schedulerOnlyRejectResponse(req.method, `/api/tasks/${task.id}/steer`);
const body = await readJson(req);
const bodyRecord = typeof body === "object" && body !== null && !Array.isArray(body) ? body as Record<string, unknown> : {};
@@ -5062,6 +5108,7 @@ async function steerTask(task: QueueTask, req: Request): Promise<Response> {
}
async function resumeTask(task: QueueTask, req: Request): Promise<Response> {
if (legacyQueueWritesFrozen()) return legacyQueueFrozenResponse(req.method, `/api/tasks/${task.id}/resume`, "task-resume");
if (!serviceRoleAllowsScheduler(config.serviceRole)) return schedulerOnlyRejectResponse(req.method, `/api/tasks/${task.id}/resume`);
const notReady = requireDatabaseReadyForWrite(req.method, `/api/tasks/${task.id}/resume`);
if (notReady !== null) return notReady;
@@ -5163,6 +5210,7 @@ async function resumeTask(task: QueueTask, req: Request): Promise<Response> {
}
async function editQueuedTaskPrompt(task: QueueTask, req: Request): Promise<Response> {
if (legacyQueueWritesFrozen()) return legacyQueueFrozenResponse(req.method, `/api/tasks/${task.id}/edit`, "queued-prompt-edit");
if (!serviceRoleAllowsWrite(config.serviceRole)) return readOnlyRejectResponse(req.method, `/api/tasks/${task.id}/edit`);
const notReady = requireDatabaseReadyForWrite(req.method, `/api/tasks/${task.id}/edit`);
if (notReady !== null) return notReady;
@@ -5238,6 +5286,7 @@ async function interruptTask(task: QueueTask, method = "POST"): Promise<Response
}
async function manualRetry(task: QueueTask, req: Request): Promise<Response> {
if (legacyQueueWritesFrozen()) return legacyQueueFrozenResponse(req.method, `/api/tasks/${task.id}/retry`, "task-retry");
if (!serviceRoleAllowsWrite(config.serviceRole)) return readOnlyRejectResponse(req.method, `/api/tasks/${task.id}/retry`);
const notReady = requireDatabaseReadyForWrite(req.method, `/api/tasks/${task.id}/retry`);
if (notReady !== null) return notReady;
@@ -5399,6 +5448,7 @@ async function markTerminalTasksRead(url: URL): Promise<Response> {
}
async function createQueue(req: Request): Promise<Response> {
if (legacyQueueWritesFrozen()) return legacyQueueFrozenResponse(req.method, "/api/queues", "queue-create");
if (!serviceRoleAllowsWrite(config.serviceRole)) return readOnlyRejectResponse(req.method, "/api/queues");
const notReady = requireDatabaseReadyForWrite(req.method, "/api/queues");
if (notReady !== null) return notReady;
@@ -5418,6 +5468,7 @@ async function createQueue(req: Request): Promise<Response> {
}
async function updateQueue(queueIdValue: string, req: Request): Promise<Response> {
if (legacyQueueWritesFrozen()) return legacyQueueFrozenResponse(req.method, `/api/queues/${queueIdValue}`, "queue-update");
if (!serviceRoleAllowsWrite(config.serviceRole)) return readOnlyRejectResponse(req.method, `/api/queues/${queueIdValue}`);
const notReady = requireDatabaseReadyForWrite(req.method, `/api/queues/${queueIdValue}`);
if (notReady !== null) return notReady;
@@ -5628,6 +5679,7 @@ function deleteQueuesFromState(queueIds: string[]): QueueRecord[] {
}
async function mergeQueues(targetQueueIdValue: string | null, req: Request): Promise<Response> {
if (legacyQueueWritesFrozen()) return legacyQueueFrozenResponse(req.method, targetQueueIdValue === null ? "/api/queues/merge" : `/api/queues/${targetQueueIdValue}/merge`, "queue-merge");
if (!serviceRoleAllowsWrite(config.serviceRole)) return readOnlyRejectResponse(req.method, targetQueueIdValue === null ? "/api/queues/merge" : `/api/queues/${targetQueueIdValue}/merge`);
const mergePath = targetQueueIdValue === null ? "/api/queues/merge" : `/api/queues/${targetQueueIdValue}/merge`;
const notReady = requireDatabaseReadyForWrite(req.method, mergePath);
@@ -5726,6 +5778,7 @@ async function mergeQueues(targetQueueIdValue: string | null, req: Request): Pro
}
async function moveTaskToQueue(task: QueueTask, req: Request, options: { bypassRoleCheck?: boolean } = {}): Promise<Response> {
if (options.bypassRoleCheck !== true && legacyQueueWritesFrozen()) return legacyQueueFrozenResponse(req.method, `/api/tasks/${task.id}/move`, "task-move");
if (options.bypassRoleCheck !== true && !serviceRoleAllowsWrite(config.serviceRole)) return readOnlyRejectResponse(req.method, `/api/tasks/${task.id}/move`);
const notReady = requireDatabaseReadyForWrite(req.method, `/api/tasks/${task.id}/move`);
if (notReady !== null) return notReady;