@opencode/client 0.0.0-dev-19563 → 0.0.0-dev-19565

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2706,9 +2706,15 @@ export type ConfigShellsOutput = ReadonlyArray<{
2706
2706
  readonly acceptable: boolean;
2707
2707
  }>;
2708
2708
  export type ConfigShellsOperation<E = never> = () => Effect.Effect<ConfigShellsOutput, E>;
2709
+ export type ConfigUpdateInput = {
2710
+ readonly shell: string | null;
2711
+ };
2712
+ export type ConfigUpdateOutput = void;
2713
+ export type ConfigUpdateOperation<E = never> = (input: ConfigUpdateInput) => Effect.Effect<ConfigUpdateOutput, E>;
2709
2714
  export interface ConfigApi<E = never> {
2710
2715
  readonly get: ConfigGetOperation<E>;
2711
2716
  readonly shells: ConfigShellsOperation<E>;
2717
+ readonly update: ConfigUpdateOperation<E>;
2712
2718
  }
2713
2719
  export interface AppApi<E = never> {
2714
2720
  readonly server: ServerApi<E>;
@@ -2450,5 +2450,6 @@ export declare const make: (options?: {
2450
2450
  config: {
2451
2451
  get: (input?: import("./api.js").ConfigGetInput) => Effect.Effect<import("./api.js").ConfigGetOutput, import("@opencode/protocol/errors").InvalidRequestError | import("@opencode/protocol/errors").UnauthorizedError | import("effect/Schema").SchemaError | ClientError | import("effect/unstable/http/HttpClientError").HttpClientError, never>;
2452
2452
  shells: () => Effect.Effect<import("./api.js").ConfigShellsOutput, import("@opencode/protocol/errors").InvalidRequestError | import("@opencode/protocol/errors").UnauthorizedError | import("effect/Schema").SchemaError | ClientError | import("effect/unstable/http/HttpClientError").HttpClientError, never>;
2453
+ update: (input: import("./api.js").ConfigUpdateInput) => Effect.Effect<void, import("@opencode/protocol/errors").InvalidRequestError | import("@opencode/protocol/errors").UnauthorizedError | import("effect/Schema").SchemaError | ClientError | import("effect/unstable/http/HttpClientError").HttpClientError, never>;
2453
2454
  };
2454
2455
  }, never, HttpClient.HttpClient>;
@@ -1,7 +1,7 @@
1
1
  import { Effect, Stream, Schema } from "effect";
2
2
  import { Sse } from "effect/unstable/encoding";
3
3
  import { HttpClientError } from "effect/unstable/http";
4
- import type { ServerStatusOutput, LocationGetInput, AgentListInput, AgentListOutput, AgentGetInput, AgentGetOutput, PluginListInput, PluginListOutput, PluginCheckInput, PluginCheckOutput, PluginUpdateInput, SessionListInput, SessionListOutput, SessionStatsInput, SessionStatsOutput, SessionCreateInput, SessionImportInput, SessionExportInput, SessionExportOutput, SessionActiveOutput, SessionGetInput, SessionRemoveInput, SessionForkInput, SessionSwitchAgentInput, SessionSwitchModelInput, SessionRenameInput, SessionMoveInput, SessionPromptInput, SessionCommandInput, SessionSkillInput, SessionSyntheticInput, SessionShellInput, SessionCompactInput, SessionWaitInput, SessionRevertStageInput, SessionRevertClearInput, SessionRevertCommitInput, SessionContextInput, SessionContextOutput, SessionDiffInput, SessionDiffOutput, SessionInboxListInput, SessionInboxListOutput, SessionInboxCancelInput, SessionInboxSteerInput, SessionInboxQueueInput, SessionInstructionsEntryListInput, SessionInstructionsEntryListOutput, SessionInstructionsEntryPutInput, SessionInstructionsEntryRemoveInput, SessionGenerateInput, SessionGenerateOutput, SessionLogInput, SessionLogOutput, SessionInterruptInput, SessionInterruptOutput, SessionBackgroundInput, SessionMessageInput, SessionEnvironmentInput, SessionViewInput, MessageListInput, MessageListOutput, ModelListInput, ModelListOutput, ModelDefaultInput, ModelDefaultOutput, GenerateTextInput, GenerateTextOutput, ProviderListInput, ProviderListOutput, ProviderGetInput, ProviderGetOutput, IntegrationListInput, IntegrationListOutput, IntegrationGetInput, IntegrationGetOutput, IntegrationWellknownAddInput, IntegrationConnectKeyInput, IntegrationOauthConnectInput, IntegrationOauthConnectOutput, IntegrationOauthStatusInput, IntegrationOauthStatusOutput, IntegrationOauthCompleteInput, IntegrationOauthCancelInput, IntegrationCommandConnectInput, IntegrationCommandConnectOutput, IntegrationCommandStatusInput, IntegrationCommandStatusOutput, IntegrationCommandCancelInput, McpListInput, McpListOutput, McpAddInput, McpRemoveInput, McpConnectInput, McpDisconnectInput, McpResourceCatalogInput, McpResourceCatalogOutput, CredentialUpdateInput, CredentialActivateInput, CredentialRemoveInput, ProjectListOutput, ProjectUpdateInput, FormRequestListInput, FormRequestListOutput, FormListInput, FormListOutput, FormCreateInput, FormGetInput, FormStateInput, FormReplyInput, FormCancelInput, PermissionRequestListInput, PermissionRequestListOutput, PermissionSavedListInput, PermissionSavedListOutput, PermissionSavedRemoveInput, PermissionCreateInput, PermissionCreateOutput, PermissionListInput, PermissionListOutput, PermissionGetInput, PermissionReplyInput, PermissionRulesInput, FileListInput, FileListOutput, FileFindInput, FileFindOutput, CommandListInput, CommandListOutput, SkillListInput, SkillListOutput, RpcCallInput, RpcCallOutput, PtyListInput, PtyListOutput, PtyCreateInput, PtyCreateOutput, PtyGetInput, PtyGetOutput, PtyUpdateInput, PtyUpdateOutput, PtyRemoveInput, PtyConnectTokenInput, PtyConnectTokenOutput, ExperimentalPersistentPtyReadInput, ExperimentalPersistentPtyReadOutput, ExperimentalPersistentPtyListInput, ExperimentalPersistentPtyListOutput, ExperimentalPersistentPtyCreateInput, ExperimentalPersistentPtyCreateOutput, ExperimentalPersistentPtyHandoffOutput, ExperimentalPersistentPtyGetInput, ExperimentalPersistentPtyGetOutput, ExperimentalPersistentPtyUpdateInput, ExperimentalPersistentPtyUpdateOutput, ExperimentalPersistentPtySnapshotInput, ExperimentalPersistentPtySnapshotOutput, ExperimentalPersistentPtyRemoveInput, ExperimentalPersistentPtyConnectTokenInput, ShellListInput, ShellListOutput, ShellCreateInput, ShellCreateOutput, ShellGetInput, ShellGetOutput, ShellTimeoutInput, ShellTimeoutOutput, ShellOutputInput, ShellOutputOutput, ShellRemoveInput, ReferenceListInput, ReferenceListOutput, WorktreeListInput, WorktreeCreateInput, WorktreeRemoveInput, WorktreeRefreshInput, VcsGetInput, VcsGetOutput, VcsBaseInput, VcsBaseOutput, VcsStatusInput, VcsStatusOutput, VcsBranchesInput, VcsBranchesOutput, VcsDiffInput, VcsDiffOutput, DebugLocationListOutput, DebugLocationEvictInput, MigrationV1StatusOutput, WebsearchProvidersInput, WebsearchProvidersOutput, WebsearchQueryInput, WebsearchQueryOutput, ConfigGetInput, ConfigGetOutput, ConfigShellsOutput } from "../api/api.js";
4
+ import type { ServerStatusOutput, LocationGetInput, AgentListInput, AgentListOutput, AgentGetInput, AgentGetOutput, PluginListInput, PluginListOutput, PluginCheckInput, PluginCheckOutput, PluginUpdateInput, SessionListInput, SessionListOutput, SessionStatsInput, SessionStatsOutput, SessionCreateInput, SessionImportInput, SessionExportInput, SessionExportOutput, SessionActiveOutput, SessionGetInput, SessionRemoveInput, SessionForkInput, SessionSwitchAgentInput, SessionSwitchModelInput, SessionRenameInput, SessionMoveInput, SessionPromptInput, SessionCommandInput, SessionSkillInput, SessionSyntheticInput, SessionShellInput, SessionCompactInput, SessionWaitInput, SessionRevertStageInput, SessionRevertClearInput, SessionRevertCommitInput, SessionContextInput, SessionContextOutput, SessionDiffInput, SessionDiffOutput, SessionInboxListInput, SessionInboxListOutput, SessionInboxCancelInput, SessionInboxSteerInput, SessionInboxQueueInput, SessionInstructionsEntryListInput, SessionInstructionsEntryListOutput, SessionInstructionsEntryPutInput, SessionInstructionsEntryRemoveInput, SessionGenerateInput, SessionGenerateOutput, SessionLogInput, SessionLogOutput, SessionInterruptInput, SessionInterruptOutput, SessionBackgroundInput, SessionMessageInput, SessionEnvironmentInput, SessionViewInput, MessageListInput, MessageListOutput, ModelListInput, ModelListOutput, ModelDefaultInput, ModelDefaultOutput, GenerateTextInput, GenerateTextOutput, ProviderListInput, ProviderListOutput, ProviderGetInput, ProviderGetOutput, IntegrationListInput, IntegrationListOutput, IntegrationGetInput, IntegrationGetOutput, IntegrationWellknownAddInput, IntegrationConnectKeyInput, IntegrationOauthConnectInput, IntegrationOauthConnectOutput, IntegrationOauthStatusInput, IntegrationOauthStatusOutput, IntegrationOauthCompleteInput, IntegrationOauthCancelInput, IntegrationCommandConnectInput, IntegrationCommandConnectOutput, IntegrationCommandStatusInput, IntegrationCommandStatusOutput, IntegrationCommandCancelInput, McpListInput, McpListOutput, McpAddInput, McpRemoveInput, McpConnectInput, McpDisconnectInput, McpResourceCatalogInput, McpResourceCatalogOutput, CredentialUpdateInput, CredentialActivateInput, CredentialRemoveInput, ProjectListOutput, ProjectUpdateInput, FormRequestListInput, FormRequestListOutput, FormListInput, FormListOutput, FormCreateInput, FormGetInput, FormStateInput, FormReplyInput, FormCancelInput, PermissionRequestListInput, PermissionRequestListOutput, PermissionSavedListInput, PermissionSavedListOutput, PermissionSavedRemoveInput, PermissionCreateInput, PermissionCreateOutput, PermissionListInput, PermissionListOutput, PermissionGetInput, PermissionReplyInput, PermissionRulesInput, FileListInput, FileListOutput, FileFindInput, FileFindOutput, CommandListInput, CommandListOutput, SkillListInput, SkillListOutput, RpcCallInput, RpcCallOutput, PtyListInput, PtyListOutput, PtyCreateInput, PtyCreateOutput, PtyGetInput, PtyGetOutput, PtyUpdateInput, PtyUpdateOutput, PtyRemoveInput, PtyConnectTokenInput, PtyConnectTokenOutput, ExperimentalPersistentPtyReadInput, ExperimentalPersistentPtyReadOutput, ExperimentalPersistentPtyListInput, ExperimentalPersistentPtyListOutput, ExperimentalPersistentPtyCreateInput, ExperimentalPersistentPtyCreateOutput, ExperimentalPersistentPtyHandoffOutput, ExperimentalPersistentPtyGetInput, ExperimentalPersistentPtyGetOutput, ExperimentalPersistentPtyUpdateInput, ExperimentalPersistentPtyUpdateOutput, ExperimentalPersistentPtySnapshotInput, ExperimentalPersistentPtySnapshotOutput, ExperimentalPersistentPtyRemoveInput, ExperimentalPersistentPtyConnectTokenInput, ShellListInput, ShellListOutput, ShellCreateInput, ShellCreateOutput, ShellGetInput, ShellGetOutput, ShellTimeoutInput, ShellTimeoutOutput, ShellOutputInput, ShellOutputOutput, ShellRemoveInput, ReferenceListInput, ReferenceListOutput, WorktreeListInput, WorktreeCreateInput, WorktreeRemoveInput, WorktreeRefreshInput, VcsGetInput, VcsGetOutput, VcsBaseInput, VcsBaseOutput, VcsStatusInput, VcsStatusOutput, VcsBranchesInput, VcsBranchesOutput, VcsDiffInput, VcsDiffOutput, DebugLocationListOutput, DebugLocationEvictInput, MigrationV1StatusOutput, WebsearchProvidersInput, WebsearchProvidersOutput, WebsearchQueryInput, WebsearchQueryOutput, ConfigGetInput, ConfigGetOutput, ConfigShellsOutput, ConfigUpdateInput } from "../api/api.js";
5
5
  import { ClientError } from "./client-error.js";
6
6
  export declare const make: (options?: {
7
7
  readonly baseUrl?: URL | string;
@@ -2449,5 +2449,6 @@ export declare const make: (options?: {
2449
2449
  config: {
2450
2450
  get: (input?: ConfigGetInput) => Effect.Effect<ConfigGetOutput, import("@opencode/protocol/errors").InvalidRequestError | import("@opencode/protocol/errors").UnauthorizedError | Schema.SchemaError | ClientError | HttpClientError.HttpClientError, never>;
2451
2451
  shells: () => Effect.Effect<ConfigShellsOutput, import("@opencode/protocol/errors").InvalidRequestError | import("@opencode/protocol/errors").UnauthorizedError | Schema.SchemaError | ClientError | HttpClientError.HttpClientError, never>;
2452
+ update: (input: ConfigUpdateInput) => Effect.Effect<void, import("@opencode/protocol/errors").InvalidRequestError | import("@opencode/protocol/errors").UnauthorizedError | Schema.SchemaError | ClientError | HttpClientError.HttpClientError, never>;
2452
2453
  };
2453
2454
  }, never, import("effect/unstable/http/HttpClient").HttpClient>;
@@ -558,9 +558,11 @@ const adaptGroupWebsearch = (raw) => ({
558
558
  });
559
559
  const EndpointConfigGet = (raw) => (input) => preserveEffect()(raw["config.get"]({ query: { location: input?.["location"] } }).pipe(Effect.mapError(mapClientError)));
560
560
  const EndpointConfigShells = (raw) => () => preserveEffect()(raw["config.shells"]({}).pipe(Effect.mapError(mapClientError)));
561
+ const EndpointConfigUpdate = (raw) => (input) => preserveEffect()(raw["config.update"]({ payload: { shell: input["shell"] } }).pipe(Effect.mapError(mapClientError)));
561
562
  const adaptGroupConfig = (raw) => ({
562
563
  get: EndpointConfigGet(raw),
563
564
  shells: EndpointConfigShells(raw),
565
+ update: EndpointConfigUpdate(raw),
564
566
  });
565
567
  const adaptClient = (raw) => ({
566
568
  server: adaptGroupServer(raw["server.server"]),
@@ -1,4 +1,3 @@
1
- import { ServerStatus } from "@opencode/protocol/groups/server";
2
1
  import { Effect, FileSystem, Option, Schedule, Schema } from "effect";
3
2
  import { homedir } from "node:os";
4
3
  import { join } from "node:path";
@@ -21,6 +20,8 @@ export const discover = Effect.fn("service.discover")(function* (options = {}) {
21
20
  const found = (yield* registered(options.file)).service;
22
21
  if (found?.state !== "ready")
23
22
  return undefined;
23
+ if (!found.compatible)
24
+ return undefined;
24
25
  if (!matchesVersion(found.version, options))
25
26
  return undefined;
26
27
  return found.endpoint;
@@ -31,6 +32,8 @@ export const incumbent = Effect.fn("service.incumbent")(function* (options) {
31
32
  const found = info === undefined ? undefined : yield* probe({ ...info, url: options.url });
32
33
  if (found === undefined)
33
34
  return undefined;
35
+ if (!found.compatible)
36
+ return undefined;
34
37
  if (!matchesVersion(found.version, options))
35
38
  return undefined;
36
39
  return { endpoint: found.endpoint, state: found.state };
@@ -86,7 +89,7 @@ export const ensure = Effect.fn("service.ensure")(function* (options = {}) {
86
89
  timeouts = undefined;
87
90
  if (service !== undefined) {
88
91
  spawnDelay = timing.spawnDelay;
89
- const compatible = matchesVersion(service.version, options);
92
+ const compatible = service.compatible && matchesVersion(service.version, options);
90
93
  if (compatible && service.state === "ready") {
91
94
  yield* Effect.tryPromise(() => PtyHandoff.complete(options.file ?? fallback(), service.info));
92
95
  return Option.some(service);
@@ -159,7 +162,10 @@ export const Info = Schema.Struct({
159
162
  password: Schema.optional(Schema.String),
160
163
  });
161
164
  const decode = Schema.decodeUnknownEffect(Schema.fromJsonString(Info));
162
- const decodeStatus = Schema.decodeUnknownOption(ServerStatus);
165
+ const decodeStatus = Schema.decodeUnknownOption(Schema.Struct({
166
+ version: Schema.String,
167
+ pid: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
168
+ }));
163
169
  // A missing or corrupt file means no valid info; callers treat both
164
170
  // the same (the registering server self-evicts, clients rediscover).
165
171
  const read = Effect.fnUntraced(function* (file) {
@@ -181,11 +187,27 @@ const probeResult = Effect.fnUntraced(function* (info, timeout = defaultEnsureTi
181
187
  };
182
188
  const signal = AbortSignal.timeout(timeout);
183
189
  const result = yield* Effect.promise(() => fetch(new URL("/api/status", info.url), { headers: headers(endpoint), signal })
184
- .then(async (response) => ({ response, body: (await response.json()) }))
190
+ .then(async (response) => ({
191
+ response,
192
+ body: response.status === 404 ? undefined : (await response.json()),
193
+ }))
185
194
  .then((value) => ({ value }), (cause) => ({ cause })));
186
195
  if ("cause" in result)
187
196
  return { service: undefined, timedOut: signal.aborted };
188
197
  const response = result.value.response;
198
+ // The previous V2 service exposes /api/health instead. Its authenticated 404 is enough
199
+ // to recognize the registered daemon as incompatible and route it through replacement.
200
+ if (response.status === 404)
201
+ return {
202
+ service: {
203
+ info,
204
+ endpoint,
205
+ version: info.version,
206
+ state: "ready",
207
+ compatible: false,
208
+ },
209
+ timedOut: false,
210
+ };
189
211
  const body = result.value.body;
190
212
  const status = decodeStatus(body);
191
213
  if (Option.isSome(status)) {
@@ -199,6 +221,7 @@ const probeResult = Effect.fnUntraced(function* (info, timeout = defaultEnsureTi
199
221
  endpoint,
200
222
  version: status.value.version,
201
223
  state: response.ok ? "ready" : response.status === 500 ? "failed" : "waiting",
224
+ compatible: true,
202
225
  },
203
226
  timedOut: false,
204
227
  };
@@ -246,5 +246,6 @@ export declare function make(options: ClientOptions): {
246
246
  config: {
247
247
  get: (input?: import("./index.js").ConfigGetInput, requestOptions?: OpenCode.RequestOptions) => Promise<import("./index.js").ConfigGetOutput>;
248
248
  shells: (requestOptions?: OpenCode.RequestOptions) => Promise<import("./index.js").ConfigShellsOutput>;
249
+ update: (input: import("./index.js").ConfigUpdateInput, requestOptions?: OpenCode.RequestOptions) => Promise<void>;
249
250
  };
250
251
  };
@@ -1,4 +1,4 @@
1
- import type { LocationGetInput, AgentListInput, AgentListOutput, AgentGetInput, AgentGetOutput, PluginListInput, PluginListOutput, PluginCheckInput, PluginCheckOutput, PluginUpdateInput, SessionListInput, SessionStatsInput, SessionCreateInput, SessionImportInput, SessionExportInput, SessionGetInput, SessionRemoveInput, SessionForkInput, SessionSwitchAgentInput, SessionSwitchModelInput, SessionRenameInput, SessionMoveInput, SessionPromptInput, SessionCommandInput, SessionSkillInput, SessionSyntheticInput, SessionShellInput, SessionCompactInput, SessionWaitInput, SessionRevertStageInput, SessionRevertClearInput, SessionRevertCommitInput, SessionContextInput, SessionDiffInput, SessionInboxListInput, SessionInboxCancelInput, SessionInboxSteerInput, SessionInboxQueueInput, SessionInstructionsEntryListInput, SessionInstructionsEntryPutInput, SessionInstructionsEntryRemoveInput, SessionGenerateInput, SessionLogInput, SessionLogOutput, SessionInterruptInput, SessionBackgroundInput, SessionMessageInput, SessionEnvironmentInput, SessionViewInput, MessageListInput, ModelListInput, ModelListOutput, ModelDefaultInput, ModelDefaultOutput, GenerateTextInput, ProviderListInput, ProviderListOutput, ProviderGetInput, ProviderGetOutput, IntegrationListInput, IntegrationListOutput, IntegrationGetInput, IntegrationGetOutput, IntegrationWellknownAddInput, IntegrationConnectKeyInput, IntegrationOauthConnectInput, IntegrationOauthConnectOutput, IntegrationOauthStatusInput, IntegrationOauthStatusOutput, IntegrationOauthCompleteInput, IntegrationOauthCancelInput, IntegrationCommandConnectInput, IntegrationCommandConnectOutput, IntegrationCommandStatusInput, IntegrationCommandStatusOutput, IntegrationCommandCancelInput, McpListInput, McpListOutput, McpAddInput, McpRemoveInput, McpConnectInput, McpDisconnectInput, McpResourceCatalogInput, McpResourceCatalogOutput, CredentialUpdateInput, CredentialActivateInput, CredentialRemoveInput, ProjectListOutput, ProjectUpdateInput, FormRequestListInput, FormRequestListOutput, FormListInput, FormCreateInput, FormGetInput, FormStateInput, FormReplyInput, FormCancelInput, PermissionRequestListInput, PermissionRequestListOutput, PermissionSavedListInput, PermissionSavedRemoveInput, PermissionCreateInput, PermissionListInput, PermissionGetInput, PermissionReplyInput, PermissionRulesInput, FileReadInput, FileReadOutput, FileListInput, FileListOutput, FileFindInput, FileFindOutput, CommandListInput, CommandListOutput, SkillListInput, SkillListOutput, RpcCallInput, EventSubscribeOutput, PtyListInput, PtyListOutput, PtyCreateInput, PtyCreateOutput, PtyGetInput, PtyGetOutput, PtyUpdateInput, PtyUpdateOutput, PtyRemoveInput, PtyConnectTokenInput, PtyConnectTokenOutput, ExperimentalPersistentPtyReadInput, ExperimentalPersistentPtyListInput, ExperimentalPersistentPtyCreateInput, ExperimentalPersistentPtyHandoffOutput, ExperimentalPersistentPtyGetInput, ExperimentalPersistentPtyUpdateInput, ExperimentalPersistentPtySnapshotInput, ExperimentalPersistentPtyRemoveInput, ExperimentalPersistentPtyConnectTokenInput, ShellListInput, ShellListOutput, ShellCreateInput, ShellCreateOutput, ShellGetInput, ShellGetOutput, ShellTimeoutInput, ShellTimeoutOutput, ShellOutputInput, ShellOutputOutput, ShellRemoveInput, ReferenceListInput, ReferenceListOutput, WorktreeListInput, WorktreeCreateInput, WorktreeRemoveInput, WorktreeRefreshInput, VcsGetInput, VcsGetOutput, VcsBaseInput, VcsBaseOutput, VcsStatusInput, VcsStatusOutput, VcsBranchesInput, VcsBranchesOutput, VcsDiffInput, VcsDiffOutput, DebugLocationListOutput, DebugLocationEvictInput, MigrationV1StatusOutput, WebsearchProvidersInput, WebsearchProvidersOutput, WebsearchQueryInput, WebsearchQueryOutput, ConfigGetInput, ConfigGetOutput, ConfigShellsOutput } from "./types.js";
1
+ import type { LocationGetInput, AgentListInput, AgentListOutput, AgentGetInput, AgentGetOutput, PluginListInput, PluginListOutput, PluginCheckInput, PluginCheckOutput, PluginUpdateInput, SessionListInput, SessionStatsInput, SessionCreateInput, SessionImportInput, SessionExportInput, SessionGetInput, SessionRemoveInput, SessionForkInput, SessionSwitchAgentInput, SessionSwitchModelInput, SessionRenameInput, SessionMoveInput, SessionPromptInput, SessionCommandInput, SessionSkillInput, SessionSyntheticInput, SessionShellInput, SessionCompactInput, SessionWaitInput, SessionRevertStageInput, SessionRevertClearInput, SessionRevertCommitInput, SessionContextInput, SessionDiffInput, SessionInboxListInput, SessionInboxCancelInput, SessionInboxSteerInput, SessionInboxQueueInput, SessionInstructionsEntryListInput, SessionInstructionsEntryPutInput, SessionInstructionsEntryRemoveInput, SessionGenerateInput, SessionLogInput, SessionLogOutput, SessionInterruptInput, SessionBackgroundInput, SessionMessageInput, SessionEnvironmentInput, SessionViewInput, MessageListInput, ModelListInput, ModelListOutput, ModelDefaultInput, ModelDefaultOutput, GenerateTextInput, ProviderListInput, ProviderListOutput, ProviderGetInput, ProviderGetOutput, IntegrationListInput, IntegrationListOutput, IntegrationGetInput, IntegrationGetOutput, IntegrationWellknownAddInput, IntegrationConnectKeyInput, IntegrationOauthConnectInput, IntegrationOauthConnectOutput, IntegrationOauthStatusInput, IntegrationOauthStatusOutput, IntegrationOauthCompleteInput, IntegrationOauthCancelInput, IntegrationCommandConnectInput, IntegrationCommandConnectOutput, IntegrationCommandStatusInput, IntegrationCommandStatusOutput, IntegrationCommandCancelInput, McpListInput, McpListOutput, McpAddInput, McpRemoveInput, McpConnectInput, McpDisconnectInput, McpResourceCatalogInput, McpResourceCatalogOutput, CredentialUpdateInput, CredentialActivateInput, CredentialRemoveInput, ProjectListOutput, ProjectUpdateInput, FormRequestListInput, FormRequestListOutput, FormListInput, FormCreateInput, FormGetInput, FormStateInput, FormReplyInput, FormCancelInput, PermissionRequestListInput, PermissionRequestListOutput, PermissionSavedListInput, PermissionSavedRemoveInput, PermissionCreateInput, PermissionListInput, PermissionGetInput, PermissionReplyInput, PermissionRulesInput, FileReadInput, FileReadOutput, FileListInput, FileListOutput, FileFindInput, FileFindOutput, CommandListInput, CommandListOutput, SkillListInput, SkillListOutput, RpcCallInput, EventSubscribeOutput, PtyListInput, PtyListOutput, PtyCreateInput, PtyCreateOutput, PtyGetInput, PtyGetOutput, PtyUpdateInput, PtyUpdateOutput, PtyRemoveInput, PtyConnectTokenInput, PtyConnectTokenOutput, ExperimentalPersistentPtyReadInput, ExperimentalPersistentPtyListInput, ExperimentalPersistentPtyCreateInput, ExperimentalPersistentPtyHandoffOutput, ExperimentalPersistentPtyGetInput, ExperimentalPersistentPtyUpdateInput, ExperimentalPersistentPtySnapshotInput, ExperimentalPersistentPtyRemoveInput, ExperimentalPersistentPtyConnectTokenInput, ShellListInput, ShellListOutput, ShellCreateInput, ShellCreateOutput, ShellGetInput, ShellGetOutput, ShellTimeoutInput, ShellTimeoutOutput, ShellOutputInput, ShellOutputOutput, ShellRemoveInput, ReferenceListInput, ReferenceListOutput, WorktreeListInput, WorktreeCreateInput, WorktreeRemoveInput, WorktreeRefreshInput, VcsGetInput, VcsGetOutput, VcsBaseInput, VcsBaseOutput, VcsStatusInput, VcsStatusOutput, VcsBranchesInput, VcsBranchesOutput, VcsDiffInput, VcsDiffOutput, DebugLocationListOutput, DebugLocationEvictInput, MigrationV1StatusOutput, WebsearchProvidersInput, WebsearchProvidersOutput, WebsearchQueryInput, WebsearchQueryOutput, ConfigGetInput, ConfigGetOutput, ConfigShellsOutput, ConfigUpdateInput } from "./types.js";
2
2
  export interface ClientOptions {
3
3
  readonly baseUrl: string;
4
4
  readonly fetch?: typeof globalThis.fetch;
@@ -253,5 +253,6 @@ export declare function make(options: ClientOptions): {
253
253
  config: {
254
254
  get: (input?: ConfigGetInput, requestOptions?: RequestOptions) => Promise<ConfigGetOutput>;
255
255
  shells: (requestOptions?: RequestOptions) => Promise<ConfigShellsOutput>;
256
+ update: (input: ConfigUpdateInput, requestOptions?: RequestOptions) => Promise<void>;
256
257
  };
257
258
  };
@@ -1344,6 +1344,14 @@ export function make(options) {
1344
1344
  empty: false,
1345
1345
  }, requestOptions),
1346
1346
  shells: (requestOptions) => request({ method: "GET", path: `/api/config/shell`, successStatus: 200, declaredStatuses: [400, 401], empty: false }, requestOptions),
1347
+ update: (input, requestOptions) => request({
1348
+ method: "PATCH",
1349
+ path: `/api/experimental/config`,
1350
+ body: { shell: input["shell"] },
1351
+ successStatus: 204,
1352
+ declaredStatuses: [400, 401],
1353
+ empty: true,
1354
+ }, requestOptions),
1347
1355
  },
1348
1356
  };
1349
1357
  }
@@ -8360,3 +8360,9 @@ export type ConfigGetInput = {
8360
8360
  };
8361
8361
  export type ConfigGetOutput = Array<ConfigEntry>;
8362
8362
  export type ConfigShellsOutput = Array<ConfigShellOption>;
8363
+ export type ConfigUpdateInput = {
8364
+ readonly shell: {
8365
+ readonly shell: string | null;
8366
+ }["shell"];
8367
+ };
8368
+ export type ConfigUpdateOutput = void;
@@ -16,6 +16,8 @@ export async function discover(options = {}) {
16
16
  const found = (await registered(options.file)).service;
17
17
  if (found?.state !== "ready")
18
18
  return undefined;
19
+ if (!found.compatible)
20
+ return undefined;
19
21
  if (!matchesVersion(found.version, options))
20
22
  return undefined;
21
23
  return found.endpoint;
@@ -70,7 +72,7 @@ export async function ensure(options = {}) {
70
72
  if (registration.service !== undefined) {
71
73
  spawnDelay = timing.spawnDelay;
72
74
  const service = registration.service;
73
- const compatible = matchesVersion(service.version, options);
75
+ const compatible = service.compatible && matchesVersion(service.version, options);
74
76
  if (compatible && service.state === "ready") {
75
77
  await PtyHandoff.complete(options.file ?? fallback(), service.info);
76
78
  return service.endpoint;
@@ -156,30 +158,53 @@ async function probeResult(info, timeout = defaultEnsureTiming.requestTimeout) {
156
158
  const result = await fetch(new URL("/api/status", info.url), { headers: headers(endpoint), signal })
157
159
  .then(async (response) => ({
158
160
  response,
159
- body: (await response.json()),
161
+ body: response.status === 404 ? undefined : (await response.json()),
160
162
  }))
161
163
  .then((value) => ({ value }), (cause) => ({ cause }));
162
164
  if ("cause" in result)
163
165
  return { service: undefined, timedOut: signal.aborted };
164
166
  const response = result.value.response;
165
- const body = result.value.body;
166
- if (body !== undefined && "version" in body && "pid" in body) {
167
- if (body.pid !== info.pid)
167
+ // The previous V2 service exposes /api/health instead. Its authenticated 404 is enough
168
+ // to recognize the registered daemon as incompatible and route it through replacement.
169
+ if (response.status === 404)
170
+ return {
171
+ service: {
172
+ info,
173
+ endpoint,
174
+ version: info.version,
175
+ state: "ready",
176
+ compatible: false,
177
+ },
178
+ timedOut: false,
179
+ };
180
+ const status = decodeStatus(result.value.body);
181
+ if (status !== undefined) {
182
+ if (status.pid !== info.pid)
168
183
  return { service: undefined, timedOut: false };
169
- if (info.version !== undefined && body.version !== info.version)
184
+ if (info.version !== undefined && status.version !== info.version)
170
185
  return { service: undefined, timedOut: false };
171
186
  return {
172
187
  service: {
173
188
  info,
174
189
  endpoint,
175
- version: body.version,
190
+ version: status.version,
176
191
  state: response.ok ? "ready" : response.status === 500 ? "failed" : "waiting",
192
+ compatible: true,
177
193
  },
178
194
  timedOut: false,
179
195
  };
180
196
  }
181
197
  return { service: undefined, timedOut: false };
182
198
  }
199
+ function decodeStatus(input) {
200
+ if (typeof input !== "object" || input === null)
201
+ return;
202
+ if (!("version" in input) || typeof input.version !== "string")
203
+ return;
204
+ if (!("pid" in input) || typeof input.pid !== "number" || !Number.isInteger(input.pid) || input.pid < 0)
205
+ return;
206
+ return { version: input.version, pid: input.pid };
207
+ }
183
208
  async function registered(file, timeout) {
184
209
  const info = await read(file);
185
210
  if (info === undefined)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@opencode/client",
4
- "version": "0.0.0-dev-19563",
4
+ "version": "0.0.0-dev-19565",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -57,8 +57,8 @@
57
57
  "typecheck": "tsgo --noEmit"
58
58
  },
59
59
  "dependencies": {
60
- "@opencode/schema": "0.0.0-dev-19563",
61
- "@opencode/protocol": "0.0.0-dev-19563"
60
+ "@opencode/schema": "0.0.0-dev-19565",
61
+ "@opencode/protocol": "0.0.0-dev-19565"
62
62
  },
63
63
  "peerDependencies": {
64
64
  "effect": "4.0.0-rc.112",
@@ -74,7 +74,7 @@
74
74
  },
75
75
  "devDependencies": {
76
76
  "@effect/platform-node": "4.0.0-rc.112",
77
- "@opencode/httpapi-codegen": "0.0.0-dev-19563",
77
+ "@opencode/httpapi-codegen": "0.0.0-dev-19565",
78
78
  "@tsconfig/bun": "1.0.9",
79
79
  "@types/bun": "1.4.0",
80
80
  "@typescript/native-preview": "7.0.0-dev.20251207.1",