fix(client): singularize generated api groups (#34534)

This commit is contained in:
Kit Langton 2026-06-29 21:07:01 -04:00 committed by GitHub
commit 6846542115
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 1913 additions and 557 deletions

View file

@ -14,7 +14,7 @@ export function runTui(transport: Transport, reload?: () => Promise<Transport>)
return Effect.gen(function* () {
const options = { baseUrl: transport.url, headers: transport.headers }
const api = OpenCode.make(options)
const directory = yield* Effect.tryPromise(() => api.files.list({ location: { directory: process.cwd() } })).pipe(
const directory = yield* Effect.tryPromise(() => api.file.list({ location: { directory: process.cwd() } })).pipe(
Effect.map((response) => response.location.directory),
Effect.catch(() =>
Effect.tryPromise(() => api.location.get()).pipe(Effect.map((response) => response.directory)),

View file

@ -19,24 +19,25 @@ export const ClientApi = makeDefaultApi({
export const groupNames = {
"server.health": "health",
"server.location": "location",
"server.agent": "agents",
"server.session": "sessions",
"server.message": "messages",
"server.model": "models",
"server.agent": "agent",
"server.session": "session",
"server.message": "message",
"server.model": "model",
"server.generate": "generate",
"server.provider": "providers",
"server.integration": "integrations",
"server.credential": "credentials",
"server.permission": "permissions",
"server.fs": "files",
"server.command": "commands",
"server.skill": "skills",
"server.event": "events",
"server.pty": "ptys",
"server.question": "questions",
"server.reference": "references",
"server.provider": "provider",
"server.integration": "integration",
"server.credential": "credential",
"server.permission": "permission",
"server.fs": "file",
"server.command": "command",
"server.skill": "skill",
"server.event": "event",
"server.pty": "pty",
"server.shell": "shell",
"server.question": "question",
"server.reference": "reference",
"server.project": "project",
"server.projectCopy": "projectCopies",
"server.projectCopy": "projectCopy",
} as const
export const endpointNames = {

View file

@ -805,25 +805,25 @@ const adaptGroup20 = (raw: RawClient["server.projectCopy"]) => ({
const adaptClient = (raw: RawClient) => ({
health: adaptGroup0(raw["server.health"]),
location: adaptGroup1(raw["server.location"]),
agents: adaptGroup2(raw["server.agent"]),
sessions: adaptGroup3(raw["server.session"]),
messages: adaptGroup4(raw["server.message"]),
models: adaptGroup5(raw["server.model"]),
agent: adaptGroup2(raw["server.agent"]),
session: adaptGroup3(raw["server.session"]),
message: adaptGroup4(raw["server.message"]),
model: adaptGroup5(raw["server.model"]),
generate: adaptGroup6(raw["server.generate"]),
providers: adaptGroup7(raw["server.provider"]),
integrations: adaptGroup8(raw["server.integration"]),
credentials: adaptGroup9(raw["server.credential"]),
provider: adaptGroup7(raw["server.provider"]),
integration: adaptGroup8(raw["server.integration"]),
credential: adaptGroup9(raw["server.credential"]),
project: adaptGroup10(raw["server.project"]),
permissions: adaptGroup11(raw["server.permission"]),
files: adaptGroup12(raw["server.fs"]),
commands: adaptGroup13(raw["server.command"]),
skills: adaptGroup14(raw["server.skill"]),
events: adaptGroup15(raw["server.event"]),
ptys: adaptGroup16(raw["server.pty"]),
"server.shell": adaptGroup17(raw["server.shell"]),
questions: adaptGroup18(raw["server.question"]),
references: adaptGroup19(raw["server.reference"]),
projectCopies: adaptGroup20(raw["server.projectCopy"]),
permission: adaptGroup11(raw["server.permission"]),
file: adaptGroup12(raw["server.fs"]),
command: adaptGroup13(raw["server.command"]),
skill: adaptGroup14(raw["server.skill"]),
event: adaptGroup15(raw["server.event"]),
pty: adaptGroup16(raw["server.pty"]),
shell: adaptGroup17(raw["server.shell"]),
question: adaptGroup18(raw["server.question"]),
reference: adaptGroup19(raw["server.reference"]),
projectCopy: adaptGroup20(raw["server.projectCopy"]),
})
export const make = (options?: { readonly baseUrl?: URL | string }) =>

View file

@ -2,138 +2,138 @@ import type {
HealthGetOutput,
LocationGetInput,
LocationGetOutput,
AgentsListInput,
AgentsListOutput,
SessionsListInput,
SessionsListOutput,
SessionsCreateInput,
SessionsCreateOutput,
SessionsActiveOutput,
SessionsGetInput,
SessionsGetOutput,
SessionsForkInput,
SessionsForkOutput,
SessionsSwitchAgentInput,
SessionsSwitchAgentOutput,
SessionsSwitchModelInput,
SessionsSwitchModelOutput,
SessionsRenameInput,
SessionsRenameOutput,
SessionsPromptInput,
SessionsPromptOutput,
SessionsCompactInput,
SessionsCompactOutput,
SessionsWaitInput,
SessionsWaitOutput,
SessionsStageInput,
SessionsStageOutput,
SessionsClearInput,
SessionsClearOutput,
SessionsCommitInput,
SessionsCommitOutput,
SessionsContextInput,
SessionsContextOutput,
SessionsHistoryInput,
SessionsHistoryOutput,
SessionsEventsInput,
SessionsEventsOutput,
SessionsInterruptInput,
SessionsInterruptOutput,
SessionsMessageInput,
SessionsMessageOutput,
MessagesListInput,
MessagesListOutput,
ModelsListInput,
ModelsListOutput,
AgentListInput,
AgentListOutput,
SessionListInput,
SessionListOutput,
SessionCreateInput,
SessionCreateOutput,
SessionActiveOutput,
SessionGetInput,
SessionGetOutput,
SessionForkInput,
SessionForkOutput,
SessionSwitchAgentInput,
SessionSwitchAgentOutput,
SessionSwitchModelInput,
SessionSwitchModelOutput,
SessionRenameInput,
SessionRenameOutput,
SessionPromptInput,
SessionPromptOutput,
SessionCompactInput,
SessionCompactOutput,
SessionWaitInput,
SessionWaitOutput,
SessionStageInput,
SessionStageOutput,
SessionClearInput,
SessionClearOutput,
SessionCommitInput,
SessionCommitOutput,
SessionContextInput,
SessionContextOutput,
SessionHistoryInput,
SessionHistoryOutput,
SessionEventsInput,
SessionEventsOutput,
SessionInterruptInput,
SessionInterruptOutput,
SessionMessageInput,
SessionMessageOutput,
MessageListInput,
MessageListOutput,
ModelListInput,
ModelListOutput,
GenerateTextInput,
GenerateTextOutput,
ProvidersListInput,
ProvidersListOutput,
ProvidersGetInput,
ProvidersGetOutput,
IntegrationsListInput,
IntegrationsListOutput,
IntegrationsGetInput,
IntegrationsGetOutput,
IntegrationsConnectKeyInput,
IntegrationsConnectKeyOutput,
IntegrationsConnectOauthInput,
IntegrationsConnectOauthOutput,
IntegrationsAttemptStatusInput,
IntegrationsAttemptStatusOutput,
IntegrationsAttemptCompleteInput,
IntegrationsAttemptCompleteOutput,
IntegrationsAttemptCancelInput,
IntegrationsAttemptCancelOutput,
CredentialsUpdateInput,
CredentialsUpdateOutput,
CredentialsRemoveInput,
CredentialsRemoveOutput,
ProviderListInput,
ProviderListOutput,
ProviderGetInput,
ProviderGetOutput,
IntegrationListInput,
IntegrationListOutput,
IntegrationGetInput,
IntegrationGetOutput,
IntegrationConnectKeyInput,
IntegrationConnectKeyOutput,
IntegrationConnectOauthInput,
IntegrationConnectOauthOutput,
IntegrationAttemptStatusInput,
IntegrationAttemptStatusOutput,
IntegrationAttemptCompleteInput,
IntegrationAttemptCompleteOutput,
IntegrationAttemptCancelInput,
IntegrationAttemptCancelOutput,
CredentialUpdateInput,
CredentialUpdateOutput,
CredentialRemoveInput,
CredentialRemoveOutput,
ProjectCurrentInput,
ProjectCurrentOutput,
ProjectDirectoriesInput,
ProjectDirectoriesOutput,
PermissionsListRequestsInput,
PermissionsListRequestsOutput,
PermissionsListSavedInput,
PermissionsListSavedOutput,
PermissionsRemoveSavedInput,
PermissionsRemoveSavedOutput,
PermissionsCreateInput,
PermissionsCreateOutput,
PermissionsListInput,
PermissionsListOutput,
PermissionsGetInput,
PermissionsGetOutput,
PermissionsReplyInput,
PermissionsReplyOutput,
FilesReadInput,
FilesReadOutput,
FilesListInput,
FilesListOutput,
FilesFindInput,
FilesFindOutput,
CommandsListInput,
CommandsListOutput,
SkillsListInput,
SkillsListOutput,
EventsSubscribeOutput,
PtysListInput,
PtysListOutput,
PtysCreateInput,
PtysCreateOutput,
PtysGetInput,
PtysGetOutput,
PtysUpdateInput,
PtysUpdateOutput,
PtysRemoveInput,
PtysRemoveOutput,
ServerShellListInput,
ServerShellListOutput,
ServerShellCreateInput,
ServerShellCreateOutput,
ServerShellGetInput,
ServerShellGetOutput,
ServerShellOutputInput,
ServerShellOutputOutput,
ServerShellRemoveInput,
ServerShellRemoveOutput,
QuestionsListRequestsInput,
QuestionsListRequestsOutput,
QuestionsListInput,
QuestionsListOutput,
QuestionsReplyInput,
QuestionsReplyOutput,
QuestionsRejectInput,
QuestionsRejectOutput,
ReferencesListInput,
ReferencesListOutput,
ProjectCopiesCreateInput,
ProjectCopiesCreateOutput,
ProjectCopiesRemoveInput,
ProjectCopiesRemoveOutput,
ProjectCopiesRefreshInput,
ProjectCopiesRefreshOutput,
PermissionListRequestsInput,
PermissionListRequestsOutput,
PermissionListSavedInput,
PermissionListSavedOutput,
PermissionRemoveSavedInput,
PermissionRemoveSavedOutput,
PermissionCreateInput,
PermissionCreateOutput,
PermissionListInput,
PermissionListOutput,
PermissionGetInput,
PermissionGetOutput,
PermissionReplyInput,
PermissionReplyOutput,
FileReadInput,
FileReadOutput,
FileListInput,
FileListOutput,
FileFindInput,
FileFindOutput,
CommandListInput,
CommandListOutput,
SkillListInput,
SkillListOutput,
EventSubscribeOutput,
PtyListInput,
PtyListOutput,
PtyCreateInput,
PtyCreateOutput,
PtyGetInput,
PtyGetOutput,
PtyUpdateInput,
PtyUpdateOutput,
PtyRemoveInput,
PtyRemoveOutput,
ShellListInput,
ShellListOutput,
ShellCreateInput,
ShellCreateOutput,
ShellGetInput,
ShellGetOutput,
ShellOutputInput,
ShellOutputOutput,
ShellRemoveInput,
ShellRemoveOutput,
QuestionListRequestsInput,
QuestionListRequestsOutput,
QuestionListInput,
QuestionListOutput,
QuestionReplyInput,
QuestionReplyOutput,
QuestionRejectInput,
QuestionRejectOutput,
ReferenceListInput,
ReferenceListOutput,
ProjectCopyCreateInput,
ProjectCopyCreateOutput,
ProjectCopyRemoveInput,
ProjectCopyRemoveOutput,
ProjectCopyRefreshInput,
ProjectCopyRefreshOutput,
} from "./types"
import { ClientError } from "./client-error"
@ -292,9 +292,9 @@ export function make(options: ClientOptions) {
requestOptions,
),
},
agents: {
list: (input?: AgentsListInput, requestOptions?: RequestOptions) =>
request<AgentsListOutput>(
agent: {
list: (input?: AgentListInput, requestOptions?: RequestOptions) =>
request<AgentListOutput>(
{
method: "GET",
path: `/api/agent`,
@ -306,9 +306,9 @@ export function make(options: ClientOptions) {
requestOptions,
),
},
sessions: {
list: (input?: SessionsListInput, requestOptions?: RequestOptions) =>
request<SessionsListOutput>(
session: {
list: (input?: SessionListInput, requestOptions?: RequestOptions) =>
request<SessionListOutput>(
{
method: "GET",
path: `/api/session`,
@ -328,8 +328,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
create: (input?: SessionsCreateInput, requestOptions?: RequestOptions) =>
request<{ readonly data: SessionsCreateOutput }>(
create: (input?: SessionCreateInput, requestOptions?: RequestOptions) =>
request<{ readonly data: SessionCreateOutput }>(
{
method: "POST",
path: `/api/session`,
@ -346,7 +346,7 @@ export function make(options: ClientOptions) {
requestOptions,
).then((value) => value.data),
active: (requestOptions?: RequestOptions) =>
request<{ readonly data: SessionsActiveOutput }>(
request<{ readonly data: SessionActiveOutput }>(
{
method: "GET",
path: `/api/session/active`,
@ -356,8 +356,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
).then((value) => value.data),
get: (input: SessionsGetInput, requestOptions?: RequestOptions) =>
request<{ readonly data: SessionsGetOutput }>(
get: (input: SessionGetInput, requestOptions?: RequestOptions) =>
request<{ readonly data: SessionGetOutput }>(
{
method: "GET",
path: `/api/session/${encodeURIComponent(input.sessionID)}`,
@ -367,8 +367,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
).then((value) => value.data),
fork: (input: SessionsForkInput, requestOptions?: RequestOptions) =>
request<{ readonly data: SessionsForkOutput }>(
fork: (input: SessionForkInput, requestOptions?: RequestOptions) =>
request<{ readonly data: SessionForkOutput }>(
{
method: "POST",
path: `/api/session/${encodeURIComponent(input.sessionID)}/fork`,
@ -379,8 +379,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
).then((value) => value.data),
switchAgent: (input: SessionsSwitchAgentInput, requestOptions?: RequestOptions) =>
request<SessionsSwitchAgentOutput>(
switchAgent: (input: SessionSwitchAgentInput, requestOptions?: RequestOptions) =>
request<SessionSwitchAgentOutput>(
{
method: "POST",
path: `/api/session/${encodeURIComponent(input.sessionID)}/agent`,
@ -391,8 +391,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
switchModel: (input: SessionsSwitchModelInput, requestOptions?: RequestOptions) =>
request<SessionsSwitchModelOutput>(
switchModel: (input: SessionSwitchModelInput, requestOptions?: RequestOptions) =>
request<SessionSwitchModelOutput>(
{
method: "POST",
path: `/api/session/${encodeURIComponent(input.sessionID)}/model`,
@ -403,8 +403,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
rename: (input: SessionsRenameInput, requestOptions?: RequestOptions) =>
request<SessionsRenameOutput>(
rename: (input: SessionRenameInput, requestOptions?: RequestOptions) =>
request<SessionRenameOutput>(
{
method: "POST",
path: `/api/session/${encodeURIComponent(input.sessionID)}/rename`,
@ -415,8 +415,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
prompt: (input: SessionsPromptInput, requestOptions?: RequestOptions) =>
request<{ readonly data: SessionsPromptOutput }>(
prompt: (input: SessionPromptInput, requestOptions?: RequestOptions) =>
request<{ readonly data: SessionPromptOutput }>(
{
method: "POST",
path: `/api/session/${encodeURIComponent(input.sessionID)}/prompt`,
@ -427,8 +427,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
).then((value) => value.data),
compact: (input: SessionsCompactInput, requestOptions?: RequestOptions) =>
request<SessionsCompactOutput>(
compact: (input: SessionCompactInput, requestOptions?: RequestOptions) =>
request<SessionCompactOutput>(
{
method: "POST",
path: `/api/session/${encodeURIComponent(input.sessionID)}/compact`,
@ -438,8 +438,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
wait: (input: SessionsWaitInput, requestOptions?: RequestOptions) =>
request<SessionsWaitOutput>(
wait: (input: SessionWaitInput, requestOptions?: RequestOptions) =>
request<SessionWaitOutput>(
{
method: "POST",
path: `/api/session/${encodeURIComponent(input.sessionID)}/wait`,
@ -449,8 +449,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
stage: (input: SessionsStageInput, requestOptions?: RequestOptions) =>
request<{ readonly data: SessionsStageOutput }>(
stage: (input: SessionStageInput, requestOptions?: RequestOptions) =>
request<{ readonly data: SessionStageOutput }>(
{
method: "POST",
path: `/api/session/${encodeURIComponent(input.sessionID)}/revert/stage`,
@ -461,8 +461,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
).then((value) => value.data),
clear: (input: SessionsClearInput, requestOptions?: RequestOptions) =>
request<SessionsClearOutput>(
clear: (input: SessionClearInput, requestOptions?: RequestOptions) =>
request<SessionClearOutput>(
{
method: "POST",
path: `/api/session/${encodeURIComponent(input.sessionID)}/revert/clear`,
@ -472,8 +472,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
commit: (input: SessionsCommitInput, requestOptions?: RequestOptions) =>
request<SessionsCommitOutput>(
commit: (input: SessionCommitInput, requestOptions?: RequestOptions) =>
request<SessionCommitOutput>(
{
method: "POST",
path: `/api/session/${encodeURIComponent(input.sessionID)}/revert/commit`,
@ -483,8 +483,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
context: (input: SessionsContextInput, requestOptions?: RequestOptions) =>
request<{ readonly data: SessionsContextOutput }>(
context: (input: SessionContextInput, requestOptions?: RequestOptions) =>
request<{ readonly data: SessionContextOutput }>(
{
method: "GET",
path: `/api/session/${encodeURIComponent(input.sessionID)}/context`,
@ -494,8 +494,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
).then((value) => value.data),
history: (input: SessionsHistoryInput, requestOptions?: RequestOptions) =>
request<SessionsHistoryOutput>(
history: (input: SessionHistoryInput, requestOptions?: RequestOptions) =>
request<SessionHistoryOutput>(
{
method: "GET",
path: `/api/session/${encodeURIComponent(input.sessionID)}/history`,
@ -506,8 +506,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
events: (input: SessionsEventsInput, requestOptions?: RequestOptions): AsyncIterable<SessionsEventsOutput> =>
sse<SessionsEventsOutput>(
events: (input: SessionEventsInput, requestOptions?: RequestOptions): AsyncIterable<SessionEventsOutput> =>
sse<SessionEventsOutput>(
{
method: "GET",
path: `/api/session/${encodeURIComponent(input.sessionID)}/event`,
@ -518,8 +518,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
interrupt: (input: SessionsInterruptInput, requestOptions?: RequestOptions) =>
request<SessionsInterruptOutput>(
interrupt: (input: SessionInterruptInput, requestOptions?: RequestOptions) =>
request<SessionInterruptOutput>(
{
method: "POST",
path: `/api/session/${encodeURIComponent(input.sessionID)}/interrupt`,
@ -529,8 +529,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
message: (input: SessionsMessageInput, requestOptions?: RequestOptions) =>
request<{ readonly data: SessionsMessageOutput }>(
message: (input: SessionMessageInput, requestOptions?: RequestOptions) =>
request<{ readonly data: SessionMessageOutput }>(
{
method: "GET",
path: `/api/session/${encodeURIComponent(input.sessionID)}/message/${encodeURIComponent(input.messageID)}`,
@ -541,9 +541,9 @@ export function make(options: ClientOptions) {
requestOptions,
).then((value) => value.data),
},
messages: {
list: (input: MessagesListInput, requestOptions?: RequestOptions) =>
request<MessagesListOutput>(
message: {
list: (input: MessageListInput, requestOptions?: RequestOptions) =>
request<MessageListOutput>(
{
method: "GET",
path: `/api/session/${encodeURIComponent(input.sessionID)}/message`,
@ -555,9 +555,9 @@ export function make(options: ClientOptions) {
requestOptions,
),
},
models: {
list: (input?: ModelsListInput, requestOptions?: RequestOptions) =>
request<ModelsListOutput>(
model: {
list: (input?: ModelListInput, requestOptions?: RequestOptions) =>
request<ModelListOutput>(
{
method: "GET",
path: `/api/model`,
@ -584,9 +584,9 @@ export function make(options: ClientOptions) {
requestOptions,
).then((value) => value.data),
},
providers: {
list: (input?: ProvidersListInput, requestOptions?: RequestOptions) =>
request<ProvidersListOutput>(
provider: {
list: (input?: ProviderListInput, requestOptions?: RequestOptions) =>
request<ProviderListOutput>(
{
method: "GET",
path: `/api/provider`,
@ -597,8 +597,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
get: (input: ProvidersGetInput, requestOptions?: RequestOptions) =>
request<ProvidersGetOutput>(
get: (input: ProviderGetInput, requestOptions?: RequestOptions) =>
request<ProviderGetOutput>(
{
method: "GET",
path: `/api/provider/${encodeURIComponent(input.providerID)}`,
@ -610,9 +610,9 @@ export function make(options: ClientOptions) {
requestOptions,
),
},
integrations: {
list: (input?: IntegrationsListInput, requestOptions?: RequestOptions) =>
request<IntegrationsListOutput>(
integration: {
list: (input?: IntegrationListInput, requestOptions?: RequestOptions) =>
request<IntegrationListOutput>(
{
method: "GET",
path: `/api/integration`,
@ -623,8 +623,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
get: (input: IntegrationsGetInput, requestOptions?: RequestOptions) =>
request<IntegrationsGetOutput>(
get: (input: IntegrationGetInput, requestOptions?: RequestOptions) =>
request<IntegrationGetOutput>(
{
method: "GET",
path: `/api/integration/${encodeURIComponent(input.integrationID)}`,
@ -635,8 +635,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
connectKey: (input: IntegrationsConnectKeyInput, requestOptions?: RequestOptions) =>
request<IntegrationsConnectKeyOutput>(
connectKey: (input: IntegrationConnectKeyInput, requestOptions?: RequestOptions) =>
request<IntegrationConnectKeyOutput>(
{
method: "POST",
path: `/api/integration/${encodeURIComponent(input.integrationID)}/connect/key`,
@ -648,8 +648,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
connectOauth: (input: IntegrationsConnectOauthInput, requestOptions?: RequestOptions) =>
request<IntegrationsConnectOauthOutput>(
connectOauth: (input: IntegrationConnectOauthInput, requestOptions?: RequestOptions) =>
request<IntegrationConnectOauthOutput>(
{
method: "POST",
path: `/api/integration/${encodeURIComponent(input.integrationID)}/connect/oauth`,
@ -661,8 +661,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
attemptStatus: (input: IntegrationsAttemptStatusInput, requestOptions?: RequestOptions) =>
request<IntegrationsAttemptStatusOutput>(
attemptStatus: (input: IntegrationAttemptStatusInput, requestOptions?: RequestOptions) =>
request<IntegrationAttemptStatusOutput>(
{
method: "GET",
path: `/api/integration/attempt/${encodeURIComponent(input.attemptID)}`,
@ -673,8 +673,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
attemptComplete: (input: IntegrationsAttemptCompleteInput, requestOptions?: RequestOptions) =>
request<IntegrationsAttemptCompleteOutput>(
attemptComplete: (input: IntegrationAttemptCompleteInput, requestOptions?: RequestOptions) =>
request<IntegrationAttemptCompleteOutput>(
{
method: "POST",
path: `/api/integration/attempt/${encodeURIComponent(input.attemptID)}/complete`,
@ -686,8 +686,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
attemptCancel: (input: IntegrationsAttemptCancelInput, requestOptions?: RequestOptions) =>
request<IntegrationsAttemptCancelOutput>(
attemptCancel: (input: IntegrationAttemptCancelInput, requestOptions?: RequestOptions) =>
request<IntegrationAttemptCancelOutput>(
{
method: "DELETE",
path: `/api/integration/attempt/${encodeURIComponent(input.attemptID)}`,
@ -699,9 +699,9 @@ export function make(options: ClientOptions) {
requestOptions,
),
},
credentials: {
update: (input: CredentialsUpdateInput, requestOptions?: RequestOptions) =>
request<CredentialsUpdateOutput>(
credential: {
update: (input: CredentialUpdateInput, requestOptions?: RequestOptions) =>
request<CredentialUpdateOutput>(
{
method: "PATCH",
path: `/api/credential/${encodeURIComponent(input.credentialID)}`,
@ -713,8 +713,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
remove: (input: CredentialsRemoveInput, requestOptions?: RequestOptions) =>
request<CredentialsRemoveOutput>(
remove: (input: CredentialRemoveInput, requestOptions?: RequestOptions) =>
request<CredentialRemoveOutput>(
{
method: "DELETE",
path: `/api/credential/${encodeURIComponent(input.credentialID)}`,
@ -752,9 +752,9 @@ export function make(options: ClientOptions) {
requestOptions,
),
},
permissions: {
listRequests: (input?: PermissionsListRequestsInput, requestOptions?: RequestOptions) =>
request<PermissionsListRequestsOutput>(
permission: {
listRequests: (input?: PermissionListRequestsInput, requestOptions?: RequestOptions) =>
request<PermissionListRequestsOutput>(
{
method: "GET",
path: `/api/permission/request`,
@ -765,8 +765,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
listSaved: (input?: PermissionsListSavedInput, requestOptions?: RequestOptions) =>
request<{ readonly data: PermissionsListSavedOutput }>(
listSaved: (input?: PermissionListSavedInput, requestOptions?: RequestOptions) =>
request<{ readonly data: PermissionListSavedOutput }>(
{
method: "GET",
path: `/api/permission/saved`,
@ -777,8 +777,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
).then((value) => value.data),
removeSaved: (input: PermissionsRemoveSavedInput, requestOptions?: RequestOptions) =>
request<PermissionsRemoveSavedOutput>(
removeSaved: (input: PermissionRemoveSavedInput, requestOptions?: RequestOptions) =>
request<PermissionRemoveSavedOutput>(
{
method: "DELETE",
path: `/api/permission/saved/${encodeURIComponent(input.id)}`,
@ -788,8 +788,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
create: (input: PermissionsCreateInput, requestOptions?: RequestOptions) =>
request<{ readonly data: PermissionsCreateOutput }>(
create: (input: PermissionCreateInput, requestOptions?: RequestOptions) =>
request<{ readonly data: PermissionCreateOutput }>(
{
method: "POST",
path: `/api/session/${encodeURIComponent(input.sessionID)}/permission`,
@ -808,8 +808,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
).then((value) => value.data),
list: (input: PermissionsListInput, requestOptions?: RequestOptions) =>
request<{ readonly data: PermissionsListOutput }>(
list: (input: PermissionListInput, requestOptions?: RequestOptions) =>
request<{ readonly data: PermissionListOutput }>(
{
method: "GET",
path: `/api/session/${encodeURIComponent(input.sessionID)}/permission`,
@ -819,8 +819,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
).then((value) => value.data),
get: (input: PermissionsGetInput, requestOptions?: RequestOptions) =>
request<{ readonly data: PermissionsGetOutput }>(
get: (input: PermissionGetInput, requestOptions?: RequestOptions) =>
request<{ readonly data: PermissionGetOutput }>(
{
method: "GET",
path: `/api/session/${encodeURIComponent(input.sessionID)}/permission/${encodeURIComponent(input.requestID)}`,
@ -830,8 +830,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
).then((value) => value.data),
reply: (input: PermissionsReplyInput, requestOptions?: RequestOptions) =>
request<PermissionsReplyOutput>(
reply: (input: PermissionReplyInput, requestOptions?: RequestOptions) =>
request<PermissionReplyOutput>(
{
method: "POST",
path: `/api/session/${encodeURIComponent(input.sessionID)}/permission/${encodeURIComponent(input.requestID)}/reply`,
@ -843,9 +843,9 @@ export function make(options: ClientOptions) {
requestOptions,
),
},
files: {
read: (input: FilesReadInput, requestOptions?: RequestOptions) =>
request<FilesReadOutput>(
file: {
read: (input: FileReadInput, requestOptions?: RequestOptions) =>
request<FileReadOutput>(
{
method: "GET",
path: `/api/fs/read/${encodePath(input.path)}`,
@ -857,8 +857,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
list: (input?: FilesListInput, requestOptions?: RequestOptions) =>
request<FilesListOutput>(
list: (input?: FileListInput, requestOptions?: RequestOptions) =>
request<FileListOutput>(
{
method: "GET",
path: `/api/fs/list`,
@ -869,8 +869,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
find: (input: FilesFindInput, requestOptions?: RequestOptions) =>
request<FilesFindOutput>(
find: (input: FileFindInput, requestOptions?: RequestOptions) =>
request<FileFindOutput>(
{
method: "GET",
path: `/api/fs/find`,
@ -882,9 +882,9 @@ export function make(options: ClientOptions) {
requestOptions,
),
},
commands: {
list: (input?: CommandsListInput, requestOptions?: RequestOptions) =>
request<CommandsListOutput>(
command: {
list: (input?: CommandListInput, requestOptions?: RequestOptions) =>
request<CommandListOutput>(
{
method: "GET",
path: `/api/command`,
@ -896,9 +896,9 @@ export function make(options: ClientOptions) {
requestOptions,
),
},
skills: {
list: (input?: SkillsListInput, requestOptions?: RequestOptions) =>
request<SkillsListOutput>(
skill: {
list: (input?: SkillListInput, requestOptions?: RequestOptions) =>
request<SkillListOutput>(
{
method: "GET",
path: `/api/skill`,
@ -910,16 +910,16 @@ export function make(options: ClientOptions) {
requestOptions,
),
},
events: {
subscribe: (requestOptions?: RequestOptions): AsyncIterable<EventsSubscribeOutput> =>
sse<EventsSubscribeOutput>(
event: {
subscribe: (requestOptions?: RequestOptions): AsyncIterable<EventSubscribeOutput> =>
sse<EventSubscribeOutput>(
{ method: "GET", path: `/api/event`, successStatus: 200, declaredStatuses: [401, 400], empty: false },
requestOptions,
),
},
ptys: {
list: (input?: PtysListInput, requestOptions?: RequestOptions) =>
request<PtysListOutput>(
pty: {
list: (input?: PtyListInput, requestOptions?: RequestOptions) =>
request<PtyListOutput>(
{
method: "GET",
path: `/api/pty`,
@ -930,8 +930,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
create: (input?: PtysCreateInput, requestOptions?: RequestOptions) =>
request<PtysCreateOutput>(
create: (input?: PtyCreateInput, requestOptions?: RequestOptions) =>
request<PtyCreateOutput>(
{
method: "POST",
path: `/api/pty`,
@ -949,8 +949,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
get: (input: PtysGetInput, requestOptions?: RequestOptions) =>
request<PtysGetOutput>(
get: (input: PtyGetInput, requestOptions?: RequestOptions) =>
request<PtyGetOutput>(
{
method: "GET",
path: `/api/pty/${encodeURIComponent(input.ptyID)}`,
@ -961,8 +961,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
update: (input: PtysUpdateInput, requestOptions?: RequestOptions) =>
request<PtysUpdateOutput>(
update: (input: PtyUpdateInput, requestOptions?: RequestOptions) =>
request<PtyUpdateOutput>(
{
method: "PUT",
path: `/api/pty/${encodeURIComponent(input.ptyID)}`,
@ -974,8 +974,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
remove: (input: PtysRemoveInput, requestOptions?: RequestOptions) =>
request<PtysRemoveOutput>(
remove: (input: PtyRemoveInput, requestOptions?: RequestOptions) =>
request<PtyRemoveOutput>(
{
method: "DELETE",
path: `/api/pty/${encodeURIComponent(input.ptyID)}`,
@ -987,9 +987,9 @@ export function make(options: ClientOptions) {
requestOptions,
),
},
"server.shell": {
list: (input?: ServerShellListInput, requestOptions?: RequestOptions) =>
request<ServerShellListOutput>(
shell: {
list: (input?: ShellListInput, requestOptions?: RequestOptions) =>
request<ShellListOutput>(
{
method: "GET",
path: `/api/shell`,
@ -1000,8 +1000,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
create: (input: ServerShellCreateInput, requestOptions?: RequestOptions) =>
request<ServerShellCreateOutput>(
create: (input: ShellCreateInput, requestOptions?: RequestOptions) =>
request<ShellCreateOutput>(
{
method: "POST",
path: `/api/shell`,
@ -1018,8 +1018,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
get: (input: ServerShellGetInput, requestOptions?: RequestOptions) =>
request<ServerShellGetOutput>(
get: (input: ShellGetInput, requestOptions?: RequestOptions) =>
request<ShellGetOutput>(
{
method: "GET",
path: `/api/shell/${encodeURIComponent(input.id)}`,
@ -1030,8 +1030,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
output: (input: ServerShellOutputInput, requestOptions?: RequestOptions) =>
request<ServerShellOutputOutput>(
output: (input: ShellOutputInput, requestOptions?: RequestOptions) =>
request<ShellOutputOutput>(
{
method: "GET",
path: `/api/shell/${encodeURIComponent(input.id)}/output`,
@ -1042,8 +1042,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
remove: (input: ServerShellRemoveInput, requestOptions?: RequestOptions) =>
request<ServerShellRemoveOutput>(
remove: (input: ShellRemoveInput, requestOptions?: RequestOptions) =>
request<ShellRemoveOutput>(
{
method: "DELETE",
path: `/api/shell/${encodeURIComponent(input.id)}`,
@ -1055,9 +1055,9 @@ export function make(options: ClientOptions) {
requestOptions,
),
},
questions: {
listRequests: (input?: QuestionsListRequestsInput, requestOptions?: RequestOptions) =>
request<QuestionsListRequestsOutput>(
question: {
listRequests: (input?: QuestionListRequestsInput, requestOptions?: RequestOptions) =>
request<QuestionListRequestsOutput>(
{
method: "GET",
path: `/api/question/request`,
@ -1068,8 +1068,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
list: (input: QuestionsListInput, requestOptions?: RequestOptions) =>
request<{ readonly data: QuestionsListOutput }>(
list: (input: QuestionListInput, requestOptions?: RequestOptions) =>
request<{ readonly data: QuestionListOutput }>(
{
method: "GET",
path: `/api/session/${encodeURIComponent(input.sessionID)}/question`,
@ -1079,8 +1079,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
).then((value) => value.data),
reply: (input: QuestionsReplyInput, requestOptions?: RequestOptions) =>
request<QuestionsReplyOutput>(
reply: (input: QuestionReplyInput, requestOptions?: RequestOptions) =>
request<QuestionReplyOutput>(
{
method: "POST",
path: `/api/session/${encodeURIComponent(input.sessionID)}/question/${encodeURIComponent(input.requestID)}/reply`,
@ -1091,8 +1091,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
reject: (input: QuestionsRejectInput, requestOptions?: RequestOptions) =>
request<QuestionsRejectOutput>(
reject: (input: QuestionRejectInput, requestOptions?: RequestOptions) =>
request<QuestionRejectOutput>(
{
method: "POST",
path: `/api/session/${encodeURIComponent(input.sessionID)}/question/${encodeURIComponent(input.requestID)}/reject`,
@ -1103,9 +1103,9 @@ export function make(options: ClientOptions) {
requestOptions,
),
},
references: {
list: (input?: ReferencesListInput, requestOptions?: RequestOptions) =>
request<ReferencesListOutput>(
reference: {
list: (input?: ReferenceListInput, requestOptions?: RequestOptions) =>
request<ReferenceListOutput>(
{
method: "GET",
path: `/api/reference`,
@ -1117,9 +1117,9 @@ export function make(options: ClientOptions) {
requestOptions,
),
},
projectCopies: {
create: (input: ProjectCopiesCreateInput, requestOptions?: RequestOptions) =>
request<ProjectCopiesCreateOutput>(
projectCopy: {
create: (input: ProjectCopyCreateInput, requestOptions?: RequestOptions) =>
request<ProjectCopyCreateOutput>(
{
method: "POST",
path: `/experimental/project/${encodeURIComponent(input.projectID)}/copy`,
@ -1131,8 +1131,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
remove: (input: ProjectCopiesRemoveInput, requestOptions?: RequestOptions) =>
request<ProjectCopiesRemoveOutput>(
remove: (input: ProjectCopyRemoveInput, requestOptions?: RequestOptions) =>
request<ProjectCopyRemoveOutput>(
{
method: "DELETE",
path: `/experimental/project/${encodeURIComponent(input.projectID)}/copy`,
@ -1144,8 +1144,8 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
refresh: (input: ProjectCopiesRefreshInput, requestOptions?: RequestOptions) =>
request<ProjectCopiesRefreshOutput>(
refresh: (input: ProjectCopyRefreshInput, requestOptions?: RequestOptions) =>
request<ProjectCopyRefreshOutput>(
{
method: "POST",
path: `/experimental/project/${encodeURIComponent(input.projectID)}/copy/refresh`,

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,3 @@
export * from "./generated/index"
export type { EventsSubscribeOutput as OpenCodeEvent } from "./generated/types"
export type { EventSubscribeOutput as OpenCodeEvent } from "./generated/types"
export type OpenCodeClient = ReturnType<typeof import("./generated/client").make>

View file

@ -3,19 +3,19 @@ import { DateTime, Effect, Stream } from "effect"
import { HttpClient, HttpClientResponse } from "effect/unstable/http"
import { AbsolutePath, Agent, Location, Model, OpenCode, Prompt, Session, SessionMessage } from "../src/effect"
test("sessions.get returns the decoded Effect projection", async () => {
test("session.get returns the decoded Effect projection", async () => {
const httpClient = HttpClient.make((request) =>
Effect.succeed(HttpClientResponse.fromWeb(request, Response.json(session))),
)
const result = await Effect.gen(function* () {
const client = yield* OpenCode.make({ baseUrl: "http://localhost:3000" })
return yield* client.sessions.get({ sessionID: Session.ID.make("ses_test") })
return yield* client.session.get({ sessionID: Session.ID.make("ses_test") })
}).pipe(Effect.provideService(HttpClient.HttpClient, httpClient), Effect.runPromise)
expect(DateTime.toEpochMillis(result.time.created)).toBe(1_717_171_717_000)
})
test("events.subscribe exposes and decodes the native Effect event stream", async () => {
test("event.subscribe exposes and decodes the native Effect event stream", async () => {
const httpClient = HttpClient.make((request) =>
Effect.succeed(
HttpClientResponse.fromWeb(
@ -30,7 +30,7 @@ test("events.subscribe exposes and decodes the native Effect event stream", asyn
)
const events = await Effect.gen(function* () {
const client = yield* OpenCode.make({ baseUrl: "http://localhost:3000" })
return yield* client.events.subscribe().pipe(Stream.runCollect)
return yield* client.event.subscribe().pipe(Stream.runCollect)
}).pipe(Effect.provideService(HttpClient.HttpClient, httpClient), Effect.runPromise)
expect(Array.from(events).map((event) => event.type)).toEqual(["server.connected", "session.next.model.switched"])
@ -40,7 +40,7 @@ test("events.subscribe exposes and decodes the native Effect event stream", asyn
expect(durable.durable).toEqual({ aggregateID: "ses_test", seq: 1, version: 1 })
})
test("events.subscribe terminates on Effect protocol decode failures", async () => {
test("event.subscribe terminates on Effect protocol decode failures", async () => {
const httpClient = HttpClient.make((request) =>
Effect.succeed(
HttpClientResponse.fromWeb(
@ -53,7 +53,7 @@ test("events.subscribe terminates on Effect protocol decode failures", async ()
)
const error = await Effect.gen(function* () {
const client = yield* OpenCode.make({ baseUrl: "http://localhost:3000" })
return yield* client.events.subscribe().pipe(Stream.runCollect, Effect.flip)
return yield* client.event.subscribe().pipe(Stream.runCollect, Effect.flip)
}).pipe(Effect.provideService(HttpClient.HttpClient, httpClient), Effect.runPromise)
expect(error._tag).toBe("ClientError")
@ -112,41 +112,41 @@ test("session methods retain decoded Effect inputs and outputs", async () => {
})
const result = await Effect.gen(function* () {
const client = yield* OpenCode.make({ baseUrl: "http://localhost:3000" })
const page = yield* client.sessions.list({ limit: 10 })
const active = yield* client.sessions.active()
const created = yield* client.sessions.create({
const page = yield* client.session.list({ limit: 10 })
const active = yield* client.session.active()
const created = yield* client.session.create({
location: Location.Ref.make({ directory: AbsolutePath.make("/tmp/project") }),
})
yield* client.sessions.switchAgent({ sessionID: Session.ID.make("ses_test"), agent: Agent.ID.make("build") })
yield* client.sessions.switchModel({
yield* client.session.switchAgent({ sessionID: Session.ID.make("ses_test"), agent: Agent.ID.make("build") })
yield* client.session.switchModel({
sessionID: Session.ID.make("ses_test"),
model: Model.Ref.make({ id: "claude", providerID: "anthropic" }),
})
const admitted = yield* client.sessions.prompt({
const admitted = yield* client.session.prompt({
sessionID: Session.ID.make("ses_test"),
prompt: Prompt.make({ text: "Hello" }),
resume: false,
})
yield* client.sessions.compact({ sessionID: Session.ID.make("ses_test") })
yield* client.sessions.wait({ sessionID: Session.ID.make("ses_test") })
const context = yield* client.sessions.context({ sessionID: Session.ID.make("ses_test") })
const history = yield* client.sessions.history({
yield* client.session.compact({ sessionID: Session.ID.make("ses_test") })
yield* client.session.wait({ sessionID: Session.ID.make("ses_test") })
const context = yield* client.session.context({ sessionID: Session.ID.make("ses_test") })
const history = yield* client.session.history({
sessionID: Session.ID.make("ses_test"),
after: 0,
limit: 1,
})
const historyNext = history.hasMore
? yield* client.sessions.history({
? yield* client.session.history({
sessionID: Session.ID.make("ses_test"),
after: history.data.at(-1)?.durable?.seq,
limit: 2,
})
: undefined
const events = yield* client.sessions
const events = yield* client.session
.events({ sessionID: Session.ID.make("ses_test"), after: 0 })
.pipe(Stream.runCollect)
yield* client.sessions.interrupt({ sessionID: Session.ID.make("ses_test") })
const message = yield* client.sessions.message({
yield* client.session.interrupt({ sessionID: Session.ID.make("ses_test") })
const message = yield* client.session.message({
sessionID: Session.ID.make("ses_test"),
messageID: SessionMessage.ID.make("msg_model"),
})
@ -171,7 +171,7 @@ test("session methods retain decoded Effect inputs and outputs", async () => {
expect(result.message).toEqual(expect.objectContaining({ id: "msg_model", type: "model-switched" }))
})
test("sessions.history retains the typed SessionNotFoundError", async () => {
test("session.history retains the typed SessionNotFoundError", async () => {
const httpClient = HttpClient.make((request) =>
Effect.succeed(
HttpClientResponse.fromWeb(
@ -185,7 +185,7 @@ test("sessions.history retains the typed SessionNotFoundError", async () => {
)
const error = await Effect.gen(function* () {
const client = yield* OpenCode.make({ baseUrl: "http://localhost:3000" })
return yield* client.sessions
return yield* client.session
.history({
sessionID: Session.ID.make("ses_missing"),
})

View file

@ -7,28 +7,28 @@ test("exposes every standard HTTP API group", () => {
expect(Object.keys(client)).toEqual([
"health",
"location",
"agents",
"sessions",
"messages",
"models",
"agent",
"session",
"message",
"model",
"generate",
"providers",
"integrations",
"credentials",
"provider",
"integration",
"credential",
"project",
"permissions",
"files",
"commands",
"skills",
"events",
"ptys",
"server.shell",
"questions",
"references",
"projectCopies",
"permission",
"file",
"command",
"skill",
"event",
"pty",
"shell",
"question",
"reference",
"projectCopy",
])
expect(Object.keys(client.messages)).toEqual(["list"])
expect(Object.keys(client.integrations)).toEqual([
expect(Object.keys(client.message)).toEqual(["list"])
expect(Object.keys(client.integration)).toEqual([
"list",
"get",
"connectKey",
@ -37,12 +37,13 @@ test("exposes every standard HTTP API group", () => {
"attemptComplete",
"attemptCancel",
])
expect(Object.keys(client.files)).toEqual(["read", "list", "find"])
expect(Object.keys(client.ptys)).toEqual(["list", "create", "get", "update", "remove"])
expect(Object.keys(client.file)).toEqual(["read", "list", "find"])
expect(Object.keys(client.pty)).toEqual(["list", "create", "get", "update", "remove"])
expect(Object.keys(client.shell)).toEqual(["list", "create", "get", "output", "remove"])
expect(Object.keys(client.project)).toEqual(["current", "directories"])
})
test("files.read returns binary content from the public HTTP contract", async () => {
test("file.read returns binary content from the public HTTP contract", async () => {
let request: Request | undefined
const client = OpenCode.make({
baseUrl: "http://localhost:3000",
@ -52,7 +53,7 @@ test("files.read returns binary content from the public HTTP contract", async ()
},
})
const content = await client.files.read({
const content = await client.file.read({
path: "src/a b#c.ts",
location: { directory: "/tmp/project" },
})
@ -89,7 +90,42 @@ test("project methods use the public HTTP contract", async () => {
])
})
test("sessions.get returns the wire projection", async () => {
test("shell list and remove use the public HTTP contract", async () => {
const requests: Array<{ method: string; url: string }> = []
const shell = {
id: "sh_test",
status: "running",
command: "pwd",
cwd: "/tmp/project",
shell: "/bin/zsh",
file: "/tmp/opencode-shell",
metadata: { sessionID: "ses_test" },
time: { started: 1_717_171_717_000 },
}
const client = OpenCode.make({
baseUrl: "http://localhost:3000",
fetch: async (input, init) => {
const request = input instanceof Request ? input : new Request(input, init)
requests.push({ method: request.method, url: request.url })
if (request.method === "DELETE") return new Response(null, { status: 204 })
return Response.json({
location: { directory: "/tmp/project", project: { id: "proj_test", directory: "/tmp/project" } },
data: [shell],
})
},
})
const result = await client.shell.list({ location: { directory: "/tmp/project" } })
await client.shell.remove({ id: shell.id })
expect(result.data).toEqual([shell])
expect(requests).toEqual([
{ method: "GET", url: "http://localhost:3000/api/shell?location%5Bdirectory%5D=%2Ftmp%2Fproject" },
{ method: "DELETE", url: "http://localhost:3000/api/shell/sh_test" },
])
})
test("session.get returns the wire projection", async () => {
const client = OpenCode.make({
baseUrl: "http://localhost:3000",
fetch: async (input) => {
@ -100,12 +136,12 @@ test("sessions.get returns the wire projection", async () => {
},
})
const result = await client.sessions.get({ sessionID: "ses_test" })
const result = await client.session.get({ sessionID: "ses_test" })
expect(result.time.created).toBe(1_717_171_717_000)
})
test("events.subscribe exposes the Promise event stream wire projection", async () => {
test("event.subscribe exposes the Promise event stream wire projection", async () => {
const client = OpenCode.make({
baseUrl: "http://localhost:3000",
fetch: async () =>
@ -116,19 +152,19 @@ test("events.subscribe exposes the Promise event stream wire projection", async
),
})
const events = []
for await (const event of client.events.subscribe()) events.push(event)
for await (const event of client.event.subscribe()) events.push(event)
expect(events).toEqual([{ id: "evt_connected", type: "server.connected", data: {} }, modelSwitchedEvent])
expect(events[1]?.type === "session.next.model.switched" && events[1].data.timestamp).toBe(1_717_171_717_000)
})
test("events.subscribe terminates on malformed Promise SSE data", async () => {
test("event.subscribe terminates on malformed Promise SSE data", async () => {
const client = OpenCode.make({
baseUrl: "http://localhost:3000",
fetch: async () => new Response("data: {not-json}\n\n", { headers: { "content-type": "text/event-stream" } }),
})
await expect(client.events.subscribe()[Symbol.asyncIterator]().next()).rejects.toMatchObject({
await expect(client.event.subscribe()[Symbol.asyncIterator]().next()).rejects.toMatchObject({
name: "ClientError",
reason: "MalformedResponse",
})
@ -163,31 +199,31 @@ test("session methods use the public HTTP contract", async () => {
},
})
const page = await client.sessions.list({ limit: 10, order: "desc" })
const active = await client.sessions.active()
const created = await client.sessions.create({ location: { directory: "/tmp/project" } })
await client.sessions.switchAgent({ sessionID: "ses_test", agent: "build" })
await client.sessions.switchModel({
const page = await client.session.list({ limit: 10, order: "desc" })
const active = await client.session.active()
const created = await client.session.create({ location: { directory: "/tmp/project" } })
await client.session.switchAgent({ sessionID: "ses_test", agent: "build" })
await client.session.switchModel({
sessionID: "ses_test",
model: { id: "claude", providerID: "anthropic" },
})
const admitted = await client.sessions.prompt({
const admitted = await client.session.prompt({
sessionID: "ses_test",
prompt: { text: "Hello" },
resume: false,
})
await client.sessions.compact({ sessionID: "ses_test" })
await client.sessions.wait({ sessionID: "ses_test" })
const context = await client.sessions.context({ sessionID: "ses_test" })
const history = await client.sessions.history({ sessionID: "ses_test", after: 0, limit: 1 })
await client.session.compact({ sessionID: "ses_test" })
await client.session.wait({ sessionID: "ses_test" })
const context = await client.session.context({ sessionID: "ses_test" })
const history = await client.session.history({ sessionID: "ses_test", after: 0, limit: 1 })
const historyAfter = history.data.at(-1)?.durable?.seq
const historyNext = history.hasMore
? await client.sessions.history({ sessionID: "ses_test", after: historyAfter, limit: 2 })
? await client.session.history({ sessionID: "ses_test", after: historyAfter, limit: 2 })
: undefined
const events = []
for await (const event of client.sessions.events({ sessionID: "ses_test", after: 0 })) events.push(event)
await client.sessions.interrupt({ sessionID: "ses_test" })
const message = await client.sessions.message({ sessionID: "ses_test", messageID: "msg_model" })
for await (const event of client.session.events({ sessionID: "ses_test", after: 0 })) events.push(event)
await client.session.interrupt({ sessionID: "ses_test" })
const message = await client.session.message({ sessionID: "ses_test", messageID: "msg_model" })
expect(page.cursor.next).toBe("next")
expect(active).toEqual({ ses_test: { type: "running" } })
@ -230,14 +266,14 @@ test("middleware errors remain declared client errors", async () => {
})
try {
await client.sessions.create({})
await client.session.create({})
throw new Error("Expected request to fail")
} catch (error) {
expect(isUnauthorizedError(error)).toBe(true)
}
})
test("sessions.history decodes SessionNotFoundError", async () => {
test("session.history decodes SessionNotFoundError", async () => {
const client = OpenCode.make({
baseUrl: "http://localhost:3000",
fetch: async () =>
@ -248,7 +284,7 @@ test("sessions.history decodes SessionNotFoundError", async () => {
})
try {
await client.sessions.history({ sessionID: "ses_missing" })
await client.session.history({ sessionID: "ses_missing" })
throw new Error("Expected request to fail")
} catch (error) {
expect(isSessionNotFoundError(error)).toBe(true)

View file

@ -1,5 +1,5 @@
import { TextAttributes } from "@opentui/core"
import type { IntegrationsConnectOauthOutput } from "@opencode-ai/client"
import type { IntegrationConnectOauthOutput } from "@opencode-ai/client"
import type { ConnectionInfo, IntegrationInfo, IntegrationOAuthMethod } from "@opencode-ai/sdk/v2"
import { createMemo, createSignal, onCleanup, onMount, Show } from "solid-js"
import { useClipboard } from "../context/clipboard"
@ -23,7 +23,7 @@ const INTEGRATION_PRIORITY: Record<string, number> = {
}
type ConnectMethod = Exclude<IntegrationInfo["methods"][number], { type: "env" }>
type IntegrationAttempt = IntegrationsConnectOauthOutput["data"]
type IntegrationAttempt = IntegrationConnectOauthOutput["data"]
export function integrationOptions(list: IntegrationInfo[]) {
return list.toSorted(
@ -111,7 +111,7 @@ function manageConnections(
title: `Disconnect ${connection.label}`,
value: connection.id,
onSelect: () => {
void sdk.api.credentials
void sdk.api.credential
.remove({ credentialID: connection.id, location: location(data) })
.then(() => disconnected(integration.name, data, dialog, toast))
.catch(toast.error)
@ -159,7 +159,7 @@ function KeyMethod(props: { integration: IntegrationInfo; method: Extract<Connec
placeholder="API key"
onConfirm={(key) => {
if (!key) return
void sdk.api.integrations
void sdk.api.integration
.connectKey({
integrationID: props.integration.id,
location: location(data),
@ -194,7 +194,7 @@ function OAuthStarting(props: {
const toast = useToast()
onMount(() => {
void sdk.api.integrations
void sdk.api.integration
.connectOauth({
integrationID: props.integration.id,
location: location(data),
@ -248,7 +248,7 @@ function OAuthAuto(props: { integration: IntegrationInfo; title: string; attempt
}))
const poll = () => {
void sdk.api.integrations
void sdk.api.integration
.attemptStatus({ attemptID: props.attempt.attemptID, location: location(data) })
.then((result) => {
const status = result.data
@ -275,7 +275,7 @@ function OAuthAuto(props: { integration: IntegrationInfo; title: string; attempt
onCleanup(() => {
if (timer) clearTimeout(timer)
if (settled) return
void sdk.api.integrations.attemptCancel({ attemptID: props.attempt.attemptID, location: location(data) })
void sdk.api.integration.attemptCancel({ attemptID: props.attempt.attemptID, location: location(data) })
})
return (
@ -300,7 +300,7 @@ function OAuthCode(props: { integration: IntegrationInfo; title: string; attempt
onCleanup(() => {
if (settled) return
void sdk.api.integrations.attemptCancel({ attemptID: props.attempt.attemptID, location: location(data) })
void sdk.api.integration.attemptCancel({ attemptID: props.attempt.attemptID, location: location(data) })
})
return (
@ -309,7 +309,7 @@ function OAuthCode(props: { integration: IntegrationInfo; title: string; attempt
placeholder="Authorization code"
onConfirm={(code) => {
if (!code) return
void sdk.api.integrations
void sdk.api.integration
.attemptComplete({ attemptID: props.attempt.attemptID, location: location(data), code })
.then(() => {
settled = true

View file

@ -77,7 +77,7 @@ export function DialogMoveSession(props: DialogMoveSessionProps) {
async (projectID, info): Promise<ReadonlyArray<ProjectDirectory> | undefined> => {
try {
const location = { directory: projectContext.instance.directory() || paths.cwd }
await sdk.api.projectCopies.refresh({
await sdk.api.projectCopy.refresh({
projectID,
location,
})
@ -227,7 +227,7 @@ export function DialogMoveSession(props: DialogMoveSessionProps) {
setToDelete(undefined)
setRemoving(selected.directory)
setWorking(true)
const error = await sdk.api.projectCopies
const error = await sdk.api.projectCopy
.remove({
projectID: props.projectID,
location: { directory: projectContext.instance.directory() || paths.cwd },
@ -252,7 +252,7 @@ export function DialogMoveSession(props: DialogMoveSessionProps) {
return
}
reopen(selected.directory)
const forcedError = await sdk.api.projectCopies
const forcedError = await sdk.api.projectCopy
.remove({
projectID: props.projectID,
location: { directory: projectContext.instance.directory() || paths.cwd },

View file

@ -32,7 +32,7 @@ export function DialogSessionList() {
const [searchResults] = createResource(search, async (query) => {
if (!query) return
const location = data.location.default()
const response = await sdk.api.sessions.list({
const response = await sdk.api.session.list({
search: query,
limit: 50,
order: "desc",

View file

@ -17,7 +17,7 @@ export function DialogSessionRename(props: { sessionID: string; currentTitle?: s
onConfirm={(value) => {
const title = value.trim()
if (!title) return
void sdk.api.sessions
void sdk.api.session
.rename({ sessionID: props.sessionID, title })
.then(() => dialog.clear())
.catch((error) =>

View file

@ -17,7 +17,7 @@ export function DialogTag(props: { onSelect?: (value: string) => void }) {
const [files] = createResource(
() => [store.filter],
async () => {
const result = await sdk.api.files
const result = await sdk.api.file
.find({
query: store.filter,
type: "file",

View file

@ -320,7 +320,7 @@ export function Autocomplete(props: {
if (referenceMatch()) return []
const { lineRange, baseQuery } = extractLineRange(input.query ?? "")
const result = await sdk.api.files
const result = await sdk.api.file
.find({
query: baseQuery,
limit: 20,

View file

@ -425,7 +425,7 @@ export function Prompt(props: PromptProps) {
}, 5000)
if (store.interrupt >= 2) {
void sdk.api.sessions.interrupt({
void sdk.api.session.interrupt({
sessionID: props.sessionID,
})
setStore("interrupt", 0)
@ -1012,7 +1012,7 @@ export function Prompt(props: PromptProps) {
finishMoveProgress = Boolean(move.progress())
const location = data.location.default()
const created = await sdk.api.sessions
const created = await sdk.api.session
.create({
location: directory
? { directory, workspaceID }
@ -1114,20 +1114,20 @@ export function Prompt(props: PromptProps) {
session = data.session.get(sessionID)
}
if (session?.agent !== agent.id) {
await sdk.api.sessions.switchAgent({ sessionID, agent: agent.id })
await sdk.api.session.switchAgent({ sessionID, agent: agent.id })
}
if (
session?.model?.providerID !== selectedModel.providerID ||
session.model.id !== selectedModel.modelID ||
session.model.variant !== variant
) {
await sdk.api.sessions.switchModel({
await sdk.api.session.switchModel({
sessionID,
model: { providerID: selectedModel.providerID, id: selectedModel.modelID, variant },
})
}
if (session?.revert) {
const error = await sdk.api.sessions.commit({ sessionID }).then(
const error = await sdk.api.session.commit({ sessionID }).then(
() => undefined,
(error) => error,
)
@ -1136,7 +1136,7 @@ export function Prompt(props: PromptProps) {
return false
}
}
const error = await sdk.api.sessions
const error = await sdk.api.session
.prompt({
sessionID,
prompt: {

View file

@ -37,7 +37,7 @@ export function usePromptMove(input: { projectID: () => string | undefined; sess
{ projectID, context },
{ throwOnError: true },
)
const result = await sdk.api.projectCopies.create({
const result = await sdk.api.projectCopy.create({
projectID,
location: { directory: project.instance.directory() || paths.cwd },
strategy: "git_worktree",

View file

@ -554,7 +554,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
return store.session.status[sessionID] ?? "idle"
},
async refresh(sessionID: string) {
setStore("session", "info", sessionID, mutable(await sdk.api.sessions.get({ sessionID })))
setStore("session", "info", sessionID, mutable(await sdk.api.session.get({ sessionID })))
},
message: {
ids(sessionID: string) {
@ -572,7 +572,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
setStore("session", "message", sessionID, [])
messageIndex.set(sessionID, new Map())
const loaded = mutable(
(await sdk.api.messages.list({ sessionID, limit: 200, order: "desc" })).data,
(await sdk.api.message.list({ sessionID, limit: 200, order: "desc" })).data,
).toReversed()
const live = store.session.message[sessionID] ?? []
const liveByID = new Map(live.map((message) => [message.id, message]))
@ -588,7 +588,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
return store.session.permission[sessionID]
},
async refresh(sessionID: string) {
setStore("session", "permission", sessionID, mutable(await sdk.api.permissions.list({ sessionID })))
setStore("session", "permission", sessionID, mutable(await sdk.api.permission.list({ sessionID })))
},
},
question: {
@ -596,7 +596,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
return store.session.question[sessionID]
},
async refresh(sessionID: string) {
setStore("session", "question", sessionID, mutable(await sdk.api.questions.list({ sessionID })))
setStore("session", "question", sessionID, mutable(await sdk.api.question.list({ sessionID })))
},
},
},
@ -606,7 +606,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
return store.project.permission[projectID]
},
async refresh(projectID: string) {
setStore("project", "permission", projectID, mutable(await sdk.api.permissions.listSaved({ projectID })))
setStore("project", "permission", projectID, mutable(await sdk.api.permission.listSaved({ projectID })))
},
},
},
@ -618,16 +618,16 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
return store.shell[id]
},
async refresh(ref?: LocationRef) {
const result = await sdk.client.v2.shell.list({ location: locationQuery(ref) }, { throwOnError: true })
const result = await sdk.api.shell.list({ location: locationQuery(ref) })
setStore(
"shell",
produce((draft) => {
for (const info of result.data.data) draft[info.id] = info
for (const info of mutable(result.data)) draft[info.id] = info
}),
)
},
async remove(id: string) {
await sdk.client.v2.shell.remove({ id }, { throwOnError: true })
await sdk.api.shell.remove({ id })
setStore("shell", id, undefined!)
},
},
@ -646,7 +646,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
return store.location[locationKey(location ?? defaultLocation())]?.agent
},
async refresh(ref?: LocationRef) {
const result = await sdk.api.agents.list({ location: locationQuery(ref ?? defaultLocation()) })
const result = await sdk.api.agent.list({ location: locationQuery(ref ?? defaultLocation()) })
const key = locationKey(result.location)
setStore("location", key, { ...store.location[key], agent: mutable(result.data) })
},
@ -656,7 +656,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
return store.location[locationKey(location ?? defaultLocation())]?.command
},
async refresh(ref?: LocationRef) {
const result = await sdk.api.commands.list({ location: locationQuery(ref ?? defaultLocation()) })
const result = await sdk.api.command.list({ location: locationQuery(ref ?? defaultLocation()) })
const key = locationKey(result.location)
setStore("location", key, { ...store.location[key], command: mutable(result.data) })
},
@ -666,7 +666,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
return store.location[locationKey(location ?? defaultLocation())]?.integration
},
async refresh(ref?: LocationRef) {
const result = await sdk.api.integrations.list({ location: locationQuery(ref ?? defaultLocation()) })
const result = await sdk.api.integration.list({ location: locationQuery(ref ?? defaultLocation()) })
const key = locationKey(result.location)
setStore("location", key, { ...store.location[key], integration: mutable(result.data) })
},
@ -676,7 +676,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
return store.location[locationKey(location ?? defaultLocation())]?.model
},
async refresh(ref?: LocationRef) {
const result = await sdk.api.models.list({ location: locationQuery(ref ?? defaultLocation()) })
const result = await sdk.api.model.list({ location: locationQuery(ref ?? defaultLocation()) })
const key = locationKey(result.location)
setStore("location", key, { ...store.location[key], model: mutable(result.data) })
},
@ -686,7 +686,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
return store.location[locationKey(location ?? defaultLocation())]?.provider
},
async refresh(ref?: LocationRef) {
const result = await sdk.api.providers.list({ location: locationQuery(ref ?? defaultLocation()) })
const result = await sdk.api.provider.list({ location: locationQuery(ref ?? defaultLocation()) })
const key = locationKey(result.location)
setStore("location", key, { ...store.location[key], provider: mutable(result.data) })
},
@ -696,7 +696,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
return store.location[locationKey(location ?? defaultLocation())]?.reference
},
async refresh(ref?: LocationRef) {
const result = await sdk.api.references.list({ location: locationQuery(ref ?? defaultLocation()) })
const result = await sdk.api.reference.list({ location: locationQuery(ref ?? defaultLocation()) })
const key = locationKey(result.location)
setStore("location", key, { ...store.location[key], reference: mutable(result.data) })
},
@ -706,7 +706,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
return store.location[locationKey(location ?? defaultLocation())]?.skill
},
async refresh(ref?: LocationRef) {
const result = await sdk.api.skills.list({ location: locationQuery(ref ?? defaultLocation()) })
const result = await sdk.api.skill.list({ location: locationQuery(ref ?? defaultLocation()) })
const key = locationKey(result.location)
setStore("location", key, { ...store.location[key], skill: mutable(result.data) })
},
@ -716,7 +716,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
async function bootstrap() {
const settled = await Promise.allSettled([
sdk.api.sessions
sdk.api.session
.list({
limit: 50,
order: "desc",
@ -732,7 +732,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
}),
),
),
sdk.api.sessions
sdk.api.session
.active()
.then((active) =>
setStore(

View file

@ -22,7 +22,7 @@ export function DialogMessage(props: { messageID: string; sessionID: string; set
value: "session.revert",
description: "undo messages and file changes",
onSelect: async (dialog) => {
await sdk.api.sessions
await sdk.api.session
.stage({ sessionID: props.sessionID, messageID: props.messageID })
.catch((error) => toast.show({ message: errorMessage(error), variant: "error", duration: 5000 }))
dialog.clear()

View file

@ -369,7 +369,7 @@ export function Session() {
aliases: ["summarize"],
},
run: () => {
void sdk.api.sessions.compact({ sessionID: route.sessionID })
void sdk.api.session.compact({ sessionID: route.sessionID })
dialog.clear()
},
},
@ -403,7 +403,7 @@ export function Session() {
dialog.clear()
return
}
const error = await sdk.api.sessions.stage({ sessionID: route.sessionID, messageID: target }).then(
const error = await sdk.api.session.stage({ sessionID: route.sessionID, messageID: target }).then(
() => undefined,
(error) => error,
)
@ -420,7 +420,7 @@ export function Session() {
slash: { name: "redo" },
run: () => {
void (async () => {
const error = await sdk.api.sessions.clear({ sessionID: route.sessionID }).then(
const error = await sdk.api.session.clear({ sessionID: route.sessionID }).then(
() => undefined,
(error) => error,
)
@ -843,7 +843,12 @@ export function Session() {
// snap to bottom when session changes
createEffect(on(() => route.sessionID, toBottom))
createEffect(on(() => route.sessionID, () => setComposer("open", false)))
createEffect(
on(
() => route.sessionID,
() => setComposer("open", false),
),
)
return (
<LocationProvider location={location()}>
@ -913,9 +918,7 @@ export function Session() {
onClose={() => setComposer("open", false)}
/>
<Switch>
<Match when={composer.open || !!session()?.parentID}>
{null}
</Match>
<Match when={composer.open || !!session()?.parentID}>{null}</Match>
<Match when={permissions().length > 0}>
<PermissionPrompt request={permissions()[0]} directory={session()?.location.directory} />
</Match>
@ -1230,7 +1233,7 @@ function RevertMessage(props: {
onMouseUp={() => {
if (renderer.getSelection()?.getSelectedText()) return
void (async () => {
const error = await sdk.api.sessions.clear({ sessionID: route.sessionID }).then(
const error = await sdk.api.session.clear({ sessionID: route.sessionID }).then(
() => undefined,
(error) => error,
)

View file

@ -186,7 +186,7 @@ export function PermissionPrompt(props: { request: PermissionV2Request; director
onSelect={(option) => {
setStore("stage", "permission")
if (option === "cancel") return
void sdk.api.permissions.reply({
void sdk.api.permission.reply({
sessionID: props.request.sessionID,
reply: "always",
requestID: props.request.id,
@ -197,7 +197,7 @@ export function PermissionPrompt(props: { request: PermissionV2Request; director
<Match when={store.stage === "reject"}>
<RejectPrompt
onConfirm={(message) => {
void sdk.api.permissions.reply({
void sdk.api.permission.reply({
sessionID: props.request.sessionID,
reply: "reject",
requestID: props.request.id,
@ -443,14 +443,14 @@ export function PermissionPrompt(props: { request: PermissionV2Request; director
setStore("stage", "reject")
return
}
void sdk.api.permissions.reply({
void sdk.api.permission.reply({
sessionID: props.request.sessionID,
reply: "reject",
requestID: props.request.id,
})
return
}
void sdk.api.permissions.reply({
void sdk.api.permission.reply({
sessionID: props.request.sessionID,
reply: "once",
requestID: props.request.id,

View file

@ -47,7 +47,7 @@ export function QuestionPrompt(props: { request: QuestionV2Request; directory?:
function submit() {
const answers = questions().map((_, i) => store.answers[i] ?? [])
void sdk.api.questions.reply({
void sdk.api.question.reply({
sessionID: props.request.sessionID,
requestID: props.request.id,
answers,
@ -55,7 +55,7 @@ export function QuestionPrompt(props: { request: QuestionV2Request; directory?:
}
function reject() {
void sdk.api.questions.reject({
void sdk.api.question.reject({
sessionID: props.request.sessionID,
requestID: props.request.id,
})
@ -71,7 +71,7 @@ export function QuestionPrompt(props: { request: QuestionV2Request; directory?:
setStore("custom", inputs)
}
if (single()) {
void sdk.api.questions.reply({
void sdk.api.question.reply({
sessionID: props.request.sessionID,
requestID: props.request.id,
answers: [[answer]],