Drop code that nothing consumed. Verified by full renderer+shared grep:
every removed channel had zero callers via window.agentCompany.* and
zero references from desktop-api types. No backend internal use either —
the database/API-server layers keep their methods, only the IPC exposure
goes.
Removed IPC handlers (26 total):
Thread CRUD surface (12) — writes happen inside the backend
createThread, listThreads, addThreadEvent,
setThreadWaitState, resolveThreadWaitState,
addParticipant, removeParticipant, listParticipants,
subscribeThread, unsubscribeThread,
listSubscriptions, listSubscribedThreads
(kept reads: getThread, listThreadEvents, listThreadWaitStates)
Half-implemented features (13)
saveSecret, listComments, getAgentMetrics, getApiPort,
listWakeupRequests, listAgentMessages, autoAssignTask,
listRunEvents, recoveryDismiss,
getHeartbeatPolicy, setHeartbeatPolicy,
getRuntimeState, setRuntimeState
Whole vertical slice: openConnectorAuthTerminal
IPC handler + channel + preload + DesktopApi type +
connector-auth-service function + useConnectorCallbacks
handleLoginConnector + OnboardingContext.onLoginConnector +
OnboardingWizard wiring. Pi-mono has no CLI auth flow;
the no-op that "returned false for legacy UI compatibility"
had no legacy UI left.
Orphaned modules (zero importers in repo):
src/main/runtime-env.ts
src/main/database-stale-recovery.ts
Dead schema files (only referenced by their own barrel re-export):
schemas-participants, schemas-subscriptions, schemas-heartbeat,
schemas-run-events, schemas-runtime-state, schemas-wakeup
Renderer leftovers:
.activity-row-enter CSS + its two unreferenced keyframes
5 orphan i18n keys (app.console, app.refresh, app.expand,
activity.timeline, auto.trigger) left over from earlier feature
deletions
Also update two unit tests that mocked openConnectorAuthTerminal in
the RegisterCoreHandlersDependencies pick.
158 lines
5.0 KiB
TypeScript
158 lines
5.0 KiB
TypeScript
import { mkdtemp, rm } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { tmpdir } from "node:os";
|
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import type { IpcMainInvokeEvent } from "electron";
|
|
import type { DesktopResult } from "@shared/contracts";
|
|
import { IPC_CHANNELS } from "@shared/contracts";
|
|
import { AppDatabase } from "../../src/main/database";
|
|
import { registerCoreAdminHandlers } from "../../src/main/ipc-core-admin-handlers";
|
|
import { createThreadIntegration } from "../../src/main/thread-integration";
|
|
|
|
type IpcHandler = (
|
|
event: IpcMainInvokeEvent,
|
|
...args: unknown[]
|
|
) => Promise<DesktopResult<unknown>> | DesktopResult<unknown>;
|
|
|
|
const tempDirs: string[] = [];
|
|
|
|
async function createTempDir(prefix: string) {
|
|
const dir = await mkdtemp(join(tmpdir(), prefix));
|
|
tempDirs.push(dir);
|
|
return dir;
|
|
}
|
|
|
|
afterEach(async () => {
|
|
await Promise.all(tempDirs.splice(0).map((dir) => rm(dir, { recursive: true, force: true })));
|
|
});
|
|
|
|
describe("company mode switching", () => {
|
|
it("clears cofounder review artifacts when switching back to AI CEO", async () => {
|
|
const profileDir = await createTempDir("agentcompany-mode-switch-");
|
|
const db = new AppDatabase(profileDir);
|
|
db.init();
|
|
|
|
db.updateConnectorHealth({
|
|
id: "openai-codex",
|
|
status: "ready",
|
|
authState: "authenticated",
|
|
version: "test",
|
|
lastError: null,
|
|
});
|
|
|
|
const companyId = db.saveCompany({
|
|
name: "Mode Switch Co",
|
|
description: "Execution mode cleanup",
|
|
status: "active",
|
|
executionMode: "ai_cofounder",
|
|
autoApproveHires: false,
|
|
reviewDeliverables: true,
|
|
});
|
|
const workspaceId = db.saveWorkspace({
|
|
companyId,
|
|
name: "Primary",
|
|
localPath: profileDir,
|
|
repoUrl: "",
|
|
repoRef: "",
|
|
isPrimary: true,
|
|
});
|
|
const ceoId = db.saveAgent({
|
|
companyId,
|
|
name: "CEO",
|
|
role: "CEO",
|
|
title: "Chief Executive Officer",
|
|
status: "active",
|
|
reportsTo: null,
|
|
connectorId: "openai-codex",
|
|
workspaceId,
|
|
model: null,
|
|
capabilities: "Lead the company",
|
|
budgetMonthlyUsd: 250,
|
|
});
|
|
const engineerId = db.saveAgent({
|
|
companyId,
|
|
name: "Engineer",
|
|
role: "Engineer",
|
|
title: "Lead Engineer",
|
|
status: "active",
|
|
reportsTo: ceoId,
|
|
connectorId: "openai-codex",
|
|
workspaceId,
|
|
model: null,
|
|
capabilities: "Ship features",
|
|
budgetMonthlyUsd: 180,
|
|
department: "engineering",
|
|
});
|
|
const taskId = db.saveTask({
|
|
companyId,
|
|
title: "Ship feature",
|
|
description: "Waits for cofounder review.",
|
|
assigneeAgentId: engineerId,
|
|
workspaceId,
|
|
priority: "high",
|
|
status: "in_progress",
|
|
});
|
|
|
|
const threadIntegration = createThreadIntegration({
|
|
db,
|
|
logger: { info: () => {}, warn: () => {}, error: () => {} },
|
|
});
|
|
|
|
threadIntegration.onTaskCreated(taskId, companyId);
|
|
threadIntegration.onRunFinished("run-1", taskId, engineerId, companyId, "succeeded", null);
|
|
db.setTaskRequiresUserReview(taskId, true);
|
|
const approvalId = db.requestApproval({
|
|
companyId,
|
|
relatedTaskId: taskId,
|
|
requestedByAgentId: engineerId,
|
|
type: "deliverable_review",
|
|
payloadSummary: "Review deliverable",
|
|
impactSummary: "Needs review",
|
|
payloadJson: "{}",
|
|
});
|
|
threadIntegration.onApprovalCreated(approvalId, companyId, taskId, "deliverable_review", "Review deliverable");
|
|
|
|
expect(db.listThreadWaitStates(companyId).length).toBeGreaterThan(0);
|
|
expect(db.getTask(taskId).requiresUserReview).toBe(true);
|
|
expect(db.getApprovalRecord(approvalId).state).toBe("pending");
|
|
|
|
const handlers = new Map<string, IpcHandler>();
|
|
registerCoreAdminHandlers({
|
|
registerHandle: (channel, handler) => {
|
|
handlers.set(channel, handler);
|
|
},
|
|
db,
|
|
ensureCompanyExists: (id) => (db.hasCompany(id) ? null : { ok: false, error: { code: "COMPANY_NOT_FOUND", message: "missing" } }),
|
|
publishDomainChanged: vi.fn(),
|
|
handleApprovalResolved: (resolvedApprovalId, resolvedCompanyId, decision) => {
|
|
threadIntegration.onApprovalResolved(resolvedApprovalId, resolvedCompanyId, decision);
|
|
},
|
|
checkConnector: vi.fn(),
|
|
openGenericTerminal: vi.fn(),
|
|
});
|
|
|
|
const saveCompany = handlers.get(IPC_CHANNELS.saveCompany);
|
|
if (!saveCompany) {
|
|
throw new Error("saveCompany handler was not registered.");
|
|
}
|
|
|
|
const result = await saveCompany(null as unknown as IpcMainInvokeEvent, {
|
|
id: companyId,
|
|
name: "Mode Switch Co",
|
|
description: "Execution mode cleanup",
|
|
status: "active",
|
|
autoApproveHires: true,
|
|
reviewDeliverables: false,
|
|
executionMode: "ai_ceo",
|
|
}) as { ok: boolean };
|
|
|
|
expect(result.ok).toBe(true);
|
|
expect(db.getCompanyExecutionMode(companyId)).toBe("ai_ceo");
|
|
expect(db.listThreadWaitStates(companyId)).toHaveLength(0);
|
|
expect(db.getTask(taskId).requiresUserReview).toBe(false);
|
|
expect(db.getApprovalRecord(approvalId).state).toBe("approved");
|
|
|
|
db.close();
|
|
});
|
|
});
|