@opencode-ai/client 0.0.0-dev-18706 → 0.0.0-dev-18708

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.
@@ -27,6 +27,17 @@ export type PluginSource = {
27
27
  } | {
28
28
  type: "sdk";
29
29
  };
30
+ export type PluginFeatures = {
31
+ server?: true;
32
+ tui?: true;
33
+ rpc?: true;
34
+ };
35
+ export type PluginState = {
36
+ status: "active";
37
+ } | {
38
+ status: "failed";
39
+ error: string;
40
+ };
30
41
  export type SessionForkBoundary = {
31
42
  type: "before";
32
43
  messageID: string;
@@ -504,6 +515,9 @@ export type SkillInfo = {
504
515
  location: string;
505
516
  content: string;
506
517
  };
518
+ export type RpcOutput = {
519
+ output?: any;
520
+ };
507
521
  export type PermissionReply = "once" | "always" | "reject";
508
522
  export type Pty = {
509
523
  id: string;
@@ -669,16 +683,10 @@ export type PermissionRule = {
669
683
  effect: PermissionEffect;
670
684
  };
671
685
  export type PluginInfo = {
672
- id: string;
673
- source: PluginSource;
674
- status: "active";
675
- tui: boolean;
676
- } | {
677
686
  id?: string;
678
687
  source: PluginSource;
679
- status: "failed";
680
- error: string;
681
- tui: boolean;
688
+ features: PluginFeatures;
689
+ state: PluginState;
682
690
  };
683
691
  export type SessionMessageLocationSwitched = {
684
692
  id: string;
@@ -703,6 +711,18 @@ export type SessionInboxMovePayload = {
703
711
  projectID: string;
704
712
  subpath?: string;
705
713
  };
714
+ export type V2EventRpc = {
715
+ id: string;
716
+ created: number;
717
+ metadata?: {
718
+ [x: string]: any;
719
+ } | undefined;
720
+ type: `${"rpc."}${string}`;
721
+ location: LocationRef;
722
+ data: {
723
+ [x: string]: any;
724
+ };
725
+ };
706
726
  export type V2EventServerConnected = {
707
727
  id: string;
708
728
  metadata?: {
@@ -3105,7 +3125,7 @@ export type IntegrationInfo = {
3105
3125
  methods: Array<IntegrationMethod>;
3106
3126
  connections: Array<ConnectionInfo>;
3107
3127
  };
3108
- export type V2Event = ModelsDevRefreshed | CredentialUpdated | CredentialSwitched | IntegrationUpdated | CatalogUpdated | AgentUpdated | SessionCreated | SessionAgentSelected | SessionModelSelected | SessionMoved | SessionRenamed | SessionViewed | SessionUsageUpdated | SessionDeleted | SessionForked | SessionInboxDelivered | SessionInboxEnqueued | SessionInboxCancelled | SessionInboxDeliveryChanged | SessionExecutionStarted | SessionExecutionSucceeded | SessionExecutionFailed | SessionExecutionInterrupted | SessionInstructionsUpdated | SessionSynthetic | SessionSkillActivated | SessionShellStarted | SessionShellEnded | SessionStepStarted | SessionStepStreamed | SessionStepEnded | SessionStepFailed | SessionTextStarted | SessionTextDelta | SessionTextEnded | SessionReasoningStarted | SessionReasoningDelta | SessionReasoningEnded | SessionToolInputStarted | SessionToolInputDelta | SessionToolInputEnded | SessionToolCalled | SessionToolProgress | SessionToolSuccess | SessionToolFailed | SessionRetryScheduled | SessionCompactionStarted | SessionCompactionDelta | SessionCompactionEnded | SessionCompactionFailed | SessionRevertStaged | SessionRevertCleared | SessionRevertCommitted | SessionMessageContentUpdated | FilesystemChanged | ReferenceUpdated | PermissionAsked | PermissionReplied | PluginAdded | PluginUpdated | ProjectUpdated | WorktreeUpdated | WorktreeResolved | CommandUpdated | ConfigUpdated | SkillUpdated | PtyCreated | PtyUpdated | PtyExited | PtyDeleted | PersistentPtyAdded | PersistentPtyRemoved | ShellCreated | ShellExited | ShellDeleted | FormCreated | FormReplied | FormCancelled | WebsearchUpdated | SessionStatusUpdated | SessionIdle | TuiPromptAppend | TuiCommandExecute | TuiToastShow | TuiSessionSelect | InstallationUpdated | InstallationUpdateAvailable | VcsBranchUpdated | McpStatusChanged | McpResourcesChanged | V2EventServerConnected;
3128
+ export type V2Event = ModelsDevRefreshed | CredentialUpdated | CredentialSwitched | IntegrationUpdated | CatalogUpdated | AgentUpdated | SessionCreated | SessionAgentSelected | SessionModelSelected | SessionMoved | SessionRenamed | SessionViewed | SessionUsageUpdated | SessionDeleted | SessionForked | SessionInboxDelivered | SessionInboxEnqueued | SessionInboxCancelled | SessionInboxDeliveryChanged | SessionExecutionStarted | SessionExecutionSucceeded | SessionExecutionFailed | SessionExecutionInterrupted | SessionInstructionsUpdated | SessionSynthetic | SessionSkillActivated | SessionShellStarted | SessionShellEnded | SessionStepStarted | SessionStepStreamed | SessionStepEnded | SessionStepFailed | SessionTextStarted | SessionTextDelta | SessionTextEnded | SessionReasoningStarted | SessionReasoningDelta | SessionReasoningEnded | SessionToolInputStarted | SessionToolInputDelta | SessionToolInputEnded | SessionToolCalled | SessionToolProgress | SessionToolSuccess | SessionToolFailed | SessionRetryScheduled | SessionCompactionStarted | SessionCompactionDelta | SessionCompactionEnded | SessionCompactionFailed | SessionRevertStaged | SessionRevertCleared | SessionRevertCommitted | SessionMessageContentUpdated | FilesystemChanged | ReferenceUpdated | PermissionAsked | PermissionReplied | PluginAdded | PluginUpdated | ProjectUpdated | WorktreeUpdated | WorktreeResolved | CommandUpdated | ConfigUpdated | SkillUpdated | PtyCreated | PtyUpdated | PtyExited | PtyDeleted | PersistentPtyAdded | PersistentPtyRemoved | ShellCreated | ShellExited | ShellDeleted | FormCreated | FormReplied | FormCancelled | WebsearchUpdated | SessionStatusUpdated | SessionIdle | TuiPromptAppend | TuiCommandExecute | TuiToastShow | TuiSessionSelect | InstallationUpdated | InstallationUpdateAvailable | VcsBranchUpdated | McpStatusChanged | McpResourcesChanged | V2EventRpc | V2EventServerConnected;
3109
3129
  export type SessionLogItem = SessionEventDurable | EventLogSynced;
3110
3130
  export type UnauthorizedError = {
3111
3131
  readonly _tag: "UnauthorizedError";
@@ -3234,6 +3254,20 @@ export type PermissionNotFoundError = {
3234
3254
  readonly message: string;
3235
3255
  };
3236
3256
  export declare const isPermissionNotFoundError: (value: unknown) => value is PermissionNotFoundError;
3257
+ export type RpcError = {
3258
+ readonly _tag: "RpcError";
3259
+ readonly type: string;
3260
+ readonly message: string;
3261
+ readonly data?: unknown | undefined;
3262
+ };
3263
+ export declare const isRpcError: (value: unknown) => value is RpcError;
3264
+ export type RpcInternalError = {
3265
+ readonly _tag: "RpcInternalError";
3266
+ readonly type: "rpc.internal" | "rpc.invalid_output";
3267
+ readonly message: string;
3268
+ readonly data?: unknown | undefined;
3269
+ };
3270
+ export declare const isRpcInternalError: (value: unknown) => value is RpcInternalError;
3237
3271
  export type PtyNotFoundError = {
3238
3272
  readonly _tag: "PtyNotFoundError";
3239
3273
  readonly ptyID: string;
@@ -7637,6 +7671,26 @@ export type SkillListOutput = {
7637
7671
  };
7638
7672
  data: Array<SkillInfo>;
7639
7673
  };
7674
+ export type RpcCallInput = {
7675
+ readonly rpcID: {
7676
+ readonly rpcID: string;
7677
+ readonly method: string;
7678
+ }["rpcID"];
7679
+ readonly method: {
7680
+ readonly rpcID: string;
7681
+ readonly method: string;
7682
+ }["method"];
7683
+ readonly location?: {
7684
+ readonly location?: {
7685
+ readonly directory?: string | undefined;
7686
+ readonly workspace?: string | undefined;
7687
+ } | undefined;
7688
+ }["location"];
7689
+ readonly input?: {
7690
+ readonly input: JsonValue;
7691
+ }["input"];
7692
+ };
7693
+ export type RpcCallOutput = RpcOutput;
7640
7694
  export type EventSubscribeOutput = V2Event;
7641
7695
  export type PtyListInput = {
7642
7696
  readonly location?: {
@@ -22,6 +22,8 @@ export const isFormNotFoundError = (value) => typeof value === "object" && value
22
22
  export const isFormAlreadySettledError = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "FormAlreadySettledError";
23
23
  export const isFormInvalidAnswerError = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "FormInvalidAnswerError";
24
24
  export const isPermissionNotFoundError = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "PermissionNotFoundError";
25
+ export const isRpcError = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "RpcError";
26
+ export const isRpcInternalError = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "RpcInternalError";
25
27
  export const isPtyNotFoundError = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "PtyNotFoundError";
26
28
  export const isForbiddenError = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "ForbiddenError";
27
29
  export const isShellNotFoundError = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "ShellNotFoundError";
@@ -1,4 +1,6 @@
1
+ import type { OpenCode } from "./client.js";
1
2
  export * from "./generated/index.js";
2
- export type { AgentApi, CatalogApi, CommandApi, ConfigApi, EventApi, IntegrationApi, ModelApi, PluginApi, ProviderApi, ReferenceApi, WebSearchApi, SessionApi, SkillApi, } from "./api.js";
3
+ export { OpenCode } from "./client.js";
4
+ export type { AgentApi, CatalogApi, CommandApi, ConfigApi, EventApi, IntegrationApi, ModelApi, PluginApi, ProviderApi, ReferenceApi, RpcApi, RpcCallOptions, RpcClient, RpcEventPayload, WebSearchApi, SessionApi, SkillApi, } from "./api.js";
3
5
  export type { EventSubscribeOutput as OpenCodeEvent } from "./generated/types.js";
4
- export type OpenCodeClient = ReturnType<typeof import("./generated/client.js").make>;
6
+ export type OpenCodeClient = ReturnType<typeof OpenCode.make>;
@@ -1 +1,2 @@
1
1
  export * from "./generated/index.js";
2
+ export { OpenCode } from "./client.js";
@@ -0,0 +1,32 @@
1
+ import type { Rpc } from "@opencode-ai/schema/rpc";
2
+ import type { make, RequestOptions } from "./generated/client.js";
3
+ import type { EventSubscribeOutput, LocationGetInput } from "./generated/types.js";
4
+ type RpcEvent = Extract<EventSubscribeOutput, {
5
+ type: `rpc.${string}`;
6
+ }>;
7
+ export interface RpcCallOptions extends RequestOptions {
8
+ readonly location?: LocationGetInput["location"];
9
+ }
10
+ export type RpcArguments<Input, Options> = unknown extends Input ? [input: Input, options?: Options] : undefined extends Input ? [input?: Input, options?: Options] : [input: Input, options?: Options];
11
+ export type RpcClient<D extends Rpc.PortableDefinition, Options = RpcCallOptions> = {
12
+ readonly [Name in keyof D["methods"]]: (...args: RpcArguments<Rpc.Input<D["methods"][Name]["input"]>, Options>) => Promise<Rpc.Output<D["methods"][Name]["output"]>>;
13
+ } & {
14
+ readonly events: {
15
+ readonly subscribe: <Name extends keyof D["events"] & string>(name: Name, options?: Pick<RequestOptions, "signal">) => AsyncIterable<RpcEventPayload<D, Name>>;
16
+ readonly on: <Name extends keyof D["events"] & string>(name: Name, handler: (event: RpcEventPayload<D, Name>) => Promise<void> | void, options?: Pick<RequestOptions, "signal">) => () => void;
17
+ };
18
+ };
19
+ type RpcEventPayloadFor<D extends Rpc.PortableDefinition, Name extends keyof D["events"] & string> = Omit<RpcEvent, "type" | "data"> & {
20
+ type: `rpc.${D["id"]}.${Name}`;
21
+ data: Rpc.EventData<D["events"][Name]["schema"]>;
22
+ };
23
+ export type RpcEventPayload<D extends Rpc.PortableDefinition, Name extends keyof D["events"] & string = keyof D["events"] & string> = {
24
+ [K in Name]: RpcEventPayloadFor<D, K>;
25
+ }[Name];
26
+ export interface RpcApi<Options = RpcCallOptions> {
27
+ <D extends Rpc.PortableDefinition>(definition: D): RpcClient<D, Options>;
28
+ }
29
+ export declare function makeRpc(raw: ReturnType<typeof make>, events: {
30
+ subscribe(options?: Pick<RequestOptions, "signal">): AsyncIterable<EventSubscribeOutput>;
31
+ }): RpcApi;
32
+ export {};
@@ -0,0 +1,86 @@
1
+ import { isRpcError, isRpcInternalError } from "./generated/types.js";
2
+ export function makeRpc(raw, events) {
3
+ return (definition) => {
4
+ const subscribe = (name, options) => {
5
+ if (!Object.hasOwn(definition.events, name))
6
+ throw new Error(`Unknown RPC event: ${definition.id}.${name}`);
7
+ const type = eventType(definition, name);
8
+ return {
9
+ [Symbol.asyncIterator]() {
10
+ const controller = new AbortController();
11
+ const signal = options?.signal ? AbortSignal.any([controller.signal, options.signal]) : controller.signal;
12
+ const iterator = (async function* () {
13
+ try {
14
+ for await (const published of events.subscribe({ signal })) {
15
+ if (signal.aborted)
16
+ return;
17
+ if (published.type !== type)
18
+ continue;
19
+ // SAFETY: The exact RPC type was selected above; Promise contracts require no client-side transform.
20
+ // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion
21
+ yield published;
22
+ }
23
+ }
24
+ catch (error) {
25
+ if (!signal.aborted)
26
+ throw error;
27
+ }
28
+ finally {
29
+ controller.abort();
30
+ }
31
+ })();
32
+ return {
33
+ next: () => iterator.next(),
34
+ return: () => {
35
+ // Interrupt a pending source read before closing the generator.
36
+ controller.abort();
37
+ return iterator.return();
38
+ },
39
+ };
40
+ },
41
+ };
42
+ };
43
+ // SAFETY: Every runtime key comes from this definition's method and event maps, which define RpcClient's mapped keys.
44
+ // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion
45
+ return Object.assign(Object.fromEntries(Object.keys(definition.methods).map((name) => [
46
+ name,
47
+ async (input, options) => {
48
+ try {
49
+ const result = await raw.rpc.call({
50
+ rpcID: definition.id,
51
+ method: name,
52
+ // SAFETY: The method schema defines the accepted input; this assertion bridges it to the generic JSON transport.
53
+ // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion
54
+ input: input,
55
+ location: options?.location,
56
+ }, { signal: options?.signal, headers: options?.headers });
57
+ return result.output;
58
+ }
59
+ catch (error) {
60
+ if (!isRpcError(error) && !isRpcInternalError(error))
61
+ throw error;
62
+ throw error.data === undefined
63
+ ? { type: error.type, message: error.message }
64
+ : { type: error.type, message: error.message, data: error.data };
65
+ }
66
+ },
67
+ ])), {
68
+ events: {
69
+ subscribe,
70
+ on: (name, handler, options) => {
71
+ const controller = new AbortController();
72
+ const signal = options?.signal ? AbortSignal.any([controller.signal, options.signal]) : controller.signal;
73
+ const source = subscribe(name, { signal });
74
+ void (async () => {
75
+ for await (const event of source)
76
+ await handler(event);
77
+ })().catch((error) => console.error(error));
78
+ return () => controller.abort();
79
+ },
80
+ },
81
+ });
82
+ };
83
+ }
84
+ function eventType(definition, name) {
85
+ return `rpc.${definition.id}.${name}`;
86
+ }
@@ -0,0 +1,21 @@
1
+ export * as RpcRuntime from "./rpc-runtime.js";
2
+ import type { Rpc } from "@opencode-ai/schema/rpc";
3
+ import { Effect, Schema } from "effect";
4
+ export declare function read(schema: Rpc.Method["output"], value: unknown): Effect.Effect<unknown, Schema.SchemaError, never>;
5
+ export declare function readError(method: Rpc.Method, error: unknown): Effect.Effect<never, unknown>;
6
+ export declare const event: <D extends Rpc.Definition, Name extends keyof D["events"] & string>(definition: D, name: Name, schema: Rpc.EventDefinition, event: {
7
+ readonly id: string & import("effect/Brand").Brand<"Event.ID">;
8
+ readonly location: {
9
+ readonly directory: string & import("effect/Brand").Brand<"AbsolutePath">;
10
+ readonly workspaceID?: (string & import("effect/Brand").Brand<"Workspace.ID">) | undefined;
11
+ };
12
+ readonly data: {
13
+ readonly [x: string]: unknown;
14
+ };
15
+ readonly type: `rpc.${string}`;
16
+ readonly created: number;
17
+ readonly metadata?: {
18
+ readonly [x: string]: unknown;
19
+ } | undefined;
20
+ }) => Effect.Effect<Rpc.EventPayload<D, Name>, unknown, never>;
21
+ export declare function eventType<const D extends Rpc.Definition, const Name extends keyof D["events"] & string>(definition: D, name: Name): `rpc.${D["id"]}.${Name}`;
@@ -0,0 +1,32 @@
1
+ export * as RpcRuntime from "./rpc-runtime.js";
2
+ import { RpcError, RpcInternalError } from "@opencode-ai/protocol/errors";
3
+ import { Effect, Schema } from "effect";
4
+ export function read(schema, value) {
5
+ // Standard Schema results have already been parsed by the server.
6
+ return Schema.isSchema(schema) ? Schema.decodeUnknownEffect(schema)(value) : Effect.succeed(value);
7
+ }
8
+ export function readError(method, error) {
9
+ if (!(error instanceof RpcError) && !(error instanceof RpcInternalError))
10
+ return Effect.fail(error);
11
+ if (!method.errors || !Object.hasOwn(method.errors, error.type)) {
12
+ return Effect.fail(error.data === undefined
13
+ ? { type: error.type, message: error.message }
14
+ : { type: error.type, message: error.message, data: error.data });
15
+ }
16
+ return read(method.errors[error.type], error.data).pipe(Effect.catch((cause) => Effect.die(cause)), Effect.flatMap((data) => Effect.fail(data === undefined
17
+ ? { type: error.type, message: error.message }
18
+ : { type: error.type, message: error.message, data })));
19
+ }
20
+ export const event = Effect.fn("Client.Rpc.event")(function* (definition, name, schema, event) {
21
+ const data = yield* read(schema.schema, event.data);
22
+ // SAFETY: The event type was selected by the caller and data was decoded with this event's schema.
23
+ // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion
24
+ return {
25
+ ...event,
26
+ type: eventType(definition, name),
27
+ data,
28
+ };
29
+ });
30
+ export function eventType(definition, name) {
31
+ return `rpc.${definition.id}.${name}`;
32
+ }
@@ -0,0 +1,8 @@
1
+ export * as SharedEvents from "./shared-events.js";
2
+ export declare function make<A extends {
3
+ readonly type: string;
4
+ }>(connect: (signal: AbortSignal) => AsyncIterable<A>): {
5
+ subscribe(options?: {
6
+ readonly signal?: AbortSignal;
7
+ }): AsyncIterable<A>;
8
+ };
@@ -0,0 +1,133 @@
1
+ export * as SharedEvents from "./shared-events.js";
2
+ export function make(connect) {
3
+ let current;
4
+ const delivered = Promise.resolve();
5
+ function stop(connection) {
6
+ connection.connected = undefined;
7
+ connection.controller.abort();
8
+ if (current === connection)
9
+ current = undefined;
10
+ }
11
+ async function run(connection) {
12
+ let iterator;
13
+ let completion = {};
14
+ try {
15
+ if (connection.controller.signal.aborted)
16
+ return;
17
+ iterator = connect(connection.controller.signal)[Symbol.asyncIterator]();
18
+ while (!connection.controller.signal.aborted) {
19
+ const item = await iterator.next();
20
+ if (item.done || connection.controller.signal.aborted)
21
+ break;
22
+ if (item.value.type === "server.connected")
23
+ connection.connected = item.value;
24
+ await Promise.all(Array.from(connection.subscribers, (subscriber) => subscriber.push(item.value)));
25
+ }
26
+ }
27
+ catch (error) {
28
+ completion = { error };
29
+ }
30
+ finally {
31
+ stop(connection);
32
+ try {
33
+ await iterator?.return?.();
34
+ }
35
+ catch (error) {
36
+ if (!("error" in completion))
37
+ completion = { error };
38
+ }
39
+ connection.subscribers.forEach((subscriber) => subscriber.finish(completion));
40
+ }
41
+ }
42
+ return {
43
+ subscribe(options) {
44
+ return {
45
+ [Symbol.asyncIterator]() {
46
+ const pending = [];
47
+ let started = false;
48
+ let completion;
49
+ let connection;
50
+ let offered;
51
+ function finish(result) {
52
+ completion = result;
53
+ offered?.accepted.resolve();
54
+ offered = undefined;
55
+ options?.signal?.removeEventListener("abort", abort);
56
+ if (connection?.subscribers.delete(subscriber) && !connection.subscribers.size)
57
+ stop(connection);
58
+ pending.splice(0).forEach((request) => {
59
+ if ("error" in result)
60
+ request.reject(result.error);
61
+ else
62
+ request.resolve({ done: true, value: undefined });
63
+ });
64
+ }
65
+ function abort() {
66
+ finish({});
67
+ }
68
+ const subscriber = {
69
+ finish,
70
+ push(value) {
71
+ if (completion)
72
+ return delivered;
73
+ const request = pending.shift();
74
+ if (request) {
75
+ request.resolve({ done: false, value });
76
+ return delivered;
77
+ }
78
+ const accepted = Promise.withResolvers();
79
+ offered = { value, accepted };
80
+ return accepted.promise;
81
+ },
82
+ };
83
+ function start() {
84
+ if (completion)
85
+ return;
86
+ const fresh = !current;
87
+ connection = current ?? {
88
+ controller: new AbortController(),
89
+ subscribers: new Set(),
90
+ };
91
+ current = connection;
92
+ connection.subscribers.add(subscriber);
93
+ if (connection.connected)
94
+ void subscriber.push(connection.connected);
95
+ if (fresh)
96
+ void run(connection);
97
+ }
98
+ return {
99
+ next() {
100
+ if (offered) {
101
+ const current = offered;
102
+ offered = undefined;
103
+ current.accepted.resolve();
104
+ return Promise.resolve({ done: false, value: current.value });
105
+ }
106
+ if (completion) {
107
+ if ("error" in completion)
108
+ return Promise.reject(completion.error);
109
+ return Promise.resolve({ done: true, value: undefined });
110
+ }
111
+ if (options?.signal?.aborted) {
112
+ abort();
113
+ return Promise.resolve({ done: true, value: undefined });
114
+ }
115
+ const request = Promise.withResolvers();
116
+ pending.push(request);
117
+ if (!started) {
118
+ started = true;
119
+ options?.signal?.addEventListener("abort", abort, { once: true });
120
+ start();
121
+ }
122
+ return request.promise;
123
+ },
124
+ return() {
125
+ finish({});
126
+ return Promise.resolve({ done: true, value: undefined });
127
+ },
128
+ };
129
+ },
130
+ };
131
+ },
132
+ };
133
+ }
@@ -62,7 +62,7 @@ export function createClientConnection(initialApi, options) {
62
62
  return { error: undefined, connectedAt };
63
63
  if (event.done)
64
64
  return { error: new Error("Event stream disconnected"), connectedAt };
65
- if ("durable" in event.value)
65
+ if ("durable" in event.value && event.value.durable)
66
66
  options.log?.debug?.("event", {
67
67
  type: event.value.type,
68
68
  aggregateID: event.value.durable.aggregateID,
@@ -1,13 +1,16 @@
1
1
  import type { AgentInfo, CommandInfo, FormCancelInput, FormInfo, FormReplyInput, IntegrationInfo, LocationRef, LocationGetOutput, McpResource, McpServer, ModelInfo, ModelRef, PermissionSavedInfo, PermissionRequest, PermissionReplyInput, Project, ProviderInfo, ReferenceInfo, SessionMessageInfo, SessionInfo, SessionInboxInfo, SessionInboxCompaction, ShellInfo, SkillInfo, VcsInfo, OpenCodeEvent, OpenCodeClient, WebSearchProvider } from "../promise";
2
2
  import { type SessionPromptInput } from "../promise";
3
3
  export type DataSessionStatus = "idle" | "running";
4
+ type OpenCodeEventMap = {
5
+ [Type in OpenCodeEvent["type"]]: Extract<OpenCodeEvent, {
6
+ type: Type;
7
+ }>;
8
+ };
4
9
  export type CreateDataInput = {
5
10
  readonly api: () => OpenCodeClient;
6
11
  readonly directory: string;
7
12
  readonly event: {
8
- readonly on: <Type extends OpenCodeEvent["type"]>(type: Type, handler: (event: Extract<OpenCodeEvent, {
9
- type: Type;
10
- }>) => void) => () => void;
13
+ readonly on: <Type extends OpenCodeEvent["type"]>(type: Type, handler: (event: OpenCodeEventMap[Type]) => void) => () => void;
11
14
  readonly listen: (handler: (event: {
12
15
  name: OpenCodeEvent["type"];
13
16
  details: OpenCodeEvent;
@@ -25,9 +28,7 @@ type ShellWithLocation = ShellInfo & {
25
28
  };
26
29
  export declare function locationKey(location: LocationRef): string;
27
30
  export declare function createData(config: CreateDataInput): {
28
- on: <Type extends OpenCodeEvent["type"]>(type: Type, handler: (event: Extract<OpenCodeEvent, {
29
- type: Type;
30
- }>) => void) => () => void;
31
+ on: <Type extends OpenCodeEvent["type"]>(type: Type, handler: (event: OpenCodeEventMap[Type]) => void) => () => void;
31
32
  listen: (handler: (event: {
32
33
  name: OpenCodeEvent["type"];
33
34
  details: OpenCodeEvent;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@opencode-ai/client",
4
- "version": "0.0.0-dev-18706",
4
+ "version": "0.0.0-dev-18708",
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-ai/schema": "0.0.0-dev-18706",
61
- "@opencode-ai/protocol": "0.0.0-dev-18706"
60
+ "@opencode-ai/schema": "0.0.0-dev-18708",
61
+ "@opencode-ai/protocol": "0.0.0-dev-18708"
62
62
  },
63
63
  "peerDependencies": {
64
64
  "effect": "4.0.0-rc.112",
@@ -74,11 +74,12 @@
74
74
  },
75
75
  "devDependencies": {
76
76
  "@effect/platform-node": "4.0.0-rc.112",
77
- "@opencode-ai/httpapi-codegen": "0.0.0-dev-18706",
77
+ "@opencode-ai/httpapi-codegen": "0.0.0-dev-18708",
78
78
  "@tsconfig/bun": "1.0.9",
79
79
  "@types/bun": "1.3.13",
80
80
  "@typescript/native-preview": "7.0.0-dev.20251207.1",
81
81
  "effect": "4.0.0-rc.112",
82
- "solid-js": "1.9.15"
82
+ "solid-js": "1.9.15",
83
+ "zod": "4.1.8"
83
84
  }
84
85
  }