feat(09-01): define granular event types, IPC channels, entity getters, and Zustand patch methods

- Add 5 granular event interfaces (TaskUpdated, RunUpdated, ApprovalUpdated, AgentUpdated, BudgetChanged) to DesktopEvent union
- Add 4 entity getter IPC channels (getTask, getAgent, getRun, getApproval) with Zod validation and company ownership checks
- Add getRun method to AppDatabase following existing getTask pattern
- Add 4 preload bridge methods for entity getters
- Add 8 patch/remove methods and refreshBadges to CompanySlice
- Add selective-ipc.test.ts with exhaustive union type tests
- Extend store.test.ts with 14 patch method tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 4.6 committed 2026-03-27 19:33:33 -04:00
1 parent c1de05a7f1
commit 920a764856
8 files changed
+631 -5

No files matched your search

+55
View File
@@ -4,6 +4,7 @@ import { z } from "zod";
import {
IPC_CHANNELS,
connectorInputSchema,
entityGetterSchema,
metricsQuerySchema,
settingsSchema,
} from "@shared/contracts";
@@ -142,4 +143,58 @@ export function registerCoreReadHandlers({
if (err) return err;
return ok(db.getStandupReport(companyId));
});
// --- Entity getters for granular IPC updates ---
registerHandle(IPC_CHANNELS.getTask, (_event, payload) => {
const parsed = entityGetterSchema.parse(payload);
const companyError = ensureCompanyExists(parsed.companyId);
if (companyError) return companyError;
try {
const task = db.getTask(parsed.id);
if (task.companyId !== parsed.companyId) return fail("TASK_NOT_FOUND", "Task not found in current company.");
return ok(task);
} catch {
return fail("TASK_NOT_FOUND", "Task not found.");
}
});
registerHandle(IPC_CHANNELS.getAgent, (_event, payload) => {
const parsed = entityGetterSchema.parse(payload);
const companyError = ensureCompanyExists(parsed.companyId);
if (companyError) return companyError;
try {
const agent = db.getAgent(parsed.id);
if (agent.companyId !== parsed.companyId) return fail("AGENT_NOT_FOUND", "Agent not found in current company.");
return ok(agent);
} catch {
return fail("AGENT_NOT_FOUND", "Agent not found.");
}
});
registerHandle(IPC_CHANNELS.getRun, (_event, payload) => {
const parsed = entityGetterSchema.parse(payload);
const companyError = ensureCompanyExists(parsed.companyId);
if (companyError) return companyError;
try {
const run = db.getRun(parsed.id);
if (run.companyId !== parsed.companyId) return fail("RUN_NOT_FOUND", "Run not found in current company.");
return ok(run);
} catch {
return fail("RUN_NOT_FOUND", "Run not found.");
}
});
registerHandle(IPC_CHANNELS.getApproval, (_event, payload) => {
const parsed = entityGetterSchema.parse(payload);
const companyError = ensureCompanyExists(parsed.companyId);
if (companyError) return companyError;
try {
const approval = db.getApprovalRecord(parsed.id);
if (approval.companyId !== parsed.companyId) return fail("APPROVAL_NOT_FOUND", "Approval not found in current company.");
return ok(approval);
} catch {
return fail("APPROVAL_NOT_FOUND", "Approval not found.");
}
});
}