Archived
refactor: share api dto types
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
# 02. Extract shared DTO/event types
|
# 02. Extract shared DTO/event types
|
||||||
|
|
||||||
Status: pending
|
Status: completed
|
||||||
|
|
||||||
Move duplicated API/session DTO definitions into shared modules used by both client and server.
|
Move duplicated API/session DTO definitions into shared modules used by both client and server.
|
||||||
|
|||||||
+2
-130
@@ -1,134 +1,6 @@
|
|||||||
export interface Project {
|
import type { CommandOption, CommandResult, FileContentResponse, FileSuggestion, FileTreeEntry, FileTreeResponse, GitDiffResponse, GitFileState, GitStatusFile, GitStatusResponse, MessagePage, Project, SessionInfo, SessionStatus, SlashCommand, Workspace } from "../../shared/apiTypes";
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
path: string;
|
|
||||||
createdAt: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Workspace {
|
export type { CommandOption, CommandResult, FileContentResponse, FileSuggestion, FileTreeEntry, FileTreeResponse, GitDiffResponse, GitFileState, GitStatusFile, GitStatusResponse, MessagePage, Project, SessionActivity, SessionInfo, SessionStatus, SlashCommand, SessionUiEvent, Workspace } from "../../shared/apiTypes";
|
||||||
id: string;
|
|
||||||
projectId: string;
|
|
||||||
path: string;
|
|
||||||
label: string;
|
|
||||||
branch?: string;
|
|
||||||
isMain: boolean;
|
|
||||||
isGitWorktree: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SessionInfo {
|
|
||||||
id: string;
|
|
||||||
path: string;
|
|
||||||
cwd: string;
|
|
||||||
name?: string;
|
|
||||||
created: string;
|
|
||||||
modified: string;
|
|
||||||
messageCount: number;
|
|
||||||
firstMessage: string;
|
|
||||||
archived?: boolean;
|
|
||||||
archivedAt?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SessionActivity {
|
|
||||||
sessionId: string;
|
|
||||||
phase: "active" | "idle" | "error";
|
|
||||||
label: string;
|
|
||||||
detail?: string;
|
|
||||||
at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SessionStatus {
|
|
||||||
sessionId: string;
|
|
||||||
model?: { provider?: string; id?: string; name?: string; contextWindow?: number; reasoning?: unknown };
|
|
||||||
thinkingLevel?: string;
|
|
||||||
isStreaming: boolean;
|
|
||||||
isCompacting: boolean;
|
|
||||||
isBashRunning: boolean;
|
|
||||||
pendingMessageCount: number;
|
|
||||||
tokens: { input: number; output: number; cacheRead: number; cacheWrite: number; total: number };
|
|
||||||
cost: number;
|
|
||||||
contextUsage?: { tokens: number | null; contextWindow: number; percent: number | null };
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SlashCommand {
|
|
||||||
name: string;
|
|
||||||
description?: string;
|
|
||||||
source: "extension" | "prompt" | "skill" | "builtin";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FileSuggestion {
|
|
||||||
path: string;
|
|
||||||
kind: "tracked" | "untracked" | "other";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FileTreeEntry {
|
|
||||||
name: string;
|
|
||||||
path: string;
|
|
||||||
type: "file" | "directory" | "symlink";
|
|
||||||
size?: number;
|
|
||||||
modifiedAt?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FileTreeResponse {
|
|
||||||
path: string;
|
|
||||||
entries: FileTreeEntry[];
|
|
||||||
scannedAt: string;
|
|
||||||
truncated: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FileContentResponse {
|
|
||||||
path: string;
|
|
||||||
language?: string;
|
|
||||||
encoding: "utf8";
|
|
||||||
size: number;
|
|
||||||
modifiedAt: string;
|
|
||||||
content: string;
|
|
||||||
truncated: boolean;
|
|
||||||
binary: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type GitFileState = "unmodified" | "modified" | "added" | "deleted" | "renamed" | "copied" | "untracked" | "ignored" | "conflicted";
|
|
||||||
|
|
||||||
export interface GitStatusFile {
|
|
||||||
path: string;
|
|
||||||
oldPath?: string;
|
|
||||||
index: GitFileState;
|
|
||||||
workingTree: GitFileState;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GitStatusResponse {
|
|
||||||
isGitRepo: boolean;
|
|
||||||
hash: string;
|
|
||||||
branch?: string;
|
|
||||||
upstream?: string;
|
|
||||||
ahead?: number;
|
|
||||||
behind?: number;
|
|
||||||
files: GitStatusFile[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GitDiffResponse {
|
|
||||||
path?: string;
|
|
||||||
staged: boolean;
|
|
||||||
hash: string;
|
|
||||||
diff: string;
|
|
||||||
truncated: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CommandOption {
|
|
||||||
value: string;
|
|
||||||
label: string;
|
|
||||||
description?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MessagePage {
|
|
||||||
messages: unknown[];
|
|
||||||
start: number;
|
|
||||||
total: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CommandResult =
|
|
||||||
| { type: "done"; message?: string; session?: SessionInfo }
|
|
||||||
| { type: "select"; requestId: string; title: string; options: CommandOption[] }
|
|
||||||
| { type: "unsupported"; message: string };
|
|
||||||
|
|
||||||
async function request<T>(url: string, parse: (value: unknown) => T, init?: RequestInit): Promise<T> {
|
async function request<T>(url: string, parse: (value: unknown) => T, init?: RequestInit): Promise<T> {
|
||||||
const headers = new Headers(init?.headers);
|
const headers = new Headers(init?.headers);
|
||||||
|
|||||||
@@ -1,16 +1,7 @@
|
|||||||
import { globalSessionEvents, sessionEvents, type SessionActivity, type SessionStatus } from "./api";
|
import { globalSessionEvents, sessionEvents } from "./api";
|
||||||
|
import type { SessionUiEvent } from "../../shared/apiTypes";
|
||||||
|
|
||||||
export type SessionUiEvent =
|
export type { SessionUiEvent } from "../../shared/apiTypes";
|
||||||
| { type: "assistant.delta"; text: string }
|
|
||||||
| { type: "tool.start"; toolName: string; summary: string; args?: unknown }
|
|
||||||
| { type: "tool.end"; toolName: string; text: string; isError: boolean; content?: unknown }
|
|
||||||
| { type: "shell.start"; command: string; excludeFromContext?: boolean }
|
|
||||||
| { type: "shell.chunk"; chunk: string }
|
|
||||||
| { type: "shell.end"; output?: string; exitCode?: number | null; cancelled?: boolean; truncated?: boolean; fullOutputPath?: string; isError?: boolean }
|
|
||||||
| { type: "status.update"; status: SessionStatus }
|
|
||||||
| { type: "activity.update"; activity: SessionActivity }
|
|
||||||
| { type: "command.output"; level: "info" | "success" | "error"; message: string }
|
|
||||||
| { type: "session.error"; message: string };
|
|
||||||
|
|
||||||
export class SessionSocket {
|
export class SessionSocket {
|
||||||
private socket: WebSocket | undefined;
|
private socket: WebSocket | undefined;
|
||||||
|
|||||||
@@ -1,34 +1,8 @@
|
|||||||
import { createHash } from "node:crypto";
|
import { createHash } from "node:crypto";
|
||||||
import { spawn } from "node:child_process";
|
import { spawn } from "node:child_process";
|
||||||
|
import type { GitDiffResponse, GitFileState, GitStatusFile, GitStatusResponse } from "../../shared/apiTypes.js";
|
||||||
import { normalizeRelativePath } from "../workspaces/pathSafety.js";
|
import { normalizeRelativePath } from "../workspaces/pathSafety.js";
|
||||||
|
|
||||||
export type GitFileState = "unmodified" | "modified" | "added" | "deleted" | "renamed" | "copied" | "untracked" | "ignored" | "conflicted";
|
|
||||||
|
|
||||||
export interface GitStatusFile {
|
|
||||||
path: string;
|
|
||||||
oldPath?: string;
|
|
||||||
index: GitFileState;
|
|
||||||
workingTree: GitFileState;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GitStatusResponse {
|
|
||||||
isGitRepo: boolean;
|
|
||||||
hash: string;
|
|
||||||
branch?: string;
|
|
||||||
upstream?: string;
|
|
||||||
ahead?: number;
|
|
||||||
behind?: number;
|
|
||||||
files: GitStatusFile[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GitDiffResponse {
|
|
||||||
path?: string;
|
|
||||||
staged: boolean;
|
|
||||||
hash: string;
|
|
||||||
diff: string;
|
|
||||||
truncated: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MAX_OUTPUT = 2 * 1024 * 1024;
|
const MAX_OUTPUT = 2 * 1024 * 1024;
|
||||||
|
|
||||||
export async function gitStatus(cwd: string): Promise<GitStatusResponse> {
|
export async function gitStatus(cwd: string): Promise<GitStatusResponse> {
|
||||||
|
|||||||
+13
-70
@@ -1,70 +1,13 @@
|
|||||||
export interface Project {
|
export type {
|
||||||
id: string;
|
Project,
|
||||||
name: string;
|
Workspace,
|
||||||
path: string;
|
SessionInfo as ClientSession,
|
||||||
createdAt: string;
|
MessagePage as ClientMessagePage,
|
||||||
}
|
SessionStatus as ClientSessionStatus,
|
||||||
|
SlashCommand as ClientCommand,
|
||||||
export interface Workspace {
|
FileSuggestion as ClientFileSuggestion,
|
||||||
id: string;
|
CommandOption as ClientCommandOption,
|
||||||
projectId: string;
|
CommandResult as ClientCommandResult,
|
||||||
path: string;
|
SessionActivity as ClientSessionActivity,
|
||||||
label: string;
|
SessionUiEvent,
|
||||||
branch?: string;
|
} from "../shared/apiTypes.js";
|
||||||
isMain: boolean;
|
|
||||||
isGitWorktree: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ClientSession {
|
|
||||||
id: string;
|
|
||||||
path: string;
|
|
||||||
cwd: string;
|
|
||||||
name?: string;
|
|
||||||
created: string;
|
|
||||||
modified: string;
|
|
||||||
messageCount: number;
|
|
||||||
firstMessage: string;
|
|
||||||
archived?: boolean;
|
|
||||||
archivedAt?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ClientMessagePage {
|
|
||||||
messages: unknown[];
|
|
||||||
start: number;
|
|
||||||
total: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ClientSessionStatus {
|
|
||||||
sessionId: string;
|
|
||||||
model?: { provider?: string; id?: string; name?: string; contextWindow?: number; reasoning?: unknown };
|
|
||||||
thinkingLevel?: string;
|
|
||||||
isStreaming: boolean;
|
|
||||||
isCompacting: boolean;
|
|
||||||
isBashRunning: boolean;
|
|
||||||
pendingMessageCount: number;
|
|
||||||
tokens: { input: number; output: number; cacheRead: number; cacheWrite: number; total: number };
|
|
||||||
cost: number;
|
|
||||||
contextUsage?: { tokens: number | null; contextWindow: number; percent: number | null };
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ClientCommand {
|
|
||||||
name: string;
|
|
||||||
description?: string;
|
|
||||||
source: "extension" | "prompt" | "skill" | "builtin";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ClientFileSuggestion {
|
|
||||||
path: string;
|
|
||||||
kind: "tracked" | "untracked" | "other";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ClientCommandOption {
|
|
||||||
value: string;
|
|
||||||
label: string;
|
|
||||||
description?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ClientCommandResult =
|
|
||||||
| { type: "done"; message?: string; session?: ClientSession }
|
|
||||||
| { type: "select"; requestId: string; title: string; options: ClientCommandOption[] }
|
|
||||||
| { type: "unsupported"; message: string };
|
|
||||||
|
|||||||
@@ -1,17 +1,7 @@
|
|||||||
import { readFile, stat } from "node:fs/promises";
|
import { readFile, stat } from "node:fs/promises";
|
||||||
|
import type { FileContentResponse } from "../../shared/apiTypes.js";
|
||||||
import { resolveInsideWorkspace } from "./pathSafety.js";
|
import { resolveInsideWorkspace } from "./pathSafety.js";
|
||||||
|
|
||||||
export interface FileContentResponse {
|
|
||||||
path: string;
|
|
||||||
language?: string;
|
|
||||||
encoding: "utf8";
|
|
||||||
size: number;
|
|
||||||
modifiedAt: string;
|
|
||||||
content: string;
|
|
||||||
truncated: boolean;
|
|
||||||
binary: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MAX_BYTES = 512 * 1024;
|
const MAX_BYTES = 512 * 1024;
|
||||||
|
|
||||||
export async function readWorkspaceFile(rootPath: string, path: string | undefined): Promise<FileContentResponse> {
|
export async function readWorkspaceFile(rootPath: string, path: string | undefined): Promise<FileContentResponse> {
|
||||||
|
|||||||
@@ -1,22 +1,8 @@
|
|||||||
import { lstat, readdir } from "node:fs/promises";
|
import { lstat, readdir } from "node:fs/promises";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
|
import type { FileTreeEntry, FileTreeResponse } from "../../shared/apiTypes.js";
|
||||||
import { resolveInsideWorkspace } from "./pathSafety.js";
|
import { resolveInsideWorkspace } from "./pathSafety.js";
|
||||||
|
|
||||||
export interface FileTreeEntry {
|
|
||||||
name: string;
|
|
||||||
path: string;
|
|
||||||
type: "file" | "directory" | "symlink";
|
|
||||||
size?: number;
|
|
||||||
modifiedAt?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FileTreeResponse {
|
|
||||||
path: string;
|
|
||||||
entries: FileTreeEntry[];
|
|
||||||
scannedAt: string;
|
|
||||||
truncated: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MAX_ENTRIES = 1000;
|
const MAX_ENTRIES = 1000;
|
||||||
|
|
||||||
export async function listWorkspaceTree(rootPath: string, path: string | undefined): Promise<FileTreeResponse> {
|
export async function listWorkspaceTree(rootPath: string, path: string | undefined): Promise<FileTreeResponse> {
|
||||||
|
|||||||
@@ -0,0 +1,143 @@
|
|||||||
|
export interface Project {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
path: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Workspace {
|
||||||
|
id: string;
|
||||||
|
projectId: string;
|
||||||
|
path: string;
|
||||||
|
label: string;
|
||||||
|
branch?: string;
|
||||||
|
isMain: boolean;
|
||||||
|
isGitWorktree: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SessionInfo {
|
||||||
|
id: string;
|
||||||
|
path: string;
|
||||||
|
cwd: string;
|
||||||
|
name?: string;
|
||||||
|
created: string;
|
||||||
|
modified: string;
|
||||||
|
messageCount: number;
|
||||||
|
firstMessage: string;
|
||||||
|
archived?: boolean;
|
||||||
|
archivedAt?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SessionActivity {
|
||||||
|
sessionId: string;
|
||||||
|
phase: "active" | "idle" | "error";
|
||||||
|
label: string;
|
||||||
|
detail?: string;
|
||||||
|
at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SessionStatus {
|
||||||
|
sessionId: string;
|
||||||
|
model?: { provider?: string; id?: string; name?: string; contextWindow?: number; reasoning?: unknown };
|
||||||
|
thinkingLevel?: string;
|
||||||
|
isStreaming: boolean;
|
||||||
|
isCompacting: boolean;
|
||||||
|
isBashRunning: boolean;
|
||||||
|
pendingMessageCount: number;
|
||||||
|
tokens: { input: number; output: number; cacheRead: number; cacheWrite: number; total: number };
|
||||||
|
cost: number;
|
||||||
|
contextUsage?: { tokens: number | null; contextWindow: number; percent: number | null };
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlashCommand {
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
source: "extension" | "prompt" | "skill" | "builtin";
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileSuggestion {
|
||||||
|
path: string;
|
||||||
|
kind: "tracked" | "untracked" | "other";
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileTreeEntry {
|
||||||
|
name: string;
|
||||||
|
path: string;
|
||||||
|
type: "file" | "directory" | "symlink";
|
||||||
|
size?: number;
|
||||||
|
modifiedAt?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileTreeResponse {
|
||||||
|
path: string;
|
||||||
|
entries: FileTreeEntry[];
|
||||||
|
scannedAt: string;
|
||||||
|
truncated: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileContentResponse {
|
||||||
|
path: string;
|
||||||
|
language?: string;
|
||||||
|
encoding: "utf8";
|
||||||
|
size: number;
|
||||||
|
modifiedAt: string;
|
||||||
|
content: string;
|
||||||
|
truncated: boolean;
|
||||||
|
binary: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GitFileState = "unmodified" | "modified" | "added" | "deleted" | "renamed" | "copied" | "untracked" | "ignored" | "conflicted";
|
||||||
|
|
||||||
|
export interface GitStatusFile {
|
||||||
|
path: string;
|
||||||
|
oldPath?: string;
|
||||||
|
index: GitFileState;
|
||||||
|
workingTree: GitFileState;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GitStatusResponse {
|
||||||
|
isGitRepo: boolean;
|
||||||
|
hash: string;
|
||||||
|
branch?: string;
|
||||||
|
upstream?: string;
|
||||||
|
ahead?: number;
|
||||||
|
behind?: number;
|
||||||
|
files: GitStatusFile[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GitDiffResponse {
|
||||||
|
path?: string;
|
||||||
|
staged: boolean;
|
||||||
|
hash: string;
|
||||||
|
diff: string;
|
||||||
|
truncated: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CommandOption {
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MessagePage {
|
||||||
|
messages: unknown[];
|
||||||
|
start: number;
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CommandResult =
|
||||||
|
| { type: "done"; message?: string; session?: SessionInfo }
|
||||||
|
| { type: "select"; requestId: string; title: string; options: CommandOption[] }
|
||||||
|
| { type: "unsupported"; message: string };
|
||||||
|
|
||||||
|
export type SessionUiEvent =
|
||||||
|
| { type: "assistant.delta"; text: string }
|
||||||
|
| { type: "tool.start"; toolName: string; summary: string; args?: unknown }
|
||||||
|
| { type: "tool.end"; toolName: string; text: string; isError: boolean; content?: unknown }
|
||||||
|
| { type: "shell.start"; command: string; excludeFromContext?: boolean }
|
||||||
|
| { type: "shell.chunk"; chunk: string }
|
||||||
|
| { type: "shell.end"; output?: string; exitCode?: number | null; cancelled?: boolean; truncated?: boolean; fullOutputPath?: string; isError?: boolean }
|
||||||
|
| { type: "status.update"; status: SessionStatus }
|
||||||
|
| { type: "activity.update"; activity: SessionActivity }
|
||||||
|
| { type: "command.output"; level: "info" | "success" | "error"; message: string }
|
||||||
|
| { type: "session.error"; message: string };
|
||||||
Reference in New Issue
Block a user