Files
AgentCompany/src/main/api-server/routes-approvals.ts
T
ZacharyZhang-NY f041336721 refactor: nuke dead exports, dead files, dead DB column, dead zero-value wrappers
Full-codebase ts-prune + manual audit sweep. Every change below is a pure
deletion (or a 2-line re-wire where a dead function was supposed to be
alive). No scope additions.

Dead wrappers / phantom features
  - shouldAutoApproveApproval: zero-value wrapper over shouldAutoApprove.
    Four call sites now import shouldAutoApprove from execution-policy
    directly.
  - evaluateRotation(session, connectorId, thresholdsOverride): the
    connectorId arg was never read (underscored), and thresholdsOverride
    was only exercised by the test suite — no production caller. Signature
    collapses to evaluateRotation(session). DEFAULT_THRESHOLDS /
    RotationThresholds exports and their tests go with it.
  - installLogRedactor: defensive console wrapper that was never wired
    from worker-entry. buildRedactor handles the known threat (env-value
    leaks); the pattern-based redactTokens stays for tests and future
    composition.

Dead files
  - resume-interrupted-tasks.ts: helper function never imported.
  - service-graph-orchestration-deps.ts: three factory closures
    superseded by the inline closures in create-orchestration-service.

Dead exports
  - listConnectorsByAuthKind (shared/connector-catalog)
  - getLocalePromptInstruction + whole localization.ts file
  - ImportantDocType
  - main-side ConnectorAuthKind (duplicated the shared one; not referenced)
  - CheckpointEngineService, RunHousekeepingService types
  - WorkspaceResolution type
  - cmdOrCtrlSymbol
  - AgentEventPush, CredentialPayload type aliases
  - parseApprovalPayloadJson, parseEnvValue, ProviderCard
  - getSOP — buildSOPSection reads the SOPS map directly; the individual
    getter had no callers. Deduped to a flat array.
  - renderWakeReason in wake-reasons/en.ts: byte-for-byte duplicate of the
    one in wake-reasons/index.ts.

Forgotten wiring (not cleanup, but adjacent)
  - registerAgentStandupRoute: the GET /api/agents/me/standup endpoint is
    advertised in every system prompt and wake-reason doc, but the route
    handler was never registered in api-server/index.ts. Agents have been
    hitting 404 since Pi Mono. Registered.

Dead DB column
  - v44 migration drops runs.context_snapshot_json. Column was added by
    v16-v25, never written or read, and v43's deliberate preservation
    was an interim measure. Same idempotent table-rebuild pattern as
    v41/v43.

Test tree
  - Phantom-feature threshold override tests removed (3). The rest of
    the rotation suite re-expressed against the real maxRuns=20 floor.

495/495 unit tests pass. typecheck + build clean.
2026-04-18 23:37:37 -04:00

213 lines
8.9 KiB
TypeScript

