Promote AgentCompany-New to the repository root and retire the old app

The legacy application - its src, tests, landing site, promo assets, docs,
release tooling, CI workflows, and root configs - leaves the tree; it stays
reachable in history. Everything under AgentCompany-New moves up unchanged:
same package name, so the production userData/database path is untouched,
and e2e/build scripts already resolved paths relative to the project. The
developer cred.txt stays gitignored at its new location. Full verify:ci
passes from the new root.
This commit is contained in:
ZacharyZhang-NY committed 2026-07-07 00:04:13 -04:00
1 parent 2350f744e3
commit 07d0b4587d
1904 files changed
+1133 -282075

No files matched your search

-140
View File
@@ -1,140 +0,0 @@
export interface ApprovalDocumentReference {
id: string
title?: string
type?: string
}
export type ApprovalPayloadInspection =
| { kind: "empty" }
| { kind: "ok"; payload: Record<string, unknown> }
| { kind: "malformed"; reason: string }
/**
* Inspect an approval payloadJson and classify it. Unlike the tolerant
* extractors (which collapse malformed rows to "no attachments"), this
* returns an explicit "malformed" signal so the inspector can surface a
* dignified error card instead of rendering as if nothing was attached.
*
* The HTTP route + file_approval tool both reject malformed payloads at
* write time via mergeApprovalAttachments. This detector exists for the
* read path, where a legacy row with a broken payload could otherwise
* silently render as empty.
*/
export function inspectApprovalPayload(payloadJson: string | null | undefined): ApprovalPayloadInspection {
if (payloadJson == null || payloadJson.length === 0) return { kind: "empty" }
let parsed: unknown
try {
parsed = JSON.parse(payloadJson)
} catch (error) {
const detail = error instanceof Error ? error.message : String(error)
return { kind: "malformed", reason: `payloadJson is not valid JSON (${detail})` }
}
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
const actual = Array.isArray(parsed) ? "array" : parsed === null ? "null" : typeof parsed
return { kind: "malformed", reason: `payloadJson must be a JSON object (got ${actual})` }
}
return { kind: "ok", payload: parsed as Record<string, unknown> }
}
function parsePayload(payloadJson: string | null): Record<string, unknown> | null {
if (!payloadJson) return null
try {
const parsed = JSON.parse(payloadJson)
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
? parsed as Record<string, unknown>
: null
} catch {
return null
}
}
/**
* Extract document references from an approval's persisted payloadJson.
*
* Priority order (canonical → legacy), with later sources providing
* enrichment only for ids introduced by earlier sources:
* 1. payload.documentIds — canonical schema top-level field (written by
* mergeApprovalAttachments). This is the authoritative id set.
* 2. payload.documentId / documentTitle / documentType — singular legacy
* shape; kept for back-compat with old rows.
* 3. payload.documents[] — legacy rich shape; used to enrich title/type
* metadata on ids already present from the canonical list, and to
* contribute ids that pre-date the canonical field.
*/
export function extractApprovalDocumentReferences(payloadJson: string | null): ApprovalDocumentReference[] {
const payload = parsePayload(payloadJson)
if (!payload) return []
const refs = new Map<string, ApprovalDocumentReference>()
const addId = (id: unknown) => {
if (typeof id !== "string" || id.length === 0) return
if (!refs.has(id)) refs.set(id, { id })
}
const enrich = (id: unknown, title?: unknown, type?: unknown) => {
if (typeof id !== "string" || id.length === 0) return
const prior = refs.get(id) ?? { id }
refs.set(id, {
id,
title: prior.title ?? (typeof title === "string" && title.length > 0 ? title : undefined),
type: prior.type ?? (typeof type === "string" && type.length > 0 ? type : undefined),
})
}
// 1. Canonical top-level list first — establishes the authoritative ids.
const documentIds = payload.documentIds
if (Array.isArray(documentIds)) {
for (const entry of documentIds) addId(entry)
}
// 2. Legacy singular shape.
enrich(payload.documentId, payload.documentTitle, payload.documentType)
// 3. Legacy rich shape — enriches metadata on canonical ids and adds
// ids that only ever lived in the legacy form.
const documents = payload.documents
if (Array.isArray(documents)) {
for (const entry of documents) {
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue
const record = entry as Record<string, unknown>
enrich(record.id, record.title, record.type)
}
}
return [...refs.values()]
}
export function extractApprovalDocumentIds(payloadJson: string | null): string[] {
return extractApprovalDocumentReferences(payloadJson).map((entry) => entry.id)
}
/**
* Mirror of extractApprovalDocumentReferences for work products. Work products
* are filesystem-backed (or URL-backed) artifacts — the board inspector opens
* them via the OS default handler rather than editing them inline.
*
* Canonical source is payload.workProductIds (schema top-level, folded in by
* mergeApprovalAttachments). Legacy payload.workProducts[] is still read for
* back-compat but new callers must not write it.
*/
export function extractApprovalWorkProductIds(payloadJson: string | null): string[] {
const payload = parsePayload(payloadJson)
if (!payload) return []
const out = new Set<string>()
// Canonical first.
const workProductIds = payload.workProductIds
if (Array.isArray(workProductIds)) {
for (const entry of workProductIds) {
if (typeof entry === "string" && entry.length > 0) out.add(entry)
}
}
// Legacy rich shape; back-compat only.
const workProducts = payload.workProducts
if (Array.isArray(workProducts)) {
for (const entry of workProducts) {
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue
const record = entry as Record<string, unknown>
if (typeof record.id === "string" && record.id.length > 0) out.add(record.id)
}
}
return [...out]
}
+10
View File
@@ -0,0 +1,10 @@
export interface AuditReplayRunRecord {
id: string;
orgId: string;
threadId: string;
eventCount: number;
eventDigest: string;
replayJson: string;
createdByEmployeeId: string | null;
createdAt: string;
}
+41
View File
@@ -0,0 +1,41 @@
export const CHAT_THREAD_BOARD_STATE = {
OPEN: "open",
FROZEN: "frozen",
TAKEOVER: "takeover",
} as const;
export const BOARD_INTERVENTION_MODE = {
OBSERVE: "observe",
INTERVENE: "intervene",
TAKEOVER: "takeover",
} as const;
export const BOARD_INTERVENTION_ACTION = {
DECISION: "decision",
FREEZE: "freeze",
TAKEOVER: "takeover",
ROLLBACK: "rollback",
FORCE_APPROVAL: "force_approval",
} as const;
type ValueOf<T> = T[keyof T];
export type ChatThreadBoardState = ValueOf<typeof CHAT_THREAD_BOARD_STATE>;
export type BoardInterventionMode = ValueOf<typeof BOARD_INTERVENTION_MODE>;
export type BoardInterventionAction = ValueOf<typeof BOARD_INTERVENTION_ACTION>;
export interface BoardInterventionRecord {
id: string;
orgId: string;
threadId: string;
messageId: string;
mode: BoardInterventionMode;
action: BoardInterventionAction;
details: string;
targetType: "employee" | "agent" | "board" | null;
targetId: string | null;
approvalId: string | null;
createdByType: "employee" | "agent" | "board" | "system";
createdById: string | null;
createdAt: string;
}
+91
View File
@@ -0,0 +1,91 @@
import type { ChatThreadBoardState } from "./board-domain";
export interface ChatSpaceRecord {
id: string;
orgId: string;
spaceType: string;
name: string;
topic: string;
visibility: string;
retentionPolicy: string;
createdAt: string;
}
export interface ChatMessageRecord {
id: string;
orgId: string;
spaceId: string;
threadId: string | null;
senderType: "employee" | "agent" | "board" | "system";
senderId: string | null;
bodyMd: string;
bodyStructuredJson: string;
deliveryState: string;
createdAt: string;
editedAt: string | null;
deletedAt: string | null;
}
export interface ChatMembershipRecord {
spaceId: string;
principalType: "employee" | "agent";
principalId: string;
role: string;
muteState: string;
}
export interface ChatThreadRecord {
id: string;
orgId: string;
spaceId: string;
rootMessageId: string | null;
title: string;
state: string;
boardState: ChatThreadBoardState;
controlledByType: "employee" | "agent" | "board" | null;
controlledById: string | null;
createdAt: string;
updatedAt: string;
}
export interface ChatAttachmentRecord {
messageId: string;
fileId: string;
transferType: string;
checksum: string;
previewKey: string | null;
}
export interface ChatMentionRecord {
messageId: string;
targetType: "employee" | "agent" | "board" | "org_group";
targetId: string;
offsetStart: number;
offsetEnd: number;
wakeState: "none" | "woken" | "failed";
}
export interface ChatSlashInvocationRecord {
id: string;
messageId: string;
command: string;
argsJson: string;
resultRef: string | null;
createdAt: string;
}
export interface ChatPresenceRecord {
principalType: string;
principalId: string;
status: string;
statusText: string;
lastSeenAt: string;
}
export interface ChatReadStateRecord {
orgId: string;
employeeId: string;
spaceId: string;
lastReadMessageId: string | null;
lastReadAt: string;
}
+41
View File
@@ -0,0 +1,41 @@
export interface SendMessageInput {
orgId: string;
spaceId: string;
threadId: string | null;
senderType: "employee" | "agent" | "board" | "system";
senderId: string | null;
bodyMd: string;
attachmentFileIds?: string[];
}
export interface EditMessageInput {
orgId: string;
messageId: string;
actorType: SendMessageInput["senderType"];
actorId: string | null;
bodyMd: string;
}
export interface DeleteMessageInput {
orgId: string;
messageId: string;
actorType: SendMessageInput["senderType"];
actorId: string | null;
}
export interface CreateChatSpaceInput {
orgId: string;
spaceType: "company" | "division" | "department" | "project" | "pod" | "ad_hoc" | "direct";
name: string;
topic: string;
visibility: "workspace" | "restricted";
retentionPolicy?: "standard_365d" | "restricted_365d";
memberEmployeeIds?: string[];
memberAgentIds?: string[];
}
export interface MarkChatSpaceReadInput {
orgId: string;
employeeId: string;
spaceId: string;
}
+94
View File
@@ -0,0 +1,94 @@
export interface CreateDocumentInput {
orgId: string;
title: string;
docType: string;
content: string;
authorAgentId: string | null;
reviewerAgentId: string | null;
projectId: string | null;
goalId: string | null;
taskId: string | null;
}
export interface UpdateDocumentInput {
orgId: string;
documentId: string;
title: string;
content: string;
status: string;
}
export interface DeleteDocumentInput {
orgId: string;
documentId: string;
}
export interface CreateKnowledgeEntryInput {
orgId: string;
topic: string;
category: string;
content: string;
importance: string;
sourceType: string;
sourceId: string | null;
}
export interface DeleteKnowledgeEntryInput {
orgId: string;
entryId: string;
}
export interface CreateAutomationRuleInput {
orgId: string;
name: string;
triggerEvent: string;
conditions: Record<string, unknown>;
actionType: string;
actionConfig: Record<string, unknown>;
priority: number;
enabled: boolean;
}
export interface UpdateAutomationRuleInput {
orgId: string;
ruleId: string;
name: string;
triggerEvent: string;
conditions: Record<string, unknown>;
actionType: string;
actionConfig: Record<string, unknown>;
priority: number;
enabled: boolean;
}
export interface DeleteAutomationRuleInput {
orgId: string;
ruleId: string;
}
export interface CreateMeetingInput {
orgId: string;
title: string;
meetingType: string;
scheduledAt: string | null;
durationMinutes: number;
agenda: string;
}
export interface DeleteMeetingInput {
orgId: string;
meetingId: string;
}
export interface CreateSprintInput {
orgId: string;
name: string;
goal: string;
startDate: string;
endDate: string;
}
export interface DeleteSprintInput {
orgId: string;
sprintId: string;
}
+43
View File
@@ -0,0 +1,43 @@
export interface SaveComposioSettingsInput {
orgId: string;
apiKey: string;
toolkits: string[];
}
export interface ComposioToolkitSummaryDto {
slug: string;
name: string;
description: string;
logo: string | null;
categories: string[];
authSchemes: string[];
noAuth: boolean;
toolsCount: number;
}
export interface ListComposioToolkitsInput {
orgId: string;
}
export interface ConnectComposioToolkitInput {
orgId: string;
toolkitSlug: string;
toolkitName: string;
}
export interface ConnectComposioToolkitResult {
accountId: string;
status: string;
redirectUrl: string | null;
}
export interface RefreshComposioAccountsInput {
orgId: string;
}
export interface ConnectorGrantInput {
orgId: string;
agentId: string;
toolkitSlug: string;
employeeId: string;
}
+19
View File
@@ -0,0 +1,19 @@
export interface ImportFileInput {
orgId: string;
}
export interface OpenFileInput {
orgId: string;
fileId: string;
}
export interface SetFilePinnedInput {
orgId: string;
fileId: string;
pinned: boolean;
}
export interface NativeDialogResult {
canceled: boolean;
filePaths: string[];
}
+104
View File
@@ -0,0 +1,104 @@
import type {
ComplianceExportType,
ComplianceSubjectType,
LegalHoldEntityType,
RetentionFreezeScopeType,
SdlcReviewTargetType,
} from "../domain";
export interface CreateMigrationReportInput {
orgId: string;
sourceDatabasePath: string;
}
export interface CreateRollbackSnapshotInput {
orgId: string;
migrationReportId: string;
createdByEmployeeId: string;
}
export interface SetRollbackSnapshotActiveInput {
orgId: string;
snapshotId: string;
active: boolean;
employeeId: string;
}
export interface ResolveMigrationReconciliationInput {
orgId: string;
reconciliationItemId: string;
employeeId: string;
}
export interface CreateComplianceExportInput {
orgId: string;
subjectType: ComplianceSubjectType;
subjectId: string;
exportType: ComplianceExportType;
requestedByEmployeeId: string;
}
export interface CreateAuditReplayInput {
orgId: string;
threadId: string;
createdByEmployeeId: string;
}
export interface CreateLegalHoldInput {
orgId: string;
entityType: LegalHoldEntityType;
entityId: string;
reason: string;
createdByEmployeeId: string;
}
export interface SetLegalHoldStateInput {
orgId: string;
legalHoldId: string;
active: boolean;
employeeId: string;
}
export interface CreateRetentionFreezeInput {
orgId: string;
scopeType: RetentionFreezeScopeType;
scopeId: string;
reason: string;
createdByEmployeeId: string;
}
export interface SetRetentionFreezeStateInput {
orgId: string;
retentionFreezeId: string;
active: boolean;
employeeId: string;
}
export interface SetFeatureFlagInput {
orgId: string;
flagId: string;
enabled: boolean;
}
export interface RunChaosDrillInput {
orgId: string;
drillId: string;
}
export interface RunSdlcReviewInput {
orgId: string;
reviewAgentId: string;
targetType: SdlcReviewTargetType;
targetRef: string;
}
export interface RunEvalSuiteInput {
orgId: string;
suiteId: string;
}
export interface SetPrBotGateInput {
orgId: string;
gateId: string;
enabled: boolean;
}
+10
View File
@@ -0,0 +1,10 @@
export * from "./organization";
export * from "./chat";
export * from "./provider";
export * from "./skills";
export * from "./social";
export * from "./files";
export * from "./governance";
export * from "./collaboration";
export * from "./onboarding";
export * from "./composio";
+36
View File
@@ -0,0 +1,36 @@
import type { SearchEntityType } from "../domain";
export interface BootstrapOnboardingInput {
companyName: string;
companyDescription: string;
employeeName: string;
workspacePath: string;
executionMode: "ai_ceo" | "ai_cofounder";
autoApproveHires: boolean;
reviewDeliverables: boolean;
goalTitle: string;
goalDescription: string;
providerKey: string;
providerSecret: string;
providerModel: string;
}
export interface BootstrapOnboardingSummary {
orgId: string;
employeeId: string;
ceoAgentId: string;
workspaceId: string | null;
goalId: string;
projectId: string;
taskId: string;
runId: string;
providerId: string;
}
export interface SearchInput {
orgId: string;
employeeId: string;
query: string;
entityTypes?: SearchEntityType[];
limit?: number;
}
+148
View File
@@ -0,0 +1,148 @@
import type { ApprovalState, IdentitySource, PrincipalType, RiskLevel, RoleKey, TaskPriority, TaskStatus } from "../domain";
export interface SetActiveOrganizationInput {
orgId: string;
}
export interface DeleteOrganizationInput {
orgId: string;
}
export interface CreateOrganizationInput {
organizationName: string;
description?: string;
mission: string;
goal: string;
employeeName: string;
executionMode?: "ai_ceo" | "ai_cofounder";
autoApproveHires?: boolean;
reviewDeliverables?: boolean;
}
export interface UpdateAgentInput {
orgId: string;
agentId: string;
role: string;
title: string;
roleLevel: string;
department: string;
budgetCents: number;
modelProviderId: string | null;
modelId: string | null;
}
export interface CreateAgentInput {
orgId: string;
name: string;
role: string;
department: string;
modelProviderId: string | null;
modelId: string | null;
budgetCents: number;
managerAgentId: string | null;
title?: string;
roleLevel?: string;
modelStrategy?: string;
workspaceId?: string | null;
heartbeatEnabled?: boolean;
heartbeatIntervalSec?: number;
}
export interface CreateTaskInput {
orgId: string;
title: string;
description: string;
status: TaskStatus;
assigneeAgentId: string | null;
risk: RiskLevel;
projectId: string | null;
goalId: string | null;
workspaceId: string | null;
priority: TaskPriority;
requiresFilesystem: boolean;
}
export interface UpdateTaskStatusInput {
orgId: string;
taskId: string;
status: TaskStatus;
}
export interface RunTaskInput {
orgId: string;
taskId: string;
}
export interface UpdateTaskInput {
orgId: string;
taskId: string;
title: string;
description: string;
assigneeAgentId: string | null;
risk: RiskLevel;
priority: TaskPriority;
parentTaskId: string | null;
}
export interface DeleteTaskInput {
orgId: string;
taskId: string;
}
export interface CreateGoalInput {
orgId: string;
title: string;
description: string;
ownerAgentId: string | null;
}
export interface CreateProjectInput {
orgId: string;
goalId: string | null;
name: string;
description: string;
leadAgentId: string | null;
}
export interface CreateWorkspaceInput {
orgId: string;
name: string;
localPath: string;
projectId: string | null;
}
export interface CreateApprovalInput {
orgId: string;
kind: string;
title: string;
details: string;
risk: RiskLevel;
requestedByType: "employee" | "agent" | "system";
requestedById: string | null;
}
export interface DecideApprovalInput {
orgId: string;
approvalId: string;
state: Extract<ApprovalState, "approved" | "declined">;
decidedByEmployeeId: string;
notes?: string;
}
export interface SyncEmployeeIdentityInput {
orgId: string;
employeeId: string;
source: IdentitySource;
externalSubject: string;
email: string | null;
}
export interface GrantRoleInput {
orgId: string;
principalType: PrincipalType;
principalId: string;
roleKey: RoleKey;
scopeType: "organization" | "workspace" | "project" | "department";
scopeId: string;
grantedByEmployeeId: string;
}
+81
View File
@@ -0,0 +1,81 @@
import type { ProviderDataPolicy, ProviderExecutionMode } from "../domain";
export interface SaveProviderCredentialInput {
orgId: string;
providerId: string;
secret: string;
model: string | null;
employeeId?: string | null;
}
export interface RevokeProviderCredentialInput {
orgId: string;
providerId: string;
}
export interface LaunchProviderSignInInput {
orgId: string;
providerId: string;
employeeId: string;
}
export interface StartProviderOAuthInput {
providerKey: string;
enterpriseDomain?: string | null;
/** Present when connecting an existing org's provider (Settings); absent
* during onboarding, where the obtained credential is returned to the caller. */
orgId?: string;
providerId?: string;
employeeId?: string;
model?: string | null;
}
export interface StartProviderOAuthResult {
/** The obtained credential JSON when no org context was supplied, else null
* (the credential was already stored). */
secret: string | null;
}
export interface CancelProviderOAuthInput {
providerKey: string;
}
export interface CheckProviderHealthInput {
orgId: string;
providerId: string;
}
export interface ListProviderModelsInput {
providerKey: string;
/** A just-typed/authorized credential (onboarding or the connect-new dialog). */
secret?: string;
/** A stored provider whose secret is decrypted server-side (settings refresh). */
orgId?: string;
providerId?: string;
}
export interface UpdateProviderPolicyInput {
orgId: string;
providerId: string;
dataPolicy: ProviderDataPolicy;
backgroundEnabled: boolean;
monthlyRequestLimit: number;
workspaceScope: "organization" | "workspace";
}
export interface CreateProviderResponseInput {
orgId: string;
providerId: string;
workspaceId?: string | null;
prompt: string;
instructions: string | null;
executionMode?: ProviderExecutionMode;
}
export type StreamProviderResponseInput = CreateProviderResponseInput;
export interface CancelProviderResponseInput {
orgId: string;
requestId: string;
providerResponseId?: string;
}
+23
View File
@@ -0,0 +1,23 @@
export interface ImportSkillDirectoryInput {
orgId: string;
directoryPath: string;
versionSemver: string;
}
export interface BindSkillInput {
orgId: string;
agentId: string;
skillId: string;
revisionId: string;
}
export interface ResolveAgentSkillsInput {
orgId: string;
agentId: string;
runId: string;
}
export interface RunSkillTestsInput {
orgId: string;
revisionId: string;
}
+31
View File
@@ -0,0 +1,31 @@
import type { SocialPlatform } from "../domain";
export interface CreateSocialAccountInput {
orgId: string;
platform: SocialPlatform;
handle: string;
displayName: string;
createdByEmployeeId: string;
authorizedEmployeeId: string | null;
}
export interface LaunchSocialLoginInput {
orgId: string;
socialAccountId: string;
employeeId: string;
}
export interface CreateScheduledPostInput {
orgId: string;
socialAccountId: string;
bodyMd: string;
scheduledFor: string;
createdByEmployeeId: string;
}
export interface SetScheduledPostStateInput {
orgId: string;
scheduledPostId: string;
state: "draft" | "scheduled" | "published" | "cancelled";
employeeId: string;
}
+53
View File
@@ -0,0 +1,53 @@
export const COMPLIANCE_EXPORT_TYPE = {
GDPR_EXPORT: "gdpr_export",
GDPR_DELETE: "gdpr_delete",
} as const;
export const COMPLIANCE_EXPORT_STATE = {
COMPLETED: "completed",
} as const;
type ValueOf<T> = T[keyof T];
export type ComplianceExportType = ValueOf<typeof COMPLIANCE_EXPORT_TYPE>;
export type ComplianceExportState = ValueOf<typeof COMPLIANCE_EXPORT_STATE>;
export type ComplianceSubjectType = "employee" | "agent";
export type LegalHoldEntityType = "organization" | "employee" | "agent" | "chat_thread" | "file_object";
export type RetentionFreezeScopeType = "organization" | "chat_space" | "file_object";
export interface ComplianceExportRecord {
id: string;
orgId: string;
subjectType: ComplianceSubjectType;
subjectId: string;
exportType: ComplianceExportType;
state: ComplianceExportState;
payloadJson: string;
requestedByEmployeeId: string | null;
createdAt: string;
completedAt: string | null;
}
export interface LegalHoldRecord {
id: string;
orgId: string;
entityType: LegalHoldEntityType;
entityId: string;
reason: string;
createdByEmployeeId: string | null;
active: boolean;
createdAt: string;
releasedAt: string | null;
}
export interface RetentionFreezeRecord {
id: string;
orgId: string;
scopeType: RetentionFreezeScopeType;
scopeId: string;
reason: string;
createdByEmployeeId: string | null;
active: boolean;
createdAt: string;
releasedAt: string | null;
}
-312
View File
@@ -1,312 +0,0 @@
/**
* Renderer-visible pi-mono connector catalog.
*
* Mirrors the authoritative definitions in `src/main/connector-definitions*.ts`
* so the renderer can drive UI from the same 26-entry list without importing
* Node/main-process modules. Keep this file in strict lockstep with the main
* catalog when new connectors are added.
*/
import type { ConnectorId } from "./types/enums";
export type PiOAuthProviderId =
| "anthropic"
| "openai-codex"
| "github-copilot"
| "google-gemini-cli"
| "google-antigravity";
export type ConnectorAuthKind = "oauth" | "api_key" | "aws" | "azure" | "gcp_adc" | "local";
export interface ConnectorAuthOAuth { type: "oauth"; oauthId: PiOAuthProviderId }
export interface ConnectorAuthApiKey { type: "api_key"; envKey: string }
export interface ConnectorAuthAws { type: "aws" }
export interface ConnectorAuthAzure { type: "azure" }
export interface ConnectorAuthGcpAdc { type: "gcp_adc" }
export interface ConnectorAuthLocal { type: "local"; defaultBaseUrl: string }
export type ConnectorAuth =
| ConnectorAuthOAuth
| ConnectorAuthApiKey
| ConnectorAuthAws
| ConnectorAuthAzure
| ConnectorAuthGcpAdc
| ConnectorAuthLocal;
export interface ConnectorCatalogEntry {
id: ConnectorId;
provider: string;
label: string;
description: string;
defaultModel: string;
auth: ConnectorAuth;
onboardingFeatured?: boolean;
notes?: string;
}
const OAUTH_ENTRIES: ConnectorCatalogEntry[] = [
{
id: "claude-pro",
provider: "anthropic",
label: "Claude Pro/Max",
description: "Anthropic Claude via Claude Pro / Max subscription OAuth.",
defaultModel: "claude-sonnet-4-5",
auth: { type: "oauth", oauthId: "anthropic" },
onboardingFeatured: true,
notes: "Requires an active Claude Pro or Max subscription. Tokens refresh automatically.",
},
{
id: "openai-codex",
provider: "openai-codex",
label: "ChatGPT Plus/Pro (Codex)",
description: "OpenAI Codex via a ChatGPT Plus or Pro subscription.",
defaultModel: "gpt-5.3-codex",
auth: { type: "oauth", oauthId: "openai-codex" },
onboardingFeatured: true,
notes: "Personal use only; requires ChatGPT Plus or Pro.",
},
{
id: "github-copilot",
provider: "github-copilot",
label: "GitHub Copilot",
description: "Models exposed through a GitHub Copilot subscription.",
defaultModel: "claude-opus-4.5",
auth: { type: "oauth", oauthId: "github-copilot" },
notes: "Supports github.com and GitHub Enterprise Server.",
},
{
id: "gemini-cli",
provider: "google-gemini-cli",
label: "Google Gemini CLI",
description: "Google Gemini models via Cloud Code Assist OAuth. Free tier works with any Google account.",
defaultModel: "gemini-2.5-pro",
auth: { type: "oauth", oauthId: "google-gemini-cli" },
notes: "For paid Cloud Code Assist, set GOOGLE_CLOUD_PROJECT.",
},
{
id: "antigravity",
provider: "google-antigravity",
label: "Google Antigravity",
description: "Google Antigravity sandbox with Gemini 3, Claude, and GPT-OSS models.",
defaultModel: "claude-sonnet-4-5",
auth: { type: "oauth", oauthId: "google-antigravity" },
notes: "Free with any Google account.",
},
];
const API_KEY_ENTRIES: ConnectorCatalogEntry[] = [
{
id: "anthropic",
provider: "anthropic",
label: "Anthropic API",
description: "Direct Anthropic Messages API for production workloads.",
defaultModel: "claude-sonnet-4-5",
auth: { type: "api_key", envKey: "ANTHROPIC_API_KEY" },
onboardingFeatured: true,
},
{
id: "openai",
provider: "openai",
label: "OpenAI API",
description: "OpenAI Responses + Chat Completions endpoints. GPT-5 family and Codex deployments.",
defaultModel: "gpt-5.4",
auth: { type: "api_key", envKey: "OPENAI_API_KEY" },
onboardingFeatured: true,
},
{
id: "google",
provider: "google",
label: "Google Gemini API",
description: "Google Gemini Generative Language API using the standard GEMINI_API_KEY variable.",
defaultModel: "gemini-2.5-pro",
auth: { type: "api_key", envKey: "GEMINI_API_KEY" },
},
{
id: "mistral",
provider: "mistral",
label: "Mistral",
description: "Mistral La Plateforme — Codestral, Devstral, Mistral Medium/Large families.",
defaultModel: "mistral-medium-latest",
auth: { type: "api_key", envKey: "MISTRAL_API_KEY" },
},
{
id: "groq",
provider: "groq",
label: "Groq",
description: "Groq LPU cloud. High-throughput inference for Llama 3, Qwen, DeepSeek, Groq Compound.",
defaultModel: "groq/compound",
auth: { type: "api_key", envKey: "GROQ_API_KEY" },
},
{
id: "cerebras",
provider: "cerebras",
label: "Cerebras",
description: "Cerebras Inference cloud — wafer-scale hardware for Qwen, Llama, GPT-OSS.",
defaultModel: "qwen-3-235b-a22b-instruct-2507",
auth: { type: "api_key", envKey: "CEREBRAS_API_KEY" },
},
{
id: "xai",
provider: "xai",
label: "xAI",
description: "xAI Grok API including Grok 4 Fast and Grok Code Fast.",
defaultModel: "grok-4-fast",
auth: { type: "api_key", envKey: "XAI_API_KEY" },
},
{
id: "openrouter",
provider: "openrouter",
label: "OpenRouter",
description: "OpenRouter aggregator — Anthropic, OpenAI, Google, open-weights through one key.",
defaultModel: "anthropic/claude-sonnet-4.5",
auth: { type: "api_key", envKey: "OPENROUTER_API_KEY" },
},
{
id: "vercel-ai-gateway",
provider: "vercel-ai-gateway",
label: "Vercel AI Gateway",
description: "Vercel multi-provider proxy using provider/model slugs on one billing profile.",
defaultModel: "anthropic/claude-sonnet-4.5",
auth: { type: "api_key", envKey: "AI_GATEWAY_API_KEY" },
},
{
id: "zai",
provider: "zai",
label: "Z.AI",
description: "Z.AI GLM-4.5/4.6 family — coding-tuned Chinese models with tool use.",
defaultModel: "glm-4.6",
auth: { type: "api_key", envKey: "ZAI_API_KEY" },
},
{
id: "opencode",
provider: "opencode",
label: "OpenCode Zen",
description: "OpenCode Zen managed endpoint. Shares OPENCODE_API_KEY with OpenCode Go.",
defaultModel: "claude-sonnet-4.5",
auth: { type: "api_key", envKey: "OPENCODE_API_KEY" },
},
{
id: "opencode-go",
provider: "opencode-go",
label: "OpenCode Go",
description: "OpenCode Go managed endpoint. Shares OPENCODE_API_KEY with OpenCode Zen.",
defaultModel: "kimi-k2.5",
auth: { type: "api_key", envKey: "OPENCODE_API_KEY" },
},
{
id: "huggingface",
provider: "huggingface",
label: "Hugging Face",
description: "Hugging Face Inference Endpoints — Kimi K2, GLM, DeepSeek, MiniMax, open-weights.",
defaultModel: "moonshotai/Kimi-K2.5",
auth: { type: "api_key", envKey: "HF_TOKEN" },
},
{
id: "kimi-coding",
provider: "kimi-coding",
label: "Kimi For Coding",
description: "Moonshot AI Kimi For Coding endpoint — tuned for agentic coding workloads.",
defaultModel: "kimi-for-coding",
auth: { type: "api_key", envKey: "KIMI_API_KEY" },
},
{
id: "minimax",
provider: "minimax",
label: "MiniMax",
description: "MiniMax international endpoint for M2 coding models.",
defaultModel: "MiniMax-M2.7",
auth: { type: "api_key", envKey: "MINIMAX_API_KEY" },
},
{
id: "minimax-cn",
provider: "minimax-cn",
label: "MiniMax (China)",
description: "MiniMax mainland China endpoint. Separate key from the international tier.",
defaultModel: "MiniMax-M2.7",
auth: { type: "api_key", envKey: "MINIMAX_CN_API_KEY" },
},
{
id: "fireworks",
provider: "fireworks",
label: "Fireworks AI",
description: "Fireworks inference cloud — Kimi K2.5 Turbo and more.",
defaultModel: "accounts/fireworks/models/kimi-k2.5-turbo",
auth: { type: "api_key", envKey: "FIREWORKS_API_KEY" },
},
{
id: "fireworks-firepass",
provider: "fireworks-firepass",
label: "Fireworks Fire Pass",
description: "Fireworks Fire Pass — subscription bundle. Same FIREWORKS_API_KEY.",
defaultModel: "accounts/fireworks/routers/kimi-k2p6-turbo",
auth: { type: "api_key", envKey: "FIREWORKS_API_KEY" },
notes: "Fire Pass uses the dedicated router id accounts/fireworks/routers/kimi-k2p6-turbo documented at docs.fireworks.ai/firepass.",
},
];
const LOCAL_ENTRIES: ConnectorCatalogEntry[] = [
{
id: "ollama",
provider: "ollama",
label: "Ollama",
description: "Local Ollama server — open-weights models on your own machine via the OpenAI-compatible endpoint.",
defaultModel: "llama3.2",
auth: { type: "local", defaultBaseUrl: "http://localhost:11434/v1" },
notes: "Default port 11434. Override with a loopback or private-network address.",
},
{
id: "lm-studio",
provider: "lm-studio",
label: "LM Studio",
description: "Local LM Studio server — host any loaded model via the OpenAI-compatible endpoint.",
defaultModel: "local-model",
auth: { type: "local", defaultBaseUrl: "http://localhost:1234/v1" },
notes: "Enable LM Studio's local server from the Developer tab. Use a loopback or private-network address.",
},
];
const CLOUD_ENTRIES: ConnectorCatalogEntry[] = [
{
id: "amazon-bedrock",
provider: "amazon-bedrock",
label: "AWS Bedrock",
description: "Anthropic, Amazon Nova, and Llama models served through AWS Bedrock.",
defaultModel: "us.anthropic.claude-sonnet-4-20250514-v1:0",
auth: { type: "aws" },
onboardingFeatured: true,
notes: "Honours standard AWS credential discovery. Region defaults to us-east-1.",
},
{
id: "azure-openai",
provider: "azure-openai-responses",
label: "Azure OpenAI",
description: "Azure-hosted OpenAI deployments via the Responses API.",
defaultModel: "gpt-5.4",
auth: { type: "azure" },
notes: "Provide AZURE_OPENAI_API_KEY plus AZURE_OPENAI_BASE_URL or AZURE_OPENAI_RESOURCE_NAME.",
},
{
id: "google-vertex",
provider: "google-vertex",
label: "Google Vertex AI",
description: "Gemini, Claude, and third-party models on Google Vertex AI using ADC.",
defaultModel: "gemini-2.5-pro",
auth: { type: "gcp_adc" },
notes: "Set GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION.",
},
];
export const CONNECTOR_CATALOG: ConnectorCatalogEntry[] = [
...OAUTH_ENTRIES,
...API_KEY_ENTRIES,
...CLOUD_ENTRIES,
...LOCAL_ENTRIES,
];
export function findConnectorCatalogEntry(id: string): ConnectorCatalogEntry | undefined {
return CONNECTOR_CATALOG.find((entry) => entry.id === id);
}
export function listFeaturedOnboardingConnectors(): ConnectorCatalogEntry[] {
return CONNECTOR_CATALOG.filter((entry) => entry.onboardingFeatured === true);
}
-37
View File
@@ -1,37 +0,0 @@
export interface ConnectorModelEntry {
id: string;
label: string;
enabled: boolean;
}
function dedupeById(entries: Array<{ id: string; label: string; enabled: boolean }>) {
const seen = new Map<string, ConnectorModelEntry>();
for (const entry of entries) {
if (!entry.id.trim()) continue;
const existing = seen.get(entry.id);
if (!existing) {
seen.set(entry.id, { ...entry, id: entry.id.trim() });
continue;
}
seen.set(entry.id, {
...existing,
label: existing.label || entry.label,
enabled: existing.enabled || entry.enabled,
});
}
return Array.from(seen.values());
}
export function mergeConnectorModelEntries(
enabledModels: Array<{ id: string; label: string }>,
disabledModels: Array<{ id: string; label: string }>,
): ConnectorModelEntry[] {
return dedupeById([
...enabledModels.map((entry) => ({ ...entry, enabled: true })),
...disabledModels.map((entry) => ({ ...entry, enabled: false })),
]).sort((a, b) => {
if (a.enabled !== b.enabled) return a.enabled ? -1 : 1;
return a.label.localeCompare(b.label);
});
}
-21
View File
@@ -1,21 +0,0 @@
import type { ConnectorRecord } from "./types";
type ConnectorExecutionCandidate = Pick<ConnectorRecord, "status" | "capabilityMatrix"> & Partial<Pick<ConnectorRecord, "label">>;
export function isConnectorExecutionReady(connector: ConnectorExecutionCandidate) {
return connector.status === "ready";
}
export function getConnectorExecutionReadinessIssue(connector: ConnectorExecutionCandidate) {
const label = connector.label ?? "Connector";
if (connector.status === "ready") {
return null;
}
if (connector.status === "not_installed") {
return `${label} is not installed.`;
}
if (connector.status === "auth_required") {
return `${label} requires authentication. Run the CLI login command first.`;
}
return `${label} is ${connector.status.replaceAll("_", " ")} and cannot be used for autonomous execution.`;
}
-36
View File
@@ -1,36 +0,0 @@
import type { DepartmentId } from "./types";
export const DEPARTMENT_LABELS: Record<DepartmentId, string> = {
executive: "Executive Suite",
engineering: "Engineering",
product: "Product & Design",
marketing: "Marketing",
sales: "Sales & BD",
hr: "People & Culture",
finance: "Finance & Legal",
legal: "Legal",
operations: "Operations",
customer_support: "Customer Success",
research: "Research",
design: "Design",
};
export const DEPARTMENT_OPTIONS: Array<{ value: DepartmentId | ""; label: string }> = [
{ value: "", label: "Any department" },
...(Object.entries(DEPARTMENT_LABELS) as [DepartmentId, string][]).map(([value, label]) => ({ value, label })),
];
export const DEPARTMENT_COLORS: Record<DepartmentId, string> = {
executive: "var(--primary)",
engineering: "var(--kami-ink)",
product: "var(--kami-dark-warm)",
marketing: "var(--kami-olive)",
sales: "var(--kami-olive)",
hr: "var(--kami-charcoal)",
finance: "var(--kami-charcoal)",
legal: "var(--kami-stone)",
operations: "var(--kami-dark-warm)",
customer_support: "var(--kami-stone)",
research: "var(--kami-ink)",
design: "var(--primary)",
};
-13
View File
@@ -1,13 +0,0 @@
export * from "./contracts/channels";
export * from "./contracts/helpers";
export * from "./contracts/json-fields";
export * from "./contracts/schemas-company";
export * from "./contracts/schemas-agents";
export * from "./contracts/schemas-tasks";
export * from "./contracts/schemas-approvals";
export * from "./contracts/schemas-messages";
export * from "./contracts/schemas-execution";
export * from "./contracts/schemas-misc";
export * from "./contracts/schemas-work-products";
export * from "./contracts/desktop-api";
export * from "./contracts/preload-forwarders";
-111
View File
@@ -1,111 +0,0 @@
export const IPC_CHANNELS = {
loadSnapshot: "agent-company:load-snapshot",
pickDirectory: "agent-company:pick-directory",
openPath: "agent-company:open-path",
openWorkProduct: "agent-company:open-work-product",
saveCompany: "agent-company:save-company",
setCurrentCompany: "agent-company:set-current-company",
saveConnector: "agent-company:save-connector",
testConnector: "agent-company:test-connector",
saveWorkspace: "agent-company:save-workspace",
saveAgent: "agent-company:save-agent",
requestHire: "agent-company:request-hire",
saveGoal: "agent-company:save-goal",
saveProject: "agent-company:save-project",
saveTask: "agent-company:save-task",
requestApproval: "agent-company:request-approval",
decideApproval: "agent-company:decide-approval",
startTaskRun: "agent-company:start-task-run",
cancelRun: "agent-company:cancel-run",
getRunLog: "agent-company:get-run-log",
getRunLogChunk: "agent-company:get-run-log-chunk",
backupProfile: "agent-company:backup-profile",
restoreProfile: "agent-company:restore-profile",
updateSettings: "agent-company:update-settings",
checkForUpdates: "agent-company:check-for-updates",
deleteCompany: "agent-company:delete-company",
deleteAgent: "agent-company:delete-agent",
deleteTask: "agent-company:delete-task",
deleteGoal: "agent-company:delete-goal",
deleteProject: "agent-company:delete-project",
deleteWorkspace: "agent-company:delete-workspace",
deleteApproval: "agent-company:delete-approval",
deleteSecret: "agent-company:delete-secret",
listConnectorModels: "agent-company:list-connector-models",
addComment: "agent-company:add-comment",
setHeartbeat: "agent-company:set-heartbeat",
triggerHeartbeat: "agent-company:trigger-heartbeat",
rendererEvent: "agent-company:event",
getCompanyMetrics: "agent-company:get-company-metrics",
getStandupReport: "agent-company:get-standup-report",
bootstrapOnboarding: "agent-company:bootstrap-onboarding",
checkNodeInstalled: "agent-company:check-node-installed",
openTerminalCommand: "agent-company:open-terminal-command",
saveSocialAccount: "agent-company:save-social-account",
deleteSocialAccount: "agent-company:delete-social-account",
listBrowserActions: "agent-company:list-browser-actions",
cancelBrowserAction: "agent-company:cancel-browser-action",
triggerBrowserLogin: "agent-company:trigger-browser-login",
saveMeeting: "agent-company:save-meeting",
deleteMeeting: "agent-company:delete-meeting",
saveDocument: "agent-company:save-document",
deleteDocument: "agent-company:delete-document",
saveKnowledgeEntry: "agent-company:save-knowledge-entry",
deleteKnowledgeEntry: "agent-company:delete-knowledge-entry",
saveSprint: "agent-company:save-sprint",
deleteSprint: "agent-company:delete-sprint",
saveAutomationRule: "agent-company:save-automation-rule",
deleteAutomationRule: "agent-company:delete-automation-rule",
toggleAutomationRule: "agent-company:toggle-automation-rule",
getAutomationLog: "agent-company:get-automation-log",
sendAgentMessage: "agent-company:send-agent-message",
markMessageRead: "agent-company:mark-message-read",
saveWorkflow: "agent-company:save-workflow",
deleteWorkflow: "agent-company:delete-workflow",
runWorkflow: "agent-company:run-workflow",
searchMessages: "agent-company:search-messages",
importSkill: "agent-company:import-skill",
listSkills: "agent-company:list-skills",
getSkillDetail: "agent-company:get-skill-detail",
getSkillMarkdown: "agent-company:get-skill-markdown",
deleteSkill: "agent-company:delete-skill",
assignSkillToAgent: "agent-company:assign-skill-to-agent",
removeSkillFromAgent: "agent-company:remove-skill-from-agent",
checkSkillUpdate: "agent-company:check-skill-update",
listSkillAgents: "agent-company:list-skill-agents",
listAgentSkills: "agent-company:list-agent-skills",
saveBudgetPolicy: "agent-company:save-budget-policy",
deleteBudgetPolicy: "agent-company:delete-budget-policy",
listBudgetPolicies: "agent-company:list-budget-policies",
listBudgetIncidents: "agent-company:list-budget-incidents",
resolveBudgetIncident: "agent-company:resolve-budget-incident",
getBudgetStatus: "agent-company:get-budget-status",
getTask: "agent-company:get-task",
getAgent: "agent-company:get-agent",
getRun: "agent-company:get-run",
getApproval: "agent-company:get-approval",
getConnectorDisabledModels: "agent-company:get-connector-disabled-models",
setConnectorDisabledModels: "agent-company:set-connector-disabled-models",
// Recovery
recoveryRetry: "recovery:retry",
recoveryFail: "recovery:fail",
// Thread runtime (read-only — writes happen inside the backend)
getThread: "agent-company:get-thread",
listThreadEvents: "agent-company:list-thread-events",
listThreadWaitStates: "agent-company:list-thread-wait-states",
listThreadParticipants: "agent-company:list-thread-participants",
windowMinimize: "window:minimize",
windowMaximize: "window:maximize",
windowClose: "window:close",
windowIsMaximized: "window:isMaximized",
// Credentials (pi-mono)
credentialsList: "credentials:list",
credentialsSave: "credentials:save",
credentialsRemove: "credentials:remove",
credentialsTest: "credentials:test",
// OAuth (pi-mono)
oauthStart: "oauth:start",
oauthCancel: "oauth:cancel",
oauthPromptResponse: "oauth:submit-prompt",
oauthManualCodeResponse: "oauth:submit-manual-code",
} as const;
-52
View File
@@ -1,52 +0,0 @@
// DesktopApi composition. Flat shape is preserved via intersection of sub-APIs;
// external `window.agentCompany` callers stay unchanged. Per-domain declarations
// live in `./desktop-api/*.ts`.
import type { AgentsApi } from "./desktop-api/agents";
import type { ApprovalsApi } from "./desktop-api/approvals";
import type { AutomationApi } from "./desktop-api/automation";
import type { BudgetApi } from "./desktop-api/budget";
import type { CommunicationApi } from "./desktop-api/communication";
import type { CompaniesApi } from "./desktop-api/companies";
import type { CredentialsApi } from "./desktop-api/credentials";
import type { RunsApi } from "./desktop-api/runs";
import type { SkillsApi } from "./desktop-api/skills";
import type { TasksApi } from "./desktop-api/tasks";
import type { ThreadsApi } from "./desktop-api/threads";
import type { WindowApi } from "./desktop-api/window";
export type {
DesktopResult,
SaveTaskResult,
RunEventRecord,
HeartbeatPolicy,
} from "./desktop-api/common";
export type {
AgentsApi,
ApprovalsApi,
AutomationApi,
BudgetApi,
CommunicationApi,
CompaniesApi,
CredentialsApi,
RunsApi,
SkillsApi,
TasksApi,
ThreadsApi,
WindowApi,
};
export type DesktopApi =
& CompaniesApi
& AgentsApi
& TasksApi
& RunsApi
& ApprovalsApi
& CommunicationApi
& ThreadsApi
& CredentialsApi
& SkillsApi
& BudgetApi
& AutomationApi
& WindowApi;
@@ -1,15 +0,0 @@
import type { z } from "zod";
import type { AgentRecord } from "../../types";
import type { agentInputSchema, heartbeatSettingsSchema, hireRequestSchema, triggerHeartbeatSchema } from "../schemas-agents";
import type { entityGetterSchema } from "../schemas-badges";
import type { deleteEntitySchema } from "../schemas-badges";
import type { DesktopResult } from "./common";
export type AgentsApi = {
saveAgent: (input: z.infer<typeof agentInputSchema>) => Promise<DesktopResult<string>>;
requestHire: (input: z.infer<typeof hireRequestSchema>) => Promise<DesktopResult<{ agentId: string; approvalId: string; autoApproved: boolean }>>;
deleteAgent: (input: z.infer<typeof deleteEntitySchema>) => Promise<DesktopResult<boolean>>;
getAgent: (input: z.infer<typeof entityGetterSchema>) => Promise<DesktopResult<AgentRecord>>;
setHeartbeat: (input: z.infer<typeof heartbeatSettingsSchema>) => Promise<DesktopResult<boolean>>;
triggerHeartbeat: (input: z.infer<typeof triggerHeartbeatSchema>) => Promise<DesktopResult<string>>;
};
@@ -1,12 +0,0 @@
import type { z } from "zod";
import type { ApprovalRecord } from "../../types";
import type { approvalDecisionSchema, approvalInputSchema } from "../schemas-approvals";
import type { deleteEntitySchema, entityGetterSchema } from "../schemas-badges";
import type { DesktopResult } from "./common";
export type ApprovalsApi = {
requestApproval: (input: z.infer<typeof approvalInputSchema>) => Promise<DesktopResult<string>>;
decideApproval: (input: z.infer<typeof approvalDecisionSchema>) => Promise<DesktopResult<boolean>>;
deleteApproval: (input: z.infer<typeof deleteEntitySchema>) => Promise<DesktopResult<boolean>>;
getApproval: (input: z.infer<typeof entityGetterSchema>) => Promise<DesktopResult<ApprovalRecord>>;
};
@@ -1,23 +0,0 @@
import type { z } from "zod";
import type { BrowserActionRecord } from "../../types";
import type { automationRuleInputSchema, toggleAutomationRuleSchema } from "../schemas-automation";
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 { DesktopResult } from "./common";
export type AutomationApi = {
saveAutomationRule: (input: z.infer<typeof automationRuleInputSchema>) => Promise<DesktopResult<string>>;
deleteAutomationRule: (input: z.infer<typeof deleteEntitySchema>) => Promise<DesktopResult<boolean>>;
toggleAutomationRule: (input: z.infer<typeof toggleAutomationRuleSchema>) => Promise<DesktopResult<boolean>>;
getAutomationLog: (companyId: string) => Promise<DesktopResult<Array<{ ruleId: string; ruleName: string; trigger: string; action: string; executedAt: string }>>>;
saveWorkflow: (input: z.infer<typeof workflowInputSchema>) => Promise<DesktopResult<string>>;
deleteWorkflow: (input: z.infer<typeof deleteEntitySchema>) => Promise<DesktopResult<boolean>>;
runWorkflow: (input: z.infer<typeof runWorkflowSchema>) => Promise<DesktopResult<boolean>>;
saveSocialAccount: (input: z.infer<typeof socialAccountInputSchema>) => Promise<DesktopResult<string>>;
deleteSocialAccount: (input: z.infer<typeof deleteEntitySchema>) => Promise<DesktopResult<boolean>>;
listBrowserActions: (input: z.infer<typeof browserActionQuerySchema>) => Promise<DesktopResult<BrowserActionRecord[]>>;
cancelBrowserAction: (input: z.infer<typeof cancelBrowserActionSchema>) => Promise<DesktopResult<boolean>>;
triggerBrowserLogin: (input: z.infer<typeof triggerBrowserLoginSchema>) => Promise<DesktopResult<boolean>>;
openTerminalCommand: (input: z.infer<typeof openTerminalCommandSchema>) => Promise<DesktopResult<boolean>>;
};
@@ -1,13 +0,0 @@
import type { z } from "zod";
import type { BudgetIncidentRecord, BudgetPolicyRecord, BudgetStatusSummary } from "../../types";
import type { budgetPolicyInputSchema, deleteBudgetPolicySchema, listBudgetIncidentsSchema, resolveBudgetIncidentSchema } from "../schemas-budget";
import type { DesktopResult } from "./common";
export type BudgetApi = {
saveBudgetPolicy: (input: z.infer<typeof budgetPolicyInputSchema>) => Promise<DesktopResult<string>>;
deleteBudgetPolicy: (input: z.infer<typeof deleteBudgetPolicySchema>) => Promise<DesktopResult<boolean>>;
listBudgetPolicies: (companyId: string) => Promise<DesktopResult<BudgetPolicyRecord[]>>;
listBudgetIncidents: (input: z.infer<typeof listBudgetIncidentsSchema>) => Promise<DesktopResult<BudgetIncidentRecord[]>>;
resolveBudgetIncident: (input: z.infer<typeof resolveBudgetIncidentSchema>) => Promise<DesktopResult<boolean>>;
getBudgetStatus: (companyId: string) => Promise<DesktopResult<BudgetStatusSummary>>;
};
@@ -1,29 +0,0 @@
export type DesktopResult<T> =
| { ok: true; data: T }
| { ok: false; error: { code: string; message: string } };
export interface SaveTaskResult {
id: string;
capabilityWarning?: string;
}
export interface RunEventRecord {
id: number;
runId: string;
agentId: string;
seq: number;
eventType: string;
stream: string | null;
level: string | null;
message: string | null;
payload: Record<string, unknown> | null;
createdAt: string;
}
export interface HeartbeatPolicy {
enabled: boolean;
intervalSec: number;
cooldownSec: number;
maxConcurrentRuns: number;
wakeOnDemand: boolean;
}
@@ -1,20 +0,0 @@
import type { z } from "zod";
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<typeof commentInputSchema>) => Promise<DesktopResult<string>>;
saveMeeting: (input: z.infer<typeof meetingInputSchema>) => Promise<DesktopResult<string>>;
deleteMeeting: (input: z.infer<typeof deleteEntitySchema>) => Promise<DesktopResult<boolean>>;
saveDocument: (input: z.infer<typeof documentInputSchema>) => Promise<DesktopResult<string>>;
deleteDocument: (input: z.infer<typeof deleteEntitySchema>) => Promise<DesktopResult<boolean>>;
saveKnowledgeEntry: (input: z.infer<typeof knowledgeEntryInputSchema>) => Promise<DesktopResult<string>>;
deleteKnowledgeEntry: (input: z.infer<typeof deleteEntitySchema>) => Promise<DesktopResult<boolean>>;
sendAgentMessage: (input: z.infer<typeof agentMessageInputSchema>) => Promise<DesktopResult<import("@shared/types").SendMessageResult>>;
markMessageRead: (input: z.infer<typeof markMessageReadSchema>) => Promise<DesktopResult<boolean>>;
searchMessages: (input: z.infer<typeof searchMessagesSchema>) => Promise<DesktopResult<AgentMessageRecord[]>>;
// Keep reference to silence unused-import checker for DocumentRecord/KnowledgeEntryRecord — consumers infer via schemas.
_recordsAnchor?: never & { _d?: DocumentRecord; _k?: KnowledgeEntryRecord };
};
@@ -1,28 +0,0 @@
import type { z } from "zod";
import type { CompanyMetrics, OnboardingBootstrapResult, ProfileSnapshot, StandupReport } from "../../types";
import type { bootstrapOnboardingSchema, companyInputSchema, connectorDisabledModelsSchema, connectorInputSchema, managedPathInputSchema, settingsSchema } from "../schemas-company";
import type { entityGetterSchema, metricsQuerySchema } from "../schemas-badges";
import type { DesktopResult } from "./common";
export type CompaniesApi = {
loadSnapshot: () => Promise<DesktopResult<ProfileSnapshot>>;
pickDirectory: () => Promise<DesktopResult<string | null>>;
openPath: (input: z.infer<typeof managedPathInputSchema>) => Promise<DesktopResult<boolean>>;
openWorkProduct: (input: z.infer<typeof entityGetterSchema>) => Promise<DesktopResult<boolean>>;
saveCompany: (input: z.infer<typeof companyInputSchema>) => Promise<DesktopResult<string>>;
setCurrentCompany: (companyId: string) => Promise<DesktopResult<boolean>>;
saveConnector: (input: z.infer<typeof connectorInputSchema>) => Promise<DesktopResult<boolean>>;
testConnector: (id: z.infer<typeof connectorInputSchema.shape.id>) => Promise<DesktopResult<boolean>>;
updateSettings: (input: z.infer<typeof settingsSchema>) => Promise<DesktopResult<boolean>>;
checkForUpdates: () => Promise<DesktopResult<boolean>>;
deleteCompany: (companyId: string) => Promise<DesktopResult<boolean>>;
listConnectorModels: (connectorId: string) => Promise<DesktopResult<Array<{ id: string; label: string }>>>;
getConnectorDisabledModels: (connectorId: string) => Promise<DesktopResult<Array<{ id: string; label: string }>>>;
setConnectorDisabledModels: (input: z.infer<typeof connectorDisabledModelsSchema>) => Promise<DesktopResult<boolean>>;
getCompanyMetrics: (input: z.infer<typeof metricsQuerySchema>) => Promise<DesktopResult<CompanyMetrics>>;
getStandupReport: (companyId: string) => Promise<DesktopResult<StandupReport>>;
bootstrapOnboarding: (input: z.infer<typeof bootstrapOnboardingSchema>) => Promise<DesktopResult<OnboardingBootstrapResult>>;
checkNodeInstalled: () => Promise<DesktopResult<{ installed: boolean; version: string | null }>>;
backupProfile: () => Promise<DesktopResult<string | null>>;
restoreProfile: () => Promise<DesktopResult<boolean>>;
};
@@ -1,26 +0,0 @@
import type { deleteEntitySchema } from "../schemas-badges";
import type { z } from "zod";
import type {
CredentialSummary,
SaveCredentialInput,
} from "../schemas-credentials";
import type {
OAuthStartInput,
OAuthPromptResponseInput,
OAuthManualCodeResponseInput,
} from "../schemas-oauth";
import type { DesktopResult } from "./common";
export type CredentialsApi = {
deleteSecret: (input: z.infer<typeof deleteEntitySchema>) => Promise<DesktopResult<boolean>>;
// pi-mono credentials
listCredentials: () => Promise<DesktopResult<CredentialSummary[]>>;
saveCredential: (input: SaveCredentialInput) => Promise<DesktopResult<CredentialSummary>>;
removeCredential: (input: { connectorId: string }) => Promise<DesktopResult<boolean>>;
testCredential: (input: { connectorId: string }) => Promise<DesktopResult<{ ok: boolean; message: string }>>;
// pi-mono OAuth
startOAuth: (input: OAuthStartInput) => Promise<DesktopResult<boolean>>;
cancelOAuth: (input: { connectorId: string }) => Promise<DesktopResult<boolean>>;
submitOAuthPrompt: (input: OAuthPromptResponseInput) => Promise<DesktopResult<boolean>>;
submitOAuthManualCode: (input: OAuthManualCodeResponseInput) => Promise<DesktopResult<boolean>>;
};
-15
View File
@@ -1,15 +0,0 @@
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 } from "./common";
export type RunsApi = {
startTaskRun: (input: z.infer<typeof startRunSchema>) => Promise<DesktopResult<string>>;
cancelRun: (input: z.infer<typeof cancelRunSchema>) => Promise<DesktopResult<boolean>>;
getRunLog: (input: z.infer<typeof runLogSchema>) => Promise<DesktopResult<string>>;
getRunLogChunk: (input: z.infer<typeof runLogChunkSchema>) => Promise<DesktopResult<RunLogChunk>>;
getRun: (input: z.infer<typeof entityGetterSchema>) => Promise<DesktopResult<RunRecord>>;
recoveryRetry: (taskId: string, agentId: string, companyId: string) => Promise<DesktopResult<null>>;
recoveryFail: (taskId: string, companyId: string) => Promise<DesktopResult<null>>;
};
@@ -1,15 +0,0 @@
import type { SkillImportResult, SkillRecord, SkillUpdateStatus } from "../../types";
import type { DesktopResult } from "./common";
export type SkillsApi = {
importSkill: (companyId: string, source: string) => Promise<DesktopResult<SkillImportResult[]>>;
listSkills: (companyId: string) => Promise<DesktopResult<SkillRecord[]>>;
getSkillDetail: (companyId: string, skillId: string) => Promise<DesktopResult<SkillRecord>>;
getSkillMarkdown: (companyId: string, slug: string) => Promise<DesktopResult<string>>;
deleteSkill: (companyId: string, skillId: string) => Promise<DesktopResult<void>>;
assignSkillToAgent: (companyId: string, agentId: string, skillId: string) => Promise<DesktopResult<void>>;
removeSkillFromAgent: (companyId: string, agentId: string, skillId: string) => Promise<DesktopResult<void>>;
checkSkillUpdate: (companyId: string, skillId: string) => Promise<DesktopResult<SkillUpdateStatus>>;
listSkillAgents: (companyId: string, skillId: string) => Promise<DesktopResult<string[]>>;
listAgentSkills: (companyId: string, agentId: string) => Promise<DesktopResult<string[]>>;
};
-20
View File
@@ -1,20 +0,0 @@
import type { z } from "zod";
import type { TaskRecord } from "../../types";
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";
export type TasksApi = {
saveWorkspace: (input: z.infer<typeof workspaceInputSchema>) => Promise<DesktopResult<string>>;
saveGoal: (input: z.infer<typeof goalInputSchema>) => Promise<DesktopResult<string>>;
saveProject: (input: z.infer<typeof projectInputSchema>) => Promise<DesktopResult<string>>;
saveTask: (input: z.infer<typeof taskInputSchema>) => Promise<DesktopResult<SaveTaskResult>>;
saveSprint: (input: z.infer<typeof sprintInputSchema>) => Promise<DesktopResult<string>>;
deleteTask: (input: z.infer<typeof deleteEntitySchema>) => Promise<DesktopResult<boolean>>;
deleteGoal: (input: z.infer<typeof deleteEntitySchema>) => Promise<DesktopResult<boolean>>;
deleteProject: (input: z.infer<typeof deleteEntitySchema>) => Promise<DesktopResult<boolean>>;
deleteWorkspace: (input: z.infer<typeof deleteEntitySchema>) => Promise<DesktopResult<boolean>>;
deleteSprint: (input: z.infer<typeof deleteEntitySchema>) => Promise<DesktopResult<boolean>>;
getTask: (input: z.infer<typeof entityGetterSchema>) => Promise<DesktopResult<TaskRecord>>;
};
@@ -1,11 +0,0 @@
import type { z } from "zod";
import type { ConversationEventRecord, ConversationParticipantRecord, ConversationThreadRecord, ThreadWaitStateRecord } from "../../types";
import type { listThreadEventsSchema, listThreadParticipantsSchema, listThreadWaitStatesSchema, threadGetterSchema } from "../schemas-threads";
import type { DesktopResult } from "./common";
export type ThreadsApi = {
getThread: (input: z.infer<typeof threadGetterSchema>) => Promise<DesktopResult<ConversationThreadRecord>>;
listThreadEvents: (input: z.infer<typeof listThreadEventsSchema>) => Promise<DesktopResult<ConversationEventRecord[]>>;
listThreadWaitStates: (input: z.infer<typeof listThreadWaitStatesSchema>) => Promise<DesktopResult<ThreadWaitStateRecord[]>>;
listThreadParticipants: (input: z.infer<typeof listThreadParticipantsSchema>) => Promise<DesktopResult<ConversationParticipantRecord[]>>;
};
@@ -1,10 +0,0 @@
import type { DesktopEvent } from "../../types";
export type WindowApi = {
subscribe: (callback: (event: DesktopEvent) => void) => () => void;
platform: "win32" | "darwin" | "linux";
windowMinimize: () => Promise<void>;
windowMaximize: () => Promise<void>;
windowClose: () => Promise<void>;
windowIsMaximized: () => Promise<boolean>;
};
-31
View File
@@ -1,31 +0,0 @@
import { z } from "zod";
export const optionalId = z.preprocess(
(value) => (value === "" ? null : value),
z.string().uuid().nullable().optional(),
);
/** Canonical department identifiers shared across agent and automation schemas. */
export const DEPARTMENT_IDS = z.enum([
"executive", "engineering", "product", "marketing", "sales",
"hr", "finance", "legal", "operations", "customer_support", "research", "design",
]);
/** Canonical message channel types shared across messaging schemas. */
export const MESSAGE_CHANNELS = z.enum([
"direct", "department", "company", "project", "incident",
]);
/**
* Canonical automation trigger enum shared by `automationRuleInputSchema` and
* `workflowInputSchema`. Single source of truth: the TS `AutomationTrigger`
* alias in `types/enums.ts` derives from this enum.
*/
export const automationTriggerEnum = z.enum([
"task_status_changed", "task_created", "task_blocked", "task_reassigned",
"run_completed", "run_failed", "approval_created", "approval_resolved",
"budget_threshold", "agent_idle", "comment_posted", "document_created",
"schedule", "hire_approved", "sprint_started", "sprint_ended",
]);
export type AutomationTrigger = z.infer<typeof automationTriggerEnum>;
-80
View File
@@ -1,80 +0,0 @@
import { z } from "zod";
export type JsonValue =
| null
| boolean
| number
| string
| JsonValue[]
| { [key: string]: JsonValue };
export const jsonValueSchema: z.ZodType<JsonValue> = z.lazy(() => z.union([
z.null(),
z.boolean(),
z.number(),
z.string(),
z.array(jsonValueSchema),
z.record(z.string(), jsonValueSchema),
]));
export const jsonStringArraySchema = z.array(z.string());
export const jsonArraySchema = z.array(jsonValueSchema);
export const meetingActionItemArraySchema = z.array(z.object({
title: z.string().optional(),
assigneeAgentId: z.string().optional(),
description: z.string().optional(),
}).catchall(jsonValueSchema));
export function canonicalizeJsonString<T>(value: string | null | undefined, schema: z.ZodType<T>, fallback: T): string {
const raw = value ?? JSON.stringify(fallback);
const parsed = JSON.parse(raw);
return JSON.stringify(schema.parse(parsed));
}
export function canonicalJsonString<T>(schema: z.ZodType<T>, fallback: T) {
const fallbackJson = JSON.stringify(fallback);
return z.string().default(fallbackJson).superRefine((value, ctx) => {
let parsed: unknown;
try {
parsed = JSON.parse(value);
} catch {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Must be valid JSON.",
});
return;
}
const result = schema.safeParse(parsed);
if (!result.success) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "JSON value does not match the expected shape.",
});
}
}).transform((value) => canonicalizeJsonString(value, schema, fallback));
}
export function canonicalOptionalJsonString<T>(schema: z.ZodType<T>) {
return z.string().superRefine((value, ctx) => {
let parsed: unknown;
try {
parsed = JSON.parse(value);
} catch {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Must be valid JSON.",
});
return;
}
const result = schema.safeParse(parsed);
if (!result.success) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "JSON value does not match the expected shape.",
});
}
}).transform((value) => JSON.stringify(schema.parse(JSON.parse(value))));
}
-312
View File
@@ -1,312 +0,0 @@
import { z } from "zod";
import { IPC_CHANNELS } from "./channels";
import type { DesktopApi } from "./desktop-api";
import {
agentInputSchema,
heartbeatSettingsSchema,
hireRequestSchema,
triggerHeartbeatSchema,
} from "./schemas-agents";
import {
approvalDecisionSchema,
approvalInputSchema,
} from "./schemas-approvals";
import {
automationRuleInputSchema,
toggleAutomationRuleSchema,
} from "./schemas-automation";
import {
deleteEntitySchema,
entityGetterSchema,
} from "./schemas-badges";
import {
budgetPolicyInputSchema,
deleteBudgetPolicySchema,
resolveBudgetIncidentSchema,
} from "./schemas-budget";
import {
bootstrapOnboardingSchema,
companyIdSchema,
companyInputSchema,
connectorDisabledModelsSchema,
connectorInputSchema,
managedPathInputSchema,
socialAccountInputSchema,
settingsSchema,
workspaceInputSchema,
} from "./schemas-company";
import {
removeCredentialInputSchema,
saveCredentialInputSchema,
testCredentialInputSchema,
} from "./schemas-credentials";
import {
assignSkillToAgentSchema,
cancelBrowserActionSchema,
cancelRunSchema,
checkSkillUpdateSchema,
deleteSkillSchema,
importSkillSchema,
openTerminalCommandSchema,
recoveryRetrySchema,
recoveryTaskSchema,
removeSkillFromAgentSchema,
runWorkflowSchema,
startRunSchema,
triggerBrowserLoginSchema,
workflowInputSchema,
} from "./schemas-execution";
import {
agentMessageInputSchema,
commentInputSchema,
documentInputSchema,
knowledgeEntryInputSchema,
markMessageReadSchema,
meetingInputSchema,
} from "./schemas-messages";
import {
oauthCancelInputSchema,
oauthManualCodeResponseSchema,
oauthPromptResponseSchema,
oauthStartInputSchema,
} from "./schemas-oauth";
import {
goalInputSchema,
projectInputSchema,
sprintInputSchema,
taskInputSchema,
} from "./schemas-tasks";
type DesktopFunctionKey = {
[Key in keyof DesktopApi]: DesktopApi[Key] extends (...args: infer _Args) => unknown ? Key : never;
}[keyof DesktopApi];
type IpcChannelKey = keyof typeof IPC_CHANNELS;
export type PreloadPayloadSpec =
| Readonly<{ kind: "none" }>
| Readonly<{ kind: "single" }>
| Readonly<{ kind: "object"; keys: readonly string[] }>;
export type PreloadForwarder = Readonly<{
api: DesktopFunctionKey;
channel: IpcChannelKey;
payload: PreloadPayloadSpec;
}>;
const noPayload = { kind: "none" } as const;
const singlePayload = { kind: "single" } as const;
const objectPayload = <const Keys extends readonly string[]>(...keys: Keys) =>
({ kind: "object", keys } as const);
const forwardSame = <const Api extends Extract<DesktopFunctionKey, IpcChannelKey>>(
api: Api,
payload: PreloadPayloadSpec,
) => ({ api, channel: api, payload } as const);
const forwardAlias = <const Api extends DesktopFunctionKey, const Channel extends IpcChannelKey>(
api: Api,
channel: Channel,
payload: PreloadPayloadSpec,
) => ({ api, channel, payload } as const);
export const PRELOAD_FORWARDERS = [
forwardSame("loadSnapshot", noPayload),
forwardSame("pickDirectory", noPayload),
forwardSame("openPath", singlePayload),
forwardSame("openWorkProduct", singlePayload),
forwardSame("saveCompany", singlePayload),
forwardSame("setCurrentCompany", singlePayload),
forwardSame("saveConnector", singlePayload),
forwardSame("testConnector", singlePayload),
forwardSame("saveWorkspace", singlePayload),
forwardSame("saveAgent", singlePayload),
forwardSame("requestHire", singlePayload),
forwardSame("saveGoal", singlePayload),
forwardSame("saveProject", singlePayload),
forwardSame("saveTask", singlePayload),
forwardSame("requestApproval", singlePayload),
forwardSame("decideApproval", singlePayload),
forwardSame("startTaskRun", singlePayload),
forwardSame("cancelRun", singlePayload),
forwardSame("getRunLog", singlePayload),
forwardSame("getRunLogChunk", singlePayload),
forwardSame("backupProfile", noPayload),
forwardSame("restoreProfile", noPayload),
forwardSame("updateSettings", singlePayload),
forwardSame("checkForUpdates", noPayload),
forwardSame("deleteCompany", singlePayload),
forwardSame("deleteAgent", singlePayload),
forwardSame("deleteTask", singlePayload),
forwardSame("deleteGoal", singlePayload),
forwardSame("deleteProject", singlePayload),
forwardSame("deleteWorkspace", singlePayload),
forwardSame("deleteApproval", singlePayload),
forwardSame("deleteSecret", singlePayload),
forwardSame("listConnectorModels", singlePayload),
forwardSame("getConnectorDisabledModels", singlePayload),
forwardSame("setConnectorDisabledModels", singlePayload),
forwardSame("addComment", singlePayload),
forwardSame("setHeartbeat", singlePayload),
forwardSame("triggerHeartbeat", singlePayload),
forwardSame("getCompanyMetrics", singlePayload),
forwardSame("getStandupReport", singlePayload),
forwardSame("bootstrapOnboarding", singlePayload),
forwardSame("checkNodeInstalled", noPayload),
forwardSame("openTerminalCommand", singlePayload),
forwardSame("saveSocialAccount", singlePayload),
forwardSame("deleteSocialAccount", singlePayload),
forwardSame("listBrowserActions", singlePayload),
forwardSame("cancelBrowserAction", singlePayload),
forwardSame("triggerBrowserLogin", singlePayload),
forwardSame("saveMeeting", singlePayload),
forwardSame("deleteMeeting", singlePayload),
forwardSame("saveDocument", singlePayload),
forwardSame("deleteDocument", singlePayload),
forwardSame("saveKnowledgeEntry", singlePayload),
forwardSame("deleteKnowledgeEntry", singlePayload),
forwardSame("saveSprint", singlePayload),
forwardSame("deleteSprint", singlePayload),
forwardSame("saveAutomationRule", singlePayload),
forwardSame("deleteAutomationRule", singlePayload),
forwardSame("toggleAutomationRule", singlePayload),
forwardSame("getAutomationLog", singlePayload),
forwardSame("sendAgentMessage", singlePayload),
forwardSame("searchMessages", singlePayload),
forwardSame("markMessageRead", singlePayload),
forwardSame("saveWorkflow", singlePayload),
forwardSame("deleteWorkflow", singlePayload),
forwardSame("runWorkflow", singlePayload),
forwardSame("importSkill", objectPayload("companyId", "source")),
forwardSame("listSkills", objectPayload("companyId")),
forwardSame("getSkillDetail", objectPayload("companyId", "skillId")),
forwardSame("getSkillMarkdown", objectPayload("companyId", "slug")),
forwardSame("deleteSkill", objectPayload("companyId", "skillId")),
forwardSame("assignSkillToAgent", objectPayload("companyId", "agentId", "skillId")),
forwardSame("removeSkillFromAgent", objectPayload("companyId", "agentId", "skillId")),
forwardSame("checkSkillUpdate", objectPayload("companyId", "skillId")),
forwardSame("listSkillAgents", objectPayload("companyId", "skillId")),
forwardSame("listAgentSkills", objectPayload("companyId", "agentId")),
forwardSame("saveBudgetPolicy", singlePayload),
forwardSame("deleteBudgetPolicy", singlePayload),
forwardSame("listBudgetPolicies", objectPayload("companyId")),
forwardSame("listBudgetIncidents", singlePayload),
forwardSame("resolveBudgetIncident", singlePayload),
forwardSame("getBudgetStatus", objectPayload("companyId")),
forwardSame("recoveryRetry", objectPayload("taskId", "agentId", "companyId")),
forwardSame("recoveryFail", objectPayload("taskId", "companyId")),
forwardSame("getTask", singlePayload),
forwardSame("getAgent", singlePayload),
forwardSame("getRun", singlePayload),
forwardSame("getApproval", singlePayload),
forwardSame("getThread", singlePayload),
forwardSame("listThreadEvents", singlePayload),
forwardSame("listThreadWaitStates", singlePayload),
forwardSame("listThreadParticipants", singlePayload),
forwardAlias("listCredentials", "credentialsList", noPayload),
forwardAlias("saveCredential", "credentialsSave", singlePayload),
forwardAlias("removeCredential", "credentialsRemove", singlePayload),
forwardAlias("testCredential", "credentialsTest", singlePayload),
forwardAlias("startOAuth", "oauthStart", singlePayload),
forwardAlias("cancelOAuth", "oauthCancel", singlePayload),
forwardAlias("submitOAuthPrompt", "oauthPromptResponse", singlePayload),
forwardAlias("submitOAuthManualCode", "oauthManualCodeResponse", singlePayload),
] as const satisfies readonly PreloadForwarder[];
export type PreloadForwardedMethod = (typeof PRELOAD_FORWARDERS)[number]["api"];
export type PreloadForwardedApi = Pick<DesktopApi, PreloadForwardedMethod>;
export const PRELOAD_INPUT_SCHEMAS: Partial<Record<PreloadForwardedMethod, z.ZodType<unknown>>> = {
openPath: managedPathInputSchema,
openWorkProduct: entityGetterSchema,
saveCompany: companyInputSchema,
setCurrentCompany: companyIdSchema,
saveConnector: connectorInputSchema,
testConnector: connectorInputSchema.shape.id,
saveWorkspace: workspaceInputSchema,
saveAgent: agentInputSchema,
requestHire: hireRequestSchema,
saveGoal: goalInputSchema,
saveProject: projectInputSchema,
saveTask: taskInputSchema,
requestApproval: approvalInputSchema,
decideApproval: approvalDecisionSchema,
startTaskRun: startRunSchema,
cancelRun: cancelRunSchema,
updateSettings: settingsSchema,
deleteCompany: companyIdSchema,
deleteAgent: deleteEntitySchema,
deleteTask: deleteEntitySchema,
deleteGoal: deleteEntitySchema,
deleteProject: deleteEntitySchema,
deleteWorkspace: deleteEntitySchema,
deleteApproval: deleteEntitySchema,
deleteSecret: deleteEntitySchema,
setConnectorDisabledModels: connectorDisabledModelsSchema,
addComment: commentInputSchema,
setHeartbeat: heartbeatSettingsSchema,
triggerHeartbeat: triggerHeartbeatSchema,
bootstrapOnboarding: bootstrapOnboardingSchema,
openTerminalCommand: openTerminalCommandSchema,
saveSocialAccount: socialAccountInputSchema,
deleteSocialAccount: deleteEntitySchema,
cancelBrowserAction: cancelBrowserActionSchema,
triggerBrowserLogin: triggerBrowserLoginSchema,
saveMeeting: meetingInputSchema,
deleteMeeting: deleteEntitySchema,
saveDocument: documentInputSchema,
deleteDocument: deleteEntitySchema,
saveKnowledgeEntry: knowledgeEntryInputSchema,
deleteKnowledgeEntry: deleteEntitySchema,
saveSprint: sprintInputSchema,
deleteSprint: deleteEntitySchema,
saveAutomationRule: automationRuleInputSchema,
deleteAutomationRule: deleteEntitySchema,
toggleAutomationRule: toggleAutomationRuleSchema,
sendAgentMessage: agentMessageInputSchema,
markMessageRead: markMessageReadSchema,
saveWorkflow: workflowInputSchema,
deleteWorkflow: deleteEntitySchema,
runWorkflow: runWorkflowSchema,
importSkill: importSkillSchema,
deleteSkill: deleteSkillSchema,
assignSkillToAgent: assignSkillToAgentSchema,
removeSkillFromAgent: removeSkillFromAgentSchema,
checkSkillUpdate: checkSkillUpdateSchema,
saveBudgetPolicy: budgetPolicyInputSchema,
deleteBudgetPolicy: deleteBudgetPolicySchema,
resolveBudgetIncident: resolveBudgetIncidentSchema,
recoveryRetry: recoveryRetrySchema,
recoveryFail: recoveryTaskSchema,
saveCredential: saveCredentialInputSchema,
removeCredential: removeCredentialInputSchema,
testCredential: testCredentialInputSchema,
startOAuth: oauthStartInputSchema,
cancelOAuth: oauthCancelInputSchema,
submitOAuthPrompt: oauthPromptResponseSchema,
submitOAuthManualCode: oauthManualCodeResponseSchema,
};
export function mapPreloadInvokeArgs(
payload: PreloadPayloadSpec,
args: readonly unknown[],
schema?: z.ZodType<unknown>,
): readonly unknown[] {
if (payload.kind === "none") {
assertArgCount(payload.kind, args.length, 0);
return [];
}
if (payload.kind === "single") {
assertArgCount(payload.kind, args.length, 1);
return [schema ? schema.parse(args[0]) : args[0]];
}
assertArgCount(payload.kind, args.length, payload.keys.length);
const objectPayload = Object.fromEntries(payload.keys.map((key, index) => [key, args[index]]));
return [schema ? schema.parse(objectPayload) : objectPayload];
}
function assertArgCount(kind: PreloadPayloadSpec["kind"], actual: number, expected: number): void {
if (actual !== expected) {
throw new Error(`Invalid preload ${kind} argument count: expected ${expected}, received ${actual}`);
}
}
@@ -1,19 +0,0 @@
import { z } from "zod";
/**
* The renderer-bound `agent-event` push payload.
*
* The `event` payload is pi's AgentEvent (discriminated by `type`). We do not
* mirror pi's type system in Zod (it would couple the renderer to pi's
* internals); we validate the envelope and pass the event through opaquely.
*/
export const agentEventPushSchema = z.object({
runId: z.string(),
agentId: z.string(),
companyId: z.string(),
taskId: z.string().nullable(),
emittedAt: z.string(),
event: z.object({
type: z.string(),
}).passthrough(),
});
-53
View File
@@ -1,53 +0,0 @@
import { z } from "zod";
import { DEPARTMENT_IDS, optionalId } from "./helpers";
import { connectorInputSchema } from "./schemas-company";
const agentNameSchema = z.string().trim().min(2).max(80);
const agentRoleSchema = z.string().trim().min(2).max(80);
const agentTitleSchema = z.string().trim().max(80).default("");
export const agentInputSchema = z.object({
id: optionalId,
companyId: z.string().uuid(),
name: agentNameSchema,
role: agentRoleSchema,
title: agentTitleSchema,
department: DEPARTMENT_IDS.nullable().optional(),
reportsTo: optionalId,
connectorId: connectorInputSchema.shape.id,
workspaceId: optionalId,
model: z.string().nullable().optional(),
metadataJson: z.string().default("{}").optional(),
capabilities: z.string().default(""),
budgetMonthlyUsd: z.number().min(0).default(0),
status: z.enum(["idle", "active", "running", "paused", "error", "pending_approval", "terminated"]).default("idle"),
});
export const hireRequestSchema = z.object({
companyId: z.string().uuid(),
requestedByAgentId: optionalId,
name: agentNameSchema,
role: agentRoleSchema,
title: agentTitleSchema,
department: DEPARTMENT_IDS.nullable().optional(),
reportsTo: optionalId,
connectorId: connectorInputSchema.shape.id,
workspaceId: optionalId,
model: z.string().nullable().optional(),
metadataJson: z.string().default("{}").optional(),
capabilities: z.string().default(""),
budgetMonthlyUsd: z.number().min(0).default(0),
});
export const heartbeatSettingsSchema = z.object({
agentId: z.string().uuid(),
companyId: z.string().uuid(),
enabled: z.boolean(),
intervalSec: z.number().int().min(30).max(86400).default(120),
});
export const triggerHeartbeatSchema = z.object({
agentId: z.string().uuid(),
companyId: z.string().uuid(),
trigger: z.enum(["manual", "timer", "assignment", "goal_activated", "approval_resolved", "subtask_completed", "task_review_requested", "comment", "report_blocked", "report_failed", "recovery", "message", "peer_request", "task_continuation"]).default("manual"),
});
-85
View File
@@ -1,85 +0,0 @@
import { z } from "zod";
import { optionalId } from "./helpers";
// Schema-typed attachment pointers. Agents used to jam everything into the
// free-form `payloadJson` string, which meant the board UI had to parse JSON
// blind and hope the keys matched. documentIds / workProductIds make the
// attachment contract schema-visible: validators see them, the HTTP route
// folds them back into payloadJson for persistence, and the inspector renders
// them deterministically in the "linked documents" panel on the first screen.
// payloadJson remains as the escape hatch for type-specific structured
// fields (social post drafts, hire proposals, etc.).
export const approvalInputSchema = z.object({
companyId: z.string().uuid(),
relatedTaskId: optionalId,
requestedByAgentId: optionalId,
relatedAgentId: optionalId,
type: z.enum(["hire_agent", "approve_ceo_strategy", "dangerous_command", "secret_access", "budget_request", "promotion", "termination", "vendor_approval", "document_review", "production_deploy", "incident_escalation", "social_post", "deliverable_review", "budget_override", "plan_review", "scope_review", "draft_review", "strategy_review", "exception_review"]),
payloadSummary: z.string().min(2).max(280),
impactSummary: z.string().min(2).max(400),
// payloadJson: type-specific structured fields only (social draft, hire
// proposal, etc). DEPRECATED: embedding `documentIds` / `workProductIds` /
// `documents[]` / `workProducts[]` here. Use the top-level schema fields
// below — they are the canonical source of truth for attachment pointers.
// Legacy embedded mirrors are still read for back-compat but new callers
// must not write them.
payloadJson: z.string().nullable().optional(),
// CANONICAL attachment pointers. mergeApprovalAttachments folds these into
// payloadJson at persist time so on-disk rows have a single readable shape,
// but the schema top-level is the authoritative contract.
documentIds: z.array(z.string().uuid()).optional(),
workProductIds: z.array(z.string().uuid()).optional(),
});
/**
* Merge canonical documentIds / workProductIds (schema top-level) into
* payloadJson so downstream readers (ApprovalDocumentsPanel,
* extractApprovalDocumentReferences) see a single source of truth.
*
* Throws if payloadJson is non-empty but not valid JSON-object: the previous
* behavior stuffed the opaque string under `rawPayload` which hid producer
* bugs (an agent passing a stringified-twice JSON, or a literal "undefined")
* and silently broke attachment rendering. Let it crash at the boundary.
*/
export function mergeApprovalAttachments(
payloadJson: string | null | undefined,
documentIds: string[] | undefined,
workProductIds: string[] | undefined,
): string | null {
const hasDocs = Array.isArray(documentIds) && documentIds.length > 0;
const hasProducts = Array.isArray(workProductIds) && workProductIds.length > 0;
if (!hasDocs && !hasProducts) return payloadJson ?? null;
let base: Record<string, unknown> = {};
if (payloadJson) {
let parsed: unknown;
try {
parsed = JSON.parse(payloadJson);
} catch (error) {
const detail = error instanceof Error ? error.message : String(error);
throw new Error(
`mergeApprovalAttachments: payloadJson is not valid JSON (${detail}). ` +
`payloadJson must be a JSON object or null; free-text payloads are not supported.`,
);
}
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
throw new Error(
`mergeApprovalAttachments: payloadJson must be a JSON object (got ${
Array.isArray(parsed) ? "array" : parsed === null ? "null" : typeof parsed
}).`,
);
}
base = parsed as Record<string, unknown>;
}
if (hasDocs) base.documentIds = documentIds;
if (hasProducts) base.workProductIds = workProductIds;
return JSON.stringify(base);
}
export const approvalDecisionSchema = z.object({
companyId: z.string().uuid(),
approvalId: z.string().uuid(),
state: z.enum(["approved", "rejected", "revision_requested"]),
decisionNote: z.string().max(400).default(""),
});
@@ -1,28 +0,0 @@
import { z } from "zod";
import { DEPARTMENT_IDS, automationTriggerEnum } from "./helpers";
export const automationRuleInputSchema = z.object({
id: z.preprocess((v) => (v === "" ? null : v), z.string().uuid().nullable().optional()),
companyId: z.string().uuid(),
name: z.string().min(2).max(120),
description: z.string().max(500).default(""),
trigger: automationTriggerEnum,
conditionsJson: z.string().default("{}"),
action: z.enum([
"assign_task", "create_task", "notify_agent", "send_message",
"trigger_heartbeat", "create_approval", "update_task_status",
"escalate_to_manager", "cross_department_notify", "schedule_meeting",
"create_document", "auto_approve", "reassign_task", "run_task",
]),
actionConfigJson: z.string().default("{}"),
sourceDepartment: DEPARTMENT_IDS.nullable().optional(),
targetDepartment: DEPARTMENT_IDS.nullable().optional(),
priority: z.number().int().min(0).max(100).default(50),
status: z.enum(["active", "paused", "disabled", "error"]).default("active"),
});
export const toggleAutomationRuleSchema = z.object({
id: z.string().uuid(),
companyId: z.string().uuid(),
status: z.enum(["active", "paused"]),
});
-23
View File
@@ -1,23 +0,0 @@
import { z } from "zod";
export const deleteEntitySchema = z.object({
id: z.string().uuid(),
companyId: z.string().uuid(),
});
export const entityGetterSchema = z.object({
companyId: z.string().uuid(),
id: z.string().uuid(),
});
export const metricsQuerySchema = z.object({
companyId: z.string().uuid(),
agentId: z.string().uuid().optional(),
days: z.number().int().min(1).max(90).default(30),
});
// `SidebarBadges` and its Zod schema used to live here as an IPC
// response type. Sidebar badges are now derived in the renderer from
// `ProfileSnapshot` (see `src/shared/sidebar-badges.ts`), so no wire
// contract is needed — `deriveSidebarBadges(snapshot)` is the only
// path that produces a `SidebarBadges` value.
-39
View File
@@ -1,39 +0,0 @@
import { z } from "zod";
import { optionalId } from "./helpers";
export const budgetPolicyInputSchema = z.object({
id: optionalId,
companyId: z.string().uuid(),
scopeType: z.enum(["company", "agent", "project"]),
scopeId: z.string().uuid(),
metric: z.literal("billed_cents").default("billed_cents"),
windowKind: z.literal("calendar_month_utc").default("calendar_month_utc"),
amount: z.number().int().min(1),
warnPercent: z.number().int().min(1).max(100).default(80),
hardStopEnabled: z.boolean().default(true),
notifyEnabled: z.boolean().default(true),
isActive: z.boolean().default(true),
});
export const listBudgetPoliciesSchema = z.object({
companyId: z.string().uuid(),
});
export const deleteBudgetPolicySchema = z.object({
companyId: z.string().uuid(),
policyId: z.string().uuid(),
});
export const listBudgetIncidentsSchema = z.object({
companyId: z.string().uuid(),
status: z.enum(["open", "resolved", "auto_resolved_limit_increase", "auto_closed", "all"]).default("all"),
});
export const resolveBudgetIncidentSchema = z.object({
companyId: z.string().uuid(),
incidentId: z.string().uuid(),
});
export const getBudgetStatusSchema = z.object({
companyId: z.string().uuid(),
});
-143
View File
@@ -1,143 +0,0 @@
import { z } from "zod";
import { optionalId } from "./helpers";
export const companyIdSchema = z.string().uuid();
export const managedPathInputSchema = z.object({
companyId: companyIdSchema,
path: z.string().min(1),
});
export const companyInputSchema = z.object({
id: optionalId,
name: z.string().min(2).max(80),
description: z.string().max(500).default(""),
status: z.enum(["active", "paused", "archived"]).default("active"),
autoApproveHires: z.boolean().default(false),
reviewDeliverables: z.boolean().default(false),
executionMode: z.enum(["ai_ceo", "ai_cofounder"]).default("ai_ceo"),
});
/**
* Pure pi-mono connector catalog ids. Single source of truth: this zod enum.
* The TS `ConnectorId` alias (`shared/types/enums.ts`) and the catalog
* (`shared/connector-catalog.ts`) both derive from it. Adding a connector
* requires editing this list only.
*/
export const connectorIdEnum = z.enum([
// OAuth (5)
"claude-pro",
"openai-codex",
"github-copilot",
"gemini-cli",
"antigravity",
// API key (18)
"anthropic",
"openai",
"google",
"mistral",
"groq",
"cerebras",
"xai",
"openrouter",
"vercel-ai-gateway",
"zai",
"opencode",
"opencode-go",
"huggingface",
"kimi-coding",
"minimax",
"minimax-cn",
"fireworks",
"fireworks-firepass",
// Cloud (3)
"amazon-bedrock",
"azure-openai",
"google-vertex",
// Local (2)
"ollama",
"lm-studio",
]);
export type ConnectorId = z.infer<typeof connectorIdEnum>;
export const connectorInputSchema = z.object({
id: connectorIdEnum,
model: z.string().nullable().optional(),
envBindingText: z.string().default(""),
notes: z.string().default(""),
});
export const connectorDisabledModelsSchema = z.object({
companyId: z.string().uuid(),
connectorId: connectorInputSchema.shape.id,
disabledModels: z.array(z.object({ id: z.string(), label: z.string() })),
});
export const connectorModelPoolQuerySchema = z.object({
companyId: z.string().uuid(),
connectorId: connectorInputSchema.shape.id,
});
export const workspaceInputSchema = z.object({
id: optionalId,
companyId: z.string().uuid(),
name: z.string().min(2).max(80),
localPath: z.string().min(1),
repoUrl: z.string().default(""),
repoRef: z.string().default(""),
projectId: optionalId,
isPrimary: z.boolean().default(false),
});
export const settingsSchema = z.object({
theme: z.enum(["system", "light", "dark"]).optional(),
locale: z.enum(["en", "zh"]).optional(),
updatesEnabled: z.boolean().optional(),
logRetentionDays: z.number().int().min(1).max(365).optional(),
});
export const bootstrapOnboardingSchema = z.object({
companyName: z.string().min(2).max(80),
companyDescription: z.string().max(500).default(""),
workspacePath: z.string().default(""),
autoApproveHires: z.boolean().default(true),
reviewDeliverables: z.boolean().default(false),
executionMode: z.enum(["ai_ceo", "ai_cofounder"]).default("ai_ceo"),
goalTitle: z.string().default(""),
goalDescription: z.string().default(""),
connectorId: connectorInputSchema.shape.id.optional(),
connectorModel: z.string().default(""),
// Per-connector disabled-model selections gathered during onboarding.
// Persisted against the new company's id once it is created, so they
// are scoped correctly from the first moment the company exists.
connectorPoolSelections: z
.array(
z.object({
connectorId: connectorInputSchema.shape.id,
disabledModels: z.array(z.object({ id: z.string(), label: z.string() })),
}),
)
.default([]),
});
export const socialAccountInputSchema = z.object({
id: optionalId,
companyId: z.string().uuid(),
platform: z.enum(["twitter", "linkedin", "instagram", "facebook", "reddit", "youtube", "tiktok", "bluesky", "discord", "threads", "pinterest", "telegram", "whatsapp", "wechat", "weibo", "xiaohongshu", "douyin", "bilibili", "zhihu", "other"]),
accountName: z.string().min(1).max(120),
displayName: z.string().max(120).default(""),
profileUrl: z.string().max(500).default(""),
credentialSecretId: optionalId,
status: z.enum(["active", "logged_in", "login_required", "suspended", "paused"]).default("login_required"),
requireApproval: z.boolean().default(true),
metadataJson: z.string().default("{}"),
});
export const secretInputSchema = z.object({
id: optionalId,
companyId: z.string().uuid(),
name: z.string().min(2).max(80),
description: z.string().default(""),
value: z.string().min(1).max(2000),
});
-200
View File
@@ -1,200 +0,0 @@
import { z } from "zod";
export const credentialKindSchema = z.enum([
"oauth",
"api_key",
"aws",
"azure",
"gcp_adc",
"local",
]);
export const credentialStatusSchema = z.enum([
"active",
"expired",
"revoked",
"error",
"not_configured",
]);
export const apiKeyValueSchema = z.object({
source: z.enum(["literal", "env"]),
value: z.string().min(1),
});
const AWS_REGION_SEGMENT = "[a-z]{2}(?:-gov)?-[a-z]+-\\d";
const AWS_BEDROCK_RUNTIME_HOSTNAME = new RegExp(
`^bedrock-runtime(?:-fips)?\\.${AWS_REGION_SEGMENT}\\.amazonaws\\.com(?:\\.cn)?$`,
);
const AWS_BEDROCK_VPCE_HOSTNAME = new RegExp(
`^vpce-[a-z0-9-]+\\.bedrock-runtime(?:-fips)?\\.${AWS_REGION_SEGMENT}\\.vpce\\.amazonaws\\.com(?:\\.cn)?$`,
);
export const azureCredentialSchema = z.object({
apiKey: z.string().min(1),
baseUrl: z.string().url().optional().or(z.literal("")),
resourceName: z.string().optional().or(z.literal("")),
apiVersion: z.string().optional().or(z.literal("")),
deploymentMap: z.record(z.string(), z.string()).optional(),
});
export const awsEndpointUrlSchema = z
.string()
.url()
.refine(
isAwsBedrockEndpointUrl,
"AWS Bedrock endpointUrl must be an HTTPS AWS Bedrock runtime endpoint or a private endpoint.",
);
export const awsCredentialSchema = z.object({
authMode: z.enum(["profile", "iam", "bearer"]),
region: z.string().min(1).default("us-east-1"),
awsProfile: z.string().optional(),
accessKeyId: z.string().optional(),
secretAccessKey: z.string().optional(),
sessionToken: z.string().optional(),
bearerToken: z.string().optional(),
forceCache: z.boolean().optional(),
endpointUrl: awsEndpointUrlSchema.optional(),
skipAuth: z.boolean().optional(),
forceHttp1: z.boolean().optional(),
});
export const gcpAdcCredentialSchema = z.object({
project: z.string().min(1),
location: z.string().min(1),
credentialsPath: z.string().optional(),
});
function normalizeUrlHostname(hostname: string): string {
const trimmed = hostname.trim().toLowerCase();
return trimmed.startsWith("[") && trimmed.endsWith("]")
? trimmed.slice(1, -1)
: trimmed;
}
function parseIpv4(hostname: string): [number, number, number, number] | null {
const parts = hostname.split(".");
if (parts.length !== 4) return null;
const octets = parts.map((part) => {
if (!/^\d+$/.test(part)) return null;
const value = Number(part);
return Number.isInteger(value) && value >= 0 && value <= 255 ? value : null;
});
if (octets.some((part) => part === null)) return null;
return octets as [number, number, number, number];
}
function isPrivateIpv4(hostname: string): boolean {
const octets = parseIpv4(hostname);
if (!octets) return false;
const [first, second] = octets;
return first === 10
|| first === 127
|| (first === 172 && second >= 16 && second <= 31)
|| (first === 192 && second === 168)
|| (first === 169 && second === 254);
}
function isPrivateIpv6(hostname: string): boolean {
if (hostname === "::1") return true;
return /^f[cd][0-9a-f]{2}:/i.test(hostname) || /^fe80:/i.test(hostname);
}
function isPrivateNetworkHostname(hostname: string): boolean {
return hostname === "localhost" || isPrivateIpv4(hostname) || isPrivateIpv6(hostname);
}
function hasOnlyRootUrlPath(value: string): boolean {
const trimmed = value.trim();
if (trimmed.includes("?") || trimmed.includes("#")) return false;
const schemeSeparator = trimmed.indexOf("://");
if (schemeSeparator < 0) return false;
const authorityAndPath = trimmed.slice(schemeSeparator + 3);
const pathStart = authorityAndPath.indexOf("/");
if (pathStart < 0) return true;
return authorityAndPath.slice(pathStart) === "/";
}
export function isLocalConnectorBaseUrl(value: string): boolean {
let url: URL;
try {
url = new URL(value);
} catch {
return false;
}
if (url.protocol !== "http:" && url.protocol !== "https:") return false;
if (url.username || url.password) return false;
const hostname = normalizeUrlHostname(url.hostname);
return isPrivateNetworkHostname(hostname);
}
export const localBaseUrlSchema = z
.string()
.url()
.refine(
isLocalConnectorBaseUrl,
"Local connector baseUrl must use HTTP(S) with localhost, loopback, or a private IP host.",
);
export const localCredentialSchema = z.object({
baseUrl: localBaseUrlSchema,
});
function isAwsBedrockHostname(hostname: string): boolean {
return AWS_BEDROCK_RUNTIME_HOSTNAME.test(hostname) || AWS_BEDROCK_VPCE_HOSTNAME.test(hostname);
}
export function isAwsBedrockEndpointUrl(value: string): boolean {
let url: URL;
try {
url = new URL(value);
} catch {
return false;
}
if (url.protocol !== "https:") return false;
if (url.username || url.password) return false;
if (!hasOnlyRootUrlPath(value)) return false;
const hostname = normalizeUrlHostname(url.hostname);
return isAwsBedrockHostname(hostname) || isPrivateNetworkHostname(hostname);
}
export const credentialPayloadSchema = z.discriminatedUnion("kind", [
z.object({ kind: z.literal("api_key"), value: apiKeyValueSchema }),
z.object({ kind: z.literal("azure"), value: azureCredentialSchema }),
z.object({ kind: z.literal("aws"), value: awsCredentialSchema }),
z.object({ kind: z.literal("gcp_adc"), value: gcpAdcCredentialSchema }),
z.object({ kind: z.literal("local"), value: localCredentialSchema }),
]);
export const saveCredentialInputSchema = z.object({
connectorId: z.string().min(1),
payload: credentialPayloadSchema,
});
export const removeCredentialInputSchema = z.object({
connectorId: z.string().min(1),
});
export const testCredentialInputSchema = z.object({
connectorId: z.string().min(1),
});
export const credentialSummarySchema = z.object({
connectorId: z.string(),
kind: credentialKindSchema,
displayHint: z.string(),
status: credentialStatusSchema,
expiresAt: z.string().nullable(),
lastRefreshedAt: z.string().nullable(),
lastError: z.string().nullable(),
updatedAt: z.string().nullable(),
});
export type CredentialSummary = z.infer<typeof credentialSummarySchema>;
export type SaveCredentialInput = z.infer<typeof saveCredentialInputSchema>;
export type AwsCredential = z.infer<typeof awsCredentialSchema>;
export type AzureCredential = z.infer<typeof azureCredentialSchema>;
export type GcpAdcCredential = z.infer<typeof gcpAdcCredentialSchema>;
export type LocalCredential = z.infer<typeof localCredentialSchema>;
export type ApiKeyValue = z.infer<typeof apiKeyValueSchema>;
-135
View File
@@ -1,135 +0,0 @@
import { z } from "zod";
import { automationTriggerEnum } from "./helpers";
export const startRunSchema = z.object({
companyId: z.string().uuid(),
taskId: z.string().uuid(),
});
export const cancelRunSchema = z.object({
companyId: z.string().uuid(),
runId: z.string().uuid(),
});
export const recoveryRetrySchema = z.object({
taskId: z.string().uuid(),
agentId: z.string().uuid(),
companyId: z.string().uuid(),
});
export const recoveryTaskSchema = z.object({
taskId: z.string().uuid(),
companyId: z.string().uuid(),
});
export const runLogSchema = z.object({
companyId: z.string().uuid(),
runId: z.string().uuid(),
});
export const runLogChunkSchema = z.object({
companyId: z.string().uuid(),
runId: z.string().uuid(),
offset: z.number().int().min(0).default(0),
limit: z.number().int().min(1024).max(262_144).default(65_536),
});
export const triggerBrowserLoginSchema = z.object({
companyId: z.string().uuid(),
socialAccountId: z.string().uuid(),
});
export const browserActionQuerySchema = z.object({
companyId: z.string().uuid(),
socialAccountId: z.string().uuid().optional(),
status: z.string().optional(),
limit: z.number().int().min(1).max(100).default(50),
});
export const cancelBrowserActionSchema = z.object({
actionId: z.string().uuid(),
companyId: z.string().uuid(),
});
export const workflowInputSchema = z.object({
id: z.preprocess((v) => (v === "" ? null : v), z.string().uuid().nullable().optional()),
companyId: z.string().uuid(),
name: z.string().min(2).max(120),
description: z.string().max(500).default(""),
stepsJson: z.string().default("[]"),
triggerType: automationTriggerEnum,
triggerConfigJson: z.string().default("{}"),
status: z.enum(["draft", "active", "paused", "completed", "failed"]).default("draft"),
});
export const runWorkflowSchema = z.object({
id: z.string().uuid(),
companyId: z.string().uuid(),
});
export const importSkillSchema = z.object({
companyId: z.string().min(1),
source: z.string().min(1),
});
export const listSkillsSchema = z.object({
companyId: z.string().min(1),
});
export const getSkillDetailSchema = z.object({
companyId: z.string().min(1),
skillId: z.string().min(1),
});
export const getSkillMarkdownSchema = z.object({
companyId: z.string().min(1),
slug: z.string().min(1),
});
export const deleteSkillSchema = z.object({
companyId: z.string().min(1),
skillId: z.string().min(1),
});
export const assignSkillToAgentSchema = z.object({
companyId: z.string().min(1),
agentId: z.string().min(1),
skillId: z.string().min(1),
});
export const removeSkillFromAgentSchema = z.object({
companyId: z.string().min(1),
agentId: z.string().min(1),
skillId: z.string().min(1),
});
export const checkSkillUpdateSchema = z.object({
companyId: z.string().min(1),
skillId: z.string().min(1),
});
export const listSkillAgentsSchema = z.object({
companyId: z.string().min(1),
skillId: z.string().min(1),
});
export const listAgentSkillsSchema = z.object({
companyId: z.string().min(1),
agentId: z.string().min(1),
});
export const terminalCommandKeys = [
"install_node_darwin",
"install_node_win32",
"install_node_linux",
"install_claude_unix",
"install_claude_win32",
"install_codex",
"install_gemini",
] as const;
export type TerminalCommandKey = (typeof terminalCommandKeys)[number];
export const openTerminalCommandSchema = z.object({
commandKey: z.enum(terminalCommandKeys),
});
-140
View File
@@ -1,140 +0,0 @@
import { z } from "zod";
import { canonicalJsonString, jsonArraySchema, jsonStringArraySchema, meetingActionItemArraySchema } from "./json-fields";
import { MESSAGE_CHANNELS, optionalId } from "./helpers";
export const agentMessageInputSchema = z.object({
companyId: z.string().uuid(),
fromAgentId: z.union([z.string().uuid(), z.literal("__board__")]),
toAgentId: z.preprocess(
(v) => (v === "" ? null : v),
z.union([z.string().uuid(), z.literal("__board__")]).nullable().optional(),
),
channel: MESSAGE_CHANNELS.default("direct"),
channelTargetId: z.string().nullable().optional(),
subject: z.preprocess((v) => (v === "" ? "(no subject)" : v), z.string().min(1).max(200)),
body: z.string().min(1).max(8000),
priority: z.enum(["urgent", "normal", "low"]).default("normal"),
parentMessageId: z.preprocess((v) => (v === "" ? null : v), z.string().uuid().nullable().optional()),
attachmentsJson: z.string().default("[]"),
threadId: z.preprocess((v) => (v === "" ? null : v), z.string().uuid().nullable().optional()),
waitStateId: z.preprocess((v) => (v === "" ? null : v), z.string().uuid().nullable().optional()),
}).superRefine((value, ctx) => {
if (value.channel === "direct" && !value.toAgentId) {
ctx.addIssue({
path: ["toAgentId"],
code: z.ZodIssueCode.custom,
message: "Direct messages require toAgentId.",
});
}
if ((value.channel === "department" || value.channel === "project") && !value.channelTargetId) {
ctx.addIssue({
path: ["channelTargetId"],
code: z.ZodIssueCode.custom,
message: `${value.channel} messages require channelTargetId.`,
});
}
if (value.channel !== "direct" && value.toAgentId) {
ctx.addIssue({
path: ["toAgentId"],
code: z.ZodIssueCode.custom,
message: "Only direct messages may set toAgentId.",
});
}
});
export const messageQuerySchema = z.object({
companyId: z.string().uuid(),
agentId: z.string().uuid().optional(),
channel: MESSAGE_CHANNELS.optional(),
channelTargetId: z.string().nullable().optional(),
unreadOnly: z.boolean().optional(),
limit: z.number().int().min(1).max(500).default(200),
});
export const searchMessagesSchema = z.object({
companyId: z.string().uuid(),
query: z.string().min(1).max(200),
channel: MESSAGE_CHANNELS.optional(),
channelTargetId: z.string().nullable().optional(),
limit: z.number().int().min(1).max(100).default(50),
});
export const commentInputSchema = z.object({
companyId: z.string().uuid(),
taskId: z.string().uuid(),
authorAgentId: optionalId,
authorName: z.string().min(1).max(80),
body: z.string().min(1).max(4000),
});
export const listCommentsSchema = z.object({
companyId: z.string().uuid(),
taskId: z.string().uuid(),
});
export const documentInputSchema = z.object({
id: optionalId,
companyId: z.string().uuid(),
type: z.enum(["prd", "technical_spec", "design_doc", "test_plan", "post_mortem", "meeting_notes", "budget_proposal", "hiring_requisition", "performance_review_doc", "sop", "knowledge_article", "project_brief", "sprint_report", "incident_report", "onboarding_guide", "architecture_decision", "status_report", "contract", "proposal"]),
title: z.string().min(2).max(200),
content: z.string().default(""),
authorAgentId: optionalId,
reviewerAgentId: optionalId,
projectId: optionalId,
goalId: optionalId,
parentDocId: optionalId,
version: z.number().int().min(1).default(1),
status: z.enum(["draft", "in_review", "approved", "archived", "superseded"]).default("draft"),
tagsJson: canonicalJsonString(jsonStringArraySchema, []),
});
export const knowledgeEntryInputSchema = z.object({
id: optionalId,
companyId: z.string().uuid(),
category: z.enum(["lesson_learned", "best_practice", "decision", "process", "technical", "business", "onboarding", "incident"]),
topic: z.string().min(2).max(200),
content: z.string().min(1),
authorAgentId: optionalId,
importance: z.enum(["critical", "high", "medium", "low"]).default("medium"),
tagsJson: canonicalJsonString(jsonStringArraySchema, []),
referencedEntityType: z.enum([
"agents",
"goals",
"projects",
"tasks",
"approvals",
"runs",
"secrets",
"meetings",
"documents",
"knowledge_base",
"sprints",
"automation_rules",
"workflow_pipelines",
]).nullable().optional(),
referencedEntityId: z.string().nullable().optional(),
});
export const meetingInputSchema = z.object({
id: optionalId,
companyId: z.string().uuid(),
type: z.enum(["standup", "sprint_planning", "sprint_review", "retrospective", "one_on_one", "all_hands", "department_sync", "incident_review", "hiring_committee", "budget_review", "design_review", "architecture_review"]),
title: z.string().min(2).max(160),
organizerAgentId: optionalId,
participantAgentIds: canonicalJsonString(jsonStringArraySchema, []),
scheduledAt: z.string(),
durationMinutes: z.number().int().min(5).max(480).default(30),
agendaJson: canonicalJsonString(jsonArraySchema, []),
notesJson: canonicalJsonString(jsonArraySchema, []),
decisionsJson: canonicalJsonString(jsonArraySchema, []),
actionItemsJson: canonicalJsonString(meetingActionItemArraySchema, []),
status: z.enum(["scheduled", "in_progress", "completed", "cancelled"]).default("scheduled"),
});
export const markMessageReadSchema = z.object({
messageId: z.string().uuid(),
companyId: z.string().uuid(),
readerAgentId: optionalId,
});
-6
View File
@@ -1,6 +0,0 @@
// Barrel re-export. Canonical domain files live alongside.
// New code should import directly from the domain file.
export * from "./schemas-badges";
export * from "./schemas-automation";
export * from "./schemas-budget";
export * from "./schemas-threads";
-31
View File
@@ -1,31 +0,0 @@
import { z } from "zod";
export const oauthStartInputSchema = z.object({
connectorId: z.string().min(1),
});
export const oauthCancelInputSchema = z.object({
connectorId: z.string().min(1),
});
export const oauthPromptResponseSchema = z.object({
connectorId: z.string().min(1),
requestId: z.string().min(1),
value: z.string(),
});
export const oauthManualCodeResponseSchema = z.object({
connectorId: z.string().min(1),
requestId: z.string().min(1),
code: z.string().min(1),
});
// Event shapes (OAuthStatusEvent, OAuthAuthUrlEvent, OAuthProgressEvent,
// OAuthPromptRequestEvent, OAuthManualCodeRequestEvent) live in
// `shared/types/events.ts` — that's the runtime shape emitted by
// `oauth-login-service` and consumed by the renderer via `DesktopEvent`.
// This module only owns the renderer→main request schemas.
export type OAuthStartInput = z.infer<typeof oauthStartInputSchema>;
export type OAuthPromptResponseInput = z.infer<typeof oauthPromptResponseSchema>;
export type OAuthManualCodeResponseInput = z.infer<typeof oauthManualCodeResponseSchema>;
-56
View File
@@ -1,56 +0,0 @@
import { z } from "zod";
import { optionalId } from "./helpers";
export const goalInputSchema = z.object({
id: optionalId,
companyId: z.string().uuid(),
title: z.string().min(2).max(120),
description: z.string().default(""),
parentId: optionalId,
ownerAgentId: optionalId,
status: z.enum(["planned", "active", "achieved", "cancelled"]).default("planned"),
});
export const projectInputSchema = z.object({
id: optionalId,
companyId: z.string().uuid(),
goalId: optionalId,
name: z.string().min(2).max(120),
description: z.string().default(""),
leadAgentId: optionalId,
targetDate: z.string().nullable().optional(),
status: z.enum(["backlog", "planned", "in_progress", "completed", "cancelled"]).default("planned"),
});
export const taskInputSchema = z.object({
id: optionalId,
companyId: z.string().uuid(),
projectId: optionalId,
goalId: optionalId,
parentId: optionalId,
title: z.string().min(2).max(160),
description: z.string().default(""),
assigneeAgentId: optionalId,
workspaceId: optionalId,
requiresFilesystem: z.boolean().default(false),
priority: z.enum(["critical", "high", "medium", "low"]).default("medium"),
status: z.enum(["backlog", "todo", "in_progress", "in_review", "done", "blocked", "cancelled"]).default("todo"),
});
export const sprintInputSchema = z.object({
id: optionalId,
companyId: z.string().uuid(),
name: z.string().min(2).max(120),
goal: z.string().default(""),
startDate: z.string(),
endDate: z.string(),
status: z.enum(["planning", "active", "review", "completed", "cancelled"]).default("planning"),
retrospectiveNotes: z.string().default(""),
velocityPoints: z.number().int().min(0).default(0),
completedPoints: z.number().int().min(0).default(0),
});
export const autoAssignSchema = z.object({
taskId: z.string().uuid(),
companyId: z.string().uuid(),
});
-23
View File
@@ -1,23 +0,0 @@
import { z } from "zod";
export const threadGetterSchema = z.object({
companyId: z.string().uuid(),
threadId: z.string().uuid(),
});
export const listThreadEventsSchema = z.object({
companyId: z.string().uuid(),
threadId: z.string().uuid(),
limit: z.number().int().min(1).max(100).default(50),
offset: z.number().int().min(0).default(0),
});
export const listThreadWaitStatesSchema = z.object({
companyId: z.string().uuid(),
resolvedOnly: z.boolean().default(false),
});
export const listThreadParticipantsSchema = z.object({
companyId: z.string().uuid(),
threadId: z.string().uuid(),
});
@@ -1,45 +0,0 @@
import { z } from "zod";
export const workProductTypeEnum = z.enum([
"file",
"link",
"pull_request",
"branch",
"commit",
"artifact",
"document",
"preview_url",
"runtime_service",
]);
export const workProductProviderEnum = z.enum([
"filesystem",
"external",
"agentcompany",
"github",
"custom",
]);
export const workProductStatusEnum = z.enum([
"active",
"ready_for_review",
"approved",
"merged",
"closed",
"failed",
"draft",
"archived",
]);
export const workProductReviewStateEnum = z.enum([
"none",
"needs_board_review",
"approved",
"changes_requested",
]);
export type WorkProductType = z.infer<typeof workProductTypeEnum>;
export type WorkProductProvider = z.infer<typeof workProductProviderEnum>;
export type WorkProductStatus = z.infer<typeof workProductStatusEnum>;
export type WorkProductReviewState = z.infer<typeof workProductReviewStateEnum>;
+194
View File
@@ -0,0 +1,194 @@
import type { DesktopResult } from "./result";
import type { AppSnapshot, SearchResultRecord } from "./domain";
import type { ProviderModelEntry } from "./provider-models";
import type {
BindSkillInput,
BootstrapOnboardingInput,
BootstrapOnboardingSummary,
CancelProviderResponseInput,
CreateAgentInput,
UpdateAgentInput,
CreateApprovalInput,
CreateAutomationRuleInput,
CreateDocumentInput,
CreateGoalInput,
CreateMeetingInput,
CreateSprintInput,
DeleteMeetingInput,
DeleteSprintInput,
CreateKnowledgeEntryInput,
CreateProjectInput,
CreateWorkspaceInput,
DeleteAutomationRuleInput,
DeleteDocumentInput,
DeleteTaskInput,
DeleteKnowledgeEntryInput,
UpdateAutomationRuleInput,
UpdateDocumentInput,
UpdateTaskInput,
CreateAuditReplayInput,
CreateChatSpaceInput,
CreateComplianceExportInput,
CreateLegalHoldInput,
CreateMigrationReportInput,
CheckProviderHealthInput,
ListProviderModelsInput,
StartProviderOAuthInput,
StartProviderOAuthResult,
CancelProviderOAuthInput,
MarkChatSpaceReadInput,
CreateOrganizationInput,
CreateProviderResponseInput,
CreateRetentionFreezeInput,
CreateRollbackSnapshotInput,
CreateScheduledPostInput,
CreateSocialAccountInput,
CreateTaskInput,
DecideApprovalInput,
DeleteMessageInput,
DeleteOrganizationInput,
EditMessageInput,
ImportFileInput,
OpenFileInput,
ImportSkillDirectoryInput,
GrantRoleInput,
LaunchProviderSignInInput,
LaunchSocialLoginInput,
ResolveAgentSkillsInput,
ResolveMigrationReconciliationInput,
RunChaosDrillInput,
RunEvalSuiteInput,
RunSdlcReviewInput,
RunSkillTestsInput,
RunTaskInput,
RevokeProviderCredentialInput,
SaveProviderCredentialInput,
SaveComposioSettingsInput,
ComposioToolkitSummaryDto,
ConnectComposioToolkitInput,
ConnectComposioToolkitResult,
ConnectorGrantInput,
ListComposioToolkitsInput,
RefreshComposioAccountsInput,
SearchInput,
SendMessageInput,
SetActiveOrganizationInput,
SetFilePinnedInput,
SetFeatureFlagInput,
SetLegalHoldStateInput,
SetPrBotGateInput,
SetRollbackSnapshotActiveInput,
SetRetentionFreezeStateInput,
SetScheduledPostStateInput,
StreamProviderResponseInput,
SyncEmployeeIdentityInput,
UpdateProviderPolicyInput,
UpdateTaskStatusInput,
} from "./commands";
import type { ProviderStreamRendererEvent } from "./provider-request-domain";
export type ProviderOAuthPhase = "authorize" | "progress" | "active" | "error" | "cancelled";
export interface ProviderOAuthEvent {
type: "provider-oauth";
providerKey: string;
phase: ProviderOAuthPhase;
url?: string;
instructions?: string;
message?: string;
}
export type RendererEvent =
| { type: "snapshot-changed" }
| { type: "provider-response-stream"; event: ProviderStreamRendererEvent }
| ProviderOAuthEvent;
export interface DesktopApi {
loadSnapshot(): Promise<DesktopResult<AppSnapshot>>;
bootstrapOnboarding(input: BootstrapOnboardingInput): Promise<DesktopResult<BootstrapOnboardingSummary>>;
setActiveOrganization(input: SetActiveOrganizationInput): Promise<DesktopResult<AppSnapshot>>;
deleteOrganization(input: DeleteOrganizationInput): Promise<DesktopResult<AppSnapshot>>;
createOrganization(input: CreateOrganizationInput): Promise<DesktopResult<AppSnapshot>>;
createAgent(input: CreateAgentInput): Promise<DesktopResult<AppSnapshot>>;
updateAgent(input: UpdateAgentInput): Promise<DesktopResult<AppSnapshot>>;
createTask(input: CreateTaskInput): Promise<DesktopResult<AppSnapshot>>;
updateTask(input: UpdateTaskInput): Promise<DesktopResult<AppSnapshot>>;
deleteTask(input: DeleteTaskInput): Promise<DesktopResult<AppSnapshot>>;
updateTaskStatus(input: UpdateTaskStatusInput): Promise<DesktopResult<AppSnapshot>>;
runTask(input: RunTaskInput): Promise<DesktopResult<AppSnapshot>>;
createGoal(input: CreateGoalInput): Promise<DesktopResult<AppSnapshot>>;
createProject(input: CreateProjectInput): Promise<DesktopResult<AppSnapshot>>;
createWorkspace(input: CreateWorkspaceInput): Promise<DesktopResult<AppSnapshot>>;
createDocument(input: CreateDocumentInput): Promise<DesktopResult<AppSnapshot>>;
updateDocument(input: UpdateDocumentInput): Promise<DesktopResult<AppSnapshot>>;
deleteDocument(input: DeleteDocumentInput): Promise<DesktopResult<AppSnapshot>>;
createKnowledgeEntry(input: CreateKnowledgeEntryInput): Promise<DesktopResult<AppSnapshot>>;
deleteKnowledgeEntry(input: DeleteKnowledgeEntryInput): Promise<DesktopResult<AppSnapshot>>;
createAutomationRule(input: CreateAutomationRuleInput): Promise<DesktopResult<AppSnapshot>>;
updateAutomationRule(input: UpdateAutomationRuleInput): Promise<DesktopResult<AppSnapshot>>;
deleteAutomationRule(input: DeleteAutomationRuleInput): Promise<DesktopResult<AppSnapshot>>;
createMeeting(input: CreateMeetingInput): Promise<DesktopResult<AppSnapshot>>;
deleteMeeting(input: DeleteMeetingInput): Promise<DesktopResult<AppSnapshot>>;
createSprint(input: CreateSprintInput): Promise<DesktopResult<AppSnapshot>>;
deleteSprint(input: DeleteSprintInput): Promise<DesktopResult<AppSnapshot>>;
createApproval(input: CreateApprovalInput): Promise<DesktopResult<AppSnapshot>>;
decideApproval(input: DecideApprovalInput): Promise<DesktopResult<AppSnapshot>>;
syncEmployeeIdentity(input: SyncEmployeeIdentityInput): Promise<DesktopResult<AppSnapshot>>;
grantRole(input: GrantRoleInput): Promise<DesktopResult<AppSnapshot>>;
createChatSpace(input: CreateChatSpaceInput): Promise<DesktopResult<AppSnapshot>>;
sendMessage(input: SendMessageInput): Promise<DesktopResult<AppSnapshot>>;
editMessage(input: EditMessageInput): Promise<DesktopResult<AppSnapshot>>;
deleteMessage(input: DeleteMessageInput): Promise<DesktopResult<AppSnapshot>>;
markChatSpaceRead(input: MarkChatSpaceReadInput): Promise<DesktopResult<AppSnapshot>>;
saveProviderCredential(input: SaveProviderCredentialInput): Promise<DesktopResult<AppSnapshot>>;
revokeProviderCredential(input: RevokeProviderCredentialInput): Promise<DesktopResult<AppSnapshot>>;
launchProviderSignIn(input: LaunchProviderSignInInput): Promise<DesktopResult<null>>;
startProviderOAuth(input: StartProviderOAuthInput): Promise<DesktopResult<StartProviderOAuthResult>>;
cancelProviderOAuth(input: CancelProviderOAuthInput): Promise<DesktopResult<null>>;
checkProviderHealth(input: CheckProviderHealthInput): Promise<DesktopResult<AppSnapshot>>;
listProviderModels(input: ListProviderModelsInput): Promise<DesktopResult<ProviderModelEntry[]>>;
updateProviderPolicy(input: UpdateProviderPolicyInput): Promise<DesktopResult<AppSnapshot>>;
openExternalUrl(url: string): Promise<DesktopResult<null>>;
createProviderResponse(input: CreateProviderResponseInput): Promise<DesktopResult<AppSnapshot>>;
streamProviderResponse(input: StreamProviderResponseInput): Promise<DesktopResult<AppSnapshot>>;
cancelProviderResponse(input: CancelProviderResponseInput): Promise<DesktopResult<AppSnapshot>>;
importSkillDirectory(input: ImportSkillDirectoryInput): Promise<DesktopResult<AppSnapshot>>;
bindSkill(input: BindSkillInput): Promise<DesktopResult<AppSnapshot>>;
resolveAgentSkills(input: ResolveAgentSkillsInput): Promise<DesktopResult<AppSnapshot>>;
runSkillTests(input: RunSkillTestsInput): Promise<DesktopResult<AppSnapshot>>;
createSocialAccount(input: CreateSocialAccountInput): Promise<DesktopResult<AppSnapshot>>;
launchSocialLogin(input: LaunchSocialLoginInput): Promise<DesktopResult<null>>;
createScheduledPost(input: CreateScheduledPostInput): Promise<DesktopResult<AppSnapshot>>;
setScheduledPostState(input: SetScheduledPostStateInput): Promise<DesktopResult<AppSnapshot>>;
importFile(input: ImportFileInput): Promise<DesktopResult<string | null>>;
openFile(input: OpenFileInput): Promise<DesktopResult<null>>;
pickDirectory(): Promise<DesktopResult<string | null>>;
setFilePinned(input: SetFilePinnedInput): Promise<DesktopResult<AppSnapshot>>;
createMigrationReport(input: CreateMigrationReportInput): Promise<DesktopResult<AppSnapshot>>;
createRollbackSnapshot(input: CreateRollbackSnapshotInput): Promise<DesktopResult<AppSnapshot>>;
setRollbackSnapshotActive(input: SetRollbackSnapshotActiveInput): Promise<DesktopResult<AppSnapshot>>;
resolveMigrationReconciliation(input: ResolveMigrationReconciliationInput): Promise<DesktopResult<AppSnapshot>>;
setFeatureFlag(input: SetFeatureFlagInput): Promise<DesktopResult<AppSnapshot>>;
runChaosDrill(input: RunChaosDrillInput): Promise<DesktopResult<AppSnapshot>>;
runSdlcReview(input: RunSdlcReviewInput): Promise<DesktopResult<AppSnapshot>>;
runEvalSuite(input: RunEvalSuiteInput): Promise<DesktopResult<AppSnapshot>>;
setPrBotGate(input: SetPrBotGateInput): Promise<DesktopResult<AppSnapshot>>;
createComplianceExport(input: CreateComplianceExportInput): Promise<DesktopResult<AppSnapshot>>;
createAuditReplay(input: CreateAuditReplayInput): Promise<DesktopResult<AppSnapshot>>;
createLegalHold(input: CreateLegalHoldInput): Promise<DesktopResult<AppSnapshot>>;
setLegalHoldState(input: SetLegalHoldStateInput): Promise<DesktopResult<AppSnapshot>>;
createRetentionFreeze(input: CreateRetentionFreezeInput): Promise<DesktopResult<AppSnapshot>>;
setRetentionFreezeState(input: SetRetentionFreezeStateInput): Promise<DesktopResult<AppSnapshot>>;
saveComposioSettings(input: SaveComposioSettingsInput): Promise<DesktopResult<AppSnapshot>>;
listComposioToolkits(input: ListComposioToolkitsInput): Promise<DesktopResult<ComposioToolkitSummaryDto[]>>;
connectComposioToolkit(input: ConnectComposioToolkitInput): Promise<DesktopResult<ConnectComposioToolkitResult>>;
refreshComposioAccounts(input: RefreshComposioAccountsInput): Promise<DesktopResult<AppSnapshot>>;
grantConnector(input: ConnectorGrantInput): Promise<DesktopResult<AppSnapshot>>;
revokeConnector(input: ConnectorGrantInput): Promise<DesktopResult<AppSnapshot>>;
search(input: SearchInput): Promise<DesktopResult<SearchResultRecord[]>>;
subscribe(callback: (event: RendererEvent) => void): () => void;
platform: "win32" | "darwin" | "linux";
windowMinimize(): Promise<void>;
windowMaximize(): Promise<void>;
windowClose(): Promise<void>;
}
-20
View File
@@ -1,20 +0,0 @@
/**
* Document type categories shared between db, route handlers, and clients.
*
* IMPORTANT_DOC_TYPES are the document types that trigger deliverable-review
* approvals (PRDs, specs, design docs, contracts, etc.). The ordering matters
* for some lookup queries; keep this in sync with database/documents.ts.
*/
export const IMPORTANT_DOC_TYPES = [
"prd",
"technical_spec",
"design_doc",
"project_brief",
"proposal",
"budget_proposal",
"architecture_decision",
"contract",
"sop",
] as const;
export const IMPORTANT_DOC_TYPE_SET: ReadonlySet<string> = new Set(IMPORTANT_DOC_TYPES);
+449
View File
@@ -0,0 +1,449 @@
import type { ProviderDataPolicy } from "./provider-policy-domain";
export { BOARD_INTERVENTION_ACTION, BOARD_INTERVENTION_MODE, CHAT_THREAD_BOARD_STATE, type BoardInterventionAction, type BoardInterventionMode, type BoardInterventionRecord, type ChatThreadBoardState } from "./board-domain";
export type { ChatSpaceRecord, ChatMessageRecord, ChatMembershipRecord, ChatThreadRecord, ChatAttachmentRecord, ChatMentionRecord, ChatSlashInvocationRecord, ChatPresenceRecord, ChatReadStateRecord } from "./chat-domain";
export type { AuditReplayRunRecord } from "./audit-domain";
export { COMPLIANCE_EXPORT_STATE, COMPLIANCE_EXPORT_TYPE, type ComplianceExportRecord, type ComplianceExportState, type ComplianceExportType, type ComplianceSubjectType, type LegalHoldEntityType, type LegalHoldRecord, type RetentionFreezeRecord, type RetentionFreezeScopeType } from "./compliance-domain";
export { ACCESS_DECISION, IDENTITY_SOURCE, ROLE_KEY, type AccessDecision, type AccessDecisionRecord, type EmployeeIdentityRecord, type IdentitySource, type PrincipalType, type RoleGrantRecord, type RoleKey, type ServiceIdentityRecord } from "./identity-domain";
export { ROUTE_TO_TYPE, type ApprovalAssignmentRecord, type ApprovalRoutingRuleRecord, type HiringPolicyRecord, type OrgDepartmentRecord, type RouteToType } from "./org-governance-domain";
export { CHAOS_DRILL_SCENARIO, CHAOS_DRILL_STATE, FEATURE_FLAG_KEY, SLO_SIGNAL_KEY, type ChaosDrillRecord, type ChaosDrillRunRecord, type ChaosDrillScenario, type ChaosDrillState, type FeatureFlagKey, type FeatureFlagRecord, type OperationalEventRecord, type SloSignalKey, type SloTargetRecord } from "./operations-domain";
export type { ProviderAuthProfileRecord, ProviderAuthSessionRecord } from "./provider-auth-domain";
export { PROVIDER_DATA_POLICY, PROVIDER_EXECUTION_MODE, type ProviderDataPolicy, type ProviderExecutionMode } from "./provider-policy-domain";
export { PROVIDER_REQUEST_STATE, type ProviderRequestRecord, type ProviderRequestState, type ProviderStreamRendererEvent } from "./provider-request-domain";
export type { ProviderRateLimitObservationRecord, ProviderRateLimitStateRecord } from "./provider-runtime-domain";
export type { MigrationCutoverEventRecord, MigrationReconciliationItemRecord, RollbackSnapshotRecord } from "./rollback-domain";
export { EVAL_SUITE_KEY, PR_BOT_GATE_KEY, SDLC_REVIEW_AGENT_KEY, SDLC_REVIEW_TARGET_TYPE, SDLC_RUN_STATE, type EvalCaseRecord, type EvalRunRecord, type EvalSuiteKey, type EvalSuiteRecord, type PrBotGateKey, type PrBotGateRecord, type SdlcReviewAgentKey, type SdlcReviewAgentRecord, type SdlcReviewRunRecord, type SdlcReviewTargetType, type SdlcRunState } from "./sdlc-domain";
export { SEARCH_ENTITY_TYPES, type SearchEntityType, type SearchResultRecord } from "./search-domain";
export type { BrowserActionPolicyRecord, BrowserActionRecord, BrowserSessionContainerRecord, SocialAccountGrantRecord, SocialAccountRecord, SocialApprovalRouteRecord, SocialAuditRecord } from "./social-domain";
export type { AppSnapshot } from "./snapshot-domain";
export const TASK_STATUS = { BACKLOG: "backlog", IN_PROGRESS: "in_progress", REVIEW: "review", DONE: "done" } as const;
export const APPROVAL_STATE = { PENDING: "pending", APPROVED: "approved", DECLINED: "declined" } as const;
export const RISK_LEVEL = { LOW: "low", MEDIUM: "medium", HIGH: "high" } as const;
export const TASK_PRIORITY = { LOW: "low", NORMAL: "normal", HIGH: "high" } as const;
export const PROVIDER_AUTH_TYPE = { API_KEY: "api_key", OAUTH_PKCE: "oauth_pkce", ACCOUNT_SUBSCRIPTION: "account_subscription", CLOUD: "cloud" } as const;
export const SOCIAL_PLATFORM = { X: "x", LINKEDIN: "linkedin", YOUTUBE: "youtube", INSTAGRAM: "instagram" } as const;
export const FILE_SCAN_STATE = { APPROVED: "approved", BLOCKED: "blocked" } as const;
export type ValueOf<T> = T[keyof T];
export type TaskStatus = ValueOf<typeof TASK_STATUS>;
export type ApprovalState = ValueOf<typeof APPROVAL_STATE>;
export type RiskLevel = ValueOf<typeof RISK_LEVEL>;
export type TaskPriority = ValueOf<typeof TASK_PRIORITY>;
export type ProviderAuthType = ValueOf<typeof PROVIDER_AUTH_TYPE>;
export type SocialPlatform = ValueOf<typeof SOCIAL_PLATFORM>;
export type FileScanState = ValueOf<typeof FILE_SCAN_STATE>;
export interface OrganizationRecord {
id: string;
name: string;
mission: string;
goal: string;
description: string;
executionMode: string;
autoApproveHires: boolean;
reviewDeliverables: boolean;
createdAt: string;
}
export interface EmployeeRecord {
id: string;
orgId: string;
displayName: string;
role: string;
createdAt: string;
}
export interface AgentRecord {
id: string;
orgId: string;
name: string;
role: string;
department: string;
modelProviderId: string | null;
modelId: string | null;
budgetCents: number;
managerAgentId: string | null;
title: string;
roleLevel: string;
modelStrategy: string;
workspaceId: string | null;
heartbeatEnabled: boolean;
heartbeatIntervalSec: number;
lifecycle: string;
createdAt: string;
}
export interface TaskRecord {
id: string;
orgId: string;
title: string;
description: string;
status: TaskStatus;
assigneeAgentId: string | null;
risk: RiskLevel;
projectId: string | null;
goalId: string | null;
workspaceId: string | null;
priority: TaskPriority;
parentTaskId: string | null;
requiresFilesystem: boolean;
createdAt: string;
updatedAt: string;
}
export interface WorkspaceRecord {
id: string;
orgId: string;
name: string;
localPath: string;
repoUrl: string;
repoRef: string;
projectId: string | null;
isPrimary: boolean;
createdAt: string;
updatedAt: string;
}
export interface GoalRecord {
id: string;
orgId: string;
title: string;
description: string;
status: string;
ownerAgentId: string | null;
createdAt: string;
updatedAt: string;
}
export interface ProjectRecord {
id: string;
orgId: string;
goalId: string | null;
name: string;
description: string;
leadAgentId: string | null;
status: string;
createdAt: string;
updatedAt: string;
}
export interface TaskRunRecord {
id: string;
orgId: string;
taskId: string;
agentId: string | null;
providerId: string | null;
providerRequestId: string | null;
executionContextId: string | null;
serviceIdentityId: string | null;
workspaceMountJson: string;
secretScopeJson: string;
trigger: string;
state: string;
createdAt: string;
startedAt: string | null;
completedAt: string | null;
errorMessage: string | null;
}
export interface ApprovalRecord {
id: string;
orgId: string;
kind: string;
title: string;
details: string;
risk: RiskLevel;
requestedByType: "employee" | "agent" | "system";
requestedById: string | null;
sourceEntityType: string | null;
sourceEntityId: string | null;
state: ApprovalState;
decisionNotes: string | null;
decidedByEmployeeId: string | null;
createdAt: string;
decidedAt: string | null;
}
export interface MeetingRecord {
id: string;
orgId: string;
title: string;
meetingType: string;
status: string;
scheduledAt: string | null;
durationMinutes: number;
agenda: string;
notes: string;
decisions: string;
createdAt: string;
updatedAt: string;
}
export interface SprintRecord {
id: string;
orgId: string;
name: string;
goal: string;
status: string;
startDate: string;
endDate: string;
velocityPoints: number;
completedPoints: number;
retrospective: string;
createdAt: string;
updatedAt: string;
}
export interface FileObjectRecord {
id: string;
orgId: string;
name: string;
kind: string;
sizeBytes: number;
sha256: string;
storagePath: string;
ownerType: "employee" | "agent" | "system";
ownerId: string | null;
spaceId: string | null;
pinned: boolean;
scanState: FileScanState;
scanLabelsJson: string;
scannedAt: string | null;
createdAt: string;
updatedAt: string | null;
}
export interface FileAccessGrantRecord {
id: string;
orgId: string;
fileId: string;
grantedToType: "employee" | "agent" | "board" | "org_group";
grantedToId: string;
grantedByType: "employee" | "agent" | "board" | "system";
grantedById: string | null;
sourceMessageId: string | null;
sourceThreadId: string | null;
accessLevel: "read" | "manage";
createdAt: string;
}
export interface FileHandoffRecord {
id: string;
orgId: string;
messageId: string;
fileId: string;
sourcePrincipalType: "employee" | "agent" | "board" | "system";
sourcePrincipalId: string | null;
targetPrincipalType: "employee" | "agent" | "board" | "org_group";
targetPrincipalId: string;
transferType: string;
checksum: string;
scanState: FileScanState;
scanLabelsJson: string;
policyDecision: "approved_for_handoff" | "blocked_by_scan";
objectRef: string;
createdAt: string;
}
export interface ScheduledPostRecord {
id: string;
orgId: string;
socialAccountId: string;
bodyMd: string;
scheduledFor: string;
state: "draft" | "scheduled" | "published" | "cancelled";
approvalId: string | null;
createdByEmployeeId: string | null;
createdAt: string;
updatedAt: string;
}
export interface ProviderRecord {
id: string;
orgId: string;
providerKey: string;
label: string;
authType: ProviderAuthType;
model: string | null;
credentialId: string | null;
enabled: boolean;
authState: string;
healthState: string;
lastCheckedAt: string | null;
lastError: string | null;
dataPolicy: ProviderDataPolicy;
backgroundEnabled: boolean;
monthlyRequestLimit: number;
workspaceScope: string;
createdAt: string;
}
export interface ProviderCatalogModel {
id: string;
name: string;
}
export interface ProviderCatalogEntry {
key: string;
label: string;
authType: ProviderAuthType;
defaultModel: string | null;
capabilityTags: string[];
signInUrl: string | null;
credentialHelp: string;
models: ProviderCatalogModel[];
/** True when the provider exposes a real models endpoint we can fetch from.
* When false (e.g. the Codex subscription, which has no enumerable list), the
* UI offers a free-text model id instead of a fixed dropdown. */
supportsLiveModels: boolean;
/** Set for user-configured OpenAI/Anthropic-compatible endpoints: the UI
* collects a base URL + API key + model instead of a fixed provider form. */
customEndpoint?: "openai" | "anthropic";
}
export interface SkillDefinitionRecord {
id: string;
orgId: string;
slug: string;
name: string;
ownerType: string;
status: string;
createdAt: string;
}
export interface SkillRevisionRecord {
id: string;
skillId: string;
versionSemver: string;
manifestJson: string;
sourceType: string;
sourceRef: string;
publishedAt: string;
immutableChecksum: string;
}
export interface SkillBindingRecord {
id: string;
orgId: string;
agentId: string;
skillId: string;
pinnedRevisionId: string;
bindingMode: string;
priority: number;
enabled: boolean;
}
export interface SkillRuntimeSnapshotRecord {
id: string;
agentId: string;
runId: string;
compiledPrompt: string;
toolsManifest: string;
sourceRevisionIds: string;
createdAt: string;
}
export interface SkillTestRecord {
id: string;
revisionId: string;
testType: string;
expectedOutputRef: string;
lastResult: string | null;
lastRunAt: string | null;
}
export interface AuditEventRecord {
id: string;
orgId: string;
entityType: string;
entityId: string;
actorType: string;
actorId: string | null;
action: string;
payloadJson: string;
createdAt: string;
}
export interface PolicyRuleRecord {
id: string;
orgId: string;
subjectType: string;
subjectId: string | null;
action: string;
effect: string;
riskCeiling: RiskLevel;
createdAt: string;
}
export interface MigrationReportRecord {
id: string;
orgId: string;
sourceRef: string;
reportJson: string;
createdAt: string;
}
export interface DocumentRecord {
id: string;
orgId: string;
title: string;
docType: string;
content: string;
status: string;
authorAgentId: string | null;
reviewerAgentId: string | null;
projectId: string | null;
goalId: string | null;
taskId: string | null;
createdAt: string;
updatedAt: string;
}
export interface KnowledgeEntryRecord {
id: string;
orgId: string;
topic: string;
category: string;
content: string;
importance: string;
sourceType: string;
sourceId: string | null;
createdAt: string;
updatedAt: string;
}
export interface ConnectorAccountRecord {
id: string;
orgId: string;
toolkitSlug: string;
toolkitName: string;
authConfigId: string;
status: string;
createdAt: string;
updatedAt: string;
}
export interface ConnectorGrantRecord {
id: string;
orgId: string;
agentId: string;
toolkitSlug: string;
grantedByType: string;
grantedById: string | null;
createdAt: string;
}
export interface AutomationRuleRecord {
id: string;
orgId: string;
name: string;
triggerEvent: string;
conditionJson: string;
actionType: string;
actionConfigJson: string;
priority: number;
enabled: boolean;
lastFiredAt: string | null;
fireCount: number;
createdAt: string;
updatedAt: string;
}
+34
View File
@@ -0,0 +1,34 @@
type ValueOf<T> = T[keyof T];
export const IDENTITY_SOURCE = { BOOTSTRAP: "bootstrap", SSO: "sso", SCIM: "scim" } as const;
export const ROLE_KEY = {
ORG_ADMIN: "org_admin",
APPROVAL_DECIDER: "approval_decider",
HIRING_MANAGER: "hiring_manager",
SCOPED_AGENT: "scoped_agent",
} as const;
export const ACCESS_DECISION = { ALLOW: "allow", DENY: "deny" } as const;
export type IdentitySource = ValueOf<typeof IDENTITY_SOURCE>;
export type RoleKey = ValueOf<typeof ROLE_KEY>;
export type AccessDecision = ValueOf<typeof ACCESS_DECISION>;
export type PrincipalType = "employee" | "agent" | "service_identity";
export interface EmployeeIdentityRecord {
id: string; orgId: string; employeeId: string; source: IdentitySource; externalSubject: string;
email: string | null; active: boolean; createdAt: string; lastSeenAt: string | null;
}
export interface ServiceIdentityRecord {
id: string; orgId: string; agentId: string; name: string; scopeJson: string; createdAt: string;
}
export interface RoleGrantRecord {
id: string; orgId: string; principalType: PrincipalType; principalId: string; roleKey: RoleKey;
scopeType: string; scopeId: string; grantedByEmployeeId: string | null; createdAt: string;
}
export interface AccessDecisionRecord {
id: string; orgId: string; principalType: PrincipalType; principalId: string; action: string;
resourceType: string; resourceId: string; decision: AccessDecision; reason: string; createdAt: string;
}
+5
View File
@@ -0,0 +1,5 @@
export type EntityId = string;
export function createId(prefix: string): EntityId {
return `${prefix}_${crypto.randomUUID().replaceAll("-", "")}`;
}
-167
View File
@@ -1,167 +0,0 @@
import type { InboxItem, ProfileSnapshot } from "./types";
/**
* Inbox items, derived purely from `ProfileSnapshot`.
*
* Mirrors the single-source-of-truth pattern used for sidebar badges
* (`sidebar-badges.ts`). The renderer already holds every row the
* inbox would aggregate — approvals, runs, tasks, agents, messages —
* so the old `getInbox` IPC was a second aggregation path that could
* drift. Deriving on the client from the snapshot removes the drift
* class and the round-trip.
*
* Parity note: the five item categories (`pending_approval`,
* `failed_run`, `budget_warning`, `blocked_task` / `review_needed`,
* `agent_message`) match what the old `buildDocumentMethods::getInbox`
* produced. One behavioural drop: the old SQL limited failed-run
* items to the last 24 hours; we preserve that window here using the
* snapshot's `createdAt` strings and the caller's "now".
*/
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
const BUDGET_WARNING_RATIO = 0.8;
const URGENT_CHANNELS: ReadonlyArray<string> = ["company", "incident"];
const SEVERITY_ORDER: Record<InboxItem["severity"], number> = {
critical: 0,
high: 1,
medium: 2,
low: 3,
};
/** Build the inbox list from the current snapshot for the given company. */
export function deriveInboxItems(
snapshot: ProfileSnapshot,
companyId: string | null,
now: Date = new Date(),
): InboxItem[] {
if (!companyId) return [];
const agentNameMap = new Map<string, string>();
for (const agent of snapshot.agents) {
if (agent.companyId === companyId) agentNameMap.set(agent.id, agent.name);
}
const items: InboxItem[] = [];
const oneDayAgoIso = new Date(now.getTime() - ONE_DAY_MS).toISOString();
for (const approval of snapshot.approvals) {
if (approval.companyId !== companyId) continue;
if (approval.state !== "pending") continue;
const requesterName = approval.requestedByAgentId
? agentNameMap.get(approval.requestedByAgentId) ?? null
: null;
items.push({
id: `approval-${approval.id}`,
type: "pending_approval",
title: approval.payloadSummary,
subtitle: `${approval.type.replaceAll("_", " ")} — requested by ${requesterName ?? "Unknown"}`,
severity: approval.type === "dangerous_command" ? "critical" : "high",
entityType: "approval",
entityId: approval.id,
agentId: approval.requestedByAgentId,
agentName: requesterName,
createdAt: approval.createdAt,
});
}
for (const run of snapshot.runs) {
if (run.companyId !== companyId) continue;
if (run.status !== "failed" && run.status !== "timed_out") continue;
if (run.createdAt <= oneDayAgoIso) continue;
const agentName = agentNameMap.get(run.agentId) ?? null;
items.push({
id: `run-${run.id}`,
type: "failed_run",
title: run.summary || "Run failed",
subtitle: `${agentName ?? "Unknown agent"} — ${run.errorMessage?.slice(0, 100) ?? "Unknown error"}`,
severity: "high",
entityType: "run",
entityId: run.id,
agentId: run.agentId,
agentName,
createdAt: run.createdAt,
});
}
for (const agent of snapshot.agents) {
if (agent.companyId !== companyId) continue;
if (agent.budgetMonthlyUsd <= 0) continue;
const ratio = agent.spentMonthlyUsd / agent.budgetMonthlyUsd;
if (ratio <= BUDGET_WARNING_RATIO) continue;
const pct = Math.round(ratio * 100);
items.push({
id: `budget-${agent.id}`,
type: "budget_warning",
title: `${agent.name} at ${pct}% budget`,
subtitle: `$${agent.spentMonthlyUsd.toFixed(2)} of $${agent.budgetMonthlyUsd.toFixed(2)} monthly limit`,
severity: pct >= 100 ? "critical" : "high",
entityType: "agent",
entityId: agent.id,
agentId: agent.id,
agentName: agent.name,
createdAt: agent.updatedAt,
});
}
for (const task of snapshot.tasks) {
if (task.companyId !== companyId) continue;
if (task.status !== "blocked" && task.status !== "in_review") continue;
const assigneeName = task.assigneeAgentId ? agentNameMap.get(task.assigneeAgentId) ?? null : null;
if (task.status === "blocked") {
items.push({
id: `blocked-${task.id}`,
type: "blocked_task",
title: task.title,
subtitle: `Assigned to ${assigneeName ?? "Unassigned"} — blocked`,
severity: task.priority === "critical" ? "critical" : "medium",
entityType: "task",
entityId: task.id,
agentId: task.assigneeAgentId,
agentName: assigneeName,
createdAt: task.updatedAt,
});
} else {
items.push({
id: `review-${task.id}`,
type: "review_needed",
title: task.title,
subtitle: `Submitted by ${assigneeName ?? "Unknown"} — awaiting review`,
severity: task.priority === "critical" ? "high" : "medium",
entityType: "task",
entityId: task.id,
agentId: task.assigneeAgentId,
agentName: assigneeName,
createdAt: task.updatedAt,
});
}
}
for (const message of snapshot.agentMessages) {
if (message.companyId !== companyId) continue;
if (message.readAt) continue;
const visible =
URGENT_CHANNELS.includes(message.channel) || message.priority === "urgent";
if (!visible) continue;
const senderName = agentNameMap.get(message.fromAgentId) ?? null;
const urgencyTag = message.priority === "urgent" ? " (urgent)" : "";
items.push({
id: `message-${message.id}`,
type: "agent_message",
title: message.subject,
subtitle: `${senderName ?? "Unknown"} — ${message.channel === "incident" ? "INCIDENT" : message.channel}${urgencyTag}`,
severity: message.priority === "urgent" || message.channel === "incident" ? "critical" : "medium",
entityType: "message",
entityId: message.id,
agentId: message.fromAgentId,
agentName: senderName,
createdAt: message.createdAt,
});
}
items.sort(
(a, b) =>
SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity] ||
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
);
return items;
}
+88
View File
@@ -0,0 +1,88 @@
export const IPC_CHANNELS = {
loadSnapshot: "agentcompany:load-snapshot",
bootstrapOnboarding: "agentcompany:bootstrap-onboarding",
setActiveOrganization: "agentcompany:set-active-organization",
deleteOrganization: "agentcompany:delete-organization",
createOrganization: "agentcompany:create-organization",
createAgent: "agentcompany:create-agent",
updateAgent: "agentcompany:update-agent",
createTask: "agentcompany:create-task",
updateTask: "agentcompany:update-task",
deleteTask: "agentcompany:delete-task",
updateTaskStatus: "agentcompany:update-task-status",
runTask: "agentcompany:run-task",
createApproval: "agentcompany:create-approval",
decideApproval: "agentcompany:decide-approval",
syncEmployeeIdentity: "agentcompany:sync-employee-identity",
grantRole: "agentcompany:grant-role",
createChatSpace: "agentcompany:create-chat-space",
sendMessage: "agentcompany:send-message",
editMessage: "agentcompany:edit-message",
deleteMessage: "agentcompany:delete-message",
markChatSpaceRead: "agentcompany:mark-chat-space-read",
saveProviderCredential: "agentcompany:save-provider-credential",
revokeProviderCredential: "agentcompany:revoke-provider-credential",
launchProviderSignIn: "agentcompany:launch-provider-sign-in",
startProviderOAuth: "agentcompany:start-provider-oauth",
cancelProviderOAuth: "agentcompany:cancel-provider-oauth",
checkProviderHealth: "agentcompany:check-provider-health",
listProviderModels: "agentcompany:list-provider-models",
updateProviderPolicy: "agentcompany:update-provider-policy",
openExternalUrl: "agentcompany:open-external-url",
createProviderResponse: "agentcompany:create-provider-response",
streamProviderResponse: "agentcompany:stream-provider-response",
cancelProviderResponse: "agentcompany:cancel-provider-response",
importSkillDirectory: "agentcompany:import-skill-directory",
bindSkill: "agentcompany:bind-skill",
resolveAgentSkills: "agentcompany:resolve-agent-skills",
runSkillTests: "agentcompany:run-skill-tests",
createSocialAccount: "agentcompany:create-social-account",
launchSocialLogin: "agentcompany:launch-social-login",
createScheduledPost: "agentcompany:create-scheduled-post",
setScheduledPostState: "agentcompany:set-scheduled-post-state",
importFile: "agentcompany:import-file",
openFile: "agentcompany:open-file",
pickDirectory: "agentcompany:pick-directory",
setFilePinned: "agentcompany:set-file-pinned",
createMigrationReport: "agentcompany:create-migration-report",
createRollbackSnapshot: "agentcompany:create-rollback-snapshot",
setRollbackSnapshotActive: "agentcompany:set-rollback-snapshot-active",
resolveMigrationReconciliation: "agentcompany:resolve-migration-reconciliation",
setFeatureFlag: "agentcompany:set-feature-flag",
runChaosDrill: "agentcompany:run-chaos-drill",
runSdlcReview: "agentcompany:run-sdlc-review",
runEvalSuite: "agentcompany:run-eval-suite",
setPrBotGate: "agentcompany:set-pr-bot-gate",
createComplianceExport: "agentcompany:create-compliance-export",
createAuditReplay: "agentcompany:create-audit-replay",
createLegalHold: "agentcompany:create-legal-hold",
setLegalHoldState: "agentcompany:set-legal-hold-state",
createRetentionFreeze: "agentcompany:create-retention-freeze",
setRetentionFreezeState: "agentcompany:set-retention-freeze-state",
createGoal: "agentcompany:create-goal",
createProject: "agentcompany:create-project",
createWorkspace: "agentcompany:create-workspace",
createDocument: "agentcompany:create-document",
updateDocument: "agentcompany:update-document",
deleteDocument: "agentcompany:delete-document",
createKnowledgeEntry: "agentcompany:create-knowledge-entry",
deleteKnowledgeEntry: "agentcompany:delete-knowledge-entry",
createAutomationRule: "agentcompany:create-automation-rule",
updateAutomationRule: "agentcompany:update-automation-rule",
deleteAutomationRule: "agentcompany:delete-automation-rule",
createMeeting: "agentcompany:create-meeting",
deleteMeeting: "agentcompany:delete-meeting",
createSprint: "agentcompany:create-sprint",
deleteSprint: "agentcompany:delete-sprint",
saveComposioSettings: "agentcompany:save-composio-settings",
listComposioToolkits: "agentcompany:list-composio-toolkits",
connectComposioToolkit: "agentcompany:connect-composio-toolkit",
refreshComposioAccounts: "agentcompany:refresh-composio-accounts",
grantConnector: "agentcompany:grant-connector",
revokeConnector: "agentcompany:revoke-connector",
search: "agentcompany:search",
rendererEvent: "agentcompany:renderer-event",
windowMinimize: "agentcompany:window-minimize",
windowMaximize: "agentcompany:window-maximize",
windowClose: "agentcompany:window-close",
} as const;
-4
View File
@@ -1,4 +0,0 @@
export type AppLocale = "en" | "zh";
export const APP_LOCALES: readonly AppLocale[] = ["en", "zh"] as const;
export const LOCALE_LABELS: Record<AppLocale, string> = { en: "English", zh: "中文" };
export const DEFAULT_LOCALE: AppLocale = "en";
-12
View File
@@ -1,12 +0,0 @@
const ACTUAL_LINE_BREAKS = /\r\n?/g;
const ESCAPED_CRLF = /\\r\\n/g;
const ESCAPED_LF = /\\n/g;
const ESCAPED_CR = /\\r/g;
export function normalizeMarkdownText(text: string): string {
return text
.replace(ACTUAL_LINE_BREAKS, "\n")
.replace(ESCAPED_CRLF, "\n")
.replace(ESCAPED_LF, "\n")
.replace(ESCAPED_CR, "\n");
}
+11
View File
@@ -0,0 +1,11 @@
export const RESERVED_MENTION_HANDLES = new Set(["board", "oncall"]);
export function canonicalMentionHandle(value: string): string {
return value.toLowerCase().replace(/[^a-z0-9]/g, "");
}
export function assertUsableMentionName(value: string): void {
if (RESERVED_MENTION_HANDLES.has(canonicalMentionHandle(value))) {
throw new Error("Mention handle is reserved.");
}
}
+50
View File
@@ -0,0 +1,50 @@
type ValueOf<T> = T[keyof T];
export const FEATURE_FLAG_KEY = {
PROVIDER_BACKGROUND_EXECUTION: "provider_background_execution",
SOCIAL_PUBLISH_APPROVAL: "social_publish_approval",
BOARD_INTERVENTION: "board_intervention",
CHAOS_DRILLS: "chaos_drills",
} as const;
export const SLO_SIGNAL_KEY = {
PROVIDER_REQUEST_SUCCESS: "provider_request_success",
APPROVAL_ROUTE_COVERAGE: "approval_route_coverage",
BROWSER_SESSION_BOUNDARY: "browser_session_boundary",
SKILL_RESOLVE_SUCCESS: "skill_resolve_success",
MIGRATION_VALIDATION_SUCCESS: "migration_validation_success",
} as const;
export const CHAOS_DRILL_SCENARIO = {
PROVIDER_OUTAGE_POLICY_GATE: "provider_outage_policy_gate",
APPROVAL_BACKLOG_GATE: "approval_backlog_gate",
BROWSER_SESSION_BOUNDARY: "browser_session_boundary",
MIGRATION_ROLLBACK_PACK: "migration_rollback_pack",
} as const;
export const CHAOS_DRILL_STATE = { PASSED: "passed", FAILED: "failed" } as const;
export type FeatureFlagKey = ValueOf<typeof FEATURE_FLAG_KEY>;
export type SloSignalKey = ValueOf<typeof SLO_SIGNAL_KEY>;
export type ChaosDrillScenario = ValueOf<typeof CHAOS_DRILL_SCENARIO>;
export type ChaosDrillState = ValueOf<typeof CHAOS_DRILL_STATE>;
export interface FeatureFlagRecord {
id: string; orgId: string; key: FeatureFlagKey; label: string; enabled: boolean; createdAt: string; updatedAt: string;
}
export interface SloTargetRecord {
id: string; orgId: string; signalKey: SloSignalKey; label: string; targetBasisPoints: number; windowMinutes: number; createdAt: string; updatedAt: string;
}
export interface OperationalEventRecord {
id: string; orgId: string; signalKey: SloSignalKey; source: string; success: boolean; durationMs: number | null; detailJson: string; createdAt: string;
}
export interface ChaosDrillRecord {
id: string; orgId: string; key: string; label: string; scenarioKey: ChaosDrillScenario; enabled: boolean; createdAt: string; updatedAt: string;
}
export interface ChaosDrillRunRecord {
id: string; orgId: string; drillId: string; state: ChaosDrillState; resultJson: string; startedAt: string; completedAt: string;
}
+24
View File
@@ -0,0 +1,24 @@
type ValueOf<T> = T[keyof T];
export const ROUTE_TO_TYPE = { EMPLOYEE: "employee", AGENT: "agent", BOARD: "board" } as const;
export type RouteToType = ValueOf<typeof ROUTE_TO_TYPE>;
export interface OrgDepartmentRecord {
id: string; orgId: string; name: string; leadAgentId: string | null;
headcountLimit: number; monthlyBudgetLimitCents: number; createdAt: string; updatedAt: string;
}
export interface HiringPolicyRecord {
id: string; orgId: string; departmentName: string; maxHeadcount: number;
monthlyBudgetLimitCents: number; requireApprovalAboveCents: number; createdAt: string; updatedAt: string;
}
export interface ApprovalRoutingRuleRecord {
id: string; orgId: string; kind: string; minimumRisk: string;
routeToType: RouteToType; routeToId: string; createdAt: string;
}
export interface ApprovalAssignmentRecord {
id: string; orgId: string; approvalId: string; assigneeType: RouteToType;
assigneeId: string; routingRuleId: string | null; createdAt: string;
}
+34
View File
@@ -0,0 +1,34 @@
import type { ProviderAuthType } from "./domain";
export interface ProviderAuthProfileRecord {
id: string;
orgId: string;
providerId: string;
credentialId: string;
providerKey: string;
authType: ProviderAuthType;
profileKind: string;
displayHint: string;
sourceType: string;
sourceRef: string | null;
capabilityJson: string;
active: boolean;
createdAt: string;
}
export interface ProviderAuthSessionRecord {
id: string;
orgId: string;
providerId: string;
providerKey: string;
employeeId: string;
state: string;
nonce: string;
codeVerifierSha256: string;
redirectUri: string;
signInUrl: string;
partition: string;
createdAt: string;
expiresAt: string;
completedAt: string | null;
}
+172
View File
@@ -0,0 +1,172 @@
import { PROVIDER_AUTH_TYPE, type ProviderCatalogEntry } from "./domain";
import { listProviderModels } from "./provider-models";
const RAW_CATALOG: Omit<ProviderCatalogEntry, "models" | "supportsLiveModels">[] = [
{
key: "openai",
label: "OpenAI",
authType: PROVIDER_AUTH_TYPE.API_KEY,
defaultModel: "gpt-5.4",
capabilityTags: ["responses", "tools", "background"],
signInUrl: null,
credentialHelp: "Generate an API key at platform.openai.com → API keys.",
},
{
key: "anthropic",
label: "Anthropic",
authType: PROVIDER_AUTH_TYPE.API_KEY,
defaultModel: "claude-sonnet-4-5",
capabilityTags: ["messages", "tool-use", "token-bucket"],
signInUrl: null,
credentialHelp: "Generate an API key at console.anthropic.com → API keys.",
},
{
key: "claude-pro",
label: "Claude Pro/Max",
authType: PROVIDER_AUTH_TYPE.OAUTH_PKCE,
defaultModel: "claude-sonnet-4-5",
capabilityTags: ["account", "subscription"],
signInUrl: "https://claude.ai/login",
credentialHelp: "Sign in with your Claude Pro or Max account in the browser; AgentCompany finishes the handshake.",
},
{
key: "xai",
label: "xAI Grok",
authType: PROVIDER_AUTH_TYPE.API_KEY,
defaultModel: "grok-4",
capabilityTags: ["chat", "reasoning"],
signInUrl: null,
credentialHelp: "Generate an API key at console.x.ai → API keys.",
},
{
key: "groq",
label: "Groq",
authType: PROVIDER_AUTH_TYPE.API_KEY,
defaultModel: "groq/compound",
capabilityTags: ["inference", "low-latency"],
signInUrl: null,
credentialHelp: "Generate an API key at console.groq.com → API keys.",
},
{
key: "mistral",
label: "Mistral",
authType: PROVIDER_AUTH_TYPE.API_KEY,
defaultModel: "mistral-large-latest",
capabilityTags: ["chat", "reasoning"],
signInUrl: null,
credentialHelp: "Generate an API key at console.mistral.ai → API keys.",
},
{
key: "cerebras",
label: "Cerebras",
authType: PROVIDER_AUTH_TYPE.API_KEY,
defaultModel: "qwen-3-235b-a22b-instruct-2507",
capabilityTags: ["inference", "fast"],
signInUrl: null,
credentialHelp: "Generate an API key at cloud.cerebras.ai → API keys.",
},
{
key: "openrouter",
label: "OpenRouter",
authType: PROVIDER_AUTH_TYPE.API_KEY,
defaultModel: "anthropic/claude-sonnet-4.5",
capabilityTags: ["router", "multi-model"],
signInUrl: null,
credentialHelp: "Generate an API key at openrouter.ai → Keys.",
},
{
key: "github-copilot",
label: "GitHub Copilot",
authType: PROVIDER_AUTH_TYPE.OAUTH_PKCE,
defaultModel: "claude-opus-4-5",
capabilityTags: ["account", "coding"],
signInUrl: "https://github.com/login/device",
credentialHelp: "Sign in with the GitHub device code shown here — no token to copy.",
},
{
key: "google-antigravity",
label: "Google Antigravity",
authType: PROVIDER_AUTH_TYPE.OAUTH_PKCE,
defaultModel: "claude-sonnet-4-5",
capabilityTags: ["account", "coding"],
signInUrl: "https://antigravity.google/",
credentialHelp: "Sign in with your Google account in the browser; AgentCompany finishes the handshake.",
},
{
key: "gpt-account",
label: "GPT account",
authType: PROVIDER_AUTH_TYPE.ACCOUNT_SUBSCRIPTION,
defaultModel: "gpt-5.3-codex",
capabilityTags: ["codex", "subscription"],
signInUrl: "https://chatgpt.com/codex",
credentialHelp: "Sign in to ChatGPT Plus/Pro in the browser; AgentCompany finishes the handshake.",
},
{
key: "azure-openai",
label: "Azure OpenAI",
authType: PROVIDER_AUTH_TYPE.CLOUD,
defaultModel: "gpt-5.4",
capabilityTags: ["enterprise", "regional"],
signInUrl: null,
credentialHelp: "Set base URL (e.g. https://<resource>.openai.azure.com), deployment name, and the api-key from Azure portal.",
},
{
key: "aws-bedrock",
label: "AWS Bedrock",
authType: PROVIDER_AUTH_TYPE.CLOUD,
defaultModel: "anthropic.claude-sonnet-4-5",
capabilityTags: ["enterprise", "multi-model"],
signInUrl: null,
credentialHelp: "Provide AWS region plus an access key + secret access key with bedrock:InvokeModel permission.",
},
{
key: "vertex-ai",
label: "Vertex AI",
authType: PROVIDER_AUTH_TYPE.CLOUD,
defaultModel: "gemini-2.5-pro",
capabilityTags: ["enterprise", "regional"],
signInUrl: null,
credentialHelp: "Provide GCP project id, region, and a service-account JSON key with aiplatform.user role.",
},
{
key: "custom-openai",
label: "Custom OpenAI-compatible",
authType: PROVIDER_AUTH_TYPE.CLOUD,
defaultModel: null,
capabilityTags: ["custom", "openai-compatible"],
signInUrl: null,
credentialHelp: "Set the base URL (ending in /v1) and an API key for any OpenAI Chat Completions–compatible endpoint, then enter the model id.",
customEndpoint: "openai",
},
{
key: "custom-anthropic",
label: "Custom Anthropic-compatible",
authType: PROVIDER_AUTH_TYPE.CLOUD,
defaultModel: null,
capabilityTags: ["custom", "anthropic-compatible"],
signInUrl: null,
credentialHelp: "Set the base URL and an API key for any Anthropic Messages–compatible endpoint, then enter the model id.",
customEndpoint: "anthropic",
},
];
// Providers with no enumerable models endpoint: the Codex subscription, the
// browser-token / cloud connectors, and user-configured custom endpoints whose
// model id is entered by hand. The UI offers a fixed dropdown (when a curated
// list exists) or a free-text model id instead of a live fetch.
const CURATED_MODEL_PROVIDERS = new Set([
"github-copilot",
"google-antigravity",
"gpt-account",
"azure-openai",
"aws-bedrock",
"vertex-ai",
"custom-openai",
"custom-anthropic",
]);
export const PROVIDER_CATALOG: ProviderCatalogEntry[] = RAW_CATALOG.map((entry) => ({
...entry,
models: listProviderModels(entry.key),
supportsLiveModels: !CURATED_MODEL_PROVIDERS.has(entry.key),
}));
+237
View File
@@ -0,0 +1,237 @@
export interface ProviderModelEntry {
id: string;
name: string;
}
const ANTHROPIC_MODELS: ProviderModelEntry[] = [
{ id: "claude-opus-4-7", name: "Claude Opus 4.7" },
{ id: "claude-opus-4-6", name: "Claude Opus 4.6" },
{ id: "claude-opus-4-5", name: "Claude Opus 4.5 (latest)" },
{ id: "claude-opus-4-1", name: "Claude Opus 4.1 (latest)" },
{ id: "claude-opus-4-0", name: "Claude Opus 4 (latest)" },
{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" },
{ id: "claude-sonnet-4-5", name: "Claude Sonnet 4.5 (latest)" },
{ id: "claude-sonnet-4-0", name: "Claude Sonnet 4 (latest)" },
{ id: "claude-haiku-4-5", name: "Claude Haiku 4.5 (latest)" },
{ id: "claude-3-7-sonnet-20250219", name: "Claude Sonnet 3.7" },
{ id: "claude-3-5-sonnet-20241022", name: "Claude Sonnet 3.5 v2" },
{ id: "claude-3-5-sonnet-20240620", name: "Claude Sonnet 3.5" },
{ id: "claude-3-5-haiku-latest", name: "Claude Haiku 3.5 (latest)" },
{ id: "claude-3-5-haiku-20241022", name: "Claude Haiku 3.5" },
{ id: "claude-3-haiku-20240307", name: "Claude Haiku 3" },
{ id: "claude-3-sonnet-20240229", name: "Claude Sonnet 3" },
{ id: "claude-3-opus-20240229", name: "Claude Opus 3" },
];
export const PROVIDER_MODELS: Record<string, ProviderModelEntry[]> = {
openai: [
{ id: "gpt-5.5", name: "GPT-5.5" },
{ id: "gpt-5.4-pro", name: "GPT-5.4 Pro" },
{ id: "gpt-5.4", name: "GPT-5.4" },
{ id: "gpt-5.4-mini", name: "GPT-5.4 mini" },
{ id: "gpt-5.4-nano", name: "GPT-5.4 nano" },
{ id: "gpt-5.3-codex", name: "GPT-5.3 Codex" },
{ id: "gpt-5.3-codex-spark", name: "GPT-5.3 Codex Spark" },
{ id: "gpt-5.3-chat-latest", name: "GPT-5.3 Chat" },
{ id: "gpt-5.2-pro", name: "GPT-5.2 Pro" },
{ id: "gpt-5.2", name: "GPT-5.2" },
{ id: "gpt-5.2-codex", name: "GPT-5.2 Codex" },
{ id: "gpt-5.2-chat-latest", name: "GPT-5.2 Chat" },
{ id: "gpt-5.1", name: "GPT-5.1" },
{ id: "gpt-5.1-codex", name: "GPT-5.1 Codex" },
{ id: "gpt-5.1-codex-max", name: "GPT-5.1 Codex Max" },
{ id: "gpt-5.1-codex-mini", name: "GPT-5.1 Codex mini" },
{ id: "gpt-5.1-chat-latest", name: "GPT-5.1 Chat" },
{ id: "gpt-5-pro", name: "GPT-5 Pro" },
{ id: "gpt-5", name: "GPT-5" },
{ id: "gpt-5-codex", name: "GPT-5 Codex" },
{ id: "gpt-5-mini", name: "GPT-5 mini" },
{ id: "gpt-5-nano", name: "GPT-5 nano" },
{ id: "gpt-5-chat-latest", name: "GPT-5 Chat" },
{ id: "o4-mini", name: "o4-mini" },
{ id: "o4-mini-deep-research", name: "o4-mini deep research" },
{ id: "o3", name: "o3" },
{ id: "o3-pro", name: "o3-pro" },
{ id: "o3-mini", name: "o3-mini" },
{ id: "o3-deep-research", name: "o3 deep research" },
{ id: "o1", name: "o1" },
{ id: "o1-pro", name: "o1-pro" },
{ id: "gpt-4.1", name: "GPT-4.1" },
{ id: "gpt-4.1-mini", name: "GPT-4.1 mini" },
{ id: "gpt-4.1-nano", name: "GPT-4.1 nano" },
{ id: "gpt-4o", name: "GPT-4o" },
{ id: "gpt-4o-mini", name: "GPT-4o mini" },
{ id: "gpt-4-turbo", name: "GPT-4 Turbo" },
{ id: "gpt-4", name: "GPT-4" },
],
anthropic: ANTHROPIC_MODELS,
"claude-pro": ANTHROPIC_MODELS,
xai: [
{ id: "grok-4", name: "Grok 4" },
{ id: "grok-4-fast", name: "Grok 4 Fast" },
{ id: "grok-4-fast-non-reasoning", name: "Grok 4 Fast (Non-Reasoning)" },
{ id: "grok-4-1-fast", name: "Grok 4.1 Fast" },
{ id: "grok-4-1-fast-non-reasoning", name: "Grok 4.1 Fast (Non-Reasoning)" },
{ id: "grok-4.20-0309-reasoning", name: "Grok 4.20 (Reasoning)" },
{ id: "grok-4.20-0309-non-reasoning", name: "Grok 4.20 (Non-Reasoning)" },
{ id: "grok-code-fast-1", name: "Grok Code Fast 1" },
{ id: "grok-3", name: "Grok 3" },
{ id: "grok-3-fast", name: "Grok 3 Fast" },
{ id: "grok-3-mini", name: "Grok 3 Mini" },
{ id: "grok-3-mini-fast", name: "Grok 3 Mini Fast" },
{ id: "grok-2", name: "Grok 2" },
{ id: "grok-2-vision", name: "Grok 2 Vision" },
{ id: "grok-beta", name: "Grok Beta" },
{ id: "grok-vision-beta", name: "Grok Vision Beta" },
],
groq: [
{ id: "groq/compound", name: "Compound" },
{ id: "groq/compound-mini", name: "Compound Mini" },
{ id: "moonshotai/kimi-k2-instruct-0905", name: "Kimi K2 Instruct 0905" },
{ id: "moonshotai/kimi-k2-instruct", name: "Kimi K2 Instruct" },
{ id: "openai/gpt-oss-120b", name: "GPT OSS 120B" },
{ id: "openai/gpt-oss-20b", name: "GPT OSS 20B" },
{ id: "openai/gpt-oss-safeguard-20b", name: "Safety GPT OSS 20B" },
{ id: "llama-3.3-70b-versatile", name: "Llama 3.3 70B Versatile" },
{ id: "llama-3.1-8b-instant", name: "Llama 3.1 8B Instant" },
{ id: "meta-llama/llama-4-maverick-17b-128e-instruct", name: "Llama 4 Maverick 17B" },
{ id: "meta-llama/llama-4-scout-17b-16e-instruct", name: "Llama 4 Scout 17B" },
{ id: "qwen-qwq-32b", name: "Qwen QwQ 32B" },
{ id: "qwen/qwen3-32b", name: "Qwen3 32B" },
{ id: "mistral-saba-24b", name: "Mistral Saba 24B" },
{ id: "deepseek-r1-distill-llama-70b", name: "DeepSeek R1 Distill Llama 70B" },
{ id: "gemma2-9b-it", name: "Gemma 2 9B" },
],
"github-copilot": [
{ id: "claude-opus-4.7", name: "Claude Opus 4.7" },
{ id: "claude-opus-4.6", name: "Claude Opus 4.6" },
{ id: "claude-opus-4.5", name: "Claude Opus 4.5" },
{ id: "claude-sonnet-4.6", name: "Claude Sonnet 4.6" },
{ id: "claude-sonnet-4.5", name: "Claude Sonnet 4.5" },
{ id: "claude-sonnet-4", name: "Claude Sonnet 4" },
{ id: "claude-haiku-4.5", name: "Claude Haiku 4.5" },
{ id: "gpt-5.5", name: "GPT-5.5" },
{ id: "gpt-5.4", name: "GPT-5.4" },
{ id: "gpt-5.4-mini", name: "GPT-5.4 mini" },
{ id: "gpt-5.3-codex", name: "GPT-5.3 Codex" },
{ id: "gpt-5.2", name: "GPT-5.2" },
{ id: "gpt-5.2-codex", name: "GPT-5.2 Codex" },
{ id: "gpt-5.1", name: "GPT-5.1" },
{ id: "gpt-5.1-codex", name: "GPT-5.1 Codex" },
{ id: "gpt-5.1-codex-max", name: "GPT-5.1 Codex Max" },
{ id: "gpt-5.1-codex-mini", name: "GPT-5.1 Codex Mini" },
{ id: "gpt-5", name: "GPT-5" },
{ id: "gpt-5-mini", name: "GPT-5 mini" },
{ id: "gpt-4.1", name: "GPT-4.1" },
{ id: "gpt-4o", name: "GPT-4o" },
{ id: "gemini-3.1-pro-preview", name: "Gemini 3.1 Pro Preview" },
{ id: "gemini-3-pro-preview", name: "Gemini 3 Pro Preview" },
{ id: "gemini-3-flash-preview", name: "Gemini 3 Flash" },
{ id: "gemini-2.5-pro", name: "Gemini 2.5 Pro" },
{ id: "grok-code-fast-1", name: "Grok Code Fast 1" },
],
"google-antigravity": [
{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6 (Antigravity)" },
{ id: "claude-sonnet-4-5", name: "Claude Sonnet 4.5 (Antigravity)" },
{ id: "claude-sonnet-4-5-thinking", name: "Claude Sonnet 4.5 Thinking" },
{ id: "claude-opus-4-6-thinking", name: "Claude Opus 4.6 Thinking" },
{ id: "claude-opus-4-5-thinking", name: "Claude Opus 4.5 Thinking" },
{ id: "gemini-3.1-pro-high", name: "Gemini 3.1 Pro High" },
{ id: "gemini-3.1-pro-low", name: "Gemini 3.1 Pro Low" },
{ id: "gemini-3-flash", name: "Gemini 3 Flash" },
{ id: "gpt-oss-120b-medium", name: "GPT-OSS 120B Medium" },
],
"gpt-account": [
{ id: "gpt-5.5", name: "GPT-5.5" },
{ id: "gpt-5.4", name: "GPT-5.4" },
{ id: "gpt-5.4-mini", name: "GPT-5.4 Mini" },
{ id: "gpt-5.3-codex", name: "GPT-5.3 Codex" },
{ id: "gpt-5.3-codex-spark", name: "GPT-5.3 Codex Spark" },
{ id: "gpt-5.2", name: "GPT-5.2" },
{ id: "gpt-5.2-codex", name: "GPT-5.2 Codex" },
{ id: "gpt-5.1", name: "GPT-5.1" },
{ id: "gpt-5.1-codex-max", name: "GPT-5.1 Codex Max" },
{ id: "gpt-5.1-codex-mini", name: "GPT-5.1 Codex Mini" },
],
"azure-openai": [
{ id: "gpt-5.5", name: "GPT-5.5" },
{ id: "gpt-5.4", name: "GPT-5.4" },
{ id: "gpt-5.4-mini", name: "GPT-5.4 mini" },
{ id: "gpt-5.3-codex", name: "GPT-5.3 Codex" },
{ id: "gpt-5.2", name: "GPT-5.2" },
{ id: "gpt-5.1", name: "GPT-5.1" },
{ id: "gpt-5", name: "GPT-5" },
{ id: "gpt-5-codex", name: "GPT-5 Codex" },
{ id: "gpt-4.1", name: "GPT-4.1" },
{ id: "gpt-4o", name: "GPT-4o" },
{ id: "o4-mini", name: "o4-mini" },
{ id: "o3", name: "o3" },
],
"aws-bedrock": [
{ id: "anthropic.claude-opus-4-7", name: "Claude Opus 4.7" },
{ id: "anthropic.claude-opus-4-6-v1", name: "Claude Opus 4.6" },
{ id: "anthropic.claude-opus-4-5-20251101-v1:0", name: "Claude Opus 4.5" },
{ id: "anthropic.claude-sonnet-4-6", name: "Claude Sonnet 4.6" },
{ id: "anthropic.claude-sonnet-4-5-20250929-v1:0", name: "Claude Sonnet 4.5" },
{ id: "anthropic.claude-haiku-4-5-20251001-v1:0", name: "Claude Haiku 4.5" },
{ id: "amazon.nova-2-lite-v1:0", name: "Nova 2 Lite" },
{ id: "amazon.nova-premier-v1:0", name: "Nova Premier" },
{ id: "amazon.nova-pro-v1:0", name: "Nova Pro" },
{ id: "deepseek.v3.2", name: "DeepSeek V3.2" },
{ id: "meta.llama3-3-70b-instruct-v1:0", name: "Llama 3.3 70B" },
{ id: "moonshotai.kimi-k2.5", name: "Kimi K2.5" },
],
"vertex-ai": [
{ id: "gemini-3.1-pro-preview", name: "Gemini 3.1 Pro Preview" },
{ id: "gemini-3-pro-preview", name: "Gemini 3 Pro Preview" },
{ id: "gemini-3-flash-preview", name: "Gemini 3 Flash Preview" },
{ id: "gemini-2.5-pro", name: "Gemini 2.5 Pro" },
{ id: "gemini-2.5-flash", name: "Gemini 2.5 Flash" },
{ id: "gemini-2.5-flash-lite", name: "Gemini 2.5 Flash Lite" },
{ id: "gemini-2.0-flash", name: "Gemini 2.0 Flash" },
{ id: "gemini-2.0-flash-lite", name: "Gemini 2.0 Flash Lite" },
{ id: "gemini-1.5-pro", name: "Gemini 1.5 Pro" },
{ id: "gemini-1.5-flash", name: "Gemini 1.5 Flash" },
],
mistral: [
{ id: "mistral-large-latest", name: "Mistral Large (latest)" },
{ id: "mistral-large-2512", name: "Mistral Large 3" },
{ id: "mistral-medium-latest", name: "Mistral Medium (latest)" },
{ id: "mistral-medium-2508", name: "Mistral Medium 3.1" },
{ id: "mistral-small-latest", name: "Mistral Small (latest)" },
{ id: "mistral-small-2603", name: "Mistral Small 4" },
{ id: "magistral-medium-latest", name: "Magistral Medium (latest)" },
{ id: "magistral-small", name: "Magistral Small" },
{ id: "codestral-latest", name: "Codestral (latest)" },
{ id: "devstral-medium-latest", name: "Devstral Medium (latest)" },
{ id: "devstral-small-2507", name: "Devstral Small" },
{ id: "ministral-8b-latest", name: "Ministral 8B (latest)" },
{ id: "ministral-3b-latest", name: "Ministral 3B (latest)" },
{ id: "pixtral-large-latest", name: "Pixtral Large (latest)" },
{ id: "open-mistral-nemo", name: "Mistral Nemo" },
],
cerebras: [
{ id: "qwen-3-235b-a22b-instruct-2507", name: "Qwen 3 235B Instruct" },
{ id: "gpt-oss-120b", name: "GPT OSS 120B" },
{ id: "zai-glm-4.7", name: "Z.AI GLM-4.7" },
{ id: "llama3.1-8b", name: "Llama 3.1 8B" },
],
openrouter: [
{ id: "anthropic/claude-sonnet-4.5", name: "Anthropic: Claude Sonnet 4.5" },
{ id: "anthropic/claude-opus-4.5", name: "Anthropic: Claude Opus 4.5" },
{ id: "anthropic/claude-haiku-4.5", name: "Anthropic: Claude Haiku 4.5" },
{ id: "openai/gpt-5.2", name: "OpenAI: GPT-5.2" },
{ id: "openai/gpt-5.1", name: "OpenAI: GPT-5.1" },
{ id: "google/gemini-3-pro-preview", name: "Google: Gemini 3 Pro Preview" },
{ id: "google/gemini-2.5-pro", name: "Google: Gemini 2.5 Pro" },
{ id: "google/gemini-2.5-flash", name: "Google: Gemini 2.5 Flash" },
{ id: "x-ai/grok-4", name: "xAI: Grok 4" },
{ id: "deepseek/deepseek-chat", name: "DeepSeek: DeepSeek Chat" },
{ id: "meta-llama/llama-4-maverick", name: "Meta: Llama 4 Maverick" },
{ id: "qwen/qwen3-235b-a22b", name: "Qwen: Qwen3 235B A22B" },
],
};
export function listProviderModels(providerKey: string): ProviderModelEntry[] {
return PROVIDER_MODELS[providerKey] ?? [];
}
+14
View File
@@ -0,0 +1,14 @@
type ValueOf<T> = T[keyof T];
export const PROVIDER_DATA_POLICY = {
STANDARD: "standard",
ZERO_DATA_RETENTION: "zero_data_retention",
} as const;
export const PROVIDER_EXECUTION_MODE = {
FOREGROUND: "foreground",
BACKGROUND: "background",
} as const;
export type ProviderDataPolicy = ValueOf<typeof PROVIDER_DATA_POLICY>;
export type ProviderExecutionMode = ValueOf<typeof PROVIDER_EXECUTION_MODE>;
+47
View File
@@ -0,0 +1,47 @@
import type { ProviderExecutionMode } from "./provider-policy-domain";
export const PROVIDER_REQUEST_STATE = {
PENDING: "pending",
STREAMING: "streaming",
SUCCEEDED: "succeeded",
FAILED: "failed",
CANCELLED: "cancelled",
} as const;
export type ProviderRequestState = typeof PROVIDER_REQUEST_STATE[keyof typeof PROVIDER_REQUEST_STATE];
export interface ProviderRequestRecord {
id: string;
orgId: string;
providerId: string;
providerKey: string;
workspaceId: string | null;
model: string;
promptSha256: string;
responseText: string | null;
rawResponseJson: string | null;
state: ProviderRequestState;
errorMessage: string | null;
inputCharCount: number;
outputCharCount: number;
executionMode: ProviderExecutionMode;
policyDecision: string;
externalResponseId: string | null;
streamEventCount: number;
cancelledAt: string | null;
createdAt: string;
completedAt: string | null;
}
export interface ProviderStreamRendererEvent {
requestId: string;
providerId: string;
providerKey: string;
model: string;
streamEventType: "message_start" | "text_delta" | "message_stop" | "error";
textDelta: string | null;
responseText: string;
providerResponseId: string | null;
rawEventJson: string;
streamEventCount: number;
}
+36
View File
@@ -0,0 +1,36 @@
export interface ProviderRateLimitStateRecord {
orgId: string;
providerId: string;
providerKey: string;
windowStart: string;
windowEnd: string;
monthlyRequestLimit: number;
requestCount: number;
inputCharCount: number;
outputCharCount: number;
remainingRequestCount: number;
exhausted: boolean;
}
export interface ProviderObservedRateLimitState {
requestLimit: number | null;
remainingRequests: number | null;
resetAt: string | null;
retryAfterMs: number | null;
rawStateJson: string;
}
export interface ProviderRateLimitObservationRecord extends ProviderObservedRateLimitState {
id: string;
orgId: string;
providerId: string;
providerKey: string;
model: string | null;
observedAt: string;
}
export function currentProviderUsageWindow(now = new Date()): { start: string; end: string } {
const start = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));
const end = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1));
return { start: start.toISOString(), end: end.toISOString() };
}
+16
View File
@@ -0,0 +1,16 @@
export interface DesktopError {
code: string;
message: string;
}
export type DesktopResult<T> =
| { ok: true; data: T }
| { ok: false; error: DesktopError };
export function ok<T>(data: T): DesktopResult<T> {
return { ok: true, data };
}
export function fail(code: string, message: string): DesktopResult<never> {
return { ok: false, error: { code, message } };
}
+44
View File
@@ -0,0 +1,44 @@
export interface RollbackSnapshotRecord {
id: string;
orgId: string;
migrationReportId: string;
sourceDatabasePath: string;
sourceFingerprint: string;
sourceDatabaseSha256: string;
workspaceManifestJson: string;
workspaceManifestSha256: string;
deltaJournalJson: string;
restorePlanJson: string;
active: boolean;
createdByEmployeeId: string | null;
createdAt: string;
activatedAt: string | null;
}
export interface MigrationCutoverEventRecord {
id: string;
orgId: string;
migrationReportId: string;
rollbackSnapshotId: string | null;
eventType: string;
actorType: string;
actorId: string | null;
payloadJson: string;
createdAt: string;
}
export interface MigrationReconciliationItemRecord {
id: string;
orgId: string;
migrationReportId: string;
rollbackSnapshotId: string | null;
sourceEventId: string;
targetType: string;
targetId: string;
reason: string;
state: string;
payloadJson: string;
createdAt: string;
resolvedAt: string | null;
resolvedByEmployeeId: string | null;
}
+48
View File
@@ -0,0 +1,48 @@
type ValueOf<T> = T[keyof T];
export const SDLC_REVIEW_AGENT_KEY = {
CODE_REVIEWER: "code_reviewer",
MIGRATION_REVIEWER: "migration_reviewer",
POLICY_REVIEWER: "policy_reviewer",
} as const;
export const SDLC_REVIEW_TARGET_TYPE = { WORKSPACE: "workspace", MIGRATION: "migration", POLICY: "policy" } as const;
export const EVAL_SUITE_KEY = { CONTRACT: "contract", INTEGRATION: "integration", REPLAY: "replay" } as const;
export const SDLC_RUN_STATE = { PASSED: "passed", FAILED: "failed" } as const;
export const PR_BOT_GATE_KEY = {
STATIC_CHECKS: "static_checks",
MIGRATION_DIFF: "migration_diff",
POLICY_DIFF: "policy_diff",
HUMAN_APPROVAL: "human_approval",
} as const;
export type SdlcReviewAgentKey = ValueOf<typeof SDLC_REVIEW_AGENT_KEY>;
export type SdlcReviewTargetType = ValueOf<typeof SDLC_REVIEW_TARGET_TYPE>;
export type EvalSuiteKey = ValueOf<typeof EVAL_SUITE_KEY>;
export type SdlcRunState = ValueOf<typeof SDLC_RUN_STATE>;
export type PrBotGateKey = ValueOf<typeof PR_BOT_GATE_KEY>;
export interface SdlcReviewAgentRecord {
id: string; orgId: string; key: SdlcReviewAgentKey; label: string; specialty: string; enabled: boolean; createdAt: string; updatedAt: string;
}
export interface SdlcReviewRunRecord {
id: string; orgId: string; reviewAgentId: string; targetType: SdlcReviewTargetType; targetRef: string;
state: SdlcRunState; resultJson: string; createdAt: string; completedAt: string;
}
export interface EvalSuiteRecord {
id: string; orgId: string; key: EvalSuiteKey; label: string; scope: string; createdAt: string; updatedAt: string;
}
export interface EvalCaseRecord {
id: string; orgId: string; suiteId: string; title: string; sourceType: string; sourceRef: string; expectedSignal: string; createdAt: string;
}
export interface EvalRunRecord {
id: string; orgId: string; suiteId: string; state: SdlcRunState; passedCount: number; failedCount: number; resultJson: string; createdAt: string; completedAt: string;
}
export interface PrBotGateRecord {
id: string; orgId: string; key: PrBotGateKey; label: string; gateType: string; enabled: boolean; createdAt: string; updatedAt: string;
}
+25
View File
@@ -0,0 +1,25 @@
export const SEARCH_ENTITY_TYPES = [
"employee",
"agent",
"task",
"goal",
"project",
"workspace",
"approval",
"chat_space",
"chat_message",
"file",
"provider",
"social_account",
"scheduled_post",
] as const;
export type SearchEntityType = (typeof SEARCH_ENTITY_TYPES)[number];
export interface SearchResultRecord {
entityType: SearchEntityType;
entityId: string;
title: string;
preview: string;
facets: Record<string, string>;
}
-102
View File
@@ -1,102 +0,0 @@
import type { ProfileSnapshot } from "./types";
/**
* Sidebar badge counters, derived purely from `ProfileSnapshot`.
*
* This is a local-first desktop app: every row the badges would want
* to count is already in memory via `ProfileSnapshot` (which is scoped
* to the current company and refreshed as an atomic unit). Running a
* second server-side aggregation — as the old `getSidebarBadges` IPC
* did — created two parallel data paths for the same answer, and the
* two drifted whenever one side's data was mutated between refreshes
* (e.g. a message being marked read in Communication). The resulting
* "badge = 1, inbox = empty" mismatch was the visible symptom.
*
* Derivation eliminates the class. Same snapshot in, same badge out.
* No IPC, no state, no drift.
*/
export interface SidebarBadges {
pendingApprovals: number;
activeRuns: number;
failedRuns: number;
todoTasks: number;
budgetWarnings: number;
unreadMessages: number;
}
const FAILED_RUN_STATUSES: ReadonlyArray<string> = ["failed", "timed_out", "interrupted"];
const ACTIVE_RUN_STATUSES: ReadonlyArray<string> = ["queued", "running"];
const OPEN_TASK_STATUSES: ReadonlyArray<string> = ["todo", "in_progress", "in_review"];
const BUDGET_WARNING_RATIO = 0.8;
/**
* Derive the sidebar badge counts for the current snapshot. Call this
* from the renderer whenever the snapshot changes; it is cheap
* (O(n) linear filters over arrays that never exceed the snapshot's
* per-company caps).
*
* `snapshot.agentMessages[i].readAt` already reflects the board
* reader's read timestamp (the snapshot query joins
* `agent_message_reads` with `agent_id = BOARD_READER_ID` and projects
* that value into the `readAt` field — see
* `src/main/database/snapshot.ts`). So the unread filter here is just
* "no board read receipt" plus the same channel/priority scope the
* old server query used.
*/
export function deriveSidebarBadges(snapshot: ProfileSnapshot, companyId: string | null): SidebarBadges {
// The snapshot query is already company-scoped when `currentCompanyId`
// is non-null (see `listRendererSnapshot` → `listSnapshot`). The extra
// `companyId` filter here is defensive: on the rare path where the
// caller passes an un-scoped snapshot (e.g., cross-company testing),
// we still count the right company's rows rather than the union.
const matchesCompany = <T extends { companyId: string }>(row: T): boolean =>
companyId === null || row.companyId === companyId;
let pendingApprovals = 0;
for (const approval of snapshot.approvals) {
if (matchesCompany(approval) && approval.state === "pending") pendingApprovals += 1;
}
let activeRuns = 0;
let failedRuns = 0;
for (const run of snapshot.runs) {
if (!matchesCompany(run)) continue;
if (ACTIVE_RUN_STATUSES.includes(run.status)) activeRuns += 1;
else if (FAILED_RUN_STATUSES.includes(run.status)) failedRuns += 1;
}
let todoTasks = 0;
for (const task of snapshot.tasks) {
if (matchesCompany(task) && OPEN_TASK_STATUSES.includes(task.status)) todoTasks += 1;
}
let budgetWarnings = 0;
for (const agent of snapshot.agents) {
if (!matchesCompany(agent)) continue;
if (agent.budgetMonthlyUsd > 0 && agent.spentMonthlyUsd / agent.budgetMonthlyUsd >= BUDGET_WARNING_RATIO) {
budgetWarnings += 1;
}
}
let unreadMessages = 0;
for (const message of snapshot.agentMessages) {
if (!matchesCompany(message)) continue;
if (message.readAt) continue;
if (
message.channel === "company" ||
message.channel === "incident" ||
message.priority === "urgent"
) {
unreadMessages += 1;
}
}
return {
pendingApprovals,
activeRuns,
failedRuns,
todoTasks,
budgetWarnings,
unreadMessages,
};
}
+153
View File
@@ -0,0 +1,153 @@
import type { AuditReplayRunRecord } from "./audit-domain";
import type { BoardInterventionRecord as BoardInterventionRecordModel } from "./board-domain";
import type {
ChatAttachmentRecord,
ChatMembershipRecord,
ChatMentionRecord,
ChatMessageRecord,
ChatPresenceRecord,
ChatReadStateRecord,
ChatSlashInvocationRecord,
ChatSpaceRecord,
ChatThreadRecord,
} from "./chat-domain";
import type { ComplianceExportRecord, LegalHoldRecord, RetentionFreezeRecord } from "./compliance-domain";
import type {
AgentRecord,
ApprovalRecord,
AuditEventRecord,
AutomationRuleRecord,
ConnectorAccountRecord,
ConnectorGrantRecord,
DocumentRecord,
EmployeeRecord,
FileAccessGrantRecord,
FileHandoffRecord,
FileObjectRecord,
GoalRecord,
KnowledgeEntryRecord,
MeetingRecord,
MigrationReportRecord,
OrganizationRecord,
PolicyRuleRecord,
ProjectRecord,
ProviderCatalogEntry,
ProviderRecord,
ScheduledPostRecord,
SkillBindingRecord,
SkillDefinitionRecord,
SkillRevisionRecord,
SkillRuntimeSnapshotRecord,
SkillTestRecord,
SprintRecord,
TaskRecord,
TaskRunRecord,
WorkspaceRecord,
} from "./domain";
import type { AccessDecisionRecord, EmployeeIdentityRecord, RoleGrantRecord, ServiceIdentityRecord } from "./identity-domain";
import type { ApprovalAssignmentRecord, ApprovalRoutingRuleRecord, HiringPolicyRecord, OrgDepartmentRecord } from "./org-governance-domain";
import type { ChaosDrillRecord, ChaosDrillRunRecord, FeatureFlagRecord, OperationalEventRecord, SloTargetRecord } from "./operations-domain";
import type { ProviderAuthProfileRecord, ProviderAuthSessionRecord } from "./provider-auth-domain";
import type { ProviderRequestRecord } from "./provider-request-domain";
import type { ProviderRateLimitObservationRecord, ProviderRateLimitStateRecord } from "./provider-runtime-domain";
import type { MigrationCutoverEventRecord, MigrationReconciliationItemRecord, RollbackSnapshotRecord } from "./rollback-domain";
import type { EvalCaseRecord, EvalRunRecord, EvalSuiteRecord, PrBotGateRecord, SdlcReviewAgentRecord, SdlcReviewRunRecord } from "./sdlc-domain";
import type {
BrowserActionPolicyRecord,
BrowserActionRecord,
BrowserSessionContainerRecord,
SocialAccountGrantRecord,
SocialAccountRecord,
SocialApprovalRouteRecord,
SocialAuditRecord,
} from "./social-domain";
export interface AppSnapshot {
activeOrgId: string | null;
organizations: OrganizationRecord[];
employees: EmployeeRecord[];
agents: AgentRecord[];
tasks: TaskRecord[];
workspaces: WorkspaceRecord[];
goals: GoalRecord[];
projects: ProjectRecord[];
taskRuns: TaskRunRecord[];
approvals: ApprovalRecord[];
chatSpaces: ChatSpaceRecord[];
chatMemberships: ChatMembershipRecord[];
chatMessages: ChatMessageRecord[];
chatThreads: ChatThreadRecord[];
chatAttachments: ChatAttachmentRecord[];
chatMentions: ChatMentionRecord[];
chatSlashInvocations: ChatSlashInvocationRecord[];
boardInterventions: BoardInterventionRecordModel[];
chatPresence: ChatPresenceRecord[];
chatReadStates: ChatReadStateRecord[];
files: FileObjectRecord[];
fileAccessGrants: FileAccessGrantRecord[];
fileHandoffRecords: FileHandoffRecord[];
scheduledPosts: ScheduledPostRecord[];
providers: ProviderRecord[];
providerAuthProfiles: ProviderAuthProfileRecord[];
providerAuthSessions: ProviderAuthSessionRecord[];
providerCatalog: ProviderCatalogEntry[];
providerRequests: ProviderRequestRecord[];
providerRateLimits: ProviderRateLimitStateRecord[];
providerRateLimitObservations: ProviderRateLimitObservationRecord[];
skillDefinitions: SkillDefinitionRecord[];
skillRevisions: SkillRevisionRecord[];
skillBindings: SkillBindingRecord[];
skillRuntimeSnapshots: SkillRuntimeSnapshotRecord[];
skillTests: SkillTestRecord[];
socialAccounts: SocialAccountRecord[];
socialAccountGrants: SocialAccountGrantRecord[];
browserSessionContainers: BrowserSessionContainerRecord[];
browserActionPolicies: BrowserActionPolicyRecord[];
socialApprovalRoutes: SocialApprovalRouteRecord[];
browserActions: BrowserActionRecord[];
socialAuditRecords: SocialAuditRecord[];
policyRules: PolicyRuleRecord[];
migrationReports: MigrationReportRecord[];
rollbackSnapshots: RollbackSnapshotRecord[];
migrationCutoverEvents: MigrationCutoverEventRecord[];
migrationReconciliationItems: MigrationReconciliationItemRecord[];
complianceExports: ComplianceExportRecord[];
legalHolds: LegalHoldRecord[];
retentionFreezes: RetentionFreezeRecord[];
employeeIdentities: EmployeeIdentityRecord[];
serviceIdentities: ServiceIdentityRecord[];
roleGrants: RoleGrantRecord[];
accessDecisions: AccessDecisionRecord[];
orgDepartments: OrgDepartmentRecord[];
hiringPolicies: HiringPolicyRecord[];
approvalRoutingRules: ApprovalRoutingRuleRecord[];
approvalAssignments: ApprovalAssignmentRecord[];
featureFlags: FeatureFlagRecord[];
sloTargets: SloTargetRecord[];
operationalEvents: OperationalEventRecord[];
chaosDrills: ChaosDrillRecord[];
chaosDrillRuns: ChaosDrillRunRecord[];
sdlcReviewAgents: SdlcReviewAgentRecord[];
sdlcReviewRuns: SdlcReviewRunRecord[];
evalSuites: EvalSuiteRecord[];
evalCases: EvalCaseRecord[];
evalRuns: EvalRunRecord[];
prBotGates: PrBotGateRecord[];
auditReplayRuns: AuditReplayRunRecord[];
auditEvents: AuditEventRecord[];
documents: DocumentRecord[];
knowledgeEntries: KnowledgeEntryRecord[];
automationRules: AutomationRuleRecord[];
meetings: MeetingRecord[];
sprints: SprintRecord[];
composioSettings: ComposioSettingRecord[];
connectorAccounts: ConnectorAccountRecord[];
connectorGrants: ConnectorGrantRecord[];
}
export interface ComposioSettingRecord {
orgId: string;
key: string;
value: string;
updatedAt: string;
}
+84
View File
@@ -0,0 +1,84 @@
import type { SocialPlatform } from "./domain";
export interface SocialAccountRecord {
id: string;
orgId: string;
platform: SocialPlatform;
handle: string;
displayName: string;
authorizedEmployeeId: string | null;
createdAt: string;
}
export interface SocialAccountGrantRecord {
id: string;
orgId: string;
socialAccountId: string;
employeeId: string;
role: string;
scopeJson: string;
createdAt: string;
}
export interface BrowserSessionContainerRecord {
id: string;
orgId: string;
socialAccountId: string;
platform: SocialPlatform;
partitionKey: string;
hostAllowlistJson: string;
permissionPolicy: string;
sandboxEnabled: boolean;
createdAt: string;
lastUsedAt: string | null;
}
export interface BrowserActionPolicyRecord {
id: string;
orgId: string;
socialAccountId: string;
actionType: string;
contentCategory: string;
riskLevel: string;
approvalRequired: boolean;
approvalKind: string | null;
createdAt: string;
}
export interface SocialApprovalRouteRecord {
id: string;
orgId: string;
socialAccountId: string;
actionType: string;
riskLevel: string;
approvalKind: string;
routeToType: string;
routeToId: string | null;
createdAt: string;
}
export interface BrowserActionRecord {
id: string;
orgId: string;
socialAccountId: string;
actionType: string;
policyDecision: string;
evidenceFileId: string | null;
metadataJson: string;
createdAt: string;
}
export interface SocialAuditRecord {
id: string;
orgId: string;
socialAccountId: string | null;
sourceType: string;
sourceId: string | null;
eventType: string;
actorType: string;
actorId: string | null;
policyDecision: string;
evidenceFileId: string | null;
metadataJson: string;
createdAt: string;
}
-4
View File
@@ -1,4 +0,0 @@
export * from "./types/enums";
export * from "./types/records";
export * from "./types/events";
export * from "./types/snapshot";
-300
View File
@@ -1,300 +0,0 @@
import { z } from "zod";
export type SectionId =
| "overview"
| "inbox"
| "standup"
| "performance"
| "runs"
| "connectors"
| "agents"
| "hiring"
| "goals"
| "projects"
| "tasks"
| "approvals"
| "costs"
| "activity"
| "workspaces"
| "social"
| "skills"
| "automation"
| "communication"
| "documents"
| "knowledge"
| "meetings"
| "sprints"
| "settings";
/**
* Pure pi-mono connector catalog ids. Five OAuth, eighteen API-key, three
* cloud — see `src/main/connector-definitions.ts`. The id is what the UI, the
* database `connectors` table, and the worker resolver all key on.
*
* Single source of truth: derived from the `connectorIdEnum` zod enum in
* `contracts/schemas-company.ts`. Adding a connector requires editing the zod
* enum only; the TS union updates automatically.
*/
export type { ConnectorId } from "../contracts/schemas-company";
export type ConnectorStatus =
| "not_installed"
| "detected"
| "auth_required"
| "ready"
| "degraded"
| "error";
export type TaskType = "code" | "research" | "content" | "management" | "general";
export type WorkspaceState = "ready" | "busy" | "blocked" | "missing" | "error";
export type CompanyStatus = "active" | "paused" | "archived";
export type ExecutionMode = "ai_ceo" | "ai_cofounder";
export type AgentStatus =
| "idle"
| "active"
| "running"
| "paused"
| "error"
| "pending_approval"
| "terminated";
/**
* Hierarchical role seniority. Used by prompt generation, skill auto-assign,
* and other "am I a manager?" decisions to avoid substring-matching English
* role strings like "chief" / "vp" / "manager". `role` remains a free-text
* field that users can edit in the UI.
*/
export type AgentRoleLevel = "ic" | "lead" | "manager" | "director" | "vp" | "c_suite";
export const AGENT_ROLE_LEVELS: readonly AgentRoleLevel[] = [
"ic", "lead", "manager", "director", "vp", "c_suite",
] as const;
/** Levels that grant leadership-style prompts and cross-team visibility. */
export const LEADERSHIP_LEVELS: readonly AgentRoleLevel[] = [
"lead", "manager", "director", "vp", "c_suite",
] as const;
export function isLeadershipLevel(level: AgentRoleLevel | null | undefined): boolean {
return level != null && level !== "ic";
}
/**
* Three-dimensional capability axes used by the model dispatcher. We compress
* the marketing five ("architecture / coding / writing / math / research")
* into three because the first, fourth and fifth collapse into a single
* reasoning axis empirically — a model that can design an RFC, do the math,
* and read a paper is the same model. Writing and coding stay separate
* because the rankings between top providers diverge there.
*/
export type TaskDomain = "reasoning" | "coding" | "writing";
/**
* Difficulty tier. Agents whose work is routine tagging, formatting, or
* summarization are `trivial` and should burn the cheapest model that
* clears the domain threshold. `hard` is for architecture/audit/research —
* send the strongest model the user has enabled.
*/
export type TaskTier = "trivial" | "standard" | "hard";
/**
* Run-time model routing for an agent.
* - `explicit`: use the agent.connectorId + agent.model pair the user
* saved. This was the pre-v39 behavior; existing rows stay
* here on migration so nothing silently re-routes.
* - `auto`: ignore agent.connectorId/model; the dispatcher picks the
* cheapest enabled model that clears the agent's inferred
* task profile. Default for newly created agents.
*/
export type AgentModelStrategy = "explicit" | "auto";
export type GoalStatus = "planned" | "active" | "achieved" | "cancelled";
export type ProjectStatus = "backlog" | "planned" | "in_progress" | "completed" | "cancelled";
export type TaskStatus = "backlog" | "todo" | "in_progress" | "in_review" | "done" | "blocked" | "cancelled";
export type ApprovalState = "pending" | "approved" | "rejected" | "revision_requested";
export const approvalTypeEnum = z.enum([
"hire_agent",
"approve_ceo_strategy",
"dangerous_command",
"secret_access",
"budget_request",
"promotion",
"termination",
"vendor_approval",
"document_review",
"production_deploy",
"incident_escalation",
"social_post",
"deliverable_review",
"budget_override",
"plan_review",
"scope_review",
"draft_review",
"strategy_review",
"exception_review",
]);
export type ApprovalType = z.infer<typeof approvalTypeEnum>;
export type RunStatus =
| "queued"
| "running"
| "succeeded"
| "failed"
| "cancelled"
| "timed_out"
| "interrupted";
export const RUN_USAGE_STATUSES = [
"ok",
"pre_first_message",
"error_stop",
"aborted_before_usage",
] as const;
export type RunUsageStatus = (typeof RUN_USAGE_STATUSES)[number];
export type DepartmentId =
| "executive"
| "engineering"
| "product"
| "marketing"
| "sales"
| "hr"
| "finance"
| "legal"
| "operations"
| "customer_support"
| "research"
| "design";
export type SkillSourceType = "github" | "local_path" | "url" | "skills_sh" | "managed";
export type TrustLevel = "markdown_only" | "assets" | "scripts_executables";
export type SocialPlatform =
| "twitter"
| "linkedin"
| "instagram"
| "facebook"
| "reddit"
| "youtube"
| "tiktok"
| "bluesky"
| "discord"
| "threads"
| "pinterest"
| "telegram"
| "whatsapp"
| "wechat"
| "weibo"
| "xiaohongshu"
| "douyin"
| "bilibili"
| "zhihu"
| "other";
export type SocialAccountStatus = "active" | "logged_in" | "login_required" | "suspended" | "paused";
export type BrowserActionType = "post" | "reply" | "like" | "follow" | "browse_feed" | "screenshot" | "navigate" | "search";
export type BrowserActionStatus = "queued" | "running" | "succeeded" | "failed" | "cancelled" | "approval_required";
export type MeetingType =
| "standup"
| "sprint_planning"
| "sprint_review"
| "retrospective"
| "one_on_one"
| "all_hands"
| "department_sync"
| "incident_review"
| "hiring_committee"
| "budget_review"
| "design_review"
| "architecture_review";
export type MeetingStatus = "scheduled" | "in_progress" | "completed" | "cancelled";
export type DocumentType =
| "prd"
| "technical_spec"
| "design_doc"
| "test_plan"
| "post_mortem"
| "meeting_notes"
| "budget_proposal"
| "hiring_requisition"
| "performance_review_doc"
| "sop"
| "knowledge_article"
| "project_brief"
| "sprint_report"
| "incident_report"
| "onboarding_guide"
| "architecture_decision"
| "status_report"
| "contract"
| "proposal";
export type DocumentStatus = "draft" | "in_review" | "approved" | "archived" | "superseded";
export type {
WorkProductType,
WorkProductProvider,
WorkProductStatus,
WorkProductReviewState,
} from "../contracts/schemas-work-products";
export type KnowledgeCategory =
| "lesson_learned"
| "best_practice"
| "decision"
| "process"
| "technical"
| "business"
| "onboarding"
| "incident";
export type SprintStatus = "planning" | "active" | "review" | "completed" | "cancelled";
/**
* Single source of truth: `automationTriggerEnum` in `contracts/helpers.ts`.
* Shared by `automationRuleInputSchema` and `workflowInputSchema`.
*/
export type { AutomationTrigger } from "../contracts/helpers";
export type AutomationAction =
| "assign_task"
| "create_task"
| "notify_agent"
| "send_message"
| "trigger_heartbeat"
| "create_approval"
| "update_task_status"
| "escalate_to_manager"
| "cross_department_notify"
| "schedule_meeting"
| "create_document"
| "auto_approve"
| "reassign_task"
| "run_task";
export type AutomationStatus = "active" | "paused" | "disabled" | "error";
export type MessageChannel = "direct" | "department" | "company" | "project" | "incident";
export type MessagePriority = "urgent" | "normal" | "low";
export type WorkflowStatus = "draft" | "active" | "paused" | "completed" | "failed";
export type InboxItemType = "pending_approval" | "failed_run" | "budget_warning" | "blocked_task" | "review_needed" | "agent_message";
export type ThreadType = "task" | "approval" | "general" | "announcement";
export type ThreadEventType =
| "message"
| "status_change"
| "approval_request"
| "approval_decision"
| "file_attachment"
| "system_note";
export type ThreadActorType = "agent" | "user" | "system";
export type ThreadParticipantRole = "owner" | "member" | "observer";
export type ThreadWaitingFor = "user_review" | "user_approval" | "user_reply";
export type ThreadNotifyOn = "all" | "mentions" | "none";
-191
View File
@@ -1,191 +0,0 @@
import type { RunStatus, SectionId, AutomationTrigger, AutomationAction } from "./enums";
import type { CommentRecord } from "./records-core";
import type { AgentMessageRecord } from "./records-extended";
export interface LogChunkEvent {
type: "run-log";
runId: string;
stream: "stdout" | "stderr";
chunk: string;
}
export interface DomainChangedEvent {
type: "domain-changed";
}
export interface ShortcutEvent {
type: "shortcut";
action: "toggle-command-palette" | "refresh";
}
export interface RunStatusEvent {
type: "run-status";
runId: string;
status: RunStatus;
message: string;
}
export interface HeartbeatStatusEvent {
type: "heartbeat-status";
agentId: string;
enabled: boolean;
nextWakeAt: string | null;
}
export interface AgentMessageEvent {
type: "agent-message";
taskId: string;
comment: CommentRecord;
}
export interface AutomationFiredEvent {
type: "automation-fired";
ruleId: string;
ruleName: string;
trigger: AutomationTrigger;
action: AutomationAction;
}
export interface NewMessageEvent {
type: "new-message";
message: AgentMessageRecord;
}
export interface NotificationClickEvent {
type: "notification-click";
section: SectionId;
entityId?: string;
}
export interface TaskUpdatedEvent {
type: "task-updated";
taskId: string;
action: "created" | "updated" | "deleted";
}
export interface RunUpdatedEvent {
type: "run-updated";
runId: string;
action: "created" | "status_changed" | "completed";
}
export interface ApprovalUpdatedEvent {
type: "approval-updated";
approvalId: string;
action: "created" | "decided" | "deleted";
}
export interface AgentUpdatedEvent {
type: "agent-updated";
agentId: string;
action: "updated" | "paused";
}
export interface BudgetChangedEvent {
type: "budget-changed";
companyId: string;
}
export interface ThreadWaitStateUpdatedEvent {
type: "thread-wait-state-updated";
threadId: string;
companyId: string;
waitStateId: string;
action: "created" | "resolved";
}
export interface RecoveryNeededEvent {
type: "recovery-needed";
interruptedRuns: Array<{
runId: string; taskId: string; taskTitle: string; agentId: string;
agentName: string; companyId: string; connectorId: string; interruptedAt: string;
}>;
}
// ─── pi-mono credentials / OAuth events ────────────────────────────────────
export type OAuthStatusValue =
| "pending"
| "in_progress"
| "active"
| "error"
| "cancelled"
| "completed";
export interface OAuthStatusEvent {
type: "oauth:status";
connectorId: string;
status: OAuthStatusValue;
message?: string;
errorMessage?: string;
}
export interface OAuthAuthUrlEvent {
type: "oauth:auth-url";
connectorId: string;
url: string;
instructions?: string;
}
export interface OAuthProgressEvent {
type: "oauth:progress";
connectorId: string;
message: string;
}
export interface OAuthPromptRequestEvent {
type: "oauth:prompt-request";
connectorId: string;
requestId: string;
message: string;
placeholder?: string;
allowEmpty?: boolean;
}
export interface OAuthManualCodeRequestEvent {
type: "oauth:manual-code-request";
connectorId: string;
requestId: string;
authUrl?: string;
instructions?: string;
}
export interface CredentialsChangedEvent {
type: "credentials-changed";
connectorId?: string;
}
export interface AgentEvent {
type: "agent-event";
runId: string;
agentId: string;
companyId: string;
taskId: string | null;
emittedAt: string;
event: { type: string } & Record<string, unknown>;
}
export type DesktopEvent =
| LogChunkEvent
| DomainChangedEvent
| ShortcutEvent
| RunStatusEvent
| HeartbeatStatusEvent
| AgentMessageEvent
| AutomationFiredEvent
| NewMessageEvent
| NotificationClickEvent
| TaskUpdatedEvent
| RunUpdatedEvent
| ApprovalUpdatedEvent
| AgentUpdatedEvent
| BudgetChangedEvent
| ThreadWaitStateUpdatedEvent
| RecoveryNeededEvent
| OAuthStatusEvent
| OAuthAuthUrlEvent
| OAuthProgressEvent
| OAuthPromptRequestEvent
| OAuthManualCodeRequestEvent
| CredentialsChangedEvent
| AgentEvent;
-397
View File
@@ -1,397 +0,0 @@
import type {
ConnectorId,
ConnectorStatus,
CompanyStatus,
ExecutionMode,
WorkspaceState,
DepartmentId,
AgentStatus,
AgentRoleLevel,
AgentModelStrategy,
GoalStatus,
ProjectStatus,
TaskStatus,
ApprovalState,
ApprovalType,
RunStatus,
RunUsageStatus,
SkillSourceType,
TrustLevel,
} from "./enums";
export interface CapabilityMatrix {
sessionResume: boolean;
gracefulCancel: boolean;
modelDiscovery: boolean;
structuredTranscript: boolean;
costAttribution: boolean;
}
export interface CompanyRecord {
id: string;
name: string;
description: string;
status: CompanyStatus;
autoApproveHires: boolean;
reviewDeliverables: boolean;
executionMode: ExecutionMode;
createdAt: string;
updatedAt: string;
}
export interface ConnectorRecord {
id: ConnectorId;
label: string;
description: string;
status: ConnectorStatus;
version: string | null;
authState: "unknown" | "ok" | "required" | "error";
lastCheckedAt: string | null;
lastError: string | null;
model: string | null;
envBindingText: string;
notes: string;
configurationDoc: string;
capabilityMatrix: CapabilityMatrix;
}
export interface WorkspaceRecord {
id: string;
companyId: string;
name: string;
localPath: string;
repoUrl: string;
repoRef: string;
projectId: string | null;
state: WorkspaceState;
isPrimary: boolean;
createdAt: string;
updatedAt: string;
}
export interface AgentRecord {
id: string;
companyId: string;
name: string;
role: string;
title: string;
/**
* Seniority enum used for leadership detection; free-text `role` remains
* UI-editable. Optional on the read model because the DB column has a
* `DEFAULT 'ic'` and no write path (agent-form / saveAgent / hireRequest)
* currently accepts it. Consumers use `agentIsLeader()` which handles the
* null/undefined case via keyword fallback.
*/
roleLevel?: AgentRoleLevel | null;
department: DepartmentId | null;
status: AgentStatus;
reportsTo: string | null;
connectorId: ConnectorId;
workspaceId: string | null;
model: string | null;
/**
* Model routing strategy (v39+). See AgentModelStrategy in enums.ts.
* Optional on the read model because the DB column has a schema-level
* default of 'explicit' for existing rows and legacy AgentRecord literals
* in tests predate this field.
*/
modelStrategy?: AgentModelStrategy | null;
capabilities: string;
budgetMonthlyUsd: number;
spentMonthlyUsd: number;
metadataJson: string;
heartbeatEnabled: boolean;
heartbeatIntervalSec: number;
lastHeartbeatAt: string | null;
/**
* Agent-scoped active session id. One active session per agent (per
* company) — switching tasks appends a "now work on X" user turn to the
* agent's ongoing transcript rather than starting a fresh session.
* Optional on the read model for the same reason `roleLevel` is: existing
* callers constructing an AgentRecord literally (tests, fixtures) do not
* need to set it, and pre-migration rows legitimately have NULL.
*/
sessionId?: string | null;
createdAt: string;
updatedAt: string;
}
export interface GoalRecord {
id: string;
companyId: string;
title: string;
description: string;
parentId: string | null;
ownerAgentId: string | null;
status: GoalStatus;
createdAt: string;
updatedAt: string;
}
export interface ProjectRecord {
id: string;
companyId: string;
goalId: string | null;
name: string;
description: string;
leadAgentId: string | null;
status: ProjectStatus;
targetDate: string | null;
createdAt: string;
updatedAt: string;
}
export interface TaskRecord {
id: string;
companyId: string;
projectId: string | null;
goalId: string | null;
parentId: string | null;
title: string;
description: string;
assigneeAgentId: string | null;
workspaceId: string | null;
status: TaskStatus;
priority: "critical" | "high" | "medium" | "low";
activeRunId: string | null;
costUsd: number;
taskType: string | null;
requiresUserReview: boolean;
/**
* Per-task filesystem lock policy (v52+). `true` makes the
* orchestrator resolve a workspace and hold it exclusively for
* the duration of the run. `false` lets a task with no explicit
* workspace binding execute with `lockMode='none'`.
*/
requiresFilesystem: boolean;
startedAt: string | null;
completedAt: string | null;
cancelledAt: string | null;
createdAt: string;
updatedAt: string;
}
export interface ApprovalRecord {
id: string;
companyId: string;
relatedTaskId: string | null;
relatedAgentId: string | null;
requestedByAgentId: string | null;
type: ApprovalType;
payloadSummary: string;
impactSummary: string;
payloadJson: string | null;
decisionNote: string;
state: ApprovalState;
createdAt: string;
updatedAt: string;
}
export interface RunRecord {
id: string;
companyId: string;
taskId: string | null;
agentId: string;
workspaceId: string | null;
connectorId: ConnectorId;
status: RunStatus;
summary: string;
errorMessage: string | null;
exitCode: number | null;
signal: string | null;
model: string | null;
costUsd: number | null;
unattributedCost: boolean;
usageStatus: RunUsageStatus;
startedAt: string | null;
finishedAt: string | null;
logPath: string | null;
createdAt: string;
updatedAt: string;
}
export interface RunLogChunk {
content: string;
offset: number;
nextOffset: number;
totalBytes: number;
eof: boolean;
}
export interface CostRecord {
id: string;
companyId: string;
runId: string;
taskId: string | null;
agentId: string | null;
connectorId: ConnectorId;
amountUsd: number | null;
unattributed: boolean;
createdAt: string;
}
export interface BudgetPolicyRecord {
id: string;
companyId: string;
scopeType: "company" | "agent" | "project";
scopeId: string;
metric: string;
windowKind: string;
amount: number; // INTEGER cents
warnPercent: number;
hardStopEnabled: boolean;
notifyEnabled: boolean;
isActive: boolean;
createdAt: string;
updatedAt: string;
}
export interface BudgetIncidentRecord {
id: string;
companyId: string;
policyId: string;
scopeType: string;
scopeId: string;
metric: string;
windowKind: string;
windowStart: string;
windowEnd: string;
thresholdType: "warn_threshold" | "hard_stop";
amountLimit: number;
amountObserved: number;
status: "open" | "resolved" | "auto_resolved_limit_increase" | "auto_closed";
resolvedAt: string | null;
createdAt: string;
updatedAt: string;
}
export interface BudgetStatusSummary {
policies: Array<{
policyId: string;
scopeType: string;
scopeId: string;
amount: number;
spent: number;
warnPercent: number;
hardStopEnabled: boolean;
hasOpenIncident: boolean;
}>;
}
export interface TaskSessionRecord {
id: string;
companyId: string;
agentId: string;
adapterType: string;
lastRunId: string | null;
lastError: string | null;
runCount: number;
totalInputTokens: number;
totalOutputTokens: number;
rotatedAt: string | null;
rotationReason: string | null;
handoffMarkdown: string | null;
createdAt: string;
updatedAt: string;
}
export interface ActivityRecord {
id: string;
companyId: string;
actor: string;
action: string;
entityType: string;
entityId: string;
detail: string;
createdAt: string;
}
export interface SecretRecord {
id: string;
companyId: string;
name: string;
description: string;
backend: "safe_storage" | "vault";
updatedAt: string;
}
export interface CommentRecord {
id: string;
companyId: string;
taskId: string;
authorAgentId: string | null;
authorName: string;
body: string;
createdAt: string;
}
export interface FileInventoryEntry {
path: string;
kind: "skill" | "reference" | "script" | "asset" | "markdown" | "other";
}
export interface SkillRecord {
id: string;
companyId: string;
key: string;
slug: string;
name: string;
description: string | null;
sourceType: SkillSourceType;
sourceLocator: string | null;
sourceRef: string | null;
trustLevel: TrustLevel;
compatibility: string;
fileInventory: FileInventoryEntry[];
metadata: Record<string, unknown> | null;
createdAt: string;
updatedAt: string;
}
export interface SkillImportResult {
skillId: string;
key: string;
name: string;
isUpdate: boolean;
}
export interface SkillUpdateStatus {
skillId: string;
key: string;
currentRef: string | null;
latestRef: string | null;
hasUpdate: boolean;
}
export type MentionOutcome = "woken" | "queued" | "busy" | "not_found";
export interface MentionResult {
agentId: string;
agentName: string;
outcome: MentionOutcome;
}
export interface SendMessageResult {
id: string;
mentionResults: MentionResult[];
}
/**
* Row in `model_capabilities`. Scores are 1..5 integer ratings per domain,
* tier is the hard lower bound the dispatcher clears before considering
* `costPerMtokOut` to pick the cheapest qualifying model.
*
* Composite primary key `(provider, modelId)` — the same modelId can
* legitimately ship under multiple providers (e.g. an Anthropic-compatible
* endpoint that serves Claude via a Fireworks proxy).
*/
export interface ModelCapability {
provider: string;
modelId: string;
reasoning: number;
coding: number;
writing: number;
tier: "trivial" | "standard" | "hard";
costPerMtokOut: number;
updatedAt: string;
}
-359
View File
@@ -1,359 +0,0 @@
import type { AgentStatus, RunStatus, InboxItemType } from "./enums";
import type {
SocialPlatform,
SocialAccountStatus,
BrowserActionType,
BrowserActionStatus,
MeetingType,
MeetingStatus,
DocumentType,
DocumentStatus,
KnowledgeCategory,
SprintStatus,
AutomationTrigger,
AutomationAction,
AutomationStatus,
MessageChannel,
MessagePriority,
WorkflowStatus,
ThreadType,
ThreadActorType,
ThreadEventType,
ThreadParticipantRole,
ThreadWaitingFor,
ThreadNotifyOn,
DepartmentId,
WorkProductType,
WorkProductProvider,
WorkProductStatus,
WorkProductReviewState,
} from "./enums";
export interface SocialAccountRecord {
id: string;
companyId: string;
platform: SocialPlatform;
accountName: string;
displayName: string;
profileUrl: string;
credentialSecretId: string | null;
status: SocialAccountStatus;
requireApproval: boolean;
metadataJson: string;
lastUsedAt: string | null;
createdAt: string;
updatedAt: string;
}
export interface BrowserActionRecord {
id: string;
companyId: string;
socialAccountId: string;
agentId: string;
taskId: string | null;
actionType: BrowserActionType;
payloadJson: string;
status: BrowserActionStatus;
resultSummary: string;
screenshotPath: string | null;
approvalId: string | null;
errorMessage: string | null;
startedAt: string | null;
finishedAt: string | null;
createdAt: string;
updatedAt: string;
}
export interface MeetingRecord {
id: string;
companyId: string;
type: MeetingType;
title: string;
organizerAgentId: string | null;
participantAgentIds: string; // JSON array of agent IDs
scheduledAt: string;
durationMinutes: number;
agendaJson: string;
notesJson: string;
decisionsJson: string;
actionItemsJson: string;
status: MeetingStatus;
createdAt: string;
updatedAt: string;
}
export interface DocumentRecord {
id: string;
companyId: string;
type: DocumentType;
title: string;
content: string;
authorAgentId: string | null;
reviewerAgentId: string | null;
projectId: string | null;
goalId: string | null;
parentDocId: string | null;
version: number;
status: DocumentStatus;
tagsJson: string;
latestRevisionId: string | null;
createdAt: string;
updatedAt: string;
}
export interface WorkProductRecord {
id: string;
companyId: string;
projectId: string | null;
taskId: string | null;
workspaceId: string | null;
type: WorkProductType;
provider: WorkProductProvider;
externalId: string | null;
title: string;
url: string | null;
status: WorkProductStatus;
reviewState: WorkProductReviewState;
isPrimary: boolean;
summary: string | null;
metadataJson: string | null;
createdByRunId: string | null;
lastTouchedByRunId: string | null;
createdAt: string;
updatedAt: string;
}
export interface KnowledgeEntryRecord {
id: string;
companyId: string;
category: KnowledgeCategory;
topic: string;
content: string;
authorAgentId: string | null;
importance: "critical" | "high" | "medium" | "low";
tagsJson: string;
referencedEntityType:
| "agents"
| "goals"
| "projects"
| "tasks"
| "approvals"
| "runs"
| "secrets"
| "meetings"
| "documents"
| "knowledge_base"
| "sprints"
| "automation_rules"
| "workflow_pipelines"
| null;
referencedEntityId: string | null;
createdAt: string;
updatedAt: string;
}
export interface SprintRecord {
id: string;
companyId: string;
name: string;
goal: string;
startDate: string;
endDate: string;
status: SprintStatus;
retrospectiveNotes: string;
velocityPoints: number;
completedPoints: number;
createdAt: string;
updatedAt: string;
}
export interface AutomationRuleRecord {
id: string;
companyId: string;
name: string;
description: string;
trigger: AutomationTrigger;
conditionsJson: string;
action: AutomationAction;
actionConfigJson: string;
sourceDepartment: DepartmentId | null;
targetDepartment: DepartmentId | null;
priority: number;
status: AutomationStatus;
executionCount: number;
lastExecutedAt: string | null;
createdAt: string;
updatedAt: string;
}
export interface AgentMessageRecord {
id: string;
companyId: string;
fromAgentId: string;
toAgentId: string | null;
senderKind: "agent" | "human" | "system";
channel: MessageChannel;
channelTargetId: string | null;
subject: string;
body: string;
priority: MessagePriority;
readAt: string | null;
parentMessageId: string | null;
attachmentsJson: string;
createdAt: string;
}
export interface WorkflowPipelineRecord {
id: string;
companyId: string;
name: string;
description: string;
stepsJson: string;
triggerType: AutomationTrigger;
triggerConfigJson: string;
status: WorkflowStatus;
currentStepIndex: number;
runCount: number;
lastRunAt: string | null;
createdAt: string;
updatedAt: string;
}
export interface WorkflowStep {
id: string;
name: string;
action: AutomationAction;
configJson: string;
assigneeDepartment: DepartmentId | null;
assigneeAgentId: string | null;
requiresApproval: boolean;
timeoutSec: number;
status: "pending" | "running" | "completed" | "failed" | "skipped";
}
export interface ConversationThreadRecord {
id: string;
companyId: string;
title: string;
type: ThreadType;
relatedEntityType: string | null;
relatedEntityId: string | null;
createdAt: string;
updatedAt: string;
}
export interface ConversationEventRecord {
id: string;
threadId: string;
actorId: string;
actorType: ThreadActorType;
eventType: ThreadEventType;
body: string;
metadataJson: string;
createdAt: string;
}
export interface ConversationParticipantRecord {
threadId: string;
participantId: string;
participantType: ThreadActorType;
role: ThreadParticipantRole;
joinedAt: string;
}
export interface ThreadSubscriptionRecord {
threadId: string;
subscriberId: string;
subscriberType: ThreadActorType;
notifyOn: ThreadNotifyOn;
subscribedAt: string;
}
export interface ThreadWaitStateRecord {
id: string;
threadId: string;
companyId: string;
waitingFor: ThreadWaitingFor;
relatedApprovalId: string | null;
reason: string;
createdAt: string;
resolvedAt: string | null;
}
export interface InboxItem {
id: string;
type: InboxItemType;
title: string;
subtitle: string;
severity: "critical" | "high" | "medium" | "low";
entityType: string;
entityId: string;
agentId: string | null;
agentName: string | null;
createdAt: string;
}
export interface AgentMetrics {
agentId: string;
agentName: string;
tasksCompleted: number;
tasksAssigned: number;
tasksFailed: number;
successRate: number;
avgRunDurationSec: number;
totalCostUsd: number;
runsTotal: number;
runsSucceeded: number;
runsFailed: number;
reviewCycles: number;
lastActiveAt: string | null;
}
export interface CompanyMetrics {
totalAgents: number;
activeAgents: number;
totalTasks: number;
completedTasks: number;
blockedTasks: number;
totalRuns: number;
successfulRuns: number;
failedRuns: number;
overallSuccessRate: number;
totalCostUsd: number;
avgCostPerTask: number;
throughputTasksPerDay: number;
agentMetrics: AgentMetrics[];
}
export interface OnboardingBootstrapResult {
companyId: string;
companyName: string;
workspaceId: string | null;
leadAgentId: string | null;
projectId: string | null;
taskId: string | null;
runId: string | null;
}
export interface StandupReport {
companyId: string;
generatedAt: string;
summary: string;
agentReports: Array<{
agentId: string;
agentName: string;
role: string;
status: AgentStatus;
tasksInProgress: number;
tasksCompleted24h: number;
tasksBlocked: number;
lastRunStatus: RunStatus | null;
lastRunAt: string | null;
costLast24h: number;
highlights: string[];
}>;
companyHighlights: string[];
blockers: string[];
pendingApprovals: number;
budgetUtilization: number;
}
-2
View File
@@ -1,2 +0,0 @@
export * from "./records-core";
export * from "./records-extended";
-101
View File
@@ -1,101 +0,0 @@
import type {
CompanyRecord,
ConnectorRecord,
WorkspaceRecord,
AgentRecord,
GoalRecord,
ProjectRecord,
TaskRecord,
ApprovalRecord,
RunRecord,
CostRecord,
ActivityRecord,
SecretRecord,
CommentRecord,
} from "./records-core";
import type {
SocialAccountRecord,
MeetingRecord,
DocumentRecord,
KnowledgeEntryRecord,
SprintRecord,
AutomationRuleRecord,
AgentMessageRecord,
WorkflowPipelineRecord,
WorkProductRecord,
} from "./records-extended";
export interface ProfileSnapshot {
// ─── Profile-level (shared across all companies) ─────────────────────────
currentCompanyId: string | null;
profilePath: string;
updatesEnabled: boolean;
theme: "system" | "light" | "dark";
locale: "en" | "zh";
backend: {
secretBackend: string;
};
companies: CompanyRecord[];
connectors: ConnectorRecord[];
// ─── Company-scoped collections (current company only) ───────────────────
workspaces: WorkspaceRecord[];
agents: AgentRecord[];
goals: GoalRecord[];
projects: ProjectRecord[];
tasks: TaskRecord[];
approvals: ApprovalRecord[];
runs: RunRecord[];
costs: CostRecord[];
activity: ActivityRecord[];
secrets: SecretRecord[];
comments: CommentRecord[];
socialAccounts: SocialAccountRecord[];
meetings: MeetingRecord[];
documents: DocumentRecord[];
workProducts: WorkProductRecord[];
knowledgeBase: KnowledgeEntryRecord[];
sprints: SprintRecord[];
automationRules: AutomationRuleRecord[];
agentMessages: AgentMessageRecord[];
workflows: WorkflowPipelineRecord[];
}
/** Fields that are shared across companies and loaded regardless of currentCompanyId. */
export const PROFILE_LEVEL_KEYS = [
"currentCompanyId",
"profilePath",
"updatesEnabled",
"theme",
"locale",
"backend",
"companies",
"connectors",
] as const satisfies ReadonlyArray<keyof ProfileSnapshot>;
/** Fields that are filtered to the current company; switching companies reloads these. */
export const COMPANY_SCOPED_KEYS = [
"workspaces",
"agents",
"goals",
"projects",
"tasks",
"approvals",
"runs",
"costs",
"activity",
"secrets",
"comments",
"socialAccounts",
"meetings",
"documents",
"workProducts",
"knowledgeBase",
"sprints",
"automationRules",
"agentMessages",
"workflows",
] as const satisfies ReadonlyArray<keyof ProfileSnapshot>;
export type ProfileLevelKey = typeof PROFILE_LEVEL_KEYS[number];
export type CompanyScopedKey = typeof COMPANY_SCOPED_KEYS[number];