refactor(tui): migrate v2 calls to new client
This commit is contained in:
@@ -17,12 +17,7 @@ await Effect.runPromise(
|
|||||||
[
|
[
|
||||||
write(
|
write(
|
||||||
emitPromise(promiseContract, {
|
emitPromise(promiseContract, {
|
||||||
outputTypes: {
|
mutableOutputs: true,
|
||||||
"events.subscribe": {
|
|
||||||
name: "OpenCodeEventEncoded",
|
|
||||||
import: 'import type { OpenCodeEventEncoded } from "@opencode-ai/protocol/groups/event"',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
fileURLToPath(new URL("../src/promise/generated", import.meta.url)),
|
fileURLToPath(new URL("../src/promise/generated", import.meta.url)),
|
||||||
),
|
),
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -296,6 +296,7 @@ export function emitPromise(
|
|||||||
contract: Contract,
|
contract: Contract,
|
||||||
options?: {
|
options?: {
|
||||||
readonly outputTypes?: Readonly<Record<string, { readonly name: string; readonly import: string }>>
|
readonly outputTypes?: Readonly<Record<string, { readonly name: string; readonly import: string }>>
|
||||||
|
readonly mutableOutputs?: boolean
|
||||||
},
|
},
|
||||||
): Output {
|
): Output {
|
||||||
const groups = contract.groups
|
const groups = contract.groups
|
||||||
@@ -305,7 +306,7 @@ export function emitPromise(
|
|||||||
return {
|
return {
|
||||||
operations: promiseOperations(groups),
|
operations: promiseOperations(groups),
|
||||||
files: [
|
files: [
|
||||||
{ path: "types.ts", content: renderPromiseTypes(groups, options?.outputTypes) },
|
{ path: "types.ts", content: renderPromiseTypes(groups, options?.outputTypes, options?.mutableOutputs ?? false) },
|
||||||
{
|
{
|
||||||
path: "client-error.ts",
|
path: "client-error.ts",
|
||||||
content: `export type ClientErrorReason = "Transport" | "UnexpectedStatus" | "UnsupportedContentType" | "MalformedResponse"\n\nexport class ClientError extends Error {\n override readonly name = "ClientError"\n constructor(readonly reason: ClientErrorReason, options?: ErrorOptions) {\n super(reason, options)\n }\n}\n`,
|
content: `export type ClientErrorReason = "Transport" | "UnexpectedStatus" | "UnsupportedContentType" | "MalformedResponse"\n\nexport class ClientError extends Error {\n override readonly name = "ClientError"\n constructor(readonly reason: ClientErrorReason, options?: ErrorOptions) {\n super(reason, options)\n }\n}\n`,
|
||||||
@@ -568,6 +569,7 @@ function renderImportedProjection(groups: ReadonlyArray<Group>, endpoints: Reado
|
|||||||
function renderPromiseTypes(
|
function renderPromiseTypes(
|
||||||
groups: ReadonlyArray<Group>,
|
groups: ReadonlyArray<Group>,
|
||||||
outputTypes?: Readonly<Record<string, { readonly name: string; readonly import: string }>>,
|
outputTypes?: Readonly<Record<string, { readonly name: string; readonly import: string }>>,
|
||||||
|
mutableOutputs = false,
|
||||||
) {
|
) {
|
||||||
const types = new Map<SchemaAST.AST, string>()
|
const types = new Map<SchemaAST.AST, string>()
|
||||||
const typeOf = (schema: Schema.Top, decoded = false) => {
|
const typeOf = (schema: Schema.Top, decoded = false) => {
|
||||||
@@ -623,20 +625,25 @@ function renderPromiseTypes(
|
|||||||
: successSchema.events
|
: successSchema.events
|
||||||
: successSchema,
|
: successSchema,
|
||||||
)
|
)
|
||||||
|
const output = mutableOutputs ? mutableType(success) : success
|
||||||
return [
|
return [
|
||||||
...(promiseInputMode(endpoint) === "none" ? [] : [`export type ${prefix}Input = { ${input} }`]),
|
...(promiseInputMode(endpoint) === "none" ? [] : [`export type ${prefix}Input = { ${input} }`]),
|
||||||
`export type ${prefix}Output = ${endpoint.unwrapData ? `(${success})["data"]` : success}`,
|
`export type ${prefix}Output = ${endpoint.unwrapData ? `(${output})["data"]` : output}`,
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.join("\n\n")
|
.join("\n\n")
|
||||||
const json = operations.includes("JsonValue")
|
const json = operations.includes("JsonValue")
|
||||||
? "export type JsonValue = null | boolean | number | string | ReadonlyArray<JsonValue> | { readonly [key: string]: JsonValue }"
|
? `export type JsonValue = null | boolean | number | string | ${mutableOutputs ? "Array<JsonValue> | { [key: string]: JsonValue }" : "ReadonlyArray<JsonValue> | { readonly [key: string]: JsonValue }"}`
|
||||||
: ""
|
: ""
|
||||||
const imports = [...new Set(Object.values(outputTypes ?? {}).map((override) => override.import))]
|
const imports = [...new Set(Object.values(outputTypes ?? {}).map((override) => override.import))]
|
||||||
return [...imports, json, ...errorTypes, operations].filter(Boolean).join("\n\n")
|
return [...imports, json, ...errorTypes, operations].filter(Boolean).join("\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mutableType(type: string) {
|
||||||
|
return type.replaceAll("ReadonlyArray<", "Array<").replaceAll(/\breadonly\s+/g, "")
|
||||||
|
}
|
||||||
|
|
||||||
function renderPromiseClient(groups: ReadonlyArray<Group>) {
|
function renderPromiseClient(groups: ReadonlyArray<Group>) {
|
||||||
const imports = groups.flatMap((group) =>
|
const imports = groups.flatMap((group) =>
|
||||||
group.endpoints.flatMap((endpoint) => {
|
group.endpoints.flatMap((endpoint) => {
|
||||||
|
|||||||
@@ -513,6 +513,24 @@ describe("HttpApiCodegen.generate", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("emits mutable Promise outputs without restricting inputs", () => {
|
||||||
|
const output = emitPromise(
|
||||||
|
compileContract(
|
||||||
|
api(
|
||||||
|
HttpApiEndpoint.post("create", "/session", {
|
||||||
|
payload: Schema.Struct({ values: Schema.Array(Schema.String) }),
|
||||||
|
success: Schema.Struct({ data: Schema.Array(Schema.Struct({ values: Schema.Array(Schema.String) })) }),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
{ mutableOutputs: true },
|
||||||
|
)
|
||||||
|
const types = output.files.find((file) => file.path === "types.ts")?.content
|
||||||
|
|
||||||
|
expect(types).toContain('readonly "values": ReadonlyArray<string>')
|
||||||
|
expect(types).toContain('export type SessionCreateOutput = ({ "data": Array<{ "values": Array<string> }> })["data"]')
|
||||||
|
})
|
||||||
|
|
||||||
test("expands Promise references only at identifier boundaries", () => {
|
test("expands Promise references only at identifier boundaries", () => {
|
||||||
const Session = Schema.Struct({ name: Schema.Literal("Session"), id: Schema.String }).annotate({
|
const Session = Schema.Struct({ name: Schema.Literal("Session"), id: Schema.String }).annotate({
|
||||||
identifier: "Session",
|
identifier: "Session",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import type {
|
import type {
|
||||||
OpencodeClient,
|
OpencodeClient,
|
||||||
V2Event,
|
|
||||||
LspStatus,
|
LspStatus,
|
||||||
McpStatus,
|
McpStatus,
|
||||||
Message,
|
Message,
|
||||||
@@ -12,6 +11,7 @@ import type {
|
|||||||
SessionStatus,
|
SessionStatus,
|
||||||
Config as SdkConfig,
|
Config as SdkConfig,
|
||||||
} from "@opencode-ai/sdk/v2"
|
} from "@opencode-ai/sdk/v2"
|
||||||
|
import type { OpenCodeEvent } from "@opencode-ai/client/promise"
|
||||||
import type { PromptInput } from "@opencode-ai/schema"
|
import type { PromptInput } from "@opencode-ai/schema"
|
||||||
import type { Types } from "effect"
|
import type { Types } from "effect"
|
||||||
import type { CliRenderer, KeyEvent, RGBA, Renderable, SlotMode } from "@opentui/core"
|
import type { CliRenderer, KeyEvent, RGBA, Renderable, SlotMode } from "@opentui/core"
|
||||||
@@ -507,9 +507,9 @@ export type TuiSlots = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type TuiEventBus = {
|
export type TuiEventBus = {
|
||||||
on: <Type extends V2Event["type"]>(
|
on: <Type extends OpenCodeEvent["type"]>(
|
||||||
type: Type,
|
type: Type,
|
||||||
handler: (event: Extract<V2Event, { type: Type }>) => void,
|
handler: (event: Extract<OpenCodeEvent, { type: Type }>) => void,
|
||||||
) => () => void
|
) => () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,8 @@ export function DialogPair(props: { credentials?: DialogPairCredentials }) {
|
|||||||
dialog.setCentered(true)
|
dialog.setCentered(true)
|
||||||
|
|
||||||
const [server] = createResource(() =>
|
const [server] = createResource(() =>
|
||||||
sdk.client.v2.server
|
sdk.api.server
|
||||||
.get({ throwOnError: true })
|
.get()
|
||||||
.then((result) => result.data)
|
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setLoadError(error)
|
setLoadError(error)
|
||||||
return undefined
|
return undefined
|
||||||
|
|||||||
@@ -44,8 +44,7 @@ export function DialogSessionList() {
|
|||||||
directory: location.directory,
|
directory: location.directory,
|
||||||
workspace: location.workspaceID,
|
workspace: location.workspaceID,
|
||||||
})
|
})
|
||||||
// oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- generated client output is readonly; session list UI reuses legacy mutable session types.
|
return { query, sessions: response.data }
|
||||||
return { query, sessions: structuredClone(response.data) as SessionInfo[] }
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// A transient transport failure must degrade search, not crash the TUI
|
// A transient transport failure must degrade search, not crash the TUI
|
||||||
// through the root ErrorBoundary when the errored resource is read.
|
// through the root ErrorBoundary when the errored resource is read.
|
||||||
@@ -141,7 +140,7 @@ export function DialogSessionList() {
|
|||||||
setToDelete(option.value)
|
setToDelete(option.value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
void sdk.client.v2.session.remove({ sessionID: option.value }, { throwOnError: true }).catch((error) => {
|
void sdk.api.session.remove({ sessionID: option.value }).catch((error) => {
|
||||||
setToDelete(undefined)
|
setToDelete(undefined)
|
||||||
toast.show({
|
toast.show({
|
||||||
message: `Failed to delete session: ${errorMessage(error)}`,
|
message: `Failed to delete session: ${errorMessage(error)}`,
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import { usePromptStash } from "../../prompt/stash"
|
|||||||
import { DialogStash } from "../dialog-stash"
|
import { DialogStash } from "../dialog-stash"
|
||||||
import { type AutocompleteRef, Autocomplete } from "./autocomplete"
|
import { type AutocompleteRef, Autocomplete } from "./autocomplete"
|
||||||
import { useRenderer, useTerminalDimensions, type JSX } from "@opentui/solid"
|
import { useRenderer, useTerminalDimensions, type JSX } from "@opentui/solid"
|
||||||
import type { SessionInfo, UserMessage } from "@opencode-ai/sdk/v2"
|
import type { UserMessage } from "@opencode-ai/sdk/v2"
|
||||||
import { Locale } from "../../util/locale"
|
import { Locale } from "../../util/locale"
|
||||||
import { errorMessage } from "../../util/error"
|
import { errorMessage } from "../../util/error"
|
||||||
import { createColors, createFrames } from "../../ui/spinner"
|
import { createColors, createFrames } from "../../ui/spinner"
|
||||||
@@ -1027,8 +1027,7 @@ export function Prompt(props: PromptProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sessionID = created.id
|
sessionID = created.id
|
||||||
// oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- generated client output is readonly; prompt state still uses legacy mutable session types.
|
session = created
|
||||||
session = structuredClone(created) as SessionInfo
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const inputText = expandTrackedPastedText(
|
const inputText = expandTrackedPastedText(
|
||||||
@@ -1064,7 +1063,7 @@ export function Prompt(props: PromptProps) {
|
|||||||
|
|
||||||
if (store.mode === "shell") {
|
if (store.mode === "shell") {
|
||||||
move.startSubmit()
|
move.startSubmit()
|
||||||
void sdk.client.v2.session.shell({
|
void sdk.api.session.shell({
|
||||||
sessionID,
|
sessionID,
|
||||||
command: inputText,
|
command: inputText,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ import type {
|
|||||||
SessionInfo,
|
SessionInfo,
|
||||||
Shell,
|
Shell,
|
||||||
SkillInfo,
|
SkillInfo,
|
||||||
V2Event,
|
|
||||||
} from "@opencode-ai/sdk/v2"
|
} from "@opencode-ai/sdk/v2"
|
||||||
|
import type { OpenCodeEvent } from "@opencode-ai/client/promise"
|
||||||
import { createStore, produce, reconcile } from "solid-js/store"
|
import { createStore, produce, reconcile } from "solid-js/store"
|
||||||
import { createSimpleContext } from "./helper"
|
import { createSimpleContext } from "./helper"
|
||||||
import { useSDK } from "./sdk"
|
import { useSDK } from "./sdk"
|
||||||
@@ -82,14 +82,6 @@ function locationQuery(ref?: LocationRef) {
|
|||||||
return ref ? { directory: ref.directory, workspace: ref.workspaceID } : undefined
|
return ref ? { directory: ref.directory, workspace: ref.workspaceID } : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutable<T> =
|
|
||||||
T extends ReadonlyArray<infer U> ? Mutable<U>[] : T extends object ? { -readonly [K in keyof T]: Mutable<T[K]> } : T
|
|
||||||
|
|
||||||
function mutable<T>(value: T): Mutable<T> {
|
|
||||||
// oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- generated client data is readonly; the TUI store mutates cloned state.
|
|
||||||
return structuredClone(value) as Mutable<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
export const { use: useData, provider: DataProvider } = createSimpleContext({
|
export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||||
name: "Data",
|
name: "Data",
|
||||||
init: () => {
|
init: () => {
|
||||||
@@ -241,7 +233,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleEvent(event: V2Event) {
|
function handleEvent(event: OpenCodeEvent) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case "session.created":
|
case "session.created":
|
||||||
void result.session.refresh(event.data.sessionID)
|
void result.session.refresh(event.data.sessionID)
|
||||||
@@ -300,8 +292,8 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
.then((item) => {
|
.then((item) => {
|
||||||
message.update(event.data.sessionID, (draft, index) => {
|
message.update(event.data.sessionID, (draft, index) => {
|
||||||
const position = index.get(item.id)
|
const position = index.get(item.id)
|
||||||
if (position === undefined) return message.append(draft, index, mutable(item))
|
if (position === undefined) return message.append(draft, index, item)
|
||||||
draft[position] = mutable(item)
|
draft[position] = item
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch((error) => console.error("Failed to load projected model switch message", error))
|
.catch((error) => console.error("Failed to load projected model switch message", error))
|
||||||
@@ -312,7 +304,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
break
|
break
|
||||||
case "session.moved":
|
case "session.moved":
|
||||||
if (store.session.info[event.data.sessionID]) {
|
if (store.session.info[event.data.sessionID]) {
|
||||||
setStore("session", "info", event.data.sessionID, "location", mutable(event.data.location))
|
setStore("session", "info", event.data.sessionID, "location", event.data.location)
|
||||||
setStore("session", "info", event.data.sessionID, "subpath", event.data.subpath)
|
setStore("session", "info", event.data.sessionID, "subpath", event.data.subpath)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
@@ -745,11 +737,9 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
if (store.session.form[event.data.form.sessionID]?.some((form) => form.id === event.data.form.id)) break
|
if (store.session.form[event.data.form.sessionID]?.some((form) => form.id === event.data.form.id)) break
|
||||||
setStore("session", "form", event.data.form.sessionID, [
|
setStore("session", "form", event.data.form.sessionID, [
|
||||||
...(store.session.form[event.data.form.sessionID] ?? []),
|
...(store.session.form[event.data.form.sessionID] ?? []),
|
||||||
mutable(
|
event.data.form.sessionID === "global"
|
||||||
event.data.form.sessionID === "global"
|
? { ...event.data.form, location: event.location }
|
||||||
? { ...event.data.form, location: event.location }
|
: event.data.form,
|
||||||
: event.data.form,
|
|
||||||
),
|
|
||||||
])
|
])
|
||||||
break
|
break
|
||||||
case "form.replied":
|
case "form.replied":
|
||||||
@@ -830,7 +820,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
async refresh(sessionID: string) {
|
async refresh(sessionID: string) {
|
||||||
setStore("session", "info", sessionID, mutable(await sdk.api.session.get({ sessionID })))
|
setStore("session", "info", sessionID, await sdk.api.session.get({ sessionID }))
|
||||||
registerSession(sessionID)
|
registerSession(sessionID)
|
||||||
},
|
},
|
||||||
message: {
|
message: {
|
||||||
@@ -846,9 +836,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
return position === undefined ? undefined : messages?.[position]
|
return position === undefined ? undefined : messages?.[position]
|
||||||
},
|
},
|
||||||
async refresh(sessionID: string) {
|
async refresh(sessionID: string) {
|
||||||
const messages = mutable(
|
const messages = (await sdk.api.message.list({ sessionID, limit: 200, order: "desc" })).data.toReversed()
|
||||||
(await sdk.api.message.list({ sessionID, limit: 200, order: "desc" })).data,
|
|
||||||
).toReversed()
|
|
||||||
messageIndex.set(sessionID, new Map(messages.map((message, index) => [message.id, index])))
|
messageIndex.set(sessionID, new Map(messages.map((message, index) => [message.id, index])))
|
||||||
setStore("session", "message", sessionID, reconcile(messages))
|
setStore("session", "message", sessionID, reconcile(messages))
|
||||||
},
|
},
|
||||||
@@ -858,7 +846,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
return store.session.permission[sessionID]
|
return store.session.permission[sessionID]
|
||||||
},
|
},
|
||||||
async refresh(sessionID: string) {
|
async refresh(sessionID: string) {
|
||||||
setStore("session", "permission", sessionID, mutable(await sdk.api.permission.list({ sessionID })))
|
setStore("session", "permission", sessionID, await sdk.api.permission.list({ sessionID }))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
@@ -881,13 +869,11 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
...(store.session.form[sessionID] ?? []).filter(
|
...(store.session.form[sessionID] ?? []).filter(
|
||||||
(form) => form.location && locationKey(form.location) !== key,
|
(form) => form.location && locationKey(form.location) !== key,
|
||||||
),
|
),
|
||||||
...mutable(
|
...response.data.filter((form) => form.sessionID === "global").map((form) => ({ ...form, location })),
|
||||||
response.data.filter((form) => form.sessionID === "global").map((form) => ({ ...form, location })),
|
|
||||||
),
|
|
||||||
])
|
])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setStore("session", "form", sessionID, mutable(await sdk.api.form.list({ sessionID })))
|
setStore("session", "form", sessionID, await sdk.api.form.list({ sessionID }))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -897,7 +883,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
return store.project.permission[projectID]
|
return store.project.permission[projectID]
|
||||||
},
|
},
|
||||||
async refresh(projectID: string) {
|
async refresh(projectID: string) {
|
||||||
setStore("project", "permission", projectID, mutable(await sdk.api.permission.saved.list({ projectID })))
|
setStore("project", "permission", projectID, await sdk.api.permission.saved.list({ projectID }))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -915,7 +901,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
const key = locationKey(result.location)
|
const key = locationKey(result.location)
|
||||||
setStore("location", key, {
|
setStore("location", key, {
|
||||||
...store.location[key],
|
...store.location[key],
|
||||||
shell: Object.fromEntries(mutable(result.data).map((info) => [info.id, info])),
|
shell: Object.fromEntries(result.data.map((info) => [info.id, info])),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -936,7 +922,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
async refresh(ref?: LocationRef) {
|
async refresh(ref?: LocationRef) {
|
||||||
const result = await sdk.api.agent.list({ location: locationQuery(ref ?? defaultLocation()) })
|
const result = await sdk.api.agent.list({ location: locationQuery(ref ?? defaultLocation()) })
|
||||||
const key = locationKey(result.location)
|
const key = locationKey(result.location)
|
||||||
setStore("location", key, { ...store.location[key], agent: mutable(result.data) })
|
setStore("location", key, { ...store.location[key], agent: result.data })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
command: {
|
command: {
|
||||||
@@ -946,7 +932,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
async refresh(ref?: LocationRef) {
|
async refresh(ref?: LocationRef) {
|
||||||
const result = await sdk.api.command.list({ location: locationQuery(ref ?? defaultLocation()) })
|
const result = await sdk.api.command.list({ location: locationQuery(ref ?? defaultLocation()) })
|
||||||
const key = locationKey(result.location)
|
const key = locationKey(result.location)
|
||||||
setStore("location", key, { ...store.location[key], command: mutable(result.data) })
|
setStore("location", key, { ...store.location[key], command: result.data })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
integration: {
|
integration: {
|
||||||
@@ -956,7 +942,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
async refresh(ref?: LocationRef) {
|
async refresh(ref?: LocationRef) {
|
||||||
const result = await sdk.api.integration.list({ location: locationQuery(ref ?? defaultLocation()) })
|
const result = await sdk.api.integration.list({ location: locationQuery(ref ?? defaultLocation()) })
|
||||||
const key = locationKey(result.location)
|
const key = locationKey(result.location)
|
||||||
setStore("location", key, { ...store.location[key], integration: mutable(result.data) })
|
setStore("location", key, { ...store.location[key], integration: result.data })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mcp: {
|
mcp: {
|
||||||
@@ -964,9 +950,9 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
return store.location[locationKey(location ?? defaultLocation())]?.mcp
|
return store.location[locationKey(location ?? defaultLocation())]?.mcp
|
||||||
},
|
},
|
||||||
async refresh(ref?: LocationRef) {
|
async refresh(ref?: LocationRef) {
|
||||||
const result = await sdk.client.v2.mcp.list({ location: locationQuery(ref) }, { throwOnError: true })
|
const result = await sdk.api["server.mcp"].list({ location: locationQuery(ref) })
|
||||||
const key = locationKey(result.data.location)
|
const key = locationKey(result.location)
|
||||||
setStore("location", key, { ...store.location[key], mcp: result.data.data })
|
setStore("location", key, { ...store.location[key], mcp: result.data })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
@@ -976,7 +962,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
async refresh(ref?: LocationRef) {
|
async refresh(ref?: LocationRef) {
|
||||||
const result = await sdk.api.model.list({ location: locationQuery(ref ?? defaultLocation()) })
|
const result = await sdk.api.model.list({ location: locationQuery(ref ?? defaultLocation()) })
|
||||||
const key = locationKey(result.location)
|
const key = locationKey(result.location)
|
||||||
setStore("location", key, { ...store.location[key], model: mutable(result.data) })
|
setStore("location", key, { ...store.location[key], model: result.data })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
provider: {
|
provider: {
|
||||||
@@ -986,7 +972,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
async refresh(ref?: LocationRef) {
|
async refresh(ref?: LocationRef) {
|
||||||
const result = await sdk.api.provider.list({ location: locationQuery(ref ?? defaultLocation()) })
|
const result = await sdk.api.provider.list({ location: locationQuery(ref ?? defaultLocation()) })
|
||||||
const key = locationKey(result.location)
|
const key = locationKey(result.location)
|
||||||
setStore("location", key, { ...store.location[key], provider: mutable(result.data) })
|
setStore("location", key, { ...store.location[key], provider: result.data })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
reference: {
|
reference: {
|
||||||
@@ -996,7 +982,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
async refresh(ref?: LocationRef) {
|
async refresh(ref?: LocationRef) {
|
||||||
const result = await sdk.api.reference.list({ location: locationQuery(ref ?? defaultLocation()) })
|
const result = await sdk.api.reference.list({ location: locationQuery(ref ?? defaultLocation()) })
|
||||||
const key = locationKey(result.location)
|
const key = locationKey(result.location)
|
||||||
setStore("location", key, { ...store.location[key], reference: mutable(result.data) })
|
setStore("location", key, { ...store.location[key], reference: result.data })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
skill: {
|
skill: {
|
||||||
@@ -1006,7 +992,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
async refresh(ref?: LocationRef) {
|
async refresh(ref?: LocationRef) {
|
||||||
const result = await sdk.api.skill.list({ location: locationQuery(ref ?? defaultLocation()) })
|
const result = await sdk.api.skill.list({ location: locationQuery(ref ?? defaultLocation()) })
|
||||||
const key = locationKey(result.location)
|
const key = locationKey(result.location)
|
||||||
setStore("location", key, { ...store.location[key], skill: mutable(result.data) })
|
setStore("location", key, { ...store.location[key], skill: result.data })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1027,13 +1013,13 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
"session",
|
"session",
|
||||||
"info",
|
"info",
|
||||||
produce((draft) => {
|
produce((draft) => {
|
||||||
for (const session of response.data) draft[session.id] = mutable(session)
|
for (const session of response.data) draft[session.id] = session
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
for (const session of response.data) registerSession(session.id)
|
for (const session of response.data) registerSession(session.id)
|
||||||
}),
|
}),
|
||||||
sdk.api.permission.request.list({ location: locationQuery(defaultLocation()) }).then((response) => {
|
sdk.api.permission.request.list({ location: locationQuery(defaultLocation()) }).then((response) => {
|
||||||
const permissions = mutable(response.data).reduce<Record<string, PermissionV2Request[]>>(
|
const permissions = response.data.reduce<Record<string, PermissionV2Request[]>>(
|
||||||
(result, request) => ({
|
(result, request) => ({
|
||||||
...result,
|
...result,
|
||||||
[request.sessionID]: [...(result[request.sessionID] ?? []), request],
|
[request.sessionID]: [...(result[request.sessionID] ?? []), request],
|
||||||
@@ -1047,7 +1033,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||||||
directory: response.location.directory,
|
directory: response.location.directory,
|
||||||
workspaceID: response.location.workspaceID,
|
workspaceID: response.location.workspaceID,
|
||||||
}
|
}
|
||||||
const forms = mutable(response.data).reduce<Record<string, FormInfo[]>>(
|
const forms = response.data.reduce<Record<string, FormInfo[]>>(
|
||||||
(result, form) => ({
|
(result, form) => ({
|
||||||
...result,
|
...result,
|
||||||
[form.sessionID]: [
|
[form.sessionID]: [
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { V2Event } from "@opencode-ai/sdk/v2"
|
import type { OpenCodeEvent } from "@opencode-ai/client/promise"
|
||||||
import { useSDK } from "./sdk"
|
import { useSDK } from "./sdk"
|
||||||
|
|
||||||
type EventMetadata = {
|
type EventMetadata = {
|
||||||
@@ -9,16 +9,16 @@ type EventMetadata = {
|
|||||||
export function useEvent() {
|
export function useEvent() {
|
||||||
const sdk = useSDK()
|
const sdk = useSDK()
|
||||||
|
|
||||||
function subscribe(handler: (event: V2Event, metadata: EventMetadata) => void) {
|
function subscribe(handler: (event: OpenCodeEvent, metadata: EventMetadata) => void) {
|
||||||
return sdk.event.listen(({ details }) => {
|
return sdk.event.listen(({ details }) => {
|
||||||
if (details.type === "server.connected") return
|
if (details.type === "server.connected") return
|
||||||
handler(details, { directory: details.location?.directory, workspace: details.location?.workspaceID })
|
handler(details, { directory: details.location?.directory, workspace: details.location?.workspaceID })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function on<T extends V2Event["type"]>(
|
function on<T extends OpenCodeEvent["type"]>(
|
||||||
type: T,
|
type: T,
|
||||||
handler: (event: Extract<V2Event, { type: T }>, metadata: EventMetadata) => void,
|
handler: (event: Extract<OpenCodeEvent, { type: T }>, metadata: EventMetadata) => void,
|
||||||
) {
|
) {
|
||||||
return sdk.event.on(type, (event) => {
|
return sdk.event.on(type, (event) => {
|
||||||
handler(event, { directory: event.location?.directory, workspace: event.location?.workspaceID })
|
handler(event, { directory: event.location?.directory, workspace: event.location?.workspaceID })
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { batch, onCleanup } from "solid-js"
|
import { batch } from "solid-js"
|
||||||
import type { Path, Workspace } from "@opencode-ai/sdk/v2"
|
import type { Path, Workspace } from "@opencode-ai/sdk/v2"
|
||||||
import { createStore, reconcile } from "solid-js/store"
|
import { createStore, reconcile } from "solid-js/store"
|
||||||
import { createSimpleContext } from "./helper"
|
import { createSimpleContext } from "./helper"
|
||||||
@@ -66,12 +66,6 @@ export const { use: useProject, provider: ProjectProvider } = createSimpleContex
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onCleanup(
|
|
||||||
sdk.event.on("workspace.status", (event) => {
|
|
||||||
setStore("workspace", "status", event.data.workspaceID, event.data.status)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: store,
|
data: store,
|
||||||
project() {
|
project() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { OpenCodeClient } from "@opencode-ai/client/promise"
|
import type { OpenCodeClient, OpenCodeEvent } from "@opencode-ai/client/promise"
|
||||||
import type { OpencodeClient, V2Event } from "@opencode-ai/sdk/v2"
|
import type { OpencodeClient } from "@opencode-ai/sdk/v2"
|
||||||
import { createGlobalEmitter } from "@solid-primitives/event-bus"
|
import { createGlobalEmitter } from "@solid-primitives/event-bus"
|
||||||
import { onCleanup, onMount } from "solid-js"
|
import { onCleanup, onMount } from "solid-js"
|
||||||
import { createStore } from "solid-js/store"
|
import { createStore } from "solid-js/store"
|
||||||
@@ -17,7 +17,7 @@ export type SDKConnectionEvent = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type SDKEventMap = { [Type in V2Event["type"]]: Extract<V2Event, { type: Type }> }
|
type SDKEventMap = { [Type in OpenCodeEvent["type"]]: Extract<OpenCodeEvent, { type: Type }> }
|
||||||
const connectTimeout = 2_000
|
const connectTimeout = 2_000
|
||||||
const connectionHistoryLimit = 50
|
const connectionHistoryLimit = 50
|
||||||
|
|
||||||
@@ -72,12 +72,7 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
|
|||||||
const error = await (async () => {
|
const error = await (async () => {
|
||||||
record(attempt === 0 ? "connecting" : "reconnecting", attempt)
|
record(attempt === 0 ? "connecting" : "reconnecting", attempt)
|
||||||
log.info("event stream connecting", { attempt })
|
log.info("event stream connecting", { attempt })
|
||||||
const response = await client.v2.event.subscribe({
|
const iterator = api.event.subscribe({ signal: connection.signal })[Symbol.asyncIterator]()
|
||||||
signal: connection.signal,
|
|
||||||
sseMaxRetryAttempts: 0,
|
|
||||||
throwOnError: true,
|
|
||||||
})
|
|
||||||
const iterator = response.stream[Symbol.asyncIterator]()
|
|
||||||
const first = await iterator.next()
|
const first = await iterator.next()
|
||||||
if (abort.signal.aborted || controller.signal.aborted) return
|
if (abort.signal.aborted || controller.signal.aborted) return
|
||||||
if (first.done)
|
if (first.done)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import type { V2Event } from "@opencode-ai/sdk/v2"
|
import type { OpenCodeEvent } from "@opencode-ai/client/promise"
|
||||||
import type { TuiAttentionSoundName, TuiPlugin, TuiPluginApi } from "@opencode-ai/plugin/tui"
|
import type { TuiAttentionSoundName, TuiPlugin, TuiPluginApi } from "@opencode-ai/plugin/tui"
|
||||||
import type { BuiltinTuiPlugin } from "../builtins"
|
import type { BuiltinTuiPlugin } from "../builtins"
|
||||||
|
|
||||||
const id = "internal:notifications"
|
const id = "internal:notifications"
|
||||||
|
|
||||||
type SessionError = Extract<V2Event, { type: "session.error" }>["data"]["error"]
|
type SessionError = Extract<OpenCodeEvent, { type: "session.error" }>["data"]["error"]
|
||||||
|
|
||||||
function notify(
|
function notify(
|
||||||
api: TuiPluginApi,
|
api: TuiPluginApi,
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import Notifications from "../../../../src/feature-plugins/system/notifications"
|
import Notifications from "../../../../src/feature-plugins/system/notifications"
|
||||||
import type { PermissionRequest, QuestionRequest, Session, V2Event } from "@opencode-ai/sdk/v2"
|
import type { OpenCodeEvent } from "@opencode-ai/client/promise"
|
||||||
|
import type { PermissionRequest, QuestionRequest, Session } from "@opencode-ai/sdk/v2"
|
||||||
import type { TuiAttentionNotifyInput } from "@opencode-ai/plugin/tui"
|
import type { TuiAttentionNotifyInput } from "@opencode-ai/plugin/tui"
|
||||||
import { createTuiPluginApi } from "../../../fixture/tui-plugin"
|
import { createTuiPluginApi } from "../../../fixture/tui-plugin"
|
||||||
|
|
||||||
async function setup() {
|
async function setup() {
|
||||||
const notifications: TuiAttentionNotifyInput[] = []
|
const notifications: TuiAttentionNotifyInput[] = []
|
||||||
const handlers = new Map<V2Event["type"], ((event: V2Event) => void)[]>()
|
const handlers = new Map<OpenCodeEvent["type"], ((event: OpenCodeEvent) => void)[]>()
|
||||||
const session = (id: string, title: string, parentID?: string): Session => ({
|
const session = (id: string, title: string, parentID?: string): Session => ({
|
||||||
id,
|
id,
|
||||||
title,
|
title,
|
||||||
@@ -33,9 +34,12 @@ async function setup() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
event: {
|
event: {
|
||||||
on: <Type extends V2Event["type"]>(type: Type, handler: (event: Extract<V2Event, { type: Type }>) => void) => {
|
on: <Type extends OpenCodeEvent["type"]>(
|
||||||
|
type: Type,
|
||||||
|
handler: (event: Extract<OpenCodeEvent, { type: Type }>) => void,
|
||||||
|
) => {
|
||||||
const list = handlers.get(type) ?? []
|
const list = handlers.get(type) ?? []
|
||||||
const wrapped = handler as (event: V2Event) => void
|
const wrapped = handler as (event: OpenCodeEvent) => void
|
||||||
list.push(wrapped)
|
list.push(wrapped)
|
||||||
handlers.set(type, list)
|
handlers.set(type, list)
|
||||||
return () => {
|
return () => {
|
||||||
@@ -59,7 +63,7 @@ async function setup() {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
notifications,
|
notifications,
|
||||||
emit(event: V2Event) {
|
emit(event: OpenCodeEvent) {
|
||||||
for (const handler of handlers.get(event.type) ?? []) handler(event)
|
for (const handler of handlers.get(event.type) ?? []) handler(event)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -73,7 +77,10 @@ function question(id: string, sessionID = "session"): QuestionRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function form(id: string, sessionID = "session"): Extract<V2Event, { type: "form.created" }>["data"]["form"] {
|
function form(
|
||||||
|
id: string,
|
||||||
|
sessionID = "session",
|
||||||
|
): Extract<OpenCodeEvent, { type: "form.created" }>["data"]["form"] {
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
sessionID,
|
sessionID,
|
||||||
@@ -98,7 +105,7 @@ function durable(sessionID: string): { aggregateID: string; seq: number; version
|
|||||||
return { aggregateID: sessionID, seq: 0, version: 1 }
|
return { aggregateID: sessionID, seq: 0, version: 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
function executionStarted(id: string, sessionID = "session"): V2Event {
|
function executionStarted(id: string, sessionID = "session"): OpenCodeEvent {
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
created: 0,
|
created: 0,
|
||||||
@@ -108,7 +115,7 @@ function executionStarted(id: string, sessionID = "session"): V2Event {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function executionSucceeded(id: string, sessionID = "session"): V2Event {
|
function executionSucceeded(id: string, sessionID = "session"): OpenCodeEvent {
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
created: 0,
|
created: 0,
|
||||||
@@ -118,7 +125,7 @@ function executionSucceeded(id: string, sessionID = "session"): V2Event {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function executionFailed(id: string, sessionID = "session"): V2Event {
|
function executionFailed(id: string, sessionID = "session"): OpenCodeEvent {
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
created: 0,
|
created: 0,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/** @jsxImportSource @opentui/solid */
|
/** @jsxImportSource @opentui/solid */
|
||||||
import { expect, test } from "bun:test"
|
import { expect, test } from "bun:test"
|
||||||
import { testRender } from "@opentui/solid"
|
import { testRender } from "@opentui/solid"
|
||||||
import type { V2Event } from "@opencode-ai/sdk/v2"
|
import type { OpenCodeEvent } from "@opencode-ai/client/promise"
|
||||||
import { SessionMessage } from "@opencode-ai/core/session/message"
|
import { SessionMessage } from "@opencode-ai/core/session/message"
|
||||||
import { EventV2 } from "@opencode-ai/core/event"
|
import { EventV2 } from "@opencode-ai/core/event"
|
||||||
import { onMount } from "solid-js"
|
import { onMount } from "solid-js"
|
||||||
@@ -20,7 +20,7 @@ async function wait(fn: () => boolean, timeout = 2000) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitEvent(events: ReturnType<typeof createEventStream>, event: V2Event) {
|
function emitEvent(events: ReturnType<typeof createEventStream>, event: OpenCodeEvent) {
|
||||||
events.emit({ ...event, location: { directory } })
|
events.emit({ ...event, location: { directory } })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/** @jsxImportSource @opentui/solid */
|
/** @jsxImportSource @opentui/solid */
|
||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import type { OpenCodeClient } from "@opencode-ai/client/promise"
|
import type { OpenCodeClient, OpenCodeEvent } from "@opencode-ai/client/promise"
|
||||||
import { testRender } from "@opentui/solid"
|
import { testRender } from "@opentui/solid"
|
||||||
import type { OpencodeClient, V2Event } from "@opencode-ai/sdk/v2"
|
import type { OpencodeClient } from "@opencode-ai/sdk/v2"
|
||||||
import { onMount } from "solid-js"
|
import { onMount } from "solid-js"
|
||||||
import { ProjectProvider, useProject } from "../../../src/context/project"
|
import { ProjectProvider, useProject } from "../../../src/context/project"
|
||||||
import { SDKProvider, useSDK } from "../../../src/context/sdk"
|
import { SDKProvider, useSDK } from "../../../src/context/sdk"
|
||||||
@@ -21,14 +21,17 @@ async function wait(fn: () => boolean, timeout = 2000) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function event(payload: V2Event, input: { directory: string; project?: string; workspace?: string }): V2Event {
|
function event(
|
||||||
|
payload: OpenCodeEvent,
|
||||||
|
input: { directory: string; project?: string; workspace?: string },
|
||||||
|
): OpenCodeEvent {
|
||||||
return {
|
return {
|
||||||
...payload,
|
...payload,
|
||||||
location: { directory: input.directory, workspaceID: input.workspace },
|
location: { directory: input.directory, workspaceID: input.workspace },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function vcs(branch: string): V2Event {
|
function vcs(branch: string): OpenCodeEvent {
|
||||||
return {
|
return {
|
||||||
id: `evt_vcs_${branch}`,
|
id: `evt_vcs_${branch}`,
|
||||||
created: 0,
|
created: 0,
|
||||||
@@ -39,7 +42,7 @@ function vcs(branch: string): V2Event {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function update(version: string): V2Event {
|
function update(version: string): OpenCodeEvent {
|
||||||
return {
|
return {
|
||||||
id: `evt_update_${version}`,
|
id: `evt_update_${version}`,
|
||||||
created: 0,
|
created: 0,
|
||||||
@@ -56,7 +59,7 @@ async function mount(
|
|||||||
) {
|
) {
|
||||||
const events = createEventStream()
|
const events = createEventStream()
|
||||||
const calls = createFetch(undefined, events)
|
const calls = createFetch(undefined, events)
|
||||||
const seen: V2Event[] = []
|
const seen: OpenCodeEvent[] = []
|
||||||
const workspaces: Array<string | undefined> = []
|
const workspaces: Array<string | undefined> = []
|
||||||
let project!: ReturnType<typeof useProject>
|
let project!: ReturnType<typeof useProject>
|
||||||
let sdk!: ReturnType<typeof useSDK>
|
let sdk!: ReturnType<typeof useSDK>
|
||||||
@@ -89,7 +92,7 @@ async function mount(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Probe(props: {
|
function Probe(props: {
|
||||||
seen: V2Event[]
|
seen: OpenCodeEvent[]
|
||||||
workspaces: Array<string | undefined>
|
workspaces: Array<string | undefined>
|
||||||
onReady: (ctx: { project: ReturnType<typeof useProject>; sdk: ReturnType<typeof useSDK> }) => void
|
onReady: (ctx: { project: ReturnType<typeof useProject>; sdk: ReturnType<typeof useSDK> }) => void
|
||||||
}) {
|
}) {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { OpenCode } from "@opencode-ai/client/promise"
|
import { OpenCode, type OpenCodeEvent } from "@opencode-ai/client/promise"
|
||||||
import { createOpencodeClient } from "@opencode-ai/sdk/v2"
|
import { createOpencodeClient } from "@opencode-ai/sdk/v2"
|
||||||
import type { V2Event } from "@opencode-ai/sdk/v2"
|
|
||||||
|
|
||||||
export const worktree = "/tmp/opencode"
|
export const worktree = "/tmp/opencode"
|
||||||
export const directory = `${worktree}/packages/tui`
|
export const directory = `${worktree}/packages/tui`
|
||||||
@@ -51,7 +50,7 @@ export function createEventStream() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
emit(event: V2Event) {
|
emit(event: OpenCodeEvent) {
|
||||||
send(v2, pending, event)
|
send(v2, pending, event)
|
||||||
},
|
},
|
||||||
v2() {
|
v2() {
|
||||||
|
|||||||
Reference in New Issue
Block a user