Add v2 rewrite: monorepo with desktop and web apps, shared packages, docs, and wireframes
This commit is contained in:
313
packages/contracts/src/rpc.ts
Normal file
313
packages/contracts/src/rpc.ts
Normal file
@@ -0,0 +1,313 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const ScreenSchema = z.enum(["home", "workspace", "model", "memo", "agents"]);
|
||||
export type Screen = z.infer<typeof ScreenSchema>;
|
||||
|
||||
export const HoldingSchema = z.object({
|
||||
ticker: z.string(),
|
||||
name: z.string(),
|
||||
price: z.number(),
|
||||
changePct: z.number(),
|
||||
weight: z.number()
|
||||
});
|
||||
export type Holding = z.infer<typeof HoldingSchema>;
|
||||
|
||||
export const AgentSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
status: z.enum(["idle", "queued", "running", "completed", "paused", "failed"]),
|
||||
progress: z.number().min(0).max(100),
|
||||
action: z.string(),
|
||||
pipeline: z.enum(["research", "competitive", "cross-cutting"]).optional(),
|
||||
confidence: z.enum(["high", "medium", "low"]).optional()
|
||||
});
|
||||
export type Agent = z.infer<typeof AgentSchema>;
|
||||
|
||||
export const CompanySchema = z.object({
|
||||
id: z.string(),
|
||||
ticker: z.string(),
|
||||
name: z.string(),
|
||||
sector: z.string(),
|
||||
subIndustry: z.string().optional(),
|
||||
price: z.number(),
|
||||
changePct: z.number(),
|
||||
thesis: z.string(),
|
||||
founded: z.string().optional(),
|
||||
headquarters: z.string().optional(),
|
||||
employees: z.number().optional()
|
||||
});
|
||||
export type Company = z.infer<typeof CompanySchema>;
|
||||
|
||||
export const ModelRowSchema = z.object({
|
||||
label: z.string(),
|
||||
kind: z.enum(["actual", "forecast", "total"]),
|
||||
values: z.array(z.string())
|
||||
});
|
||||
export type ModelRow = z.infer<typeof ModelRowSchema>;
|
||||
|
||||
export const MemoSectionSchema = z.object({
|
||||
id: z.string(),
|
||||
title: z.string(),
|
||||
content: z.string(),
|
||||
updatedAt: z.string().optional(),
|
||||
primaryAgent: z.string().optional()
|
||||
});
|
||||
export type MemoSection = z.infer<typeof MemoSectionSchema>;
|
||||
|
||||
export const MemoCitationSchema = z.object({
|
||||
id: z.string(),
|
||||
label: z.string(),
|
||||
sectionId: z.string(),
|
||||
type: z.enum(["sec_filing", "earnings_transcript", "analyst_report", "model", "internal_note"]),
|
||||
title: z.string(),
|
||||
reference: z.string(),
|
||||
verificationStatus: z.enum(["verified", "unverified", "flagged"]),
|
||||
sourceUrl: z.string().optional()
|
||||
});
|
||||
export type MemoCitation = z.infer<typeof MemoCitationSchema>;
|
||||
|
||||
export const MemoAnnotationSchema = z.object({
|
||||
id: z.string(),
|
||||
sectionId: z.string(),
|
||||
kind: z.enum(["highlight", "comment", "strike"]),
|
||||
selectedText: z.string(),
|
||||
comment: z.string().optional(),
|
||||
createdBy: z.string(),
|
||||
createdAt: z.string(),
|
||||
status: z.enum(["open", "resolved"])
|
||||
});
|
||||
export type MemoAnnotation = z.infer<typeof MemoAnnotationSchema>;
|
||||
|
||||
export const MemoSectionReviewSchema = z.object({
|
||||
sectionId: z.string(),
|
||||
status: z.enum(["pending", "in_review", "approved", "changes_requested"]),
|
||||
updatedAt: z.string().optional()
|
||||
});
|
||||
export type MemoSectionReview = z.infer<typeof MemoSectionReviewSchema>;
|
||||
|
||||
export const CatalystSchema = z.object({
|
||||
id: z.string(),
|
||||
date: z.string(),
|
||||
event: z.string(),
|
||||
impact: z.enum(["high", "medium", "low"]),
|
||||
thesisRelevance: z.enum(["supports", "challenges", "neutral"]),
|
||||
source: z.string().optional()
|
||||
});
|
||||
export type Catalyst = z.infer<typeof CatalystSchema>;
|
||||
|
||||
export const AlertSchema = z.object({
|
||||
id: z.string(),
|
||||
companyId: z.string().optional(),
|
||||
timestamp: z.string(),
|
||||
type: z.enum(["filing", "price_move", "earnings_surprise", "peer_event"]),
|
||||
description: z.string(),
|
||||
thesisImpact: z.enum(["positive", "negative", "neutral"]),
|
||||
status: z.enum(["new", "reviewed"]),
|
||||
targetSection: z.string().optional()
|
||||
});
|
||||
export type Alert = z.infer<typeof AlertSchema>;
|
||||
|
||||
export const RiskSchema = z.object({
|
||||
id: z.string(),
|
||||
companyId: z.string(),
|
||||
risk: z.string(),
|
||||
category: z.enum(["business", "financial", "competitive", "regulatory", "esg"]),
|
||||
severity: z.enum(["high", "medium", "low"]),
|
||||
likelihood: z.enum(["high", "medium", "low"]),
|
||||
mitigation: z.string(),
|
||||
status: z.enum(["open", "mitigated", "accepted"])
|
||||
});
|
||||
export type Risk = z.infer<typeof RiskSchema>;
|
||||
|
||||
export const EarningsScheduleSchema = z.object({
|
||||
id: z.string(),
|
||||
companyId: z.string(),
|
||||
quarter: z.string(),
|
||||
expectedDate: z.string(),
|
||||
timing: z.enum(["bmo", "amc"]).optional(),
|
||||
actualRevenue: z.string().optional(),
|
||||
expectedRevenue: z.string().optional(),
|
||||
actualEps: z.string().optional(),
|
||||
expectedEps: z.string().optional()
|
||||
});
|
||||
export type EarningsSchedule = z.infer<typeof EarningsScheduleSchema>;
|
||||
|
||||
export const FilingSchema = z.object({
|
||||
id: z.string(),
|
||||
companyId: z.string(),
|
||||
formType: z.string(),
|
||||
filedDate: z.string(),
|
||||
title: z.string(),
|
||||
keyChanges: z.string().optional(),
|
||||
reviewed: z.boolean().optional()
|
||||
});
|
||||
export type Filing = z.infer<typeof FilingSchema>;
|
||||
|
||||
export const ExportRecordSchema = z.object({
|
||||
id: z.string(),
|
||||
type: z.enum(["pdf", "excel", "ppt"]),
|
||||
title: z.string(),
|
||||
companyId: z.string().optional(),
|
||||
format: z.string(),
|
||||
fileSize: z.string().optional(),
|
||||
status: z.enum(["processing", "complete", "failed"]),
|
||||
createdAt: z.string(),
|
||||
downloadUrl: z.string().optional()
|
||||
});
|
||||
export type ExportRecord = z.infer<typeof ExportRecordSchema>;
|
||||
|
||||
export const WorkspaceSectionSchema = z.object({
|
||||
id: z.string(),
|
||||
title: z.string(),
|
||||
content: z.string(),
|
||||
validationState: z.enum(["verified", "flagged", "unverified", "failed"]),
|
||||
sourceAgent: z.string().optional()
|
||||
});
|
||||
export type WorkspaceSection = z.infer<typeof WorkspaceSectionSchema>;
|
||||
|
||||
export const SnapshotSchema = z.object({
|
||||
id: z.string(),
|
||||
timestamp: z.string(),
|
||||
label: z.string().optional(),
|
||||
type: z.enum(["auto", "manual"]),
|
||||
changeCount: z.number()
|
||||
});
|
||||
export type Snapshot = z.infer<typeof SnapshotSchema>;
|
||||
|
||||
export type ClientSettings = {
|
||||
theme: "light" | "dark" | "system";
|
||||
density: "comfortable" | "compact" | "dense";
|
||||
sidebarWidth: number;
|
||||
navCollapsed: Record<string, boolean>;
|
||||
keybindings: Record<string, string>;
|
||||
};
|
||||
|
||||
export type ServerSettings = {
|
||||
agentConfigs: Record<string, unknown>;
|
||||
dataSources: Record<string, boolean>;
|
||||
exportPipelines: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export type RpcRequestMap = {
|
||||
"portfolio.get": undefined;
|
||||
"portfolio.addHolding": { ticker: string };
|
||||
"portfolio.removeHolding": { ticker: string };
|
||||
"company.get": { companyId: string };
|
||||
"company.search": { query: string };
|
||||
"company.setActive": { companyId: string };
|
||||
"workspace.getSection": { companyId: string; section: string };
|
||||
"workspace.listSources": { companyId: string };
|
||||
"catalyst.list": { companyId: string };
|
||||
"alert.list": { companyId?: string; since?: string };
|
||||
"risk.list": { companyId: string };
|
||||
"risk.add": { companyId: string; risk: Omit<Risk, "id" | "companyId"> };
|
||||
"earnings.getSchedule": { companyId: string };
|
||||
"filing.list": { companyId: string; since?: string };
|
||||
"model.get": { companyId: string; tab: string };
|
||||
"model.updateCell": { companyId: string; tab: string; row: number; col: number; value: string };
|
||||
"model.runScenario": { companyId: string; scenario: string; overrides: Record<string, string> };
|
||||
"memo.get": { companyId: string };
|
||||
"memo.updateSection": {
|
||||
companyId: string;
|
||||
sectionId: string;
|
||||
title?: string;
|
||||
content: string;
|
||||
};
|
||||
"memo.addAnnotation": {
|
||||
companyId: string;
|
||||
sectionId: string;
|
||||
kind: "highlight" | "comment" | "strike";
|
||||
selectedText: string;
|
||||
comment?: string;
|
||||
};
|
||||
"memo.resolveAnnotation": {
|
||||
companyId: string;
|
||||
annotationId: string;
|
||||
};
|
||||
"memo.updateSectionReview": {
|
||||
companyId: string;
|
||||
sectionId: string;
|
||||
status: "pending" | "in_review" | "approved" | "changes_requested";
|
||||
};
|
||||
"memo.acceptEdit": { companyId: string; editId: string };
|
||||
"memo.rejectEdit": { companyId: string; editId: string; reason?: string };
|
||||
"agent.list": { companyId?: string };
|
||||
"agent.start": { agentId: string; companyId: string };
|
||||
"agent.pause": { agentId: string };
|
||||
"agent.restart": { agentId: string };
|
||||
"agent.chat": { agentId: string; message: string };
|
||||
"agent.configure": { agentId: string; config: Record<string, unknown> };
|
||||
"agent.getTrace": { agentId: string; runId: string };
|
||||
"agent.runPipeline": { companyId: string; pipeline: string };
|
||||
"export.list": { companyId?: string };
|
||||
"export.create": { type: string; companyId: string; options?: Record<string, unknown> };
|
||||
"export.download": { exportId: string };
|
||||
"settings.get": { scope: "client" | "server" };
|
||||
"settings.update": { scope: "client" | "server"; changes: Record<string, unknown> };
|
||||
};
|
||||
|
||||
export type RpcResponseMap = {
|
||||
"portfolio.get": { id: string; name: string; holdings: Holding[]; activeCompanyId: string };
|
||||
"portfolio.addHolding": { holding: Holding };
|
||||
"portfolio.removeHolding": { ok: boolean };
|
||||
"company.get": { company: Company };
|
||||
"company.search": { results: Array<{ ticker: string; name: string; sector: string }> };
|
||||
"company.setActive": { ok: boolean };
|
||||
"workspace.getSection": { content: WorkspaceSection; validationState: string };
|
||||
"workspace.listSources": { sources: Array<{ type: string; title: string; metadata: string }> };
|
||||
"catalyst.list": { catalysts: Catalyst[] };
|
||||
"alert.list": { alerts: Alert[] };
|
||||
"risk.list": { risks: Risk[] };
|
||||
"risk.add": { risk: Risk };
|
||||
"earnings.getSchedule": { schedule: EarningsSchedule[] };
|
||||
"filing.list": { filings: Filing[] };
|
||||
"model.get": { headers: string[]; rows: ModelRow[] };
|
||||
"model.updateCell": { ok: boolean; affectedCells: string[] };
|
||||
"model.runScenario": { headers: string[]; rows: ModelRow[] };
|
||||
"memo.get": {
|
||||
status: "draft" | "review" | "final";
|
||||
sections: MemoSection[];
|
||||
citations: MemoCitation[];
|
||||
annotations: MemoAnnotation[];
|
||||
sectionReviews: MemoSectionReview[];
|
||||
};
|
||||
"memo.updateSection": {
|
||||
section: MemoSection;
|
||||
status: "draft" | "review" | "final";
|
||||
savedAt: string;
|
||||
};
|
||||
"memo.addAnnotation": { annotation: MemoAnnotation };
|
||||
"memo.resolveAnnotation": { annotation: MemoAnnotation };
|
||||
"memo.updateSectionReview": { review: MemoSectionReview };
|
||||
"memo.acceptEdit": { ok: boolean };
|
||||
"memo.rejectEdit": { ok: boolean };
|
||||
"agent.list": { agents: Agent[] };
|
||||
"agent.start": { runId: string };
|
||||
"agent.pause": { ok: boolean };
|
||||
"agent.restart": { runId: string };
|
||||
"agent.chat": { response: string };
|
||||
"agent.configure": { ok: boolean };
|
||||
"agent.getTrace": { steps: Array<{ step: number; label: string; detail: string }> };
|
||||
"agent.runPipeline": { runIds: string[] };
|
||||
"export.list": { exports: ExportRecord[] };
|
||||
"export.create": { exportId: string };
|
||||
"export.download": { data: ArrayBuffer };
|
||||
"settings.get": { settings: ClientSettings | ServerSettings };
|
||||
"settings.update": { ok: boolean };
|
||||
};
|
||||
|
||||
export type RpcMethod = keyof RpcRequestMap;
|
||||
|
||||
export type RpcError = {
|
||||
code: "NOT_FOUND" | "VALIDATION_ERROR" | "INTERNAL_ERROR" | "AGENT_FAILED" | "CONFLICT" | "RATE_LIMITED";
|
||||
message: string;
|
||||
detail?: unknown;
|
||||
};
|
||||
|
||||
export type RpcResult<T extends RpcMethod> =
|
||||
| { ok: true; data: RpcResponseMap[T] }
|
||||
| { ok: false; error: RpcError };
|
||||
|
||||
export type RpcClient = {
|
||||
call<T extends RpcMethod>(method: T, payload: RpcRequestMap[T]): Promise<RpcResult<T>>;
|
||||
};
|
||||
Reference in New Issue
Block a user