/** * Pure UI-domain types — TS mirrors of the backend DTOs (camelCase wire format, * ARCHITECTURE §1.3). No React, no Tauri here: these are plain data shapes the * ports speak in, so view logic and gateways stay testable in isolation. */ /** Health report returned by the `health` gateway/command. */ export interface HealthReport { version: string; alive: boolean; timeMillis: number; correlationId: string; note: string | null; } /** A domain event relayed from the backend (tagged union on `type`). */ export type DomainEvent = | { type: "projectCreated"; projectId: string } | { type: "agentLaunched"; agentId: string; sessionId: string } | { type: "agentExited"; agentId: string; code: number } | { type: "agentProfileChanged"; agentId: string; profileId: string } | { type: "templateUpdated"; templateId: string; version: number } | { type: "agentDriftDetected"; agentId: string; from: number; to: number } | { type: "agentSynced"; agentId: string; to: number } | { type: "layoutChanged"; projectId: string } | { type: "remoteConnected"; projectId: string } | { type: "gitStateChanged"; projectId: string } | { type: "orchestratorRequestProcessed"; requesterId: string; action: string; ok: boolean; /** * Which entry door the delegation arrived through: `"mcp"` (MCP server) or * `"file"` (`.ideai/requests` watcher). Optional for backward-compatibility: * an event relayed without it simply yields no source badge. */ source?: "mcp" | "file"; } | { type: "ptyOutput"; sessionId: string; bytes: number[] }; /** Where a project physically lives (mirror of the backend `RemoteRef`). */ export type RemoteRef = | { kind: "local" } | { kind: "ssh"; host: string; port: number; user: string; auth: unknown; remoteRoot: string; } | { kind: "wsl"; distro: string }; /** A project as returned by the `project` gateway (mirror of `ProjectDto`). */ export interface Project { id: string; name: string; root: string; remote: RemoteRef; createdAt: number; } /** Stable error shape mirrored from the backend `ErrorDto`. */ export interface GatewayError { code: string; message: string; } // --------------------------------------------------------------------------- // Layout (L4) — mirror of the domain `LayoutTree` (ARCHITECTURE §3, §7). // --------------------------------------------------------------------------- /** Split direction: `row` = columns (left→right), `column` = rows (top→bottom). */ export type Direction = "row" | "column"; /** A terminal-hosting leaf cell. `session` is the hosted SessionId, if any. * `agent` is the agent id if an agent is pinned to this cell (absent = plain terminal). * `conversationId` is the persistent CLI conversation id (survives PTY close/reopen, * lets the agent resume); omitted when absent (mirrors the backend `skip_serializing_if`). * `agentWasRunning` records whether the cell's agent process was running at close time; * omitted when `false`. */ export interface LeafCell { id: string; session?: string | null; agent?: string; conversationId?: string; agentWasRunning?: boolean; } /** A weighted child of a split. `weight` is a relative (`> 0`) share. */ export interface WeightedChild { node: LayoutNode; weight: number; } /** A weighted n-ary split (rows or columns). */ export interface SplitContainer { id: string; direction: Direction; children: WeightedChild[]; } /** A spreadsheet grid cell placement with spans. */ export interface GridCell { node: LayoutNode; row: number; col: number; rowSpan: number; colSpan: number; } /** A spreadsheet-style grid with per-row/col weights and span-based merging. */ export interface GridContainer { id: string; colWeights: number[]; rowWeights: number[]; cells: GridCell[]; } /** * A node in the layout tree. Tagged on `type` with the payload under `node`, * matching the backend `#[serde(tag = "type", content = "node")]`. */ export type LayoutNode = | { type: "leaf"; node: LeafCell } | { type: "split"; node: SplitContainer } | { type: "grid"; node: GridContainer }; /** The root of a tab's terminal layout. */ export interface LayoutTree { root: LayoutNode; } /** * A layout mutation (mirror of the backend `LayoutOperationDto`, tagged on * `type`). Node/session ids are UUID strings. */ export type LayoutOperation = | { type: "split"; target: string; direction: Direction; newLeaf: string; container: string; } | { type: "merge"; container: string; keepIndex: number } | { type: "resize"; container: string; weights: number[] } | { type: "move"; from: string; to: string } | { type: "setSession"; target: string; session?: string | null } | { type: "setCellAgent"; target: string; agent: string | null } | { type: "setCellConversation"; target: string; conversationId: string | null } | { type: "setAgentRunning"; target: string; running: boolean }; /** The kind of a named layout. */ export type LayoutKind = "terminal" | "gitGraph"; /** Named layout entry returned by `listLayouts`. */ export interface LayoutInfo { id: string; name: string; kind: LayoutKind; } /** * A commit node in the full git graph (DAG). `refs` carries short branch/tag * names (e.g. `"main"`, `"tag: v1.0"`). `timestamp` is seconds since Unix epoch. */ export interface GraphCommit { hash: string; summary: string; parents: string[]; refs: string[]; author: string; timestamp: number; } /** Response of `listLayouts`. */ export interface LayoutList { layouts: LayoutInfo[]; activeId: string; } /** Unsubscribe handle returned by event subscriptions. */ export type Unsubscribe = () => void; // --------------------------------------------------------------------------- // AI profiles & first-run (L5) — mirror of the domain `AgentProfile` / // `ContextInjection` (CONTEXT §9, ARCHITECTURE §3). // --------------------------------------------------------------------------- /** * Context-injection strategy (tagged on `strategy`, mirror of the backend * `ContextInjection`): * - `conventionFile`: write the `.md` to a conventional file (e.g. `CLAUDE.md`), * - `flag`: pass the context path through a CLI flag, * - `stdin`: pipe the content on stdin, * - `env`: pass the context via an environment variable. */ export type ContextInjection = | { strategy: "conventionFile"; target: string } | { strategy: "flag"; flag: string } | { strategy: "stdin" } | { strategy: "env"; var: string }; /** The four injection strategy discriminants. */ export type InjectionStrategy = ContextInjection["strategy"]; /** * A declarative AI-CLI profile (mirror of the backend `AgentProfile`). `id` is a * UUID string; `detect` is the optional detection command line. */ export interface AgentProfile { id: string; name: string; command: string; args: string[]; contextInjection: ContextInjection; detect: string | null; cwdTemplate: string; /** Optional CLI flags for agent-session continuity: `assignFlag` to bind a * conversation id at launch, `resumeFlag` to resume an existing conversation. */ session?: { assignFlag?: string; resumeFlag: string }; } /** Availability of a candidate profile after detection (mirror of the DTO). */ export interface ProfileAvailability { profile: AgentProfile; available: boolean; } /** First-run state (mirror of `FirstRunStateDto`). */ export interface FirstRunState { isFirstRun: boolean; referenceProfiles: AgentProfile[]; } // --------------------------------------------------------------------------- // Agents (L6) — mirror of the domain `Agent` / `AgentOrigin` (ARCHITECTURE §6). // --------------------------------------------------------------------------- /** * Origin of an agent (tagged on `type`, mirror of the backend `AgentOrigin`): * - `scratch`: created from scratch, no template link, * - `fromTemplate`: derived from a template, tracking the last synced version. */ export type AgentOrigin = | { type: "scratch" } | { type: "fromTemplate"; templateId: string; syncedTemplateVersion: number }; /** * A project-scoped agent (mirror of the backend `Agent` DTO, camelCase wire * format). `contextPath` is the relative path of the agent's `.md` within * `.ideai/` (e.g. `agents/foo.md`). */ export interface Agent { id: string; name: string; contextPath: string; profileId: string; origin: AgentOrigin; synchronized: boolean; /** Skills assigned to this agent (injected into its convention file). */ skills: SkillRef[]; } /** * A terminal/PTY session as returned by the backend (mirror of * `TerminalSessionDto`, camelCase wire format). Surfaced by `changeAgentProfile` * as the freshly relaunched session when a live agent was hot-swapped. */ export interface TerminalSession { /** Stable session id (UUID) — used for write/resize/close + the output channel. */ sessionId: string; /** Working directory the shell runs in. */ cwd: string; /** Current rows. */ rows: number; /** Current cols. */ cols: number; /** * Conversation id assigned by this (re)launch, when the profile supports * session assignment and the hosting cell had none yet; absent otherwise. */ assignedConversationId?: string; /** * How the frontend should render the cell hosting this session (mirror of the * backend `TerminalSessionDto.cellKind`, ARCHITECTURE §17.6). `"chat"` ⇒ a * structured AI session driven by `agent_send`/`reattach_agent_chat` (rendered * as an `AgentChatView`); `"pty"` ⇒ a raw terminal (xterm). **Derived** * backend-side from the launch routing — a single source of truth. */ cellKind: CellKind; } /** * Whether a session's hosting cell renders as a structured chat view or a raw * terminal (mirror of the backend `CellKind`, ARCHITECTURE §17.6). The * `LayoutGrid` switches `AgentChatView` vs `TerminalView` on this value. */ export type CellKind = "pty" | "chat"; /** * One incremental event of an AI agent's reply turn (mirror of the backend * `ReplyChunk`, ARCHITECTURE §17.7). Tagged on `kind` (camelCase on the wire), * so the view branches without positional parsing: * * - `textDelta`: a text fragment of the current turn (accumulated live); * - `toolActivity`: a human-readable tool-activity badge (best-effort); * - `final`: the **deterministic** end-of-turn chunk carrying the aggregated * final content — after it the turn is frozen and the stream ends. */ export type ReplyChunk = | { kind: "textDelta"; text: string } | { kind: "toolActivity"; label: string } | { kind: "final"; content: string }; /** * The retained **conversation scrollback** of a still-live structured session * (mirror of the backend `ReattachChatDto`, ARCHITECTURE §17.7), returned by * `reattachChat`. The frontend replays `scrollback` to rebuild the visible turns * before subsequent chunks arrive over the freshly-registered channel. */ export interface ReattachChatDto { /** The session that was re-attached (echoed back). */ sessionId: string; /** The chunks already streamed for this conversation, in order. */ scrollback: ReplyChunk[]; } /** * An agent that can be resumed when its project is (re)opened (mirror of the * backend `ResumableAgentDto`, camelCase wire format; ARCHITECTURE §15.2). It is * a read-only inventory entry computed at open time — never a spawn: * - `nodeId` is the layout leaf hosting the agent (where to relaunch), * - `conversationId` is the persisted CLI conversation id; absent ⇒ relaunch fresh, * - `wasRunning` is `agentWasRunning` frozen at close time (drives the status label), * - `resumeSupported` reflects whether the agent's profile exposes a usable * session strategy; when `false`, "Reprendre" relaunches fresh ("relance à neuf"). */ export interface ResumableAgent { agentId: string; name: string; nodeId: string; conversationId?: string; wasRunning: boolean; resumeSupported: boolean; } // --------------------------------------------------------------------------- // Skills (L12) — mirror of the domain `Skill` / `SkillRef`. // --------------------------------------------------------------------------- /** * Where a skill lives (selects its backing store): `global` skills are reusable * across projects; `project` skills are specific to one project's `.ideai/`. */ export type SkillScope = "global" | "project"; /** * A reusable, model-agnostic workflow assignable to agents (mirror of the * backend `Skill` DTO, camelCase wire format). */ export interface Skill { id: string; name: string; contentMd: string; scope: SkillScope; } /** A reference from an agent to one assigned skill (mirror of `SkillRef`). */ export interface SkillRef { skillId: string; scope: SkillScope; } // --------------------------------------------------------------------------- // Memory (L14) — mirror of the backend `MemoryDto` / `MemoryIndexEntryDto`. // --------------------------------------------------------------------------- /** * The category of a memory note (selects how it is recalled/injected). Mirrors * the backend `type` field; identity of a note is its **slug** (kebab-case). */ export type MemoryType = "user" | "feedback" | "project" | "reference"; /** * A memory note (mirror of the backend `Memory` DTO, camelCase wire format). * `name` doubles as the human title and the source of the slug identity. */ export interface Memory { name: string; description: string; type: MemoryType; content: string; } /** * One entry of the memory index (mirror of the backend `MemoryIndexEntry`): * a lightweight, recall-oriented projection of a note. */ export interface MemoryIndexEntry { slug: string; title: string; hook: string; type: MemoryType; } /** A resolved `[[wikilink]]` target — the slug of another note. */ export type MemoryLink = string; // --------------------------------------------------------------------------- // Embedder (L14 / lot C2) — mirror of the backend `EmbedderProfileDto` and // `EmbedderEnginesDto`. Drives the memory/embedder settings panel. Identity of // a profile is its `id`; changing the active embedder takes effect at the next // app start (the UI says so explicitly). // --------------------------------------------------------------------------- /** * Embedding strategy of an embedder profile (mirror of the backend `strategy`). * `none` ⇒ no vector tier (naïve recall); the other strategies select where the * embeddings come from. */ export type EmbedderStrategy = "localOnnx" | "localServer" | "api" | "none"; /** * A declarative embedder profile (mirror of the backend `EmbedderProfile` DTO, * camelCase wire format). Transparent by design: secrets are never stored here — * `apiKeyEnv` is the *name* of an environment variable, never the key itself. */ export interface EmbedderProfile { id: string; name: string; strategy: EmbedderStrategy; /** Model id/name (ONNX model, server/api model). Omitted for `none`. */ model?: string; /** Server/API endpoint URL. Omitted for `localOnnx` / `none`. */ endpoint?: string; /** Name of the env var holding the API key (api strategy). Never the key. */ apiKeyEnv?: string; /** Embedding vector dimension. */ dimension: number; } /** * A recommended local ONNX engine (mirror of the backend `recommendedOnnx` * entry). `e5-small` is the curated default (`recommended: true`). */ export interface RecommendedOnnxEngine { id: string; displayName: string; dimension: number; approxSizeMb: number; recommended: boolean; } /** * Capabilities/availability snapshot of the embedder engines on this build * (mirror of the backend `describe_embedder_engines`). The `vector*Enabled` * flags reflect Cargo feature flags compiled into the build: a strategy whose * flag is `false` is shown disabled ("not available in this build"). */ export interface EmbedderEngines { recommendedOnnx: RecommendedOnnxEngine[]; ollamaDetected: boolean; onnxCachedModels: string[]; vectorHttpEnabled: boolean; vectorOnnxEnabled: boolean; } // --------------------------------------------------------------------------- // Templates (L7) — mirror of the domain `Template` / `AgentDrift`. // --------------------------------------------------------------------------- /** * A reusable agent template (mirror of the backend `Template` DTO). * `version` is incremented on each `updateTemplate` call. */ export interface Template { id: string; name: string; contentMd: string; version: number; defaultProfileId: string; } /** * Drift between a synchronized agent's last-synced template version and the * template's current version (mirror of `AgentDrift` backend DTO). */ export interface AgentDrift { agentId: string; from: number; to: number; } // --------------------------------------------------------------------------- // Git (L8) — UI-domain types for the git feature. // --------------------------------------------------------------------------- /** A file in the working tree with its staging state. */ export interface GitFileStatus { path: string; staged: boolean; } /** A git commit summary (short representation). */ export interface GitCommit { hash: string; summary: string; } /** The list of branches and the currently checked-out branch. */ export interface GitBranches { branches: string[]; current: string | null; }