import { z } from "zod";
import log from "electron-log/main.js";
import { approvalInputSchema } from "@shared/contracts";
import { resolveApprovalDecision } from "../approval-policy";
import { shouldAutoApprove } from "../execution-policy";
import { requireParam, type AgentApiServer } from "./server-core";
const approvalListQuerySchema = z.object({
requestedByAgentId: z.string().uuid().optional(),
relatedTaskId: z.string().uuid().optional(),
status: z.string().optional(),
});
export function registerApprovalRoutes(server: AgentApiServer) {
const db = server.db;
const callbacks = server.callbacks;
const onDomainChanged = server.onDomainChanged;
const onWakeAgent = server.onWakeAgent;
server.addRoute("POST", "/api/companies/:companyId/approvals", (_req, res, params, token, body) => {
const companyId = requireParam(params, "companyId");
if (companyId !== token.companyId) {
server.json(res, 403, { error: "Company mismatch" });
return;
}
const parsed = approvalInputSchema.safeParse({
companyId,
...(typeof body === "object" && body ? body : {}),
requestedByAgentId: token.agentId,
});
if (!parsed.success) {
server.json(res, 400, { error: "Invalid approval payload" });
return;
}
const input = parsed.data;
if (server.companyRefError(res, companyId, [
{ id: input.relatedTaskId, table: "tasks", label: "related task" },
{ id: token.agentId, table: "agents", label: "requesting agent" },
{ id: input.relatedAgentId, table: "agents", label: "related agent" },
])) {
return;
}
let id: string;
try {
id = db.requestApproval({
companyId,
type: input.type,
relatedTaskId: input.relatedTaskId ?? null,
requestedByAgentId: token.agentId,
relatedAgentId: input.relatedAgentId ?? null,
payloadSummary: input.payloadSummary,
impactSummary: input.impactSummary,
payloadJson: input.payloadJson ?? null,
});
} catch (error) {
server.json(res, 422, { error: error instanceof Error ? error.message : "Approval could not be created" });
return;
}
db.addActivity({
companyId,
actor: token.agentId,
action: "approval.created",
entityType: "approval",
entityId: id,
detail: input.payloadSummary,
});
// Notify thread integration about the new approval
callbacks.onApprovalCreated(id, companyId, input.relatedTaskId ?? null, input.type, input.payloadSummary ?? "");
if (shouldAutoApprove(db, companyId, input.type)) {
resolveApprovalDecision({
db,
handleApprovalResolved: callbacks.onApprovalResolved,
companyId,
approvalId: id,
state: "approved",
decisionNote: "Auto-approved by company policy",
detail: "Auto-approved by company policy",
});
log.info(`[auto-approve] Auto-approved approval ${id}: ${input.payloadSummary}`);
} else {
callbacks.notify({
title: "Approval Required",
body: input.payloadSummary ?? `${input.type} approval pending`,
urgency: "critical",
navigation: { section: "approvals", entityId: id },
batchKey: "pending_approval",
});
}
onDomainChanged();
server.json(res, 201, { id });
});
server.addRoute("GET", "/api/companies/:companyId/approvals", (req, res, params, token) => {
const companyId = requireParam(params, "companyId");
if (companyId !== token.companyId) {
server.json(res, 403, { error: "Company mismatch" });
return;
}
const url = new URL(req.url ?? "/", `http://127.0.0.1:${server.port}`);
const parsedQuery = approvalListQuerySchema.safeParse({
requestedByAgentId: url.searchParams.get("requestedByAgentId") ?? undefined,
relatedTaskId: url.searchParams.get("relatedTaskId") ?? undefined,
status: url.searchParams.get("status") ?? undefined,
});
if (!parsedQuery.success) {
server.json(res, 400, { error: "Invalid approval query" });
return;
}
const statuses = parsedQuery.data.status?.split(",").filter(Boolean) ?? null;
const approvals = db.listApprovalsForApi(companyId, {
requestedByAgentId: parsedQuery.data.requestedByAgentId,
relatedTaskId: parsedQuery.data.relatedTaskId,
statuses,
});
server.json(res, 200, approvals);
});
server.addRoute("GET", "/api/approvals/:approvalId", (_req, res, params, token) => {
const approval = db.findApprovalById(requireParam(params, "approvalId"));
if (!approval || approval.companyId !== token.companyId) {
server.json(res, 404, { error: "Approval not found" });
return;
}
server.json(res, 200, approval);
});
server.addRoute("PATCH", "/api/approvals/:approvalId", (_req, res) => {
server.json(res, 403, { error: "Approvals must be decided from the desktop board, not from an agent run token" });
});
server.addRoute("GET", "/api/approvals/:approvalId/comments", (_req, res, params, token) => {
const approvalId = requireParam(params, "approvalId");
const approval = db.findApprovalById(approvalId);
if (!approval) { server.json(res, 404, { error: "Approval not found" }); return; }
if (approval.companyId !== token.companyId) { server.json(res, 403, { error: "Company mismatch" }); return; }
const comments = db.listApprovalComments(approvalId, approval.companyId);
server.json(res, 200, comments);
});
server.addRoute("POST", "/api/approvals/:approvalId/comments", (_req, res, params, token, body) => {
const approval = db.findApprovalById(requireParam(params, "approvalId"));
if (!approval) { server.json(res, 404, { error: "Approval not found" }); return; }
if (approval.companyId !== token.companyId) { server.json(res, 403, { error: "Company mismatch" }); return; }
const data = body as Record<string, unknown>;
const commentBody = typeof data.body === "string" ? data.body.trim() : "";
if (!commentBody) { server.json(res, 400, { error: "Comment body is required" }); return; }
const commentId = db.addApprovalComment({
companyId: approval.companyId,
approvalId: approval.id,
authorAgentId: token.agentId ?? null,
body: commentBody,
});
// Wake mentioned agents in comment
const mentionedIds = db.findMentionedAgentIds(approval.companyId, commentBody);
for (const mentionedId of mentionedIds) {
if (mentionedId !== token.agentId) {
onWakeAgent(mentionedId, approval.companyId, "approval_comment_mentioned");
}
}
onDomainChanged();
server.json(res, 201, { id: commentId });
});
server.addRoute("POST", "/api/approvals/:approvalId/resubmit", (_req, res, params, token) => {
const approval = db.findApprovalById(requireParam(params, "approvalId"));
if (!approval) { server.json(res, 404, { error: "Approval not found" }); return; }
if (approval.companyId !== token.companyId) { server.json(res, 403, { error: "Company mismatch" }); return; }
if (approval.state !== "revision_requested") {
server.json(res, 422, { error: "Only revision_requested approvals can be resubmitted" });
return;
}
if (token.agentId !== approval.requestedByAgentId) {
server.json(res, 403, { error: "Only the requesting agent can resubmit this approval" });
return;
}
db.resubmitApproval(approval.id, approval.companyId);
onDomainChanged();
server.json(res, 200, { resubmitted: true });
});
server.addRoute("GET", "/api/approvals/:approvalId/tasks", (_req, res, params, token) => {
const approvalId = requireParam(params, "approvalId");
const approval = db.findApprovalById(approvalId);
if (!approval) { server.json(res, 404, { error: "Approval not found" }); return; }
if (approval.companyId !== token.companyId) { server.json(res, 403, { error: "Company mismatch" }); return; }
const taskIds = db.listTasksForApproval(approvalId);
server.json(res, 200, taskIds);
});
server.addRoute("POST", "/api/approvals/:approvalId/tasks", (_req, res, params, token, body) => {
const approvalId = requireParam(params, "approvalId");
const approval = db.findApprovalById(approvalId);
if (!approval) { server.json(res, 404, { error: "Approval not found" }); return; }
if (approval.companyId !== token.companyId) { server.json(res, 403, { error: "Company mismatch" }); return; }
const data = body as Record<string, unknown>;
const taskIds = Array.isArray(data.taskIds) ? data.taskIds.filter((id): id is string => typeof id === "string") : [];
if (taskIds.length === 0) { server.json(res, 400, { error: "taskIds array is required" }); return; }
for (const taskId of taskIds) {
if (!db.belongsToCompany("tasks", taskId, token.companyId)) {
server.json(res, 400, { error: `Task ${taskId} does not belong to this company` }); return;
}
}
db.linkManyTasksToApproval(approvalId, taskIds, token.companyId, token.agentId ?? null);
onDomainChanged();
server.json(res, 200, { linked: taskIds.length });
});
}