This commit is contained in:
James Long 2026-04-13 16:54:11 -04:00
commit ba499fb405
28 changed files with 2830 additions and 406 deletions

View file

@ -35,6 +35,8 @@ import type {
ExperimentalWorkspaceListResponses,
ExperimentalWorkspaceRemoveErrors,
ExperimentalWorkspaceRemoveResponses,
ExperimentalWorkspaceSessionRestoreErrors,
ExperimentalWorkspaceSessionRestoreResponses,
ExperimentalWorkspaceStatusResponses,
FileListResponses,
FilePartInput,
@ -51,6 +53,11 @@ import type {
GlobalDisposeResponses,
GlobalEventResponses,
GlobalHealthResponses,
GlobalSyncEventSubscribeResponses,
GlobalSyncHistoryListErrors,
GlobalSyncHistoryListResponses,
GlobalSyncReplayErrors,
GlobalSyncReplayResponses,
GlobalUpgradeErrors,
GlobalUpgradeResponses,
InstanceDisposeResponses,
@ -236,6 +243,20 @@ class HeyApiRegistry<T> {
}
}
export class SyncEvent extends HeyApiClient {
/**
* Subscribe to global sync events
*
* Get global sync events
*/
public subscribe<ThrowOnError extends boolean = false>(options?: Options<never, ThrowOnError>) {
return (options?.client ?? this.client).sse.get<GlobalSyncEventSubscribeResponses, unknown, ThrowOnError>({
url: "/global/sync-event",
...options,
})
}
}
export class Config extends HeyApiClient {
/**
* Get global configuration
@ -274,6 +295,38 @@ export class Config extends HeyApiClient {
}
}
export class SyncHistory extends HeyApiClient {
/**
* List sync events
*
* List sync events for all aggregates. Keys are aggregate IDs the client already knows about, values are the last known sequence ID. Events with seq > value are returned for those aggregates. Aggregates not listed in the input get their full history.
*/
public list<ThrowOnError extends boolean = false>(
parameters?: {
body?: {
[key: string]: number
}
},
options?: Options<never, ThrowOnError>,
) {
const params = buildClientParams([parameters], [{ args: [{ key: "body", map: "body" }] }])
return (options?.client ?? this.client).get<
GlobalSyncHistoryListResponses,
GlobalSyncHistoryListErrors,
ThrowOnError
>({
url: "/sync/history",
...options,
...params,
headers: {
"Content-Type": "application/json",
...options?.headers,
...params.headers,
},
})
}
}
export class Global extends HeyApiClient {
/**
* Get health
@ -335,10 +388,63 @@ export class Global extends HeyApiClient {
})
}
/**
* Replay sync events
*
* Validate and replay a complete sync event history.
*/
public syncReplay<ThrowOnError extends boolean = false>(
parameters?: {
directory?: string
events?: Array<{
id: string
aggregateID: string
seq: number
type: string
data: {
[key: string]: unknown
}
}>
},
options?: Options<never, ThrowOnError>,
) {
const params = buildClientParams(
[parameters],
[
{
args: [
{ in: "body", key: "directory" },
{ in: "body", key: "events" },
],
},
],
)
return (options?.client ?? this.client).post<GlobalSyncReplayResponses, GlobalSyncReplayErrors, ThrowOnError>({
url: "/sync/replay",
...options,
...params,
headers: {
"Content-Type": "application/json",
...options?.headers,
...params.headers,
},
})
}
private _syncEvent?: SyncEvent
get syncEvent(): SyncEvent {
return (this._syncEvent ??= new SyncEvent({ client: this.client }))
}
private _config?: Config
get config(): Config {
return (this._config ??= new Config({ client: this.client }))
}
private _syncHistory?: SyncHistory
get syncHistory(): SyncHistory {
return (this._syncHistory ??= new SyncHistory({ client: this.client }))
}
}
export class Auth extends HeyApiClient {
@ -1243,6 +1349,49 @@ export class Workspace extends HeyApiClient {
})
}
/**
* Restore session into workspace
*
* Replay a session's sync events into the target workspace in batches.
*/
public sessionRestore<ThrowOnError extends boolean = false>(
parameters: {
id: string
directory?: string
workspace?: string
sessionID?: string
},
options?: Options<never, ThrowOnError>,
) {
const params = buildClientParams(
[parameters],
[
{
args: [
{ in: "path", key: "id" },
{ in: "query", key: "directory" },
{ in: "query", key: "workspace" },
{ in: "body", key: "sessionID" },
],
},
],
)
return (options?.client ?? this.client).post<
ExperimentalWorkspaceSessionRestoreResponses,
ExperimentalWorkspaceSessionRestoreErrors,
ThrowOnError
>({
url: "/experimental/workspace/{id}/session-restore",
...options,
...params,
headers: {
"Content-Type": "application/json",
...options?.headers,
...params.headers,
},
})
}
private _adaptor?: Adaptor
get adaptor(): Adaptor {
return (this._adaptor ??= new Adaptor({ client: this.client }))
@ -1743,7 +1892,6 @@ export class Session2 extends HeyApiClient {
directory?: string
workspace?: string
title?: string
permission?: PermissionRuleset
time?: {
archived?: number
}
@ -1759,7 +1907,6 @@ export class Session2 extends HeyApiClient {
{ in: "query", key: "directory" },
{ in: "query", key: "workspace" },
{ in: "body", key: "title" },
{ in: "body", key: "permission" },
{ in: "body", key: "time" },
],
},

View file

@ -33,13 +33,6 @@ export type EventProjectUpdated = {
properties: Project
}
export type EventServerInstanceDisposed = {
type: "server.instance.disposed"
properties: {
directory: string
}
}
export type EventInstallationUpdated = {
type: "installation.updated"
properties: {
@ -54,6 +47,13 @@ export type EventInstallationUpdateAvailable = {
}
}
export type EventServerInstanceDisposed = {
type: "server.instance.disposed"
properties: {
directory: string
}
}
export type EventServerConnected = {
type: "server.connected"
properties: {
@ -68,21 +68,6 @@ export type EventGlobalDisposed = {
}
}
export type EventFileEdited = {
type: "file.edited"
properties: {
file: string
}
}
export type EventFileWatcherUpdated = {
type: "file.watcher.updated"
properties: {
file: string
event: "add" | "change" | "unlink"
}
}
export type EventLspClientDiagnostics = {
type: "lsp.client.diagnostics"
properties: {
@ -230,133 +215,25 @@ export type EventSessionError = {
}
}
export type QuestionOption = {
/**
* Display text (1-5 words, concise)
*/
label: string
/**
* Explanation of choice
*/
description: string
}
export type QuestionInfo = {
/**
* Complete question
*/
question: string
/**
* Very short label (max 30 chars)
*/
header: string
/**
* Available choices
*/
options: Array<QuestionOption>
/**
* Allow selecting multiple choices
*/
multiple?: boolean
/**
* Allow typing a custom answer (default: true)
*/
custom?: boolean
}
export type QuestionRequest = {
id: string
sessionID: string
/**
* Questions to ask
*/
questions: Array<QuestionInfo>
tool?: {
messageID: string
callID: string
export type EventFileEdited = {
type: "file.edited"
properties: {
file: string
}
}
export type EventQuestionAsked = {
type: "question.asked"
properties: QuestionRequest
}
export type QuestionAnswer = Array<string>
export type EventQuestionReplied = {
type: "question.replied"
export type EventFileWatcherUpdated = {
type: "file.watcher.updated"
properties: {
sessionID: string
requestID: string
answers: Array<QuestionAnswer>
file: string
event: "add" | "change" | "unlink"
}
}
export type EventQuestionRejected = {
type: "question.rejected"
export type EventVcsBranchUpdated = {
type: "vcs.branch.updated"
properties: {
sessionID: string
requestID: string
}
}
export type Todo = {
/**
* Brief description of the task
*/
content: string
/**
* Current status of the task: pending, in_progress, completed, cancelled
*/
status: string
/**
* Priority level of the task: high, medium, low
*/
priority: string
}
export type EventTodoUpdated = {
type: "todo.updated"
properties: {
sessionID: string
todos: Array<Todo>
}
}
export type SessionStatus =
| {
type: "idle"
}
| {
type: "retry"
attempt: number
message: string
next: number
}
| {
type: "busy"
}
export type EventSessionStatus = {
type: "session.status"
properties: {
sessionID: string
status: SessionStatus
}
}
export type EventSessionIdle = {
type: "session.idle"
properties: {
sessionID: string
}
}
export type EventSessionCompacted = {
type: "session.compacted"
properties: {
sessionID: string
branch?: string
}
}
@ -439,28 +316,169 @@ export type EventCommandExecuted = {
}
}
export type EventVcsBranchUpdated = {
type: "vcs.branch.updated"
properties: {
branch?: string
}
}
export type EventWorktreeReady = {
type: "worktree.ready"
export type EventWorkspaceReady = {
type: "workspace.ready"
properties: {
name: string
branch: string
}
}
export type EventWorktreeFailed = {
type: "worktree.failed"
export type EventWorkspaceFailed = {
type: "workspace.failed"
properties: {
message: string
}
}
export type EventWorkspaceRestore = {
type: "workspace.restore"
properties: {
workspaceID: string
sessionID: string
total: number
step: number
}
}
export type EventWorkspaceStatus = {
type: "workspace.status"
properties: {
workspaceID: string
status: "connected" | "connecting" | "disconnected" | "error"
error?: string
}
}
export type QuestionOption = {
/**
* Display text (1-5 words, concise)
*/
label: string
/**
* Explanation of choice
*/
description: string
}
export type QuestionInfo = {
/**
* Complete question
*/
question: string
/**
* Very short label (max 30 chars)
*/
header: string
/**
* Available choices
*/
options: Array<QuestionOption>
/**
* Allow selecting multiple choices
*/
multiple?: boolean
/**
* Allow typing a custom answer (default: true)
*/
custom?: boolean
}
export type QuestionRequest = {
id: string
sessionID: string
/**
* Questions to ask
*/
questions: Array<QuestionInfo>
tool?: {
messageID: string
callID: string
}
}
export type EventQuestionAsked = {
type: "question.asked"
properties: QuestionRequest
}
export type QuestionAnswer = Array<string>
export type EventQuestionReplied = {
type: "question.replied"
properties: {
sessionID: string
requestID: string
answers: Array<QuestionAnswer>
}
}
export type EventQuestionRejected = {
type: "question.rejected"
properties: {
sessionID: string
requestID: string
}
}
export type SessionStatus =
| {
type: "idle"
}
| {
type: "retry"
attempt: number
message: string
next: number
}
| {
type: "busy"
}
export type EventSessionStatus = {
type: "session.status"
properties: {
sessionID: string
status: SessionStatus
}
}
export type EventSessionIdle = {
type: "session.idle"
properties: {
sessionID: string
}
}
export type EventSessionCompacted = {
type: "session.compacted"
properties: {
sessionID: string
}
}
export type Todo = {
/**
* Brief description of the task
*/
content: string
/**
* Current status of the task: pending, in_progress, completed, cancelled
*/
status: string
/**
* Priority level of the task: high, medium, low
*/
priority: string
}
export type EventTodoUpdated = {
type: "todo.updated"
properties: {
sessionID: string
todos: Array<Todo>
}
}
export type Pty = {
id: string
title: string
@ -500,29 +518,21 @@ export type EventPtyDeleted = {
}
}
export type EventWorkspaceReady = {
type: "workspace.ready"
export type EventWorktreeReady = {
type: "worktree.ready"
properties: {
name: string
branch: string
}
}
export type EventWorkspaceFailed = {
type: "workspace.failed"
export type EventWorktreeFailed = {
type: "worktree.failed"
properties: {
message: string
}
}
export type EventWorkspaceStatus = {
type: "workspace.status"
properties: {
workspaceID: string
status: "connected" | "connecting" | "disconnected" | "error"
error?: string
}
}
export type OutputFormatText = {
type: "text"
}
@ -971,12 +981,65 @@ export type EventSessionDeleted = {
}
}
export type Event =
| EventProjectUpdated
| EventInstallationUpdated
| EventInstallationUpdateAvailable
| EventServerInstanceDisposed
| EventServerConnected
| EventGlobalDisposed
| EventLspClientDiagnostics
| EventLspUpdated
| EventMessagePartDelta
| EventPermissionAsked
| EventPermissionReplied
| EventSessionDiff
| EventSessionError
| EventFileEdited
| EventFileWatcherUpdated
| EventVcsBranchUpdated
| EventTuiPromptAppend
| EventTuiCommandExecute
| EventTuiToastShow
| EventTuiSessionSelect
| EventMcpToolsChanged
| EventMcpBrowserOpenFailed
| EventCommandExecuted
| EventWorkspaceReady
| EventWorkspaceFailed
| EventWorkspaceRestore
| EventWorkspaceStatus
| EventQuestionAsked
| EventQuestionReplied
| EventQuestionRejected
| EventSessionStatus
| EventSessionIdle
| EventSessionCompacted
| EventTodoUpdated
| EventPtyCreated
| EventPtyUpdated
| EventPtyExited
| EventPtyDeleted
| EventWorktreeReady
| EventWorktreeFailed
| EventMessageUpdated
| EventMessageRemoved
| EventMessagePartUpdated
| EventMessagePartRemoved
| EventSessionCreated
| EventSessionUpdated
| EventSessionDeleted
export type GlobalEvent = {
directory: string
project?: string
workspace?: string
payload: Event
}
export type SyncEventMessageUpdated = {
type: "sync"
name: "message.updated.1"
id: string
seq: number
aggregateID: "sessionID"
type: "message.updated.1"
aggregate: "sessionID"
data: {
sessionID: string
info: Message
@ -984,11 +1047,8 @@ export type SyncEventMessageUpdated = {
}
export type SyncEventMessageRemoved = {
type: "sync"
name: "message.removed.1"
id: string
seq: number
aggregateID: "sessionID"
type: "message.removed.1"
aggregate: "sessionID"
data: {
sessionID: string
messageID: string
@ -996,11 +1056,8 @@ export type SyncEventMessageRemoved = {
}
export type SyncEventMessagePartUpdated = {
type: "sync"
name: "message.part.updated.1"
id: string
seq: number
aggregateID: "sessionID"
type: "message.part.updated.1"
aggregate: "sessionID"
data: {
sessionID: string
part: Part
@ -1009,11 +1066,8 @@ export type SyncEventMessagePartUpdated = {
}
export type SyncEventMessagePartRemoved = {
type: "sync"
name: "message.part.removed.1"
id: string
seq: number
aggregateID: "sessionID"
type: "message.part.removed.1"
aggregate: "sessionID"
data: {
sessionID: string
messageID: string
@ -1022,11 +1076,8 @@ export type SyncEventMessagePartRemoved = {
}
export type SyncEventSessionCreated = {
type: "sync"
name: "session.created.1"
id: string
seq: number
aggregateID: "sessionID"
type: "session.created.1"
aggregate: "sessionID"
data: {
sessionID: string
info: Session
@ -1034,11 +1085,8 @@ export type SyncEventSessionCreated = {
}
export type SyncEventSessionUpdated = {
type: "sync"
name: "session.updated.1"
id: string
seq: number
aggregateID: "sessionID"
type: "session.updated.1"
aggregate: "sessionID"
data: {
sessionID: string
info: {
@ -1077,75 +1125,16 @@ export type SyncEventSessionUpdated = {
}
export type SyncEventSessionDeleted = {
type: "sync"
name: "session.deleted.1"
id: string
seq: number
aggregateID: "sessionID"
type: "session.deleted.1"
aggregate: "sessionID"
data: {
sessionID: string
info: Session
}
}
export type GlobalEvent = {
directory: string
project?: string
workspace?: string
payload:
| EventProjectUpdated
| EventServerInstanceDisposed
| EventInstallationUpdated
| EventInstallationUpdateAvailable
| EventServerConnected
| EventGlobalDisposed
| EventFileEdited
| EventFileWatcherUpdated
| EventLspClientDiagnostics
| EventLspUpdated
| EventMessagePartDelta
| EventPermissionAsked
| EventPermissionReplied
| EventSessionDiff
| EventSessionError
| EventQuestionAsked
| EventQuestionReplied
| EventQuestionRejected
| EventTodoUpdated
| EventSessionStatus
| EventSessionIdle
| EventSessionCompacted
| EventTuiPromptAppend
| EventTuiCommandExecute
| EventTuiToastShow
| EventTuiSessionSelect
| EventMcpToolsChanged
| EventMcpBrowserOpenFailed
| EventCommandExecuted
| EventVcsBranchUpdated
| EventWorktreeReady
| EventWorktreeFailed
| EventPtyCreated
| EventPtyUpdated
| EventPtyExited
| EventPtyDeleted
| EventWorkspaceReady
| EventWorkspaceFailed
| EventWorkspaceStatus
| EventMessageUpdated
| EventMessageRemoved
| EventMessagePartUpdated
| EventMessagePartRemoved
| EventSessionCreated
| EventSessionUpdated
| EventSessionDeleted
| SyncEventMessageUpdated
| SyncEventMessageRemoved
| SyncEventMessagePartUpdated
| SyncEventMessagePartRemoved
| SyncEventSessionCreated
| SyncEventSessionUpdated
| SyncEventSessionDeleted
export type SyncEvent = {
payload: SyncEvent
}
/**
@ -2004,54 +1993,6 @@ export type File = {
status: "added" | "deleted" | "modified"
}
export type Event =
| EventProjectUpdated
| EventServerInstanceDisposed
| EventInstallationUpdated
| EventInstallationUpdateAvailable
| EventServerConnected
| EventGlobalDisposed
| EventFileEdited
| EventFileWatcherUpdated
| EventLspClientDiagnostics
| EventLspUpdated
| EventMessagePartDelta
| EventPermissionAsked
| EventPermissionReplied
| EventSessionDiff
| EventSessionError
| EventQuestionAsked
| EventQuestionReplied
| EventQuestionRejected
| EventTodoUpdated
| EventSessionStatus
| EventSessionIdle
| EventSessionCompacted
| EventTuiPromptAppend
| EventTuiCommandExecute
| EventTuiToastShow
| EventTuiSessionSelect
| EventMcpToolsChanged
| EventMcpBrowserOpenFailed
| EventCommandExecuted
| EventVcsBranchUpdated
| EventWorktreeReady
| EventWorktreeFailed
| EventPtyCreated
| EventPtyUpdated
| EventPtyExited
| EventPtyDeleted
| EventWorkspaceReady
| EventWorkspaceFailed
| EventWorkspaceStatus
| EventMessageUpdated
| EventMessageRemoved
| EventMessagePartUpdated
| EventMessagePartRemoved
| EventSessionCreated
| EventSessionUpdated
| EventSessionDeleted
export type McpStatusConnected = {
status: "connected"
}
@ -2183,6 +2124,23 @@ export type GlobalEventResponses = {
export type GlobalEventResponse = GlobalEventResponses[keyof GlobalEventResponses]
export type GlobalSyncEventSubscribeData = {
body?: never
path?: never
query?: never
url: "/global/sync-event"
}
export type GlobalSyncEventSubscribeResponses = {
/**
* Event stream
*/
200: SyncEvent
}
export type GlobalSyncEventSubscribeResponse =
GlobalSyncEventSubscribeResponses[keyof GlobalSyncEventSubscribeResponses]
export type GlobalConfigGetData = {
body?: never
path?: never
@ -2275,6 +2233,79 @@ export type GlobalUpgradeResponses = {
export type GlobalUpgradeResponse = GlobalUpgradeResponses[keyof GlobalUpgradeResponses]
export type GlobalSyncReplayData = {
body?: {
directory: string
events: Array<{
id: string
aggregateID: string
seq: number
type: string
data: {
[key: string]: unknown
}
}>
}
path?: never
query?: never
url: "/sync/replay"
}
export type GlobalSyncReplayErrors = {
/**
* Bad request
*/
400: BadRequestError
}
export type GlobalSyncReplayError = GlobalSyncReplayErrors[keyof GlobalSyncReplayErrors]
export type GlobalSyncReplayResponses = {
/**
* Replayed sync events
*/
200: {
sessionID: string
}
}
export type GlobalSyncReplayResponse = GlobalSyncReplayResponses[keyof GlobalSyncReplayResponses]
export type GlobalSyncHistoryListData = {
body?: {
[key: string]: number
}
path?: never
query?: never
url: "/sync/history"
}
export type GlobalSyncHistoryListErrors = {
/**
* Bad request
*/
400: BadRequestError
}
export type GlobalSyncHistoryListError = GlobalSyncHistoryListErrors[keyof GlobalSyncHistoryListErrors]
export type GlobalSyncHistoryListResponses = {
/**
* Sync events
*/
200: Array<{
id: string
aggregate_id: string
seq: number
type: string
data: {
[key: string]: unknown
}
}>
}
export type GlobalSyncHistoryListResponse = GlobalSyncHistoryListResponses[keyof GlobalSyncHistoryListResponses]
export type AuthRemoveData = {
body?: never
path: {
@ -3000,6 +3031,42 @@ export type ExperimentalWorkspaceRemoveResponses = {
export type ExperimentalWorkspaceRemoveResponse =
ExperimentalWorkspaceRemoveResponses[keyof ExperimentalWorkspaceRemoveResponses]
export type ExperimentalWorkspaceSessionRestoreData = {
body?: {
sessionID: string
}
path: {
id: string
}
query?: {
directory?: string
workspace?: string
}
url: "/experimental/workspace/{id}/session-restore"
}
export type ExperimentalWorkspaceSessionRestoreErrors = {
/**
* Bad request
*/
400: BadRequestError
}
export type ExperimentalWorkspaceSessionRestoreError =
ExperimentalWorkspaceSessionRestoreErrors[keyof ExperimentalWorkspaceSessionRestoreErrors]
export type ExperimentalWorkspaceSessionRestoreResponses = {
/**
* Session replay started
*/
200: {
total: number
}
}
export type ExperimentalWorkspaceSessionRestoreResponse =
ExperimentalWorkspaceSessionRestoreResponses[keyof ExperimentalWorkspaceSessionRestoreResponses]
export type WorktreeRemoveData = {
body?: WorktreeRemoveInput
path?: never
@ -3343,7 +3410,6 @@ export type SessionGetResponse = SessionGetResponses[keyof SessionGetResponses]
export type SessionUpdateData = {
body?: {
title?: string
permission?: PermissionRuleset
time?: {
archived?: number
}