mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
Share REST and RPC response types
This commit is contained in:
@@ -9,6 +9,7 @@ import { basename, dirname, isAbsolute, join, relative, resolve as resolvePath }
|
||||
import { logger } from '@/ui/logger'
|
||||
import { configuration } from '@/configuration'
|
||||
import type { Update, UpdateMachineBody } from '@hapi/protocol'
|
||||
import type { MachineDirectoryEntry, MachineListDirectoryResponse, PathExistsResponse } from '@hapi/protocol/apiTypes'
|
||||
import type { RunnerState, Machine, MachineMetadata } from './types'
|
||||
import { RunnerStateSchema, MachineMetadataSchema } from './types'
|
||||
import { backoff } from '@/utils/time'
|
||||
@@ -68,28 +69,10 @@ interface PathExistsRequest {
|
||||
paths: string[]
|
||||
}
|
||||
|
||||
interface PathExistsResponse {
|
||||
exists: Record<string, boolean>
|
||||
}
|
||||
|
||||
interface ListMachineDirectoryRequest {
|
||||
path: string
|
||||
}
|
||||
|
||||
interface ListMachineDirectoryEntry {
|
||||
name: string
|
||||
type: 'file' | 'directory' | 'other'
|
||||
size?: number
|
||||
modified?: number
|
||||
isGitRepo?: boolean
|
||||
}
|
||||
|
||||
interface ListMachineDirectoryResponse {
|
||||
success: boolean
|
||||
entries?: ListMachineDirectoryEntry[]
|
||||
error?: string
|
||||
}
|
||||
|
||||
function normalizeWorkspaceRoots(paths?: string[]): string[] | undefined {
|
||||
if (!paths?.length) {
|
||||
return undefined
|
||||
@@ -163,7 +146,7 @@ export class ApiMachineClient {
|
||||
return { exists }
|
||||
})
|
||||
|
||||
this.rpcHandlerManager.registerHandler<ListMachineDirectoryRequest, ListMachineDirectoryResponse>('list-directory', async (params) => {
|
||||
this.rpcHandlerManager.registerHandler<ListMachineDirectoryRequest, MachineListDirectoryResponse>('list-directory', async (params) => {
|
||||
if (!this.normalizedWorkspaceRoots?.length) {
|
||||
return { success: false, error: 'Workspace browsing is not enabled for this machine' }
|
||||
}
|
||||
@@ -185,7 +168,7 @@ export class ApiMachineClient {
|
||||
}
|
||||
|
||||
const dirEntries = await readdir(targetPath, { withFileTypes: true })
|
||||
const entries: ListMachineDirectoryEntry[] = []
|
||||
const entries: MachineDirectoryEntry[] = []
|
||||
|
||||
await Promise.all(dirEntries.map(async (entry) => {
|
||||
if (entry.name.startsWith('.')) return
|
||||
|
||||
@@ -1,23 +1,12 @@
|
||||
import type { CodexModelsResponse, CodexModelSummary } from '@hapi/protocol/apiTypes';
|
||||
import { CodexAppServerClient } from '@/codex/codexAppServerClient';
|
||||
import { getErrorMessage } from './rpcResponses';
|
||||
|
||||
export interface CodexModelSummary {
|
||||
id: string;
|
||||
displayName: string;
|
||||
isDefault: boolean;
|
||||
defaultReasoningEffort?: string | null;
|
||||
supportedReasoningEfforts?: string[];
|
||||
}
|
||||
|
||||
export interface ListCodexModelsRequest {
|
||||
includeHidden?: boolean;
|
||||
}
|
||||
|
||||
export interface ListCodexModelsResponse {
|
||||
success: boolean;
|
||||
models?: CodexModelSummary[];
|
||||
error?: string;
|
||||
}
|
||||
export type ListCodexModelsResponse = CodexModelsResponse;
|
||||
|
||||
function asNonEmptyString(value: unknown): string | null {
|
||||
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { logger } from '@/ui/logger'
|
||||
import { readdir, stat } from 'fs/promises'
|
||||
import { basename, join, resolve } from 'path'
|
||||
import type { DirectoryEntry, ListDirectoryResponse } from '@hapi/protocol/apiTypes'
|
||||
import type { RpcHandlerManager } from '@/api/rpc/RpcHandlerManager'
|
||||
import { validatePath } from '../pathSecurity'
|
||||
import { getErrorMessage, rpcError } from '../rpcResponses'
|
||||
@@ -9,19 +10,6 @@ interface ListDirectoryRequest {
|
||||
path: string
|
||||
}
|
||||
|
||||
interface DirectoryEntry {
|
||||
name: string
|
||||
type: 'file' | 'directory' | 'other'
|
||||
size?: number
|
||||
modified?: number
|
||||
}
|
||||
|
||||
interface ListDirectoryResponse {
|
||||
success: boolean
|
||||
entries?: DirectoryEntry[]
|
||||
error?: string
|
||||
}
|
||||
|
||||
interface GetDirectoryTreeRequest {
|
||||
path: string
|
||||
maxDepth: number
|
||||
|
||||
@@ -2,6 +2,7 @@ import { logger } from '@/ui/logger'
|
||||
import { readFile, stat, writeFile } from 'fs/promises'
|
||||
import { createHash } from 'crypto'
|
||||
import { resolve } from 'path'
|
||||
import type { FileReadResponse, GeneratedImageResponse } from '@hapi/protocol/apiTypes'
|
||||
import type { RpcHandlerManager } from '@/api/rpc/RpcHandlerManager'
|
||||
import { validatePath } from '../pathSecurity'
|
||||
import { getGeneratedImage } from '../generatedImages'
|
||||
@@ -11,23 +12,13 @@ interface ReadFileRequest {
|
||||
path: string
|
||||
}
|
||||
|
||||
interface ReadFileResponse {
|
||||
success: boolean
|
||||
content?: string
|
||||
error?: string
|
||||
}
|
||||
type ReadFileResponse = FileReadResponse
|
||||
|
||||
interface ReadGeneratedImageRequest {
|
||||
id: string
|
||||
}
|
||||
|
||||
interface ReadGeneratedImageResponse {
|
||||
success: boolean
|
||||
content?: string
|
||||
mimeType?: string
|
||||
fileName?: string
|
||||
error?: string
|
||||
}
|
||||
type ReadGeneratedImageResponse = GeneratedImageResponse
|
||||
|
||||
interface WriteFileRequest {
|
||||
path: string
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { execFile, type ExecFileOptions } from 'child_process'
|
||||
import { promisify } from 'util'
|
||||
import type { CommandResponse } from '@hapi/protocol/apiTypes'
|
||||
import type { RpcHandlerManager } from '@/api/rpc/RpcHandlerManager'
|
||||
import { validatePath } from '../pathSecurity'
|
||||
import { rpcError } from '../rpcResponses'
|
||||
@@ -24,13 +25,7 @@ interface GitDiffFileRequest {
|
||||
timeout?: number
|
||||
}
|
||||
|
||||
interface GitCommandResponse {
|
||||
success: boolean
|
||||
stdout?: string
|
||||
stderr?: string
|
||||
exitCode?: number
|
||||
error?: string
|
||||
}
|
||||
type GitCommandResponse = CommandResponse
|
||||
|
||||
function resolveCwd(requestedCwd: string | undefined, workingDirectory: string): { cwd: string; error?: string } {
|
||||
const cwd = requestedCwd ?? workingDirectory
|
||||
|
||||
@@ -2,6 +2,7 @@ import { logger } from '@/ui/logger'
|
||||
import { mkdir, mkdtemp, rm, writeFile } from 'fs/promises'
|
||||
import { join, resolve, sep } from 'path'
|
||||
import { rmSync } from 'node:fs'
|
||||
import type { DeleteUploadResponse, UploadFileResponse } from '@hapi/protocol/apiTypes'
|
||||
import type { RpcHandlerManager } from '@/api/rpc/RpcHandlerManager'
|
||||
import { getErrorMessage, rpcError } from '../rpcResponses'
|
||||
import { getHapiBlobsDir } from '@/constants/uploadPaths'
|
||||
@@ -13,22 +14,11 @@ interface UploadFileRequest {
|
||||
mimeType: string
|
||||
}
|
||||
|
||||
interface UploadFileResponse {
|
||||
success: boolean
|
||||
path?: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
interface DeleteUploadRequest {
|
||||
sessionId?: string
|
||||
path: string
|
||||
}
|
||||
|
||||
interface DeleteUploadResponse {
|
||||
success: boolean
|
||||
error?: string
|
||||
}
|
||||
|
||||
const uploadDirs = new Map<string, string>()
|
||||
const uploadDirPromises = new Map<string, Promise<string>>()
|
||||
const uploadDirCleanupRequested = new Set<string>()
|
||||
|
||||
@@ -1,23 +1,14 @@
|
||||
import { asString, isObject } from '@hapi/protocol';
|
||||
import type { OpencodeModelsResponse, OpencodeModelSummary } from '@hapi/protocol/apiTypes';
|
||||
import { AcpStdioTransport } from '@/agent/backends/acp/AcpStdioTransport';
|
||||
import packageJson from '../../../package.json';
|
||||
import { getErrorMessage } from './rpcResponses';
|
||||
|
||||
export interface OpencodeModelSummary {
|
||||
modelId: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export interface ListOpencodeModelsForCwdRequest {
|
||||
cwd?: string;
|
||||
}
|
||||
|
||||
export interface ListOpencodeModelsForCwdResponse {
|
||||
success: boolean;
|
||||
availableModels?: OpencodeModelSummary[];
|
||||
currentModelId?: string | null;
|
||||
error?: string;
|
||||
}
|
||||
export type ListOpencodeModelsForCwdResponse = OpencodeModelsResponse;
|
||||
|
||||
interface CacheEntry {
|
||||
expiresAt: number;
|
||||
|
||||
+26
-75
@@ -1,85 +1,36 @@
|
||||
import type { AgentFlavor, CodexCollaborationMode, PermissionMode } from '@hapi/protocol/types'
|
||||
import type {
|
||||
CodexModelSummary,
|
||||
CodexModelsResponse,
|
||||
CommandResponse,
|
||||
DeleteUploadResponse,
|
||||
DirectoryEntry,
|
||||
FileReadResponse,
|
||||
GeneratedImageResponse,
|
||||
ListDirectoryResponse,
|
||||
OpencodeModelsResponse,
|
||||
OpencodeModelSummary,
|
||||
PathExistsResponse,
|
||||
UploadFileResponse
|
||||
} from '@hapi/protocol/apiTypes'
|
||||
import type { Server } from 'socket.io'
|
||||
import type { RpcRegistry } from '../socket/rpcRegistry'
|
||||
|
||||
const DEFAULT_RPC_TIMEOUT_MS = 30_000
|
||||
const MODEL_LIST_RPC_TIMEOUT_MS = 120_000
|
||||
|
||||
export type RpcCommandResponse = {
|
||||
success: boolean
|
||||
stdout?: string
|
||||
stderr?: string
|
||||
exitCode?: number
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type RpcReadFileResponse = {
|
||||
success: boolean
|
||||
content?: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type RpcGeneratedImageResponse = {
|
||||
success: boolean
|
||||
content?: string
|
||||
mimeType?: string
|
||||
fileName?: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type RpcUploadFileResponse = {
|
||||
success: boolean
|
||||
path?: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type RpcDeleteUploadResponse = {
|
||||
success: boolean
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type RpcDirectoryEntry = {
|
||||
name: string
|
||||
type: 'file' | 'directory' | 'other'
|
||||
size?: number
|
||||
modified?: number
|
||||
}
|
||||
|
||||
export type RpcListDirectoryResponse = {
|
||||
success: boolean
|
||||
entries?: RpcDirectoryEntry[]
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type RpcPathExistsResponse = {
|
||||
exists: Record<string, boolean>
|
||||
}
|
||||
|
||||
export type RpcCodexModel = {
|
||||
id: string
|
||||
displayName: string
|
||||
isDefault: boolean
|
||||
defaultReasoningEffort?: string | null
|
||||
supportedReasoningEfforts?: string[]
|
||||
}
|
||||
|
||||
export type RpcListCodexModelsResponse = {
|
||||
success: boolean
|
||||
models?: RpcCodexModel[]
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type RpcOpencodeModel = {
|
||||
modelId: string
|
||||
name?: string
|
||||
}
|
||||
|
||||
export type RpcListOpencodeModelsResponse = {
|
||||
success: boolean
|
||||
availableModels?: RpcOpencodeModel[]
|
||||
currentModelId?: string | null
|
||||
error?: string
|
||||
}
|
||||
export type RpcCommandResponse = CommandResponse
|
||||
export type RpcReadFileResponse = FileReadResponse
|
||||
export type RpcGeneratedImageResponse = GeneratedImageResponse
|
||||
export type RpcUploadFileResponse = UploadFileResponse
|
||||
export type RpcDeleteUploadResponse = DeleteUploadResponse
|
||||
export type RpcDirectoryEntry = DirectoryEntry
|
||||
export type RpcListDirectoryResponse = ListDirectoryResponse
|
||||
export type RpcPathExistsResponse = PathExistsResponse
|
||||
export type RpcCodexModel = CodexModelSummary
|
||||
export type RpcListCodexModelsResponse = CodexModelsResponse
|
||||
export type RpcOpencodeModel = OpencodeModelSummary
|
||||
export type RpcListOpencodeModelsResponse = OpencodeModelsResponse
|
||||
|
||||
export class RpcGateway {
|
||||
constructor(
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"types": "./src/index.ts",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./apiTypes": "./src/apiTypes.ts",
|
||||
"./messages": "./src/messages.ts",
|
||||
"./buildInfo": "./src/buildInfo.ts",
|
||||
"./modes": "./src/modes.ts",
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
export type CommandResponse = {
|
||||
success: boolean
|
||||
stdout?: string
|
||||
stderr?: string
|
||||
exitCode?: number
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type GitCommandResponse = CommandResponse
|
||||
|
||||
export type FileReadResponse = {
|
||||
success: boolean
|
||||
content?: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type GeneratedImageResponse = {
|
||||
success: boolean
|
||||
content?: string
|
||||
mimeType?: string
|
||||
fileName?: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type UploadFileResponse = {
|
||||
success: boolean
|
||||
path?: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type DeleteUploadResponse = {
|
||||
success: boolean
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type DirectoryEntry = {
|
||||
name: string
|
||||
type: 'file' | 'directory' | 'other'
|
||||
size?: number
|
||||
modified?: number
|
||||
}
|
||||
|
||||
export type ListDirectoryResponse = {
|
||||
success: boolean
|
||||
entries?: DirectoryEntry[]
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type RpcListDirectoryResponse = ListDirectoryResponse
|
||||
|
||||
export type MachineDirectoryEntry = DirectoryEntry & {
|
||||
isGitRepo?: boolean
|
||||
}
|
||||
|
||||
export type MachineListDirectoryResponse = {
|
||||
success: boolean
|
||||
entries?: MachineDirectoryEntry[]
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type PathExistsResponse = {
|
||||
exists: Record<string, boolean>
|
||||
}
|
||||
|
||||
export type MachinePathsExistsResponse = PathExistsResponse
|
||||
|
||||
export type CodexModelSummary = {
|
||||
id: string
|
||||
displayName: string
|
||||
isDefault: boolean
|
||||
defaultReasoningEffort?: string | null
|
||||
supportedReasoningEfforts?: string[]
|
||||
}
|
||||
|
||||
export type CodexModelsResponse = {
|
||||
success: boolean
|
||||
models?: CodexModelSummary[]
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type ListCodexModelsResponse = CodexModelsResponse
|
||||
|
||||
export type OpencodeModelSummary = {
|
||||
modelId: string
|
||||
name?: string
|
||||
}
|
||||
|
||||
export type OpencodeModelsResponse = {
|
||||
success: boolean
|
||||
availableModels?: OpencodeModelSummary[]
|
||||
currentModelId?: string | null
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type ListOpencodeModelsResponse = OpencodeModelsResponse
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './apiTypes'
|
||||
export * from './messages'
|
||||
export * from './buildInfo'
|
||||
export * from './flavors'
|
||||
|
||||
+11
-9
@@ -2,17 +2,9 @@ import type {
|
||||
AttachmentMetadata,
|
||||
AuthResponse,
|
||||
CodexCollaborationMode,
|
||||
DeleteUploadResponse,
|
||||
ListDirectoryResponse,
|
||||
FileReadResponse,
|
||||
FileSearchResponse,
|
||||
GitCommandResponse,
|
||||
MachineListDirectoryResponse,
|
||||
MachinePathsExistsResponse,
|
||||
MachinesResponse,
|
||||
MessagesResponse,
|
||||
CodexModelsResponse,
|
||||
OpencodeModelsResponse,
|
||||
PermissionMode,
|
||||
PushSubscriptionPayload,
|
||||
PushUnsubscribePayload,
|
||||
@@ -20,11 +12,21 @@ import type {
|
||||
SlashCommandsResponse,
|
||||
SkillsResponse,
|
||||
SpawnResponse,
|
||||
UploadFileResponse,
|
||||
VisibilityPayload,
|
||||
SessionResponse,
|
||||
SessionsResponse
|
||||
} from '@/types/api'
|
||||
import type {
|
||||
CodexModelsResponse,
|
||||
DeleteUploadResponse,
|
||||
FileReadResponse,
|
||||
GitCommandResponse,
|
||||
ListDirectoryResponse,
|
||||
MachineListDirectoryResponse,
|
||||
MachinePathsExistsResponse,
|
||||
OpencodeModelsResponse,
|
||||
UploadFileResponse
|
||||
} from '@hapi/protocol/apiTypes'
|
||||
import type { AgentFlavor } from '@hapi/protocol'
|
||||
import type { CancelMessageResponse } from '@hapi/protocol/schemas'
|
||||
|
||||
|
||||
+18
-79
@@ -6,6 +6,24 @@ import type {
|
||||
WorktreeMetadata
|
||||
} from '@hapi/protocol/types'
|
||||
|
||||
export type {
|
||||
CodexModelsResponse,
|
||||
CodexModelSummary,
|
||||
CommandResponse,
|
||||
DeleteUploadResponse,
|
||||
DirectoryEntry,
|
||||
FileReadResponse,
|
||||
GitCommandResponse,
|
||||
ListDirectoryResponse,
|
||||
MachineDirectoryEntry,
|
||||
MachineListDirectoryResponse,
|
||||
MachinePathsExistsResponse,
|
||||
OpencodeModelsResponse,
|
||||
OpencodeModelSummary,
|
||||
PathExistsResponse,
|
||||
UploadFileResponse
|
||||
} from '@hapi/protocol/apiTypes'
|
||||
|
||||
export type {
|
||||
AgentState,
|
||||
AttachmentMetadata,
|
||||
@@ -100,34 +118,11 @@ export type MessagesResponse = {
|
||||
}
|
||||
|
||||
export type MachinesResponse = { machines: Machine[] }
|
||||
export type MachinePathsExistsResponse = { exists: Record<string, boolean> }
|
||||
|
||||
export type MachineDirectoryEntry = {
|
||||
name: string
|
||||
type: 'file' | 'directory' | 'other'
|
||||
size?: number
|
||||
modified?: number
|
||||
isGitRepo?: boolean
|
||||
}
|
||||
|
||||
export type MachineListDirectoryResponse = {
|
||||
success: boolean
|
||||
entries?: MachineDirectoryEntry[]
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type SpawnResponse =
|
||||
| { type: 'success'; sessionId: string }
|
||||
| { type: 'error'; message: string }
|
||||
|
||||
export type GitCommandResponse = {
|
||||
success: boolean
|
||||
stdout?: string
|
||||
stderr?: string
|
||||
exitCode?: number
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type FileSearchItem = {
|
||||
fileName: string
|
||||
filePath: string
|
||||
@@ -141,36 +136,6 @@ export type FileSearchResponse = {
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type DirectoryEntry = {
|
||||
name: string
|
||||
type: 'file' | 'directory' | 'other'
|
||||
size?: number
|
||||
modified?: number
|
||||
}
|
||||
|
||||
export type ListDirectoryResponse = {
|
||||
success: boolean
|
||||
entries?: DirectoryEntry[]
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type FileReadResponse = {
|
||||
success: boolean
|
||||
content?: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type UploadFileResponse = {
|
||||
success: boolean
|
||||
path?: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type DeleteUploadResponse = {
|
||||
success: boolean
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type GitFileStatus = {
|
||||
fileName: string
|
||||
filePath: string
|
||||
@@ -215,32 +180,6 @@ export type SkillsResponse = {
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type CodexModelSummary = {
|
||||
id: string
|
||||
displayName: string
|
||||
isDefault: boolean
|
||||
defaultReasoningEffort?: string | null
|
||||
supportedReasoningEfforts?: string[]
|
||||
}
|
||||
|
||||
export type CodexModelsResponse = {
|
||||
success: boolean
|
||||
models?: CodexModelSummary[]
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type OpencodeModelSummary = {
|
||||
modelId: string
|
||||
name?: string
|
||||
}
|
||||
|
||||
export type OpencodeModelsResponse = {
|
||||
success: boolean
|
||||
availableModels?: OpencodeModelSummary[]
|
||||
currentModelId?: string | null
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type PushSubscriptionKeys = {
|
||||
p256dh: string
|
||||
auth: string
|
||||
|
||||
Reference in New Issue
Block a user