From c71d033b0c223feabfe74c8c4234bdd10925df7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Fri, 17 Apr 2026 22:38:10 -0400 Subject: [PATCH] refactor: prune dead IPC surface and orphaned modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/main/connector-auth-service.ts | 20 -- src/main/database-stale-recovery.ts | 70 ------- src/main/ipc-agent-coordination-handlers.ts | 35 ---- src/main/ipc-core-admin-handlers.ts | 27 +-- src/main/ipc-core-common.ts | 2 - src/main/ipc-core-operations-handlers.ts | 69 ------- src/main/ipc-core-read-handlers.ts | 31 ---- src/main/ipc-recovery-handlers.ts | 12 -- src/main/ipc-thread-handlers.ts | 172 +----------------- src/main/main-runtime-support.ts | 7 +- src/main/runtime-env.ts | 146 --------------- src/preload/index.ts | 34 +--- .../company-onboarding/OnboardingContext.tsx | 1 - .../company-onboarding/OnboardingWizard.tsx | 4 +- .../useConnectorCallbacks.ts | 26 +-- src/renderer/i18n/en.ts | 7 - src/renderer/i18n/zh.ts | 7 - src/renderer/styles.css | 42 ----- src/shared/contracts/channels.ts | 31 +--- src/shared/contracts/desktop-api/agents.ts | 11 +- .../contracts/desktop-api/automation.ts | 2 - .../contracts/desktop-api/communication.ts | 6 +- src/shared/contracts/desktop-api/companies.ts | 2 - .../contracts/desktop-api/credentials.ts | 4 +- src/shared/contracts/desktop-api/runs.ts | 4 +- src/shared/contracts/desktop-api/tasks.ts | 3 +- src/shared/contracts/desktop-api/threads.ts | 18 +- src/shared/contracts/schemas-heartbeat.ts | 16 -- src/shared/contracts/schemas-misc.ts | 6 - src/shared/contracts/schemas-participants.ts | 20 -- src/shared/contracts/schemas-run-events.ts | 8 - src/shared/contracts/schemas-runtime-state.ts | 12 -- src/shared/contracts/schemas-subscriptions.ts | 25 --- src/shared/contracts/schemas-threads.ts | 40 ---- src/shared/contracts/schemas-wakeup.ts | 24 --- tests/unit/company-mode-switch.test.ts | 1 - tests/unit/ipc-core-admin-handlers.test.ts | 1 - 37 files changed, 17 insertions(+), 929 deletions(-) delete mode 100644 src/main/database-stale-recovery.ts delete mode 100644 src/main/runtime-env.ts delete mode 100644 src/shared/contracts/schemas-heartbeat.ts delete mode 100644 src/shared/contracts/schemas-participants.ts delete mode 100644 src/shared/contracts/schemas-run-events.ts delete mode 100644 src/shared/contracts/schemas-runtime-state.ts delete mode 100644 src/shared/contracts/schemas-subscriptions.ts delete mode 100644 src/shared/contracts/schemas-wakeup.ts diff --git a/src/main/connector-auth-service.ts b/src/main/connector-auth-service.ts index 8b6c1cab..8c21cc24 100644 --- a/src/main/connector-auth-service.ts +++ b/src/main/connector-auth-service.ts @@ -5,7 +5,6 @@ import { join } from "node:path"; import { randomBytes } from "node:crypto"; import { spawnSync } from "node:child_process"; import log from "electron-log/main.js"; -import type { ConnectorId } from "@shared/types"; function quoteShell(value: string) { return `'${value.replace(/'/g, `'"'"'`)}'`; @@ -88,25 +87,6 @@ function spawnTerminalWithScript(script: string, _title: string, _cwd: string): throw new Error("No supported terminal application was found."); } -/* ------------------------------------------------------------------ */ -/* Connector auth terminal — deprecated under pi-mono */ -/* ------------------------------------------------------------------ */ - -/** - * Pi-mono has no CLI auth flow. OAuth runs through `oauth-login-service`, - * API keys are entered via the Settings form, and cloud providers (AWS, - * Azure, GCP) use environment-driven credentials. The IPC handler still - * calls this function for legacy UI compatibility, so we keep the signature - * but treat it as a no-op that reports "not available". - */ -export async function openConnectorAuthTerminal( - _connectorId: ConnectorId, - _command: string, - _cwd?: string, -): Promise { - return false; -} - /* ------------------------------------------------------------------ */ /* Generic terminal command (for install flows, etc.) */ /* ------------------------------------------------------------------ */ diff --git a/src/main/database-stale-recovery.ts b/src/main/database-stale-recovery.ts deleted file mode 100644 index 6202d481..00000000 --- a/src/main/database-stale-recovery.ts +++ /dev/null @@ -1,70 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import { STALE_LOCK_TIMEOUT_MS } from "./database-base"; - -function nowIso(): string { - return new Date().toISOString(); -} - -/** - * Stale-state recovery helpers extracted from `database-base.ts` to keep that - * file under the 400-line cap. Both helpers are called by `AppDatabase.init` - * (interruptStaleRuns) and the orchestration recovery loop (recoverStaleLocks). - */ - -interface InterruptDeps { - db: DatabaseSync; - transaction: (op: () => T) => T; - releaseAllWorkspaceLocks: () => void; -} - -export function interruptStaleRunsImpl(deps: InterruptDeps): number { - const ts = nowIso(); - let interruptedCount = 0; - deps.transaction(() => { - const result = deps.db - .prepare( - "update runs set status = 'interrupted', error_message = 'AgentCompany restarted before the run could report completion.', finished_at = ?, updated_at = ? where status = 'running'", - ) - .run(ts, ts); - interruptedCount = Number(result.changes); - if (interruptedCount > 0) { - deps.db - .prepare( - "update tasks set status = 'blocked', updated_at = ? where id in (select task_id from runs where status = 'interrupted' and finished_at = ?) and status in ('in_progress', 'todo')", - ) - .run(ts, ts); - } - deps.db - .prepare( - "update tasks set active_run_id = null where active_run_id in (select id from runs where status = 'interrupted')", - ) - .run(); - deps.db.prepare("update agents set status = 'idle', updated_at = ? where status = 'running'").run(ts); - deps.releaseAllWorkspaceLocks(); - }); - return interruptedCount; -} - -interface RecoverDeps { - db: DatabaseSync; - readAll: (sql: string, ...params: import("node:sqlite").SQLInputValue[]) => T[]; -} - -export function recoverStaleLocksImpl( - deps: RecoverDeps, -): Array<{ taskId: string; companyId: string; title: string }> { - const cutoff = new Date(Date.now() - STALE_LOCK_TIMEOUT_MS).toISOString(); - const stale = deps.readAll<{ id: string; companyId: string; title: string }>( - "SELECT id, company_id AS companyId, title FROM tasks WHERE execution_locked_at IS NOT NULL AND execution_locked_at < ? AND status = 'in_progress' AND checkout_run_id NOT IN (SELECT id FROM runs WHERE status = 'running')", - cutoff, - ); - const ts = nowIso(); - for (const task of stale) { - deps.db - .prepare( - "UPDATE tasks SET checkout_run_id = NULL, execution_locked_at = NULL, status = 'todo', updated_at = ? WHERE id = ?", - ) - .run(ts, task.id); - } - return stale.map((t) => ({ taskId: t.id, companyId: t.companyId, title: t.title })); -} diff --git a/src/main/ipc-agent-coordination-handlers.ts b/src/main/ipc-agent-coordination-handlers.ts index 7265d7f4..4b156521 100644 --- a/src/main/ipc-agent-coordination-handlers.ts +++ b/src/main/ipc-agent-coordination-handlers.ts @@ -1,9 +1,7 @@ import { IPC_CHANNELS, agentMessageInputSchema, - autoAssignSchema, markMessageReadSchema, - messageQuerySchema, searchMessagesSchema, } from "@shared/contracts"; import { fail, ok, type RegisterDomainHandlersDependencies } from "./ipc-domain-common"; @@ -13,7 +11,6 @@ export function registerAgentCoordinationHandlers({ registerHandle, db, ensureCompanyExists, - findInvalidReference, publishDomainChanged, emitEvent, notify, @@ -24,7 +21,6 @@ export function registerAgentCoordinationHandlers({ | "registerHandle" | "db" | "ensureCompanyExists" - | "findInvalidReference" | "publishDomainChanged" | "emitEvent" | "notify" @@ -56,26 +52,6 @@ export function registerAgentCoordinationHandlers({ }); }); - registerHandle(IPC_CHANNELS.listAgentMessages, async (_event, payload) => { - const parsed = messageQuerySchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const invalidReference = findInvalidReference(parsed.companyId, [ - { id: parsed.agentId, table: "agents", label: "message reader" }, - { id: parsed.channel === "project" ? parsed.channelTargetId : null, table: "projects", label: "project channel" }, - ]); - if (invalidReference) { - return fail("INVALID_COMPANY_REFERENCE", `The selected ${invalidReference.label} does not belong to the current company.`); - } - return ok(db.listAgentMessages(parsed.companyId, { - agentId: parsed.agentId, - channel: parsed.channel, - channelTargetId: parsed.channelTargetId, - unreadOnly: parsed.unreadOnly, - limit: parsed.limit, - })); - }); - registerHandle(IPC_CHANNELS.markMessageRead, async (_event, payload) => { const parsed = markMessageReadSchema.parse(payload); const companyError = ensureCompanyExists(parsed.companyId); @@ -115,15 +91,4 @@ export function registerAgentCoordinationHandlers({ })); }); - registerHandle(IPC_CHANNELS.autoAssignTask, async (_event, payload) => { - const parsed = autoAssignSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const agentId = db.autoAssignTask(parsed.taskId, parsed.companyId); - if (!agentId) { - return fail("NO_AVAILABLE_AGENT", "No available agent could be found for this task."); - } - publishDomainChanged(); - return ok(agentId); - }); } diff --git a/src/main/ipc-core-admin-handlers.ts b/src/main/ipc-core-admin-handlers.ts index 7f917a58..e0a17876 100644 --- a/src/main/ipc-core-admin-handlers.ts +++ b/src/main/ipc-core-admin-handlers.ts @@ -6,7 +6,6 @@ import { connectorInputSchema, deleteEntitySchema, openTerminalCommandSchema, - secretInputSchema, } from "@shared/contracts"; import { validateConnectorConfigurationModel, validateConnectorModelSelection } from "./connector-model-policy"; import { reconcileExecutionModeChange } from "./execution-mode-reconciler"; @@ -40,11 +39,10 @@ export function registerCoreAdminHandlers({ publishDomainChanged, handleApprovalResolved, checkConnector, - openConnectorAuthTerminal, openGenericTerminal, }: Pick< RegisterCoreHandlersDependencies, - "registerHandle" | "db" | "ensureCompanyExists" | "publishDomainChanged" | "handleApprovalResolved" | "checkConnector" | "openConnectorAuthTerminal" | "openGenericTerminal" + "registerHandle" | "db" | "ensureCompanyExists" | "publishDomainChanged" | "handleApprovalResolved" | "checkConnector" | "openGenericTerminal" >) { registerHandle(IPC_CHANNELS.saveCompany, async (_event, payload) => { const parsed = companyInputSchema.parse(payload); @@ -123,12 +121,6 @@ export function registerCoreAdminHandlers({ return ok(true); }); - registerHandle(IPC_CHANNELS.openConnectorAuthTerminal, async (_event, id) => { - const parsed = connectorInputSchema.shape.id.parse(id); - await openConnectorAuthTerminal(parsed); - return ok(true); - }); - registerHandle(IPC_CHANNELS.checkNodeInstalled, async () => { return ok(await probeShellNode()); }); @@ -146,23 +138,6 @@ export function registerCoreAdminHandlers({ return ok(true); }); - registerHandle(IPC_CHANNELS.saveSecret, async (_event, payload) => { - const parsed = secretInputSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const id = db.saveSecret(parsed); - db.addActivity({ - companyId: parsed.companyId, - actor: "board", - action: parsed.id ? "secret.updated" : "secret.created", - entityType: "secret", - entityId: id, - detail: parsed.name, - }); - publishDomainChanged(); - return ok(id); - }); - registerHandle(IPC_CHANNELS.deleteSecret, async (_event, payload) => { const parsed = deleteEntitySchema.parse(payload); const companyError = ensureCompanyExists(parsed.companyId); diff --git a/src/main/ipc-core-common.ts b/src/main/ipc-core-common.ts index 73113adb..879ed798 100644 --- a/src/main/ipc-core-common.ts +++ b/src/main/ipc-core-common.ts @@ -26,12 +26,10 @@ export interface RegisterCoreHandlersDependencies { dispatchAutomation: (trigger: string, ctx: { companyId: string; [key: string]: unknown }) => void; queueTaskRun: (taskId: string, trigger: string, actor: string) => DesktopResult; checkConnector: (id: ConnectorId) => Promise; - openConnectorAuthTerminal: (id: ConnectorId) => Promise; openGenericTerminal: (input: { commandKey: string }) => Promise; checkForUpdates: (options?: { manual?: boolean }) => Promise; getWorkerProcess: () => { postMessage: (message: unknown) => void } | null; resetAfterRestore: () => void; - getApiPort: () => number; listConnectorModels: (connectorId: string) => Promise>; notify: (options: { title: string; body: string; urgency: "critical" | "informational"; navigation?: { section: SectionId; entityId?: string }; batchKey?: string }) => void; logger: { diff --git a/src/main/ipc-core-operations-handlers.ts b/src/main/ipc-core-operations-handlers.ts index 9b9de339..fabc3cf7 100644 --- a/src/main/ipc-core-operations-handlers.ts +++ b/src/main/ipc-core-operations-handlers.ts @@ -4,15 +4,9 @@ import { approvalInputSchema, cancelRunSchema, commentInputSchema, - heartbeatPolicySchema, heartbeatSettingsSchema, - listCommentsSchema, - listRunEventsSchema, - runtimeStateSchema, runLogChunkSchema, runLogSchema, - setHeartbeatPolicySchema, - setRuntimeStateSchema, startRunSchema, triggerHeartbeatSchema, } from "@shared/contracts"; @@ -209,16 +203,6 @@ export function registerCoreOperationHandlers({ return ok(comment.id); }); - registerHandle(IPC_CHANNELS.listComments, async (_event, payload) => { - const parsed = listCommentsSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.belongsToCompany("tasks", parsed.taskId, parsed.companyId)) { - return fail("TASK_NOT_FOUND", "Task not found in the current company."); - } - return ok(db.listComments(parsed.taskId)); - }); - registerHandle(IPC_CHANNELS.setHeartbeat, async (_event, payload) => { const parsed = heartbeatSettingsSchema.parse(payload); const companyError = ensureCompanyExists(parsed.companyId); @@ -254,57 +238,4 @@ export function registerCoreOperationHandlers({ return ok(runId); }); - registerHandle(IPC_CHANNELS.listRunEvents, async (_event, payload) => { - const parsed = listRunEventsSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.belongsToCompany("runs", parsed.runId, parsed.companyId)) { - return fail("RUN_NOT_FOUND", "Run not found in the current company."); - } - return ok(db.listRunEvents(parsed.runId, parsed.companyId, { offset: parsed.offset, limit: parsed.limit })); - }); - - registerHandle(IPC_CHANNELS.getHeartbeatPolicy, async (_event, payload) => { - const parsed = heartbeatPolicySchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.belongsToCompany("agents", parsed.agentId, parsed.companyId)) { - return fail("AGENT_NOT_FOUND", "Agent not found in the current company."); - } - return ok(db.getHeartbeatPolicy(parsed.agentId)); - }); - - registerHandle(IPC_CHANNELS.setHeartbeatPolicy, async (_event, payload) => { - const parsed = setHeartbeatPolicySchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.belongsToCompany("agents", parsed.agentId, parsed.companyId)) { - return fail("AGENT_NOT_FOUND", "Agent not found in the current company."); - } - const { companyId, agentId, ...policy } = parsed; - db.setHeartbeatPolicy(agentId, companyId, policy); - publishDomainChanged(); - return ok(null); - }); - - registerHandle(IPC_CHANNELS.getRuntimeState, async (_event, payload) => { - const parsed = runtimeStateSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.belongsToCompany("agents", parsed.agentId, parsed.companyId)) { - return fail("AGENT_NOT_FOUND", "Agent not found in the current company."); - } - return ok(db.getRuntimeState(parsed.agentId)); - }); - - registerHandle(IPC_CHANNELS.setRuntimeState, async (_event, payload) => { - const parsed = setRuntimeStateSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.belongsToCompany("agents", parsed.agentId, parsed.companyId)) { - return fail("AGENT_NOT_FOUND", "Agent not found in the current company."); - } - db.setRuntimeState(parsed.agentId, parsed.companyId, parsed.state); - return ok(null); - }); } diff --git a/src/main/ipc-core-read-handlers.ts b/src/main/ipc-core-read-handlers.ts index a2097527..269b7de5 100644 --- a/src/main/ipc-core-read-handlers.ts +++ b/src/main/ipc-core-read-handlers.ts @@ -7,7 +7,6 @@ import { entityGetterSchema, metricsQuerySchema, settingsSchema, - wakeupQuerySchema, } from "@shared/contracts"; import { fail, ok, type RegisterCoreHandlersDependencies } from "./ipc-core-common"; @@ -18,7 +17,6 @@ export function registerCoreReadHandlers({ publishDomainChanged, checkForUpdates, resetAfterRestore, - getApiPort, listConnectorModels, logger, }: Pick< @@ -29,7 +27,6 @@ export function registerCoreReadHandlers({ | "publishDomainChanged" | "checkForUpdates" | "resetAfterRestore" - | "getApiPort" | "listConnectorModels" | "logger" >) { @@ -105,8 +102,6 @@ export function registerCoreReadHandlers({ 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); @@ -141,21 +136,6 @@ export function registerCoreReadHandlers({ 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); @@ -163,17 +143,6 @@ export function registerCoreReadHandlers({ return ok(db.getStandupReport(companyId)); }); - registerHandle(IPC_CHANNELS.listWakeupRequests, (_event, input) => { - const parsed = wakeupQuerySchema.parse(input); - const err = ensureCompanyExists(parsed.companyId); - if (err) return err; - return ok(db.listWakeupRequests(parsed.companyId, { - status: parsed.status, - agentId: parsed.agentId, - limit: parsed.limit, - })); - }); - // --- Entity getters for granular IPC updates --- registerHandle(IPC_CHANNELS.getTask, (_event, payload) => { diff --git a/src/main/ipc-recovery-handlers.ts b/src/main/ipc-recovery-handlers.ts index 2c5310e8..14574d0d 100644 --- a/src/main/ipc-recovery-handlers.ts +++ b/src/main/ipc-recovery-handlers.ts @@ -46,18 +46,6 @@ export function registerRecoveryHandlers({ return ok(null); }); - registerHandle(IPC_CHANNELS.recoveryDismiss, async (_event, payload) => { - const parsed = recoveryTaskSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.belongsToCompany("tasks", parsed.taskId, parsed.companyId)) { - return fail("TASK_NOT_FOUND", "Task not found in the current company."); - } - db.dismissInterruptedTask(parsed.taskId); - publishDomainChanged(); - return ok(null); - }); - registerHandle(IPC_CHANNELS.recoveryFail, async (_event, payload) => { const parsed = recoveryTaskSchema.parse(payload); const companyError = ensureCompanyExists(parsed.companyId); diff --git a/src/main/ipc-thread-handlers.ts b/src/main/ipc-thread-handlers.ts index 2db116c7..32fa6780 100644 --- a/src/main/ipc-thread-handlers.ts +++ b/src/main/ipc-thread-handlers.ts @@ -1,55 +1,13 @@ import { IPC_CHANNELS, - addThreadEventSchema, - addParticipantSchema, - createThreadSchema, - listParticipantsSchema, - listSubscriptionsSchema, - listSubscribedThreadsSchema, listThreadEventsSchema, listThreadWaitStatesSchema, - listThreadsSchema, - removeParticipantSchema, - resolveThreadWaitStateSchema, - setThreadWaitStateSchema, - subscribeThreadSchema, threadGetterSchema, - unsubscribeThreadSchema, } from "@shared/contracts"; import type { RegisterCoreHandlersDependencies } from "./ipc-core-common"; import { fail, ok } from "./ipc-core-common"; -export function registerThreadHandlers({ registerHandle, db, ensureCompanyExists, publishDomainChanged, emitEvent }: RegisterCoreHandlersDependencies) { - registerHandle(IPC_CHANNELS.createThread, async (_event, payload) => { - const input = createThreadSchema.parse(payload); - const companyError = ensureCompanyExists(input.companyId); - if (companyError) return companyError; - const thread = db.createThread({ - companyId: input.companyId, - title: input.title, - type: input.type, - relatedEntityType: input.relatedEntityType ?? null, - relatedEntityId: input.relatedEntityId ?? null, - }); - publishDomainChanged(); - return ok(thread); - }); - - registerHandle(IPC_CHANNELS.listThreads, async (_event, payload) => { - const input = listThreadsSchema.parse(payload); - const companyError = ensureCompanyExists(input.companyId); - if (companyError) return companyError; - const threads = db.listThreads({ - companyId: input.companyId, - type: input.type, - relatedEntityType: input.relatedEntityType, - relatedEntityId: input.relatedEntityId, - limit: input.limit, - offset: input.offset, - }); - return ok(threads); - }); - +export function registerThreadHandlers({ registerHandle, db, ensureCompanyExists }: RegisterCoreHandlersDependencies) { registerHandle(IPC_CHANNELS.getThread, async (_event, payload) => { const input = threadGetterSchema.parse(payload); const companyError = ensureCompanyExists(input.companyId); @@ -59,22 +17,6 @@ export function registerThreadHandlers({ registerHandle, db, ensureCompanyExists return ok(thread); }); - registerHandle(IPC_CHANNELS.addThreadEvent, async (_event, payload) => { - const input = addThreadEventSchema.parse(payload); - const companyError = ensureCompanyExists(input.companyId); - if (companyError) return companyError; - const event = db.addThreadEvent({ - threadId: input.threadId, - actorId: input.actorId, - actorType: input.actorType, - eventType: input.eventType, - body: input.body, - metadataJson: input.metadataJson, - }); - publishDomainChanged(); - return ok(event); - }); - registerHandle(IPC_CHANNELS.listThreadEvents, async (_event, payload) => { const input = listThreadEventsSchema.parse(payload); const companyError = ensureCompanyExists(input.companyId); @@ -86,50 +28,6 @@ export function registerThreadHandlers({ registerHandle, db, ensureCompanyExists return ok(events); }); - registerHandle(IPC_CHANNELS.setThreadWaitState, async (_event, payload) => { - const input = setThreadWaitStateSchema.parse(payload); - const companyError = ensureCompanyExists(input.companyId); - if (companyError) return companyError; - const waitState = db.setThreadWaitState({ - threadId: input.threadId, - companyId: input.companyId, - waitingFor: input.waitingFor, - relatedApprovalId: input.relatedApprovalId ?? null, - reason: input.reason, - }); - publishDomainChanged(); - emitEvent({ - type: "thread-wait-state-updated", - threadId: input.threadId, - companyId: input.companyId, - waitStateId: waitState.id, - action: "created", - }); - return ok(waitState); - }); - - registerHandle(IPC_CHANNELS.resolveThreadWaitState, async (_event, payload) => { - const input = resolveThreadWaitStateSchema.parse(payload); - const companyError = ensureCompanyExists(input.companyId); - if (companyError) return companyError; - - // Query the wait state before resolving to capture its threadId for the event - const waitStates = db.listThreadWaitStates(input.companyId); - const target = waitStates.find((ws) => ws.id === input.waitStateId); - if (!target) return fail("THREAD_WAIT_STATE_NOT_FOUND", "Wait state not found"); - - db.resolveThreadWaitState(input.waitStateId, input.companyId); - publishDomainChanged(); - emitEvent({ - type: "thread-wait-state-updated", - threadId: target.threadId, - companyId: input.companyId, - waitStateId: input.waitStateId, - action: "resolved", - }); - return ok(true); - }); - registerHandle(IPC_CHANNELS.listThreadWaitStates, async (_event, payload) => { const input = listThreadWaitStatesSchema.parse(payload); const companyError = ensureCompanyExists(input.companyId); @@ -137,72 +35,4 @@ export function registerThreadHandlers({ registerHandle, db, ensureCompanyExists const waitStates = db.listThreadWaitStates(input.companyId, { resolvedOnly: input.resolvedOnly }); return ok(waitStates); }); - - registerHandle(IPC_CHANNELS.listParticipants, async (_event, payload) => { - const input = listParticipantsSchema.parse(payload); - const thread = db.getThread(input.threadId, input.companyId); - if (!thread) return fail("THREAD_NOT_FOUND", "Thread not found in this company"); - const participants = db.listParticipants(input.threadId); - return ok(participants); - }); - - registerHandle(IPC_CHANNELS.addParticipant, async (_event, payload) => { - const input = addParticipantSchema.parse(payload); - const thread = db.getThread(input.threadId, input.companyId); - if (!thread) return fail("THREAD_NOT_FOUND", "Thread not found in this company"); - const participant = db.addParticipant({ - threadId: input.threadId, - participantId: input.participantId, - participantType: input.participantType, - role: input.role, - }); - publishDomainChanged(); - return ok(participant); - }); - - registerHandle(IPC_CHANNELS.removeParticipant, async (_event, payload) => { - const input = removeParticipantSchema.parse(payload); - const thread = db.getThread(input.threadId, input.companyId); - if (!thread) return fail("THREAD_NOT_FOUND", "Thread not found in this company"); - db.removeParticipant(input.threadId, input.participantId); - publishDomainChanged(); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.subscribeThread, async (_event, payload) => { - const input = subscribeThreadSchema.parse(payload); - const thread = db.getThread(input.threadId, input.companyId); - if (!thread) return fail("THREAD_NOT_FOUND", "Thread not found in this company"); - const subscription = db.subscribe({ - threadId: input.threadId, - subscriberId: input.subscriberId, - subscriberType: input.subscriberType, - notifyOn: input.notifyOn, - }); - publishDomainChanged(); - return ok(subscription); - }); - - registerHandle(IPC_CHANNELS.unsubscribeThread, async (_event, payload) => { - const input = unsubscribeThreadSchema.parse(payload); - const thread = db.getThread(input.threadId, input.companyId); - if (!thread) return fail("THREAD_NOT_FOUND", "Thread not found in this company"); - db.unsubscribe(input.threadId, input.subscriberId); - publishDomainChanged(); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.listSubscriptions, async (_event, payload) => { - const input = listSubscriptionsSchema.parse(payload); - const thread = db.getThread(input.threadId, input.companyId); - if (!thread) return fail("THREAD_NOT_FOUND", "Thread not found in this company"); - const subscriptions = db.listSubscriptions(input.threadId); - return ok(subscriptions); - }); - - registerHandle(IPC_CHANNELS.listSubscribedThreads, async (_event, payload) => { - const input = listSubscribedThreadsSchema.parse(payload); - const threads = db.listSubscribedThreads(input.subscriberId, input.companyId); - return ok(threads); - }); } diff --git a/src/main/main-runtime-support.ts b/src/main/main-runtime-support.ts index 690085be..08a8bd36 100644 --- a/src/main/main-runtime-support.ts +++ b/src/main/main-runtime-support.ts @@ -2,7 +2,7 @@ import log from "electron-log/main.js"; import type { AgentApiServer } from "./api-server"; import { initializeAgentTokenSigningKey } from "./agent-auth"; import { bootstrapApplication } from "./bootstrap-application"; -import { openConnectorAuthTerminal as openConnectorAuthTerminalImpl, openGenericTerminal as openGenericTerminalImpl } from "./connector-auth-service"; +import { openGenericTerminal as openGenericTerminalImpl } from "./connector-auth-service"; import { getConnectorModelPolicy } from "./connector-model-policy"; import type { ConnectorId } from "@shared/types"; import type { AppDatabase } from "./database"; @@ -145,10 +145,6 @@ export function createMainRuntimeSupport(state: MainRuntimeState) { queueTaskRun: (taskId, trigger, actor) => requireOrchestrationService().queueTaskRun(taskId, trigger, actor), checkConnector: async (id) => requireConnectorHealthService().checkConnector(id), - openConnectorAuthTerminal: async (id) => { - const connector = requireDb().getConnector(id); - return openConnectorAuthTerminalImpl(id, connector.command); - }, openGenericTerminal: (input) => openGenericTerminalImpl(input), checkForUpdates: () => requireUpdaterService().checkForUpdates(), getWorkerProcess: () => requireServiceGraph().getWorkerService()?.getWorker() ?? null, @@ -156,7 +152,6 @@ export function createMainRuntimeSupport(state: MainRuntimeState) { initializeAgentTokenSigningKey(requireDb().profileDir); void requireBrowserActionService().resetBrowserManager(); }, - getApiPort: () => state.apiServer?.port ?? 0, notify: (options) => requireIpcSupport().notify(options), listConnectorModels: async (connectorId) => { const policy = getConnectorModelPolicy(requireDb(), connectorId as ConnectorId); diff --git a/src/main/runtime-env.ts b/src/main/runtime-env.ts deleted file mode 100644 index 886ddac2..00000000 --- a/src/main/runtime-env.ts +++ /dev/null @@ -1,146 +0,0 @@ -const ENV_ALLOWLIST: ReadonlySet = new Set([ - "PATH", - "HOME", - "USER", - "SHELL", - "LANG", - "LC_ALL", - "LC_CTYPE", - "TERM", - "TMPDIR", - "DEVELOPER_DIR", - "SDKROOT", - "NODE_ENV", - "GIT_AUTHOR_NAME", - "GIT_AUTHOR_EMAIL", - "GIT_COMMITTER_NAME", - "GIT_COMMITTER_EMAIL", - "GIT_SSH_COMMAND", - "GIT_ASKPASS", - "GIT_TERMINAL_PROMPT", - "XDG_CONFIG_HOME", - "XDG_DATA_HOME", - "XDG_CACHE_HOME", - "XDG_RUNTIME_DIR", - "DISPLAY", - "WAYLAND_DISPLAY", - "DBUS_SESSION_BUS_ADDRESS", - "APPDATA", - "LOCALAPPDATA", - "USERPROFILE", - "SYSTEMROOT", - "COMSPEC", - "PROGRAMFILES", - "PROGRAMFILES(X86)", - "PROGRAMDATA", - "PATHEXT", - "NODE_EXTRA_CA_CERTS", - "SSL_CERT_FILE", - "SSL_CERT_DIR", - "REQUESTS_CA_BUNDLE", - "CURL_CA_BUNDLE", - "HTTP_PROXY", - "HTTPS_PROXY", - "http_proxy", - "https_proxy", - "ALL_PROXY", - "all_proxy", - "NO_PROXY", - "no_proxy", - "DENO_CERT", - "CARGO_HTTP_CAINFO", - "CARGO_HTTP_PROXY_CAINFO", - "CARGO_HTTP_CHECK_REVOKE", - "AGENT_COMPANY_AGENT_ID", - "AGENT_COMPANY_COMPANY_ID", - "AGENT_COMPANY_API_URL", - "AGENT_COMPANY_API_KEY", - "AGENT_COMPANY_RUN_ID", - "AGENT_COMPANY_TASK_ID", - "AGENT_COMPANY_WAKE_REASON", - "AGENT_COMPANY_WAKE_COMMENT_ID", - "AGENT_COMPANY_APPROVAL_ID", - "AGENT_COMPANY_APPROVAL_STATUS", - "AGENT_COMPANY_WORKSPACE_CWD", - "AGENT_COMPANY_WORKSPACE_SOURCE", - "AGENT_COMPANY_WORKSPACE_STRATEGY", - "AGENT_COMPANY_WORKSPACE_ID", - "AGENT_COMPANY_WORKSPACE_REPO_URL", - "AGENT_COMPANY_WORKSPACE_REPO_REF", - "AGENT_COMPANY_WORKSPACE_BRANCH", - "AGENT_COMPANY_WORKSPACE_WORKTREE_PATH", - "AGENT_COMPANY_WORKSPACES_JSON", - "AGENT_COMPANY_RUNTIME_SERVICE_INTENTS_JSON", - "AGENT_COMPANY_RUNTIME_SERVICES_JSON", - "AGENT_COMPANY_RUNTIME_PRIMARY_URL", - "AGENT_COMPANY_LINKED_ISSUE_IDS", -]); - -const FORBIDDEN_RUNTIME_OVERRIDE_KEYS: ReadonlySet = new Set([ - "PATH", - "HOME", - "USER", - "SHELL", - "NODE_OPTIONS", - "ELECTRON_RUN_AS_NODE", - "DYLD_INSERT_LIBRARIES", - "LD_PRELOAD", - "PWD", -]); - -function normalizeStringEnv(input: NodeJS.ProcessEnv | Record): Record { - return Object.fromEntries( - Object.entries(input).filter((entry): entry is [string, string] => typeof entry[1] === "string"), - ); -} - -export function stripForbiddenRuntimeOverrides(env: Record): Record { - const sanitized: Record = {}; - for (const [key, value] of Object.entries(env)) { - if (FORBIDDEN_RUNTIME_OVERRIDE_KEYS.has(key)) { - continue; - } - sanitized[key] = value; - } - return sanitized; -} - -export function buildSanitizedRuntimeEnv( - hostEnv: NodeJS.ProcessEnv | Record, - runtimeOverrides: Record, -): Record { - const normalizedHostEnv = normalizeStringEnv(hostEnv); - const sanitized: Record = {}; - - if (process.platform === "win32") { - // On Windows, env var keys are case-insensitive but plain JS objects are not. - // Build a case-insensitive lookup so allowlist entries like "PATH" match "Path". - const hostKeyMap = new Map(); - for (const key of Object.keys(normalizedHostEnv)) { - hostKeyMap.set(key.toUpperCase(), key); - } - for (const allowedKey of ENV_ALLOWLIST) { - const actualKey = hostKeyMap.get(allowedKey.toUpperCase()); - if (actualKey && normalizedHostEnv[actualKey]) { - sanitized[allowedKey] = normalizedHostEnv[actualKey]!; - } - } - } else { - for (const key of ENV_ALLOWLIST) { - if (key in normalizedHostEnv) { - sanitized[key] = normalizedHostEnv[key]!; - } - } - } - - // On Windows, many CLI tools (Claude Code, etc.) use HOME to find config directories. - // Windows doesn't set HOME by default — synthesize it from USERPROFILE if missing. - if (process.platform === "win32" && !sanitized.HOME && sanitized.USERPROFILE) { - sanitized.HOME = sanitized.USERPROFILE; - } - - return { - ...sanitized, - ...stripForbiddenRuntimeOverrides(runtimeOverrides), - }; -} diff --git a/src/preload/index.ts b/src/preload/index.ts index a6c5ed1c..007e4bef 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -21,7 +21,6 @@ const api: DesktopApi = { saveTask: (input) => ipcRenderer.invoke(IPC_CHANNELS.saveTask, input), requestApproval: (input) => ipcRenderer.invoke(IPC_CHANNELS.requestApproval, input), decideApproval: (input) => ipcRenderer.invoke(IPC_CHANNELS.decideApproval, input), - saveSecret: (input) => ipcRenderer.invoke(IPC_CHANNELS.saveSecret, input), startTaskRun: (input) => ipcRenderer.invoke(IPC_CHANNELS.startTaskRun, input), cancelRun: (input) => ipcRenderer.invoke(IPC_CHANNELS.cancelRun, input), getRunLog: (input) => ipcRenderer.invoke(IPC_CHANNELS.getRunLog, input), @@ -42,15 +41,11 @@ const api: DesktopApi = { listConnectorModels: (connectorId) => ipcRenderer.invoke(IPC_CHANNELS.listConnectorModels, connectorId), getConnectorDisabledModels: (connectorId) => ipcRenderer.invoke(IPC_CHANNELS.getConnectorDisabledModels, connectorId), setConnectorDisabledModels: (input) => ipcRenderer.invoke(IPC_CHANNELS.setConnectorDisabledModels, input), - openConnectorAuthTerminal: (connectorId) => ipcRenderer.invoke(IPC_CHANNELS.openConnectorAuthTerminal, connectorId), addComment: (input) => ipcRenderer.invoke(IPC_CHANNELS.addComment, input), - listComments: (input) => ipcRenderer.invoke(IPC_CHANNELS.listComments, input), setHeartbeat: (input) => ipcRenderer.invoke(IPC_CHANNELS.setHeartbeat, input), triggerHeartbeat: (input) => ipcRenderer.invoke(IPC_CHANNELS.triggerHeartbeat, input), - getApiPort: () => ipcRenderer.invoke(IPC_CHANNELS.getApiPort), getInbox: (companyId) => ipcRenderer.invoke(IPC_CHANNELS.getInbox, companyId), getCompanyMetrics: (input) => ipcRenderer.invoke(IPC_CHANNELS.getCompanyMetrics, input), - getAgentMetrics: (input) => ipcRenderer.invoke(IPC_CHANNELS.getAgentMetrics, input), getStandupReport: (companyId) => ipcRenderer.invoke(IPC_CHANNELS.getStandupReport, companyId), bootstrapOnboarding: (input) => ipcRenderer.invoke(IPC_CHANNELS.bootstrapOnboarding, input), checkNodeInstalled: () => ipcRenderer.invoke(IPC_CHANNELS.checkNodeInstalled), @@ -73,13 +68,11 @@ const api: DesktopApi = { toggleAutomationRule: (input) => ipcRenderer.invoke(IPC_CHANNELS.toggleAutomationRule, input), getAutomationLog: (companyId) => ipcRenderer.invoke(IPC_CHANNELS.getAutomationLog, companyId), sendAgentMessage: (input) => ipcRenderer.invoke(IPC_CHANNELS.sendAgentMessage, input), - listAgentMessages: (input) => ipcRenderer.invoke(IPC_CHANNELS.listAgentMessages, input), searchMessages: (input) => ipcRenderer.invoke(IPC_CHANNELS.searchMessages, input), markMessageRead: (input) => ipcRenderer.invoke(IPC_CHANNELS.markMessageRead, input), saveWorkflow: (input) => ipcRenderer.invoke(IPC_CHANNELS.saveWorkflow, input), deleteWorkflow: (input) => ipcRenderer.invoke(IPC_CHANNELS.deleteWorkflow, input), runWorkflow: (input) => ipcRenderer.invoke(IPC_CHANNELS.runWorkflow, input), - autoAssignTask: (input) => ipcRenderer.invoke(IPC_CHANNELS.autoAssignTask, input), importSkill: (companyId, source) => ipcRenderer.invoke(IPC_CHANNELS.importSkill, { companyId, source }), listSkills: (companyId) => @@ -100,7 +93,6 @@ const api: DesktopApi = { ipcRenderer.invoke(IPC_CHANNELS.listSkillAgents, { companyId, skillId }), listAgentSkills: (companyId, agentId) => ipcRenderer.invoke(IPC_CHANNELS.listAgentSkills, { companyId, agentId }), - listWakeupRequests: (input) => ipcRenderer.invoke(IPC_CHANNELS.listWakeupRequests, input), saveBudgetPolicy: (input) => ipcRenderer.invoke(IPC_CHANNELS.saveBudgetPolicy, input), deleteBudgetPolicy: (input) => ipcRenderer.invoke(IPC_CHANNELS.deleteBudgetPolicy, input), listBudgetPolicies: (companyId) => ipcRenderer.invoke(IPC_CHANNELS.listBudgetPolicies, { companyId }), @@ -109,40 +101,16 @@ const api: DesktopApi = { getBudgetStatus: (companyId) => ipcRenderer.invoke(IPC_CHANNELS.getBudgetStatus, { companyId }), recoveryRetry: (taskId: string, agentId: string, companyId: string) => ipcRenderer.invoke(IPC_CHANNELS.recoveryRetry, { taskId, agentId, companyId }), - recoveryDismiss: (taskId: string, companyId: string) => - ipcRenderer.invoke(IPC_CHANNELS.recoveryDismiss, { taskId, companyId }), recoveryFail: (taskId: string, companyId: string) => ipcRenderer.invoke(IPC_CHANNELS.recoveryFail, { taskId, companyId }), getTask: (input) => ipcRenderer.invoke(IPC_CHANNELS.getTask, input), getAgent: (input) => ipcRenderer.invoke(IPC_CHANNELS.getAgent, input), getRun: (input) => ipcRenderer.invoke(IPC_CHANNELS.getRun, input), getApproval: (input) => ipcRenderer.invoke(IPC_CHANNELS.getApproval, input), - listRunEvents: (companyId: string, runId: string, opts?: { offset?: number; limit?: number }) => - ipcRenderer.invoke(IPC_CHANNELS.listRunEvents, { companyId, runId, ...opts }), - getHeartbeatPolicy: (agentId: string, companyId: string) => - ipcRenderer.invoke(IPC_CHANNELS.getHeartbeatPolicy, { companyId, agentId }), - setHeartbeatPolicy: (companyId, agentId, policy) => - ipcRenderer.invoke(IPC_CHANNELS.setHeartbeatPolicy, { companyId, agentId, ...policy }), - getRuntimeState: (agentId: string, companyId: string) => - ipcRenderer.invoke(IPC_CHANNELS.getRuntimeState, { companyId, agentId }), - setRuntimeState: (companyId: string, agentId: string, state: Record) => - ipcRenderer.invoke(IPC_CHANNELS.setRuntimeState, { companyId, agentId, state }), - // Thread runtime - createThread: (input) => ipcRenderer.invoke(IPC_CHANNELS.createThread, input), - listThreads: (input) => ipcRenderer.invoke(IPC_CHANNELS.listThreads, input), + // Thread runtime (read-only) getThread: (input) => ipcRenderer.invoke(IPC_CHANNELS.getThread, input), - addThreadEvent: (input) => ipcRenderer.invoke(IPC_CHANNELS.addThreadEvent, input), listThreadEvents: (input) => ipcRenderer.invoke(IPC_CHANNELS.listThreadEvents, input), - setThreadWaitState: (input) => ipcRenderer.invoke(IPC_CHANNELS.setThreadWaitState, input), - resolveThreadWaitState: (input) => ipcRenderer.invoke(IPC_CHANNELS.resolveThreadWaitState, input), listThreadWaitStates: (input) => ipcRenderer.invoke(IPC_CHANNELS.listThreadWaitStates, input), - listParticipants: (input) => ipcRenderer.invoke(IPC_CHANNELS.listParticipants, input), - addParticipant: (input) => ipcRenderer.invoke(IPC_CHANNELS.addParticipant, input), - removeParticipant: (input) => ipcRenderer.invoke(IPC_CHANNELS.removeParticipant, input), - subscribeThread: (input) => ipcRenderer.invoke(IPC_CHANNELS.subscribeThread, input), - unsubscribeThread: (input) => ipcRenderer.invoke(IPC_CHANNELS.unsubscribeThread, input), - listSubscriptions: (input) => ipcRenderer.invoke(IPC_CHANNELS.listSubscriptions, input), - listSubscribedThreads: (input) => ipcRenderer.invoke(IPC_CHANNELS.listSubscribedThreads, input), subscribe: (callback: (event: DesktopEvent) => void) => { const listener = (_event: Electron.IpcRendererEvent, payload: DesktopEvent) => callback(payload); ipcRenderer.on(IPC_CHANNELS.rendererEvent, listener); diff --git a/src/renderer/components/company-onboarding/OnboardingContext.tsx b/src/renderer/components/company-onboarding/OnboardingContext.tsx index 7899fccf..d22cf41f 100644 --- a/src/renderer/components/company-onboarding/OnboardingContext.tsx +++ b/src/renderer/components/company-onboarding/OnboardingContext.tsx @@ -59,7 +59,6 @@ export interface OnboardingConnectorsContextValue { model: string | null, notes?: string, ) => void; - onLoginConnector: (connectorId: string) => void; selectedConnectorId: ConnectorId | ""; setSelectedConnectorId: (value: ConnectorId | "") => void; diff --git a/src/renderer/components/company-onboarding/OnboardingWizard.tsx b/src/renderer/components/company-onboarding/OnboardingWizard.tsx index 308b40ee..cce471dc 100644 --- a/src/renderer/components/company-onboarding/OnboardingWizard.tsx +++ b/src/renderer/components/company-onboarding/OnboardingWizard.tsx @@ -83,7 +83,7 @@ export function CompanyOnboarding({ } }, [step, nodeStatus, checkNode]); - const { handleTestConnector, handleSaveConnector, handleLoginConnector, handleInstallCommand } = + const { handleTestConnector, handleSaveConnector, handleInstallCommand } = useConnectorCallbacks(connectors); const { @@ -208,7 +208,6 @@ export function CompanyOnboarding({ hasAtLeastOneReady, onTestConnector: (id) => void handleTestConnector(id), onSaveConnector: (id, env, model, notes) => void handleSaveConnector(id, env, model, notes), - onLoginConnector: (id) => void handleLoginConnector(id), selectedConnectorId, setSelectedConnectorId, selectedModel, @@ -228,7 +227,6 @@ export function CompanyOnboarding({ hasAtLeastOneReady, handleTestConnector, handleSaveConnector, - handleLoginConnector, selectedConnectorId, setSelectedConnectorId, selectedModel, diff --git a/src/renderer/components/company-onboarding/useConnectorCallbacks.ts b/src/renderer/components/company-onboarding/useConnectorCallbacks.ts index 62bfe8b9..16ce3a52 100644 --- a/src/renderer/components/company-onboarding/useConnectorCallbacks.ts +++ b/src/renderer/components/company-onboarding/useConnectorCallbacks.ts @@ -36,30 +36,6 @@ export function useConnectorCallbacks(connectors: ProfileSnapshot["connectors"]) } }, [connectors]); - const handleLoginConnector = useCallback(async (connectorId: string) => { - try { - unwrap(await window.agentCompany.openConnectorAuthTerminal(connectorId as ConnectorId)); - } catch (error) { - console.warn( - `[onboarding/useConnectorCallbacks] openConnectorAuthTerminal(${connectorId}) failed: ${error instanceof Error ? error.message : String(error)}`, - ); - return; - } - // Poll connector health after login terminal opens (same pattern as ConnectorEditor) - let attempts = 0; - const poll = setInterval(async () => { - attempts++; - if (attempts > 12) { clearInterval(poll); return; } - try { - unwrap(await window.agentCompany.testConnector(connectorId as ConnectorId)); - } catch (error) { - console.warn( - `[onboarding/useConnectorCallbacks] post-login testConnector(${connectorId}) failed (attempt ${attempts}): ${error instanceof Error ? error.message : String(error)}`, - ); - } - }, 5000); - }, []); - const handleInstallCommand = useCallback(async (commandKey: z.infer["commandKey"]) => { try { unwrap(await window.agentCompany.openTerminalCommand({ commandKey })); @@ -88,5 +64,5 @@ export function useConnectorCallbacks(connectors: ProfileSnapshot["connectors"]) }, 5000); }, [connectors]); - return { handleTestConnector, handleSaveConnector, handleLoginConnector, handleInstallCommand }; + return { handleTestConnector, handleSaveConnector, handleInstallCommand }; } diff --git a/src/renderer/i18n/en.ts b/src/renderer/i18n/en.ts index 286bb0ba..2420161b 100644 --- a/src/renderer/i18n/en.ts +++ b/src/renderer/i18n/en.ts @@ -39,10 +39,7 @@ export const en: Record = { "app.selectCompany": "Select company", "app.newCompany": "New company", "app.commandPalette": "Command palette", - "app.refresh": "Refresh", - "app.console": "Console", "app.collapse": "Collapse", - "app.expand": "Expand", "app.noResults": "No results for", "app.clear": "Clear", "app.search": "Search sections, agents, tasks, goals, projects...", @@ -358,9 +355,6 @@ export const en: Record = { "costs.recentEntries": "Recent cost entries", "costs.budgetPosture": "Budget posture", - // ── Activity page ── - "activity.timeline": "Activity timeline", - // ── Workspaces page ── "workspaces.registry": "Workspace registry", "workspaces.controlCenter": "Workspace control center", @@ -815,7 +809,6 @@ export const en: Record = { "auto.newRuleTitle": "New Automation Rule", "auto.ruleName": "Rule Name", "auto.ruleDescription": "Description", - "auto.trigger": "Trigger", "auto.conditionsJson": "Conditions (JSON)", "auto.action": "Action", "auto.actionConfigJson": "Action Configuration (JSON)", diff --git a/src/renderer/i18n/zh.ts b/src/renderer/i18n/zh.ts index 78c33bf6..9ae47818 100644 --- a/src/renderer/i18n/zh.ts +++ b/src/renderer/i18n/zh.ts @@ -39,10 +39,7 @@ export const zh: Record = { "app.selectCompany": "选择公司", "app.newCompany": "新建公司", "app.commandPalette": "命令面板", - "app.refresh": "刷新", - "app.console": "控制台", "app.collapse": "收起", - "app.expand": "展开", "app.noResults": "未找到匹配结果", "app.clear": "清除", "app.search": "搜索版块、智能体、任务、目标、项目...", @@ -358,9 +355,6 @@ export const zh: Record = { "costs.recentEntries": "近期费用", "costs.budgetPosture": "预算概况", - // ── 活动页面 ── - "activity.timeline": "活动时间线", - // ── 工作区页面 ── "workspaces.registry": "工作区注册表", "workspaces.controlCenter": "工作区控制中心", @@ -815,7 +809,6 @@ export const zh: Record = { "auto.newRuleTitle": "新建自动化规则", "auto.ruleName": "规则名称", "auto.ruleDescription": "描述", - "auto.trigger": "触发器", "auto.conditionsJson": "条件(JSON)", "auto.action": "动作", "auto.actionConfigJson": "动作配置(JSON)", diff --git a/src/renderer/styles.css b/src/renderer/styles.css index 67876f46..e6172f38 100644 --- a/src/renderer/styles.css +++ b/src/renderer/styles.css @@ -207,48 +207,6 @@ transition: max-width 200ms cubic-bezier(0.16, 1, 0.3, 1); } -/* Dashboard activity row entry motion */ -@keyframes dashboard-activity-enter { - 0% { - opacity: 0; - transform: translateY(-14px) scale(0.985); - filter: blur(4px); - } - 62% { - opacity: 1; - transform: translateY(2px) scale(1.002); - filter: blur(0); - } - 100% { - opacity: 1; - transform: translateY(0) scale(1); - filter: blur(0); - } -} - -@keyframes dashboard-activity-highlight { - 0% { - box-shadow: inset 2px 0 0 var(--primary); - background-color: color-mix(in oklab, var(--accent) 55%, transparent); - } - 100% { - box-shadow: inset 0 0 0 transparent; - background-color: transparent; - } -} - -.activity-row-enter { - animation: - dashboard-activity-enter 520ms cubic-bezier(0.16, 1, 0.3, 1), - dashboard-activity-highlight 920ms cubic-bezier(0.16, 1, 0.3, 1); -} - -@media (prefers-reduced-motion: reduce) { - .activity-row-enter { - animation: none; - } -} - /* MDXEditor theme integration */ .paperclip-mdxeditor-scope, .paperclip-mdxeditor { diff --git a/src/shared/contracts/channels.ts b/src/shared/contracts/channels.ts index 63b1ea55..69a1fd8f 100644 --- a/src/shared/contracts/channels.ts +++ b/src/shared/contracts/channels.ts @@ -14,7 +14,6 @@ export const IPC_CHANNELS = { saveTask: "agent-company:save-task", requestApproval: "agent-company:request-approval", decideApproval: "agent-company:decide-approval", - saveSecret: "agent-company:save-secret", startTaskRun: "agent-company:start-task-run", cancelRun: "agent-company:cancel-run", getRunLog: "agent-company:get-run-log", @@ -33,16 +32,12 @@ export const IPC_CHANNELS = { deleteSecret: "agent-company:delete-secret", getSidebarBadges: "agent-company:get-sidebar-badges", listConnectorModels: "agent-company:list-connector-models", - openConnectorAuthTerminal: "agent-company:open-connector-auth-terminal", addComment: "agent-company:add-comment", - listComments: "agent-company:list-comments", setHeartbeat: "agent-company:set-heartbeat", triggerHeartbeat: "agent-company:trigger-heartbeat", - getApiPort: "agent-company:get-api-port", rendererEvent: "agent-company:event", getInbox: "agent-company:get-inbox", getCompanyMetrics: "agent-company:get-company-metrics", - getAgentMetrics: "agent-company:get-agent-metrics", getStandupReport: "agent-company:get-standup-report", bootstrapOnboarding: "agent-company:bootstrap-onboarding", checkNodeInstalled: "agent-company:check-node-installed", @@ -65,12 +60,10 @@ export const IPC_CHANNELS = { toggleAutomationRule: "agent-company:toggle-automation-rule", getAutomationLog: "agent-company:get-automation-log", sendAgentMessage: "agent-company:send-agent-message", - listAgentMessages: "agent-company:list-agent-messages", markMessageRead: "agent-company:mark-message-read", saveWorkflow: "agent-company:save-workflow", deleteWorkflow: "agent-company:delete-workflow", runWorkflow: "agent-company:run-workflow", - autoAssignTask: "agent-company:auto-assign-task", searchMessages: "agent-company:search-messages", importSkill: "agent-company:import-skill", listSkills: "agent-company:list-skills", @@ -82,7 +75,6 @@ export const IPC_CHANNELS = { checkSkillUpdate: "agent-company:check-skill-update", listSkillAgents: "agent-company:list-skill-agents", listAgentSkills: "agent-company:list-agent-skills", - listWakeupRequests: "agent-company:list-wakeup-requests", saveBudgetPolicy: "agent-company:save-budget-policy", deleteBudgetPolicy: "agent-company:delete-budget-policy", listBudgetPolicies: "agent-company:list-budget-policies", @@ -97,32 +89,11 @@ export const IPC_CHANNELS = { setConnectorDisabledModels: "agent-company:set-connector-disabled-models", // Recovery recoveryRetry: "recovery:retry", - recoveryDismiss: "recovery:dismiss", recoveryFail: "recovery:fail", - // Run events - listRunEvents: "agent-company:list-run-events", - // Heartbeat policy - getHeartbeatPolicy: "agent-company:get-heartbeat-policy", - setHeartbeatPolicy: "agent-company:set-heartbeat-policy", - // Runtime state - getRuntimeState: "agent-company:get-runtime-state", - setRuntimeState: "agent-company:set-runtime-state", - // Thread runtime - createThread: "agent-company:create-thread", - listThreads: "agent-company:list-threads", + // Thread runtime (read-only — writes happen inside the backend) getThread: "agent-company:get-thread", - addThreadEvent: "agent-company:add-thread-event", listThreadEvents: "agent-company:list-thread-events", - setThreadWaitState: "agent-company:set-thread-wait-state", - resolveThreadWaitState: "agent-company:resolve-thread-wait-state", listThreadWaitStates: "agent-company:list-thread-wait-states", - listParticipants: "agent-company:list-participants", - addParticipant: "agent-company:add-participant", - removeParticipant: "agent-company:remove-participant", - subscribeThread: "agent-company:subscribe-thread", - unsubscribeThread: "agent-company:unsubscribe-thread", - listSubscriptions: "agent-company:list-subscriptions", - listSubscribedThreads: "agent-company:list-subscribed-threads", windowMinimize: "window:minimize", windowMaximize: "window:maximize", windowClose: "window:close", diff --git a/src/shared/contracts/desktop-api/agents.ts b/src/shared/contracts/desktop-api/agents.ts index 20db9f99..8af94cff 100644 --- a/src/shared/contracts/desktop-api/agents.ts +++ b/src/shared/contracts/desktop-api/agents.ts @@ -1,20 +1,15 @@ import type { z } from "zod"; -import type { AgentMetrics, AgentRecord } from "../../types"; +import type { AgentRecord } from "../../types"; import type { agentInputSchema, heartbeatSettingsSchema, hireRequestSchema, triggerHeartbeatSchema } from "../schemas-agents"; -import type { entityGetterSchema, metricsQuerySchema } from "../schemas-badges"; +import type { entityGetterSchema } from "../schemas-badges"; import type { deleteEntitySchema } from "../schemas-badges"; -import type { DesktopResult, HeartbeatPolicy } from "./common"; +import type { DesktopResult } from "./common"; export type AgentsApi = { saveAgent: (input: z.infer) => Promise>; requestHire: (input: z.infer) => Promise>; deleteAgent: (input: z.infer) => Promise>; getAgent: (input: z.infer) => Promise>; - getAgentMetrics: (input: z.infer) => Promise>; setHeartbeat: (input: z.infer) => Promise>; triggerHeartbeat: (input: z.infer) => Promise>; - getHeartbeatPolicy: (agentId: string, companyId: string) => Promise>; - setHeartbeatPolicy: (companyId: string, agentId: string, policy: Partial) => Promise>; - getRuntimeState: (agentId: string, companyId: string) => Promise>>; - setRuntimeState: (companyId: string, agentId: string, state: Record) => Promise>; }; diff --git a/src/shared/contracts/desktop-api/automation.ts b/src/shared/contracts/desktop-api/automation.ts index 2566aeaf..96c5241e 100644 --- a/src/shared/contracts/desktop-api/automation.ts +++ b/src/shared/contracts/desktop-api/automation.ts @@ -4,7 +4,6 @@ import type { automationRuleInputSchema, toggleAutomationRuleSchema } from "../s import type { browserActionQuerySchema, cancelBrowserActionSchema, openTerminalCommandSchema, runWorkflowSchema, triggerBrowserLoginSchema, workflowInputSchema } from "../schemas-execution"; import type { socialAccountInputSchema } from "../schemas-company"; import type { deleteEntitySchema } from "../schemas-badges"; -import type { wakeupQuerySchema, WakeupRequestRecord } from "../schemas-wakeup"; import type { DesktopResult } from "./common"; export type AutomationApi = { @@ -15,7 +14,6 @@ export type AutomationApi = { saveWorkflow: (input: z.infer) => Promise>; deleteWorkflow: (input: z.infer) => Promise>; runWorkflow: (input: z.infer) => Promise>; - listWakeupRequests: (input: z.infer) => Promise>; saveSocialAccount: (input: z.infer) => Promise>; deleteSocialAccount: (input: z.infer) => Promise>; listBrowserActions: (input: z.infer) => Promise>; diff --git a/src/shared/contracts/desktop-api/communication.ts b/src/shared/contracts/desktop-api/communication.ts index f89c6223..0fa30e62 100644 --- a/src/shared/contracts/desktop-api/communication.ts +++ b/src/shared/contracts/desktop-api/communication.ts @@ -1,12 +1,11 @@ import type { z } from "zod"; -import type { AgentMessageRecord, CommentRecord, DocumentRecord, KnowledgeEntryRecord } from "../../types"; -import type { agentMessageInputSchema, commentInputSchema, documentInputSchema, knowledgeEntryInputSchema, listCommentsSchema, markMessageReadSchema, meetingInputSchema, messageQuerySchema, searchMessagesSchema } from "../schemas-messages"; +import type { AgentMessageRecord, DocumentRecord, KnowledgeEntryRecord } from "../../types"; +import type { agentMessageInputSchema, commentInputSchema, documentInputSchema, knowledgeEntryInputSchema, markMessageReadSchema, meetingInputSchema, searchMessagesSchema } from "../schemas-messages"; import type { deleteEntitySchema } from "../schemas-badges"; import type { DesktopResult } from "./common"; export type CommunicationApi = { addComment: (input: z.infer) => Promise>; - listComments: (input: z.infer) => Promise>; saveMeeting: (input: z.infer) => Promise>; deleteMeeting: (input: z.infer) => Promise>; saveDocument: (input: z.infer) => Promise>; @@ -14,7 +13,6 @@ export type CommunicationApi = { saveKnowledgeEntry: (input: z.infer) => Promise>; deleteKnowledgeEntry: (input: z.infer) => Promise>; sendAgentMessage: (input: z.infer) => Promise>; - listAgentMessages: (input: z.infer) => Promise>; markMessageRead: (input: z.infer) => Promise>; searchMessages: (input: z.infer) => Promise>; // Keep reference to silence unused-import checker for DocumentRecord/KnowledgeEntryRecord — consumers infer via schemas. diff --git a/src/shared/contracts/desktop-api/companies.ts b/src/shared/contracts/desktop-api/companies.ts index 70b91d75..b47a9282 100644 --- a/src/shared/contracts/desktop-api/companies.ts +++ b/src/shared/contracts/desktop-api/companies.ts @@ -19,8 +19,6 @@ export type CompaniesApi = { listConnectorModels: (connectorId: string) => Promise>>; getConnectorDisabledModels: (connectorId: string) => Promise>>; setConnectorDisabledModels: (input: z.infer) => Promise>; - openConnectorAuthTerminal: (connectorId: z.infer) => Promise>; - getApiPort: () => Promise>; getInbox: (companyId: string) => Promise>; getCompanyMetrics: (input: z.infer) => Promise>; getStandupReport: (companyId: string) => Promise>; diff --git a/src/shared/contracts/desktop-api/credentials.ts b/src/shared/contracts/desktop-api/credentials.ts index b79c3fba..0d5cade6 100644 --- a/src/shared/contracts/desktop-api/credentials.ts +++ b/src/shared/contracts/desktop-api/credentials.ts @@ -1,6 +1,5 @@ -import type { z } from "zod"; -import type { secretInputSchema } from "../schemas-company"; import type { deleteEntitySchema } from "../schemas-badges"; +import type { z } from "zod"; import type { CredentialSummary, SaveCredentialInput, @@ -13,7 +12,6 @@ import type { import type { DesktopResult } from "./common"; export type CredentialsApi = { - saveSecret: (input: z.infer) => Promise>; deleteSecret: (input: z.infer) => Promise>; // pi-mono credentials listCredentials: () => Promise>; diff --git a/src/shared/contracts/desktop-api/runs.ts b/src/shared/contracts/desktop-api/runs.ts index 39d318a1..c5ec1e62 100644 --- a/src/shared/contracts/desktop-api/runs.ts +++ b/src/shared/contracts/desktop-api/runs.ts @@ -2,7 +2,7 @@ import type { z } from "zod"; import type { RunLogChunk, RunRecord } from "../../types"; import type { cancelRunSchema, runLogChunkSchema, runLogSchema, startRunSchema } from "../schemas-execution"; import type { entityGetterSchema } from "../schemas-badges"; -import type { DesktopResult, RunEventRecord } from "./common"; +import type { DesktopResult } from "./common"; export type RunsApi = { startTaskRun: (input: z.infer) => Promise>; @@ -10,8 +10,6 @@ export type RunsApi = { getRunLog: (input: z.infer) => Promise>; getRunLogChunk: (input: z.infer) => Promise>; getRun: (input: z.infer) => Promise>; - listRunEvents: (companyId: string, runId: string, opts?: { offset?: number; limit?: number }) => Promise>; recoveryRetry: (taskId: string, agentId: string, companyId: string) => Promise>; - recoveryDismiss: (taskId: string, companyId: string) => Promise>; recoveryFail: (taskId: string, companyId: string) => Promise>; }; diff --git a/src/shared/contracts/desktop-api/tasks.ts b/src/shared/contracts/desktop-api/tasks.ts index 24639c92..862f1f24 100644 --- a/src/shared/contracts/desktop-api/tasks.ts +++ b/src/shared/contracts/desktop-api/tasks.ts @@ -1,6 +1,6 @@ import type { z } from "zod"; import type { TaskRecord } from "../../types"; -import type { autoAssignSchema, goalInputSchema, projectInputSchema, sprintInputSchema, taskInputSchema } from "../schemas-tasks"; +import type { goalInputSchema, projectInputSchema, sprintInputSchema, taskInputSchema } from "../schemas-tasks"; import type { workspaceInputSchema } from "../schemas-company"; import type { deleteEntitySchema, entityGetterSchema } from "../schemas-badges"; import type { DesktopResult, SaveTaskResult } from "./common"; @@ -17,5 +17,4 @@ export type TasksApi = { deleteWorkspace: (input: z.infer) => Promise>; deleteSprint: (input: z.infer) => Promise>; getTask: (input: z.infer) => Promise>; - autoAssignTask: (input: z.infer) => Promise>; }; diff --git a/src/shared/contracts/desktop-api/threads.ts b/src/shared/contracts/desktop-api/threads.ts index 28212698..39fe5fb8 100644 --- a/src/shared/contracts/desktop-api/threads.ts +++ b/src/shared/contracts/desktop-api/threads.ts @@ -1,24 +1,10 @@ import type { z } from "zod"; -import type { ConversationEventRecord, ConversationParticipantRecord, ConversationThreadRecord, ThreadSubscriptionRecord, ThreadWaitStateRecord } from "../../types"; -import type { addThreadEventSchema, createThreadSchema, listThreadEventsSchema, listThreadsSchema, listThreadWaitStatesSchema, resolveThreadWaitStateSchema, setThreadWaitStateSchema, threadGetterSchema } from "../schemas-threads"; -import type { addParticipantSchema, listParticipantsSchema, removeParticipantSchema } from "../schemas-participants"; -import type { listSubscribedThreadsSchema, listSubscriptionsSchema, subscribeThreadSchema, unsubscribeThreadSchema } from "../schemas-subscriptions"; +import type { ConversationEventRecord, ConversationThreadRecord, ThreadWaitStateRecord } from "../../types"; +import type { listThreadEventsSchema, listThreadWaitStatesSchema, threadGetterSchema } from "../schemas-threads"; import type { DesktopResult } from "./common"; export type ThreadsApi = { - createThread: (input: z.infer) => Promise>; - listThreads: (input: z.infer) => Promise>; getThread: (input: z.infer) => Promise>; - addThreadEvent: (input: z.infer) => Promise>; listThreadEvents: (input: z.infer) => Promise>; - setThreadWaitState: (input: z.infer) => Promise>; - resolveThreadWaitState: (input: z.infer) => Promise>; listThreadWaitStates: (input: z.infer) => Promise>; - listParticipants: (input: z.infer) => Promise>; - addParticipant: (input: z.infer) => Promise>; - removeParticipant: (input: z.infer) => Promise>; - subscribeThread: (input: z.infer) => Promise>; - unsubscribeThread: (input: z.infer) => Promise>; - listSubscriptions: (input: z.infer) => Promise>; - listSubscribedThreads: (input: z.infer) => Promise>; }; diff --git a/src/shared/contracts/schemas-heartbeat.ts b/src/shared/contracts/schemas-heartbeat.ts deleted file mode 100644 index 3a972c0e..00000000 --- a/src/shared/contracts/schemas-heartbeat.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { z } from "zod"; - -export const heartbeatPolicySchema = z.object({ - companyId: z.string().min(1), - agentId: z.string().min(1), -}); - -export const setHeartbeatPolicySchema = z.object({ - companyId: z.string().min(1), - agentId: z.string().min(1), - enabled: z.boolean().optional(), - intervalSec: z.number().optional(), - cooldownSec: z.number().optional(), - maxConcurrentRuns: z.number().optional(), - wakeOnDemand: z.boolean().optional(), -}); diff --git a/src/shared/contracts/schemas-misc.ts b/src/shared/contracts/schemas-misc.ts index 28345d79..5138bad3 100644 --- a/src/shared/contracts/schemas-misc.ts +++ b/src/shared/contracts/schemas-misc.ts @@ -3,10 +3,4 @@ export * from "./schemas-badges"; export * from "./schemas-automation"; export * from "./schemas-budget"; -export * from "./schemas-wakeup"; -export * from "./schemas-run-events"; -export * from "./schemas-heartbeat"; -export * from "./schemas-runtime-state"; export * from "./schemas-threads"; -export * from "./schemas-participants"; -export * from "./schemas-subscriptions"; diff --git a/src/shared/contracts/schemas-participants.ts b/src/shared/contracts/schemas-participants.ts deleted file mode 100644 index 84ac1633..00000000 --- a/src/shared/contracts/schemas-participants.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { z } from "zod"; - -export const listParticipantsSchema = z.object({ - threadId: z.string().uuid(), - companyId: z.string().uuid(), -}); - -export const addParticipantSchema = z.object({ - threadId: z.string().uuid(), - companyId: z.string().uuid(), - participantId: z.string(), - participantType: z.enum(["agent", "user", "system"]), - role: z.enum(["owner", "member", "observer"]).default("member"), -}); - -export const removeParticipantSchema = z.object({ - threadId: z.string().uuid(), - companyId: z.string().uuid(), - participantId: z.string(), -}); diff --git a/src/shared/contracts/schemas-run-events.ts b/src/shared/contracts/schemas-run-events.ts deleted file mode 100644 index c78a1861..00000000 --- a/src/shared/contracts/schemas-run-events.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { z } from "zod"; - -export const listRunEventsSchema = z.object({ - companyId: z.string().min(1), - runId: z.string().min(1), - offset: z.number().optional(), - limit: z.number().optional(), -}); diff --git a/src/shared/contracts/schemas-runtime-state.ts b/src/shared/contracts/schemas-runtime-state.ts deleted file mode 100644 index c6355a9f..00000000 --- a/src/shared/contracts/schemas-runtime-state.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { z } from "zod"; - -export const runtimeStateSchema = z.object({ - companyId: z.string().min(1), - agentId: z.string().min(1), -}); - -export const setRuntimeStateSchema = z.object({ - companyId: z.string().min(1), - agentId: z.string().min(1), - state: z.record(z.string(), z.unknown()), -}); diff --git a/src/shared/contracts/schemas-subscriptions.ts b/src/shared/contracts/schemas-subscriptions.ts deleted file mode 100644 index 59ae2eb1..00000000 --- a/src/shared/contracts/schemas-subscriptions.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { z } from "zod"; - -export const subscribeThreadSchema = z.object({ - threadId: z.string().uuid(), - companyId: z.string().uuid(), - subscriberId: z.string(), - subscriberType: z.enum(["agent", "user", "system"]), - notifyOn: z.enum(["all", "mentions", "none"]).default("all"), -}); - -export const unsubscribeThreadSchema = z.object({ - threadId: z.string().uuid(), - companyId: z.string().uuid(), - subscriberId: z.string(), -}); - -export const listSubscriptionsSchema = z.object({ - threadId: z.string().uuid(), - companyId: z.string().uuid(), -}); - -export const listSubscribedThreadsSchema = z.object({ - subscriberId: z.string(), - companyId: z.string().uuid(), -}); diff --git a/src/shared/contracts/schemas-threads.ts b/src/shared/contracts/schemas-threads.ts index 7139b065..8478cbe6 100644 --- a/src/shared/contracts/schemas-threads.ts +++ b/src/shared/contracts/schemas-threads.ts @@ -1,37 +1,10 @@ import { z } from "zod"; -export const createThreadSchema = z.object({ - companyId: z.string().uuid(), - title: z.string().min(1).max(200), - type: z.enum(["task", "approval", "general", "announcement"]), - relatedEntityType: z.string().nullable().optional(), - relatedEntityId: z.string().nullable().optional(), -}); - -export const listThreadsSchema = z.object({ - companyId: z.string().uuid(), - type: z.enum(["task", "approval", "general", "announcement"]).optional(), - relatedEntityType: z.string().optional(), - relatedEntityId: z.string().optional(), - limit: z.number().int().min(1).max(100).default(50), - offset: z.number().int().min(0).default(0), -}); - export const threadGetterSchema = z.object({ companyId: z.string().uuid(), threadId: z.string().uuid(), }); -export const addThreadEventSchema = z.object({ - companyId: z.string().uuid(), - threadId: z.string().uuid(), - actorId: z.string().min(1), - actorType: z.enum(["agent", "user", "system"]), - eventType: z.enum(["message", "status_change", "approval_request", "approval_decision", "file_attachment", "system_note"]), - body: z.string().default(""), - metadataJson: z.string().default("{}"), -}); - export const listThreadEventsSchema = z.object({ companyId: z.string().uuid(), threadId: z.string().uuid(), @@ -39,19 +12,6 @@ export const listThreadEventsSchema = z.object({ offset: z.number().int().min(0).default(0), }); -export const setThreadWaitStateSchema = z.object({ - companyId: z.string().uuid(), - threadId: z.string().uuid(), - waitingFor: z.enum(["user_review", "user_approval", "user_reply"]), - relatedApprovalId: z.string().nullable().optional(), - reason: z.string().min(1).max(500), -}); - -export const resolveThreadWaitStateSchema = z.object({ - companyId: z.string().uuid(), - waitStateId: z.string().uuid(), -}); - export const listThreadWaitStatesSchema = z.object({ companyId: z.string().uuid(), resolvedOnly: z.boolean().default(false), diff --git a/src/shared/contracts/schemas-wakeup.ts b/src/shared/contracts/schemas-wakeup.ts deleted file mode 100644 index a16e2b8a..00000000 --- a/src/shared/contracts/schemas-wakeup.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { z } from "zod"; - -export const wakeupQuerySchema = z.object({ - companyId: z.string().uuid(), - status: z.enum(["queued", "claimed", "coalesced", "deferred", "completed"]).optional(), - agentId: z.string().uuid().optional(), - limit: z.number().int().min(1).max(100).default(50), -}); - -export interface WakeupRequestRecord { - id: string; - companyId: string; - agentId: string; - source: string; - triggerDetail: string | null; - status: string; - coalescedCount: number; - runId: string | null; - requestedAt: string; - claimedAt: string | null; - finishedAt: string | null; - createdAt: string; - updatedAt: string; -} diff --git a/tests/unit/company-mode-switch.test.ts b/tests/unit/company-mode-switch.test.ts index 11a228c1..2bbde445 100644 --- a/tests/unit/company-mode-switch.test.ts +++ b/tests/unit/company-mode-switch.test.ts @@ -128,7 +128,6 @@ describe("company mode switching", () => { threadIntegration.onApprovalResolved(resolvedApprovalId, resolvedCompanyId, decision); }, checkConnector: vi.fn(), - openConnectorAuthTerminal: vi.fn(), openGenericTerminal: vi.fn(), }); diff --git a/tests/unit/ipc-core-admin-handlers.test.ts b/tests/unit/ipc-core-admin-handlers.test.ts index 8c01aeb2..d4f1fca0 100644 --- a/tests/unit/ipc-core-admin-handlers.test.ts +++ b/tests/unit/ipc-core-admin-handlers.test.ts @@ -47,7 +47,6 @@ describe("ipc-core-admin-handlers connector saves", () => { publishDomainChanged: vi.fn(), handleApprovalResolved: vi.fn(), checkConnector: vi.fn(), - openConnectorAuthTerminal: vi.fn(), openGenericTerminal: vi.fn(), });