feat: add main features
Agents for developpement added + frontend add + backend added. Git viewer created + agent and template creator + layout and project creator
This commit is contained in:
256
frontend/src/ports/index.ts
Normal file
256
frontend/src/ports/index.ts
Normal file
@ -0,0 +1,256 @@
|
||||
/**
|
||||
* UI ports (gateways) — interfaces describing *what the UI needs*, independent
|
||||
* of transport (ARCHITECTURE §1.3). React components depend on these, never on
|
||||
* `@tauri-apps/api` directly. Implemented by the Tauri adapters and by mocks.
|
||||
*
|
||||
* Signatures are intentionally minimal/skeletal for L1; later lots flesh out
|
||||
* each gateway as their use cases land. They are aligned with the planned use
|
||||
* cases (ARCHITECTURE §6) so the shape is stable.
|
||||
*/
|
||||
|
||||
import type {
|
||||
Agent,
|
||||
AgentDrift,
|
||||
AgentProfile,
|
||||
DomainEvent,
|
||||
FirstRunState,
|
||||
GitBranches,
|
||||
GitCommit,
|
||||
GitFileStatus,
|
||||
GraphCommit,
|
||||
HealthReport,
|
||||
LayoutKind,
|
||||
LayoutList,
|
||||
LayoutOperation,
|
||||
LayoutTree,
|
||||
Project,
|
||||
ProfileAvailability,
|
||||
Template,
|
||||
Unsubscribe,
|
||||
} from "@/domain";
|
||||
|
||||
/** System-level gateway: health/ping + global domain-event subscription. */
|
||||
export interface SystemGateway {
|
||||
/** Calls the backend `health` command (smoke test of the whole pipeline). */
|
||||
health(note?: string): Promise<HealthReport>;
|
||||
/** Subscribes to relayed domain events. */
|
||||
onDomainEvent(handler: (event: DomainEvent) => void): Promise<Unsubscribe>;
|
||||
/**
|
||||
* Opens a native folder picker and returns the chosen path, or `null` if the
|
||||
* user cancelled. This is the only sanctioned way to pick a folder — all call
|
||||
* sites go through this port; the Tauri plugin is only imported in the adapter.
|
||||
*/
|
||||
pickFolder(): Promise<string | null>;
|
||||
}
|
||||
|
||||
/** Input for {@link AgentGateway.createAgent}. */
|
||||
export interface CreateAgentInput {
|
||||
name: string;
|
||||
profileId: string;
|
||||
initialContent?: string;
|
||||
}
|
||||
|
||||
/** Agents: create, list, read/update context, delete, launch (L6). */
|
||||
export interface AgentGateway {
|
||||
/** Lists all agents belonging to the given project. */
|
||||
listAgents(projectId: string): Promise<Agent[]>;
|
||||
/** Creates a new agent from scratch; returns the created agent. */
|
||||
createAgent(projectId: string, input: CreateAgentInput): Promise<Agent>;
|
||||
/** Reads an agent's `.md` context by agent id. */
|
||||
readContext(projectId: string, agentId: string): Promise<string>;
|
||||
/** Overwrites an agent's `.md` context. */
|
||||
updateContext(projectId: string, agentId: string, content: string): Promise<void>;
|
||||
/** Removes an agent from the project. */
|
||||
deleteAgent(projectId: string, agentId: string): Promise<void>;
|
||||
/**
|
||||
* Launches the agent: opens a PTY, spawns the CLI, and wires the output stream.
|
||||
* Mirrors {@link TerminalGateway.openTerminal} but invokes `launch_agent`.
|
||||
*/
|
||||
launchAgent(
|
||||
projectId: string,
|
||||
agentId: string,
|
||||
options: OpenTerminalOptions,
|
||||
onData: (bytes: Uint8Array) => void,
|
||||
): Promise<TerminalHandle>;
|
||||
}
|
||||
|
||||
/** Options for opening a terminal. */
|
||||
export interface OpenTerminalOptions {
|
||||
/** Working directory (typically the project root). */
|
||||
cwd: string;
|
||||
/** Initial terminal height in rows. */
|
||||
rows: number;
|
||||
/** Initial terminal width in columns. */
|
||||
cols: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A live terminal handle returned by {@link TerminalGateway.openTerminal}.
|
||||
*
|
||||
* The output stream is delivered to the `onData` callback passed at open time
|
||||
* (over a Tauri Channel in the real adapter); the handle exposes the input/
|
||||
* control operations and a `close` that also tears the stream down.
|
||||
*/
|
||||
export interface TerminalHandle {
|
||||
/** Stable session id (UUID) used by the backend for this PTY. */
|
||||
readonly sessionId: string;
|
||||
/** Sends bytes (xterm keystrokes) to the PTY. */
|
||||
write(data: Uint8Array): Promise<void>;
|
||||
/** Resizes the PTY. */
|
||||
resize(rows: number, cols: number): Promise<void>;
|
||||
/** Kills the PTY and stops the output stream. */
|
||||
close(): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminals (L3): open a PTY with a per-session output stream, then write/
|
||||
* resize/close it through the returned {@link TerminalHandle}.
|
||||
*/
|
||||
export interface TerminalGateway {
|
||||
/**
|
||||
* Opens a terminal. `onData` receives every chunk of PTY output (bytes) as it
|
||||
* arrives. Resolves once the PTY is spawned and the stream is wired.
|
||||
*/
|
||||
openTerminal(
|
||||
options: OpenTerminalOptions,
|
||||
onData: (bytes: Uint8Array) => void,
|
||||
): Promise<TerminalHandle>;
|
||||
}
|
||||
|
||||
/** Projects: create/open/close/list (L2). */
|
||||
export interface ProjectGateway {
|
||||
/** Lists the projects known to the registry. */
|
||||
listProjects(): Promise<Project[]>;
|
||||
/** Creates a project from a root; returns the created project. */
|
||||
createProject(name: string, root: string): Promise<Project>;
|
||||
/** Opens a project by id; returns the opened project. */
|
||||
openProject(projectId: string): Promise<Project>;
|
||||
/** Closes a project by id. */
|
||||
closeProject(projectId: string): Promise<void>;
|
||||
}
|
||||
|
||||
/** Layout: load the terminal grid tree and apply mutating operations (L4). */
|
||||
export interface LayoutGateway {
|
||||
/** Loads a project's layout tree (defaults to a single cell if none persisted).
|
||||
* When `layoutId` is omitted, the active layout for the project is used. */
|
||||
loadLayout(projectId: string, layoutId?: string): Promise<LayoutTree>;
|
||||
/**
|
||||
* Applies a split/merge/resize/move/setSession/setCellAgent operation; the backend persists
|
||||
* `.ideai/layout.json` and returns the resulting tree.
|
||||
* When `layoutId` is omitted, the active layout for the project is used.
|
||||
*/
|
||||
mutateLayout(
|
||||
projectId: string,
|
||||
operation: LayoutOperation,
|
||||
layoutId?: string,
|
||||
): Promise<LayoutTree>;
|
||||
/** Lists all named layouts for a project, with the current active id. */
|
||||
listLayouts(projectId: string): Promise<LayoutList>;
|
||||
/** Creates a new named layout for a project; returns the new layout id. */
|
||||
createLayout(projectId: string, name: string, kind?: LayoutKind): Promise<{ layoutId: string }>;
|
||||
/** Renames a layout. */
|
||||
renameLayout(projectId: string, layoutId: string, name: string): Promise<void>;
|
||||
/** Deletes a layout; returns the new active layout id. */
|
||||
deleteLayout(projectId: string, layoutId: string): Promise<{ activeId: string }>;
|
||||
/** Sets the active layout for a project. */
|
||||
setActiveLayout(projectId: string, layoutId: string): Promise<void>;
|
||||
}
|
||||
|
||||
/** Git: status/commit/checkout/… (L8). */
|
||||
export interface GitGateway {
|
||||
status(projectId: string): Promise<GitFileStatus[]>;
|
||||
stage(projectId: string, path: string): Promise<void>;
|
||||
unstage(projectId: string, path: string): Promise<void>;
|
||||
commit(projectId: string, message: string): Promise<GitCommit>;
|
||||
branches(projectId: string): Promise<GitBranches>;
|
||||
checkout(projectId: string, branch: string): Promise<void>;
|
||||
log(projectId: string, limit: number): Promise<GitCommit[]>;
|
||||
init(projectId: string): Promise<void>;
|
||||
/** Returns the full commit DAG for the git-graph layout. */
|
||||
graph(projectId: string, limit: number): Promise<GraphCommit[]>;
|
||||
}
|
||||
|
||||
/** Remote (SSH/WSL) connection management (L9). */
|
||||
export interface RemoteGateway {
|
||||
connect(projectId: string): Promise<void>;
|
||||
}
|
||||
|
||||
/** Input for {@link TemplateGateway.createTemplate}. */
|
||||
export interface CreateTemplateInput {
|
||||
name: string;
|
||||
content: string;
|
||||
defaultProfileId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Templates (L7): CRUD for agent templates, creation of agents from templates,
|
||||
* drift detection and synchronisation.
|
||||
*/
|
||||
export interface TemplateGateway {
|
||||
/** Lists all templates. */
|
||||
listTemplates(): Promise<Template[]>;
|
||||
/** Creates a new template; returns the created template. */
|
||||
createTemplate(input: CreateTemplateInput): Promise<Template>;
|
||||
/** Updates a template's content; increments its version; returns the updated template. */
|
||||
updateTemplate(templateId: string, content: string): Promise<Template>;
|
||||
/** Deletes a template by id. */
|
||||
deleteTemplate(templateId: string): Promise<void>;
|
||||
/**
|
||||
* Creates an agent in `projectId` based on the given template.
|
||||
* The agent's origin will be `fromTemplate`; its context will be the template's `contentMd`.
|
||||
*/
|
||||
createAgentFromTemplate(
|
||||
projectId: string,
|
||||
templateId: string,
|
||||
opts?: { name?: string; synchronized?: boolean },
|
||||
): Promise<Agent>;
|
||||
/** Returns the list of synchronized agents in `projectId` whose template has been updated. */
|
||||
detectDrift(projectId: string): Promise<AgentDrift[]>;
|
||||
/**
|
||||
* Syncs a single agent to the current version of its template.
|
||||
* Returns `{ synced: true, version }` on success, `{ synced: false, version: null }` for
|
||||
* scratch / non-synchronized agents.
|
||||
*/
|
||||
syncAgent(
|
||||
projectId: string,
|
||||
agentId: string,
|
||||
): Promise<{ synced: boolean; version: number | null }>;
|
||||
}
|
||||
|
||||
/**
|
||||
* AI profiles & first-run (L5). Drives the first-run wizard and profile
|
||||
* management: the pre-filled reference catalogue, detection of installed CLIs,
|
||||
* and CRUD/batch persistence of the chosen/edited/custom profiles.
|
||||
*/
|
||||
export interface ProfileGateway {
|
||||
/** First-run state: whether to show the wizard + the reference catalogue. */
|
||||
firstRunState(): Promise<FirstRunState>;
|
||||
/** The pre-filled, editable reference catalogue (Claude/Codex/Gemini/Aider). */
|
||||
referenceProfiles(): Promise<AgentProfile[]>;
|
||||
/** Probes each candidate's detection command; returns availability (✓/✗). */
|
||||
detectProfiles(candidates: AgentProfile[]): Promise<ProfileAvailability[]>;
|
||||
/** Lists the configured profiles. */
|
||||
listProfiles(): Promise<AgentProfile[]>;
|
||||
/** Creates or replaces (by id) a single profile; returns the saved profile. */
|
||||
saveProfile(profile: AgentProfile): Promise<AgentProfile>;
|
||||
/** Deletes a profile by id. */
|
||||
deleteProfile(profileId: string): Promise<void>;
|
||||
/** Persists the batch of chosen profiles, closing the first run. */
|
||||
configureProfiles(profiles: AgentProfile[]): Promise<AgentProfile[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
* The full set of gateways the app depends on, injected via the DI provider.
|
||||
* The composition (real vs mock) is chosen in `app/`.
|
||||
*/
|
||||
export interface Gateways {
|
||||
system: SystemGateway;
|
||||
agent: AgentGateway;
|
||||
terminal: TerminalGateway;
|
||||
project: ProjectGateway;
|
||||
layout: LayoutGateway;
|
||||
git: GitGateway;
|
||||
remote: RemoteGateway;
|
||||
profile: ProfileGateway;
|
||||
template: TemplateGateway;
|
||||
}
|
||||
Reference in New Issue
Block a user