146 lines
4.8 KiB
TypeScript
146 lines
4.8 KiB
TypeScript
import { dialog, shell } from "electron";
|
|
import { join } from "node:path";
|
|
import { z } from "zod";
|
|
import {
|
|
IPC_CHANNELS,
|
|
connectorInputSchema,
|
|
metricsQuerySchema,
|
|
settingsSchema,
|
|
} from "@shared/contracts";
|
|
import { fail, ok, type RegisterCoreHandlersDependencies } from "./ipc-core-common";
|
|
|
|
export function registerCoreReadHandlers({
|
|
registerHandle,
|
|
db,
|
|
ensureCompanyExists,
|
|
publishDomainChanged,
|
|
checkForUpdates,
|
|
resetAfterRestore,
|
|
getApiPort,
|
|
listConnectorModels,
|
|
}: Pick<
|
|
RegisterCoreHandlersDependencies,
|
|
| "registerHandle"
|
|
| "db"
|
|
| "ensureCompanyExists"
|
|
| "publishDomainChanged"
|
|
| "checkForUpdates"
|
|
| "resetAfterRestore"
|
|
| "getApiPort"
|
|
| "listConnectorModels"
|
|
>) {
|
|
registerHandle(IPC_CHANNELS.loadSnapshot, () => ok(db.listRendererSnapshot()));
|
|
|
|
registerHandle(IPC_CHANNELS.pickDirectory, async () => {
|
|
const result = await dialog.showOpenDialog({
|
|
properties: ["openDirectory", "createDirectory"],
|
|
});
|
|
return ok(result.canceled ? null : (result.filePaths[0] ?? null));
|
|
});
|
|
|
|
registerHandle(IPC_CHANNELS.openPath, async (_event, targetPath) => {
|
|
if (typeof targetPath !== "string" || targetPath.length === 0) {
|
|
return fail("INVALID_PATH", "A valid path is required.");
|
|
}
|
|
if (!db.canOpenPath(targetPath)) {
|
|
return fail("OPEN_PATH_FORBIDDEN", "The requested path is outside the managed desktop workspace.");
|
|
}
|
|
const error = await shell.openPath(targetPath);
|
|
return error ? fail("OPEN_PATH_FAILED", error) : ok(true);
|
|
});
|
|
|
|
registerHandle(IPC_CHANNELS.backupProfile, async () => {
|
|
const result = await dialog.showOpenDialog({
|
|
properties: ["openDirectory", "createDirectory"],
|
|
});
|
|
if (result.canceled || result.filePaths.length === 0) {
|
|
return ok(null);
|
|
}
|
|
const backupPath = join(result.filePaths[0]!, `agentcompany-backup-${Date.now()}`);
|
|
await db.exportBackup(backupPath);
|
|
return ok(backupPath);
|
|
});
|
|
|
|
registerHandle(IPC_CHANNELS.restoreProfile, async () => {
|
|
const hasActiveRuns = db.listSnapshot().runs.some((run: { status: string }) => run.status === "queued" || run.status === "running");
|
|
if (hasActiveRuns) {
|
|
return fail("RESTORE_BLOCKED", "Stop all active runs before restoring a profile backup.");
|
|
}
|
|
const result = await dialog.showOpenDialog({
|
|
properties: ["openDirectory"],
|
|
});
|
|
if (result.canceled || result.filePaths.length === 0) {
|
|
return ok(false);
|
|
}
|
|
await db.restoreFromBackup(result.filePaths[0]!);
|
|
resetAfterRestore();
|
|
publishDomainChanged();
|
|
return ok(true);
|
|
});
|
|
|
|
registerHandle(IPC_CHANNELS.updateSettings, async (_event, payload) => {
|
|
const parsed = settingsSchema.parse(payload);
|
|
db.updateSettings(parsed);
|
|
publishDomainChanged();
|
|
return ok(true);
|
|
});
|
|
|
|
registerHandle(IPC_CHANNELS.checkForUpdates, async () => {
|
|
return ok(await checkForUpdates());
|
|
});
|
|
|
|
registerHandle(IPC_CHANNELS.getSidebarBadges, async (_event, companyId) => {
|
|
if (typeof companyId !== "string" || !companyId) {
|
|
return fail("INVALID_COMPANY_ID", "A valid company id is required.");
|
|
}
|
|
return ok(db.getSidebarBadges(companyId));
|
|
});
|
|
|
|
registerHandle(IPC_CHANNELS.getApiPort, () => ok(getApiPort()));
|
|
|
|
registerHandle(IPC_CHANNELS.listConnectorModels, async (_event, connectorId) => {
|
|
try {
|
|
const parsed = connectorInputSchema.shape.id.parse(connectorId);
|
|
return ok(await listConnectorModels(parsed));
|
|
} catch {
|
|
return ok([]);
|
|
}
|
|
});
|
|
|
|
registerHandle(IPC_CHANNELS.getInbox, (_event, payload) => {
|
|
const companyId = z.string().uuid().parse(payload);
|
|
const err = ensureCompanyExists(companyId);
|
|
if (err) return err;
|
|
return ok(db.getInbox(companyId));
|
|
});
|
|
|
|
registerHandle(IPC_CHANNELS.getCompanyMetrics, (_event, payload) => {
|
|
const input = metricsQuerySchema.parse(payload);
|
|
const err = ensureCompanyExists(input.companyId);
|
|
if (err) return err;
|
|
return ok(db.getCompanyMetrics(input.companyId, input.days));
|
|
});
|
|
|
|
registerHandle(IPC_CHANNELS.getAgentMetrics, (_event, payload) => {
|
|
const input = metricsQuerySchema.parse(payload);
|
|
const err = ensureCompanyExists(input.companyId);
|
|
if (err) return err;
|
|
if (!input.agentId) {
|
|
return fail("MISSING_AGENT_ID", "agentId is required");
|
|
}
|
|
const metrics = db.getCompanyMetrics(input.companyId, input.days);
|
|
const agentMetric = metrics.agentMetrics.find((metric: { agentId: string }) => metric.agentId === input.agentId);
|
|
if (!agentMetric) {
|
|
return fail("AGENT_NOT_FOUND", "Agent metrics not found");
|
|
}
|
|
return ok(agentMetric);
|
|
});
|
|
|
|
registerHandle(IPC_CHANNELS.getStandupReport, (_event, payload) => {
|
|
const companyId = z.string().uuid().parse(payload);
|
|
const err = ensureCompanyExists(companyId);
|
|
if (err) return err;
|
|
return ok(db.getStandupReport(companyId));
|
|
});
|
|
}
|