feat: separate frontend and backend services

This commit is contained in:
luckyyzh
2026-08-10 09:45:22 +08:00
parent cb9ec7a869
commit 7a9859e60d
132 changed files with 8393 additions and 6388 deletions
+4 -141
View File
@@ -1,10 +1,7 @@
import type {
AgentSessionEvent,
SessionManager,
SettingsManager,
SlashCommandInfo,
Theme,
} from "@earendil-works/pi-coding-agent";
// Frontend-only subset of the pi type surface. The full AgentSessionLike
// contract (which references pi-coding-agent classes) lives in the backend
// (server/src/lib/pi-types.ts); the UI only renders session stats reported
// over HTTP, so this file must not import the pi packages.
export interface ContextUsage {
percent: number | null;
@@ -12,22 +9,6 @@ export interface ContextUsage {
tokens: number | null;
}
export interface ModelLike {
id: string;
provider: string;
}
export interface ToolInfo {
name: string;
description: string;
}
export interface NavigateTreeResult {
editorText?: string;
cancelled: boolean;
aborted?: boolean;
}
export interface SessionStatsInfo {
sessionFile?: string;
sessionId: string;
@@ -47,121 +28,3 @@ export interface SessionStatsInfo {
cost: number;
contextUsage?: ContextUsage;
}
interface PromptTemplateLike {
name: string;
description?: string;
sourceInfo: SlashCommandInfo["sourceInfo"];
}
interface SkillLike {
name: string;
description?: string;
sourceInfo: SlashCommandInfo["sourceInfo"];
}
interface ResourceLoaderLike {
getSkills(): { skills: SkillLike[] };
}
interface ExtensionRunnerLike {
getRegisteredCommands(): Array<{
invocationName: string;
description?: string;
sourceInfo: SlashCommandInfo["sourceInfo"];
}>;
setUIContext?(uiContext?: unknown, mode?: "tui" | "rpc" | "json" | "print"): void;
}
type DialogOptionsLike = {
signal?: AbortSignal;
timeout?: number;
};
type WidgetOptionsLike = {
placement?: "aboveEditor" | "belowEditor";
};
export interface ExtensionUiContextLike {
select(title: string, options: string[], opts?: DialogOptionsLike): Promise<string | undefined>;
confirm(title: string, message: string, opts?: DialogOptionsLike): Promise<boolean>;
input(title: string, placeholder?: string, opts?: DialogOptionsLike): Promise<string | undefined>;
editor(title: string, prefill?: string, opts?: DialogOptionsLike): Promise<string | undefined>;
notify(message: string, type?: "info" | "warning" | "error"): void;
onTerminalInput(): () => void;
setStatus(key: string, text: string | undefined): void;
setWorkingMessage(message?: string): void;
setWorkingVisible(visible: boolean): void;
setWorkingIndicator(options?: { frames?: string[]; intervalMs?: number }): void;
setHiddenThinkingLabel(label?: string): void;
setWidget(key: string, content: string[] | ((...args: never[]) => unknown) | undefined, options?: WidgetOptionsLike): void;
setFooter(factory: unknown): void;
setHeader(factory: unknown): void;
setTitle(title: string): void;
custom<T = unknown>(...args: unknown[]): Promise<T>;
pasteToEditor(text: string): void;
setEditorText(text: string): void;
getEditorText(): string;
addAutocompleteProvider(): void;
setEditorComponent(): void;
getEditorComponent(): undefined;
readonly theme: Theme;
getAllThemes(): unknown[];
getTheme(name: string): undefined;
setTheme(theme: unknown): { success: boolean; error?: string };
getToolsExpanded(): boolean;
setToolsExpanded(expanded: boolean): void;
}
export interface AgentSessionLike {
readonly sessionId: string;
readonly sessionFile: string | undefined;
readonly isStreaming: boolean;
readonly isCompacting: boolean;
readonly autoCompactionEnabled: boolean;
readonly autoRetryEnabled: boolean;
readonly model: ModelLike | undefined;
readonly modelRuntime: {
getModel: (provider: string, modelId: string) => ModelLike | undefined;
refresh: (options?: { allowNetwork?: boolean }) => Promise<unknown>;
};
readonly sessionManager: SessionManager;
readonly settingsManager: SettingsManager;
readonly agent: { state?: { systemPrompt?: string; thinkingLevel?: string } };
readonly extensionRunner: ExtensionRunnerLike;
readonly promptTemplates: readonly PromptTemplateLike[];
readonly resourceLoader: ResourceLoaderLike;
readonly bindExtensions?: unknown;
reload(options?: { beforeSessionStart?: () => void | Promise<void> }): Promise<void>;
subscribe(listener: (event: AgentSessionEvent) => void): () => void;
prompt(text: string, options?: {
images?: Array<{ type: "image"; data: string; mimeType: string }>;
streamingBehavior?: "steer" | "followUp";
source?: "interactive" | "rpc";
}): Promise<void>;
abort(): Promise<void>;
executeBash(command: string, onChunk?: (chunk: string) => void, options?: { excludeFromContext?: boolean }): Promise<{ output: string; exitCode?: number; cancelled?: boolean; truncated?: boolean; fullOutputPath?: string }>;
abortBash(): void;
readonly isBashRunning: boolean;
setModel(model: ModelLike): Promise<void>;
navigateTree(targetId: string, options?: { summarize?: boolean }): Promise<NavigateTreeResult>;
setThinkingLevel(level: string): void;
compact(customInstructions?: string): Promise<unknown>;
setSessionName(name: string): void;
getSessionStats(): Omit<SessionStatsInfo, "sessionName">;
getLastAssistantText(): string | undefined;
setAutoCompactionEnabled(enabled: boolean): void;
setAutoRetryEnabled(enabled: boolean): void;
steer(text: string, images?: Array<{ type: "image"; data: string; mimeType: string }>): Promise<void>;
followUp(text: string, images?: Array<{ type: "image"; data: string; mimeType: string }>): Promise<void>;
readonly pendingMessageCount: number;
getSteeringMessages(): readonly string[];
getFollowUpMessages(): readonly string[];
clearQueue(): { steering: string[]; followUp: string[] };
getAllTools(): ToolInfo[];
getActiveToolNames(): string[];
setActiveToolsByName(names: string[]): void;
abortCompaction(): void;
getContextUsage(): ContextUsage | undefined;
}