diff --git a/packages/core/src/event.ts b/packages/core/src/event.ts index b9cba1ede4d..2d4130493e2 100644 --- a/packages/core/src/event.ts +++ b/packages/core/src/event.ts @@ -30,6 +30,7 @@ export type Payload = { readonly type: D["type"] readonly data: Data readonly version?: number + readonly sync?: SyncMetadata readonly location?: Location.Info readonly metadata?: Record } @@ -48,6 +49,11 @@ export type SerializedEvent = { readonly data: Record } +export type SyncMetadata = { + readonly seq: number + readonly aggregateID: string +} + export class InvalidSyncEventError extends Schema.TaggedErrorClass()( "EventV2.InvalidSyncEvent", { @@ -77,6 +83,12 @@ export function define Effect.gen(function* () { @@ -208,8 +220,12 @@ export const layer = Layer.effect( }), ) } + const serialized = { + seq, + aggregateID, + } for (const projector of list) { - yield* projector(event as Payload) + yield* projector({ ...event, sync: serialized }) } yield* db .insert(EventSequenceTable) @@ -233,6 +249,7 @@ export const layer = Layer.effect( ]) .run() .pipe(Effect.orDie) + return serialized }), { behavior: "immediate" }, ) @@ -247,14 +264,15 @@ export const layer = Layer.effect( for (const sync of syncHandlers) { yield* sync(event as Payload) } - yield* commitSyncEvent(event as Payload) + const sync = yield* commitSyncEvent(event as Payload) + const payload = sync ? { ...event, sync } : event for (const listener of listeners) { - yield* listener(event as Payload) + yield* listener(payload as Payload) } const pubsub = typed.get(event.type) - if (pubsub) yield* PubSub.publish(pubsub, event as Payload) - yield* PubSub.publish(all, event as Payload) - return event + if (pubsub) yield* PubSub.publish(pubsub, payload as Payload) + yield* PubSub.publish(all, payload as Payload) + return payload }) } diff --git a/packages/core/test/event.test.ts b/packages/core/test/event.test.ts index 017ce954431..647875fc084 100644 --- a/packages/core/test/event.test.ts +++ b/packages/core/test/event.test.ts @@ -109,6 +109,19 @@ describe("EventV2", () => { }), ) + it.effect("publishes sync metadata", () => + Effect.gen(function* () { + const events = yield* EventV2.Service + const aggregateID = EventV2.ID.create() + const event = yield* events.publish(SyncMessage, { id: aggregateID, text: "hello" }) + + expect(event.sync).toEqual({ + seq: 0, + aggregateID, + }) + }), + ) + it.effect("stores definitions in the exported registry", () => Effect.sync(() => { expect(EventV2.registry.get(Message.type)).toBe(Message) diff --git a/packages/opencode/src/cli/cmd/tui/context/sync-v2.tsx b/packages/opencode/src/cli/cmd/tui/context/sync-v2.tsx index d9d23999d21..442eba84ab4 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sync-v2.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sync-v2.tsx @@ -291,7 +291,7 @@ export const { use: useSyncV2, provider: SyncProviderV2 } = createSimpleContext( message: { async sync(sessionID: string) { const response = await sdk.client.v2.session.messages({ sessionID }) - setStore("messages", sessionID, reconcile(response.data?.items ?? [])) + setStore("messages", sessionID, reconcile(response.data?.data.items ?? [])) }, fromSession(sessionID: string) { const messages = store.messages[sessionID] diff --git a/packages/opencode/src/event-v2-bridge.ts b/packages/opencode/src/event-v2-bridge.ts index e7532a965ae..07204f28d2b 100644 --- a/packages/opencode/src/event-v2-bridge.ts +++ b/packages/opencode/src/event-v2-bridge.ts @@ -44,6 +44,21 @@ export const layer = Layer.effect( workspace: workspaceID, payload: { id: event.id, type: event.type, properties: event.data }, }) + if (!event.sync || event.version === undefined) return + GlobalBus.emit("event", { + directory: event.location?.directory ?? ctx?.directory, + project: ctx?.project.id, + workspace: workspaceID, + payload: { + type: "sync", + syncEvent: { + id: event.id, + type: EventV2.versionedType(event.type, event.version), + ...event.sync, + data: event.data, + }, + }, + }) }), ) yield* Effect.addFinalizer(() => unsubscribe) diff --git a/packages/opencode/src/server/routes/instance/httpapi/groups/global.ts b/packages/opencode/src/server/routes/instance/httpapi/groups/global.ts index 4a24282a03c..cd84990524a 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/groups/global.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/groups/global.ts @@ -20,11 +20,14 @@ const SyncEventSchemas = EventV2.registry return [ Schema.Struct({ type: Schema.Literal("sync"), - name: Schema.Literal(EventV2.versionedType(definition.type, definition.sync.version)), id: Schema.String, - seq: Schema.Finite, - aggregateID: Schema.Literal(definition.sync.aggregate), - data: definition.data, + syncEvent: Schema.Struct({ + type: Schema.Literal(EventV2.versionedType(definition.type, definition.sync.version)), + id: Schema.String, + seq: Schema.Finite, + aggregateID: Schema.String, + data: definition.data, + }), }).annotate({ identifier: `SyncEvent.${definition.type}` }), ] }) diff --git a/packages/opencode/test/server/httpapi-public-openapi.test.ts b/packages/opencode/test/server/httpapi-public-openapi.test.ts index 70977eecae1..fd342cc2738 100644 --- a/packages/opencode/test/server/httpapi-public-openapi.test.ts +++ b/packages/opencode/test/server/httpapi-public-openapi.test.ts @@ -3,7 +3,13 @@ import { OpenApi } from "effect/unstable/httpapi" import { PublicApi } from "../../src/server/routes/instance/httpapi/public" type Method = "get" | "post" | "put" | "delete" | "patch" -type OpenApiSchema = { readonly $ref?: string } +type OpenApiSchema = { + readonly $ref?: string + readonly type?: string + readonly enum?: readonly unknown[] + readonly properties?: Record + readonly required?: readonly string[] +} type OpenApiResponse = { readonly description?: string readonly content?: Record @@ -19,7 +25,10 @@ type OpenApiOperation = { readonly security?: unknown } type OpenApiPathItem = Partial> -type OpenApiSpec = { readonly paths: Record } +type OpenApiSpec = { + readonly paths: Record + readonly components: { readonly schemas: Record } +} const methods = ["get", "post", "put", "delete", "patch"] as const @@ -49,6 +58,23 @@ function isBuiltInEndpointError(name: string) { } describe("PublicApi OpenAPI v2 errors", () => { + test("documents nested legacy global sync events", () => { + const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec + const schema = spec.components.schemas.SyncEventSessionCreated + + expect(schema?.required).toEqual(["type", "id", "syncEvent"]) + expect(schema?.properties?.type?.enum).toEqual(["sync"]) + expect(schema?.properties?.syncEvent).toMatchObject({ + required: ["type", "id", "seq", "aggregateID", "data"], + properties: { + type: { enum: ["session.created.1"] }, + id: { type: "string" }, + seq: { type: "number" }, + aggregateID: { type: "string" }, + }, + }) + }) + test("preserves /api auth responses", () => { const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec diff --git a/packages/opencode/test/session/session.test.ts b/packages/opencode/test/session/session.test.ts index ac29d35f2ad..b8337b963be 100644 --- a/packages/opencode/test/session/session.test.ts +++ b/packages/opencode/test/session/session.test.ts @@ -1,6 +1,7 @@ import { describe, expect } from "bun:test" import { SessionV1 } from "@opencode-ai/core/v1/session" import { Database } from "@opencode-ai/core/database/database" +import { EventV2 } from "@opencode-ai/core/event" import { SessionProjector } from "@opencode-ai/core/session/projector" import { Deferred, Effect, Exit, Layer } from "effect" import { Session as SessionNs } from "@/session/session" @@ -14,6 +15,7 @@ import { Storage } from "@/storage/storage" import { RuntimeFlags } from "@/effect/runtime-flags" import { BackgroundJob } from "@/background/job" import { EventV2Bridge } from "@/event-v2-bridge" +import { GlobalBus } from "@/bus/global" void Log.init({ print: false }) @@ -101,6 +103,31 @@ describe("session.created event", () => { yield* session.remove(info.id) }), ) + + it.instance("emits legacy global sync payload", () => + Effect.gen(function* () { + const session = yield* SessionNs.Service + const received = yield* Deferred.make<{ syncEvent: EventV2.SerializedEvent }>() + const listener = (event: { payload: { type?: string; syncEvent?: EventV2.SerializedEvent } }) => { + if (event.payload.type === "sync" && event.payload.syncEvent) + Deferred.doneUnsafe(received, Effect.succeed({ syncEvent: event.payload.syncEvent })) + } + GlobalBus.on("event", listener) + yield* Effect.addFinalizer(() => Effect.sync(() => GlobalBus.off("event", listener))) + + const info = yield* session.create({}) + const event = yield* awaitDeferred(received, "timed out waiting for legacy global sync event") + + expect(event.syncEvent).toMatchObject({ + type: EventV2.versionedType(SessionNs.Event.Created.type, 1), + seq: 0, + aggregateID: info.id, + data: { sessionID: info.id }, + }) + + yield* session.remove(info.id) + }), + ) }) describe("step-finish token propagation via event", () => { diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts index e586ba61d82..09fac6ecfb5 100644 --- a/packages/sdk/js/src/v2/gen/sdk.gen.ts +++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts @@ -255,6 +255,10 @@ import type { TuiShowToastResponses, TuiSubmitPromptErrors, TuiSubmitPromptResponses, + V2CommandListErrors, + V2CommandListResponses, + V2EventSubscribeErrors, + V2EventSubscribeResponses, V2FsListErrors, V2FsListResponses, V2FsReadErrors, @@ -287,6 +291,8 @@ import type { V2SessionPromptResponses, V2SessionWaitErrors, V2SessionWaitResponses, + V2SkillListErrors, + V2SkillListResponses, VcsApplyErrors, VcsApplyResponses, VcsDiffErrors, @@ -4990,6 +4996,78 @@ export class Fs extends HeyApiClient { } } +export class Command2 extends HeyApiClient { + /** + * List v2 commands + * + * Retrieve currently registered v2 commands. + */ + public list( + parameters?: { + location?: { + directory?: string + workspace?: string + } + }, + options?: Options, + ) { + const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "location" }] }]) + return (options?.client ?? this.client).get({ + url: "/api/command", + ...options, + ...params, + }) + } +} + +export class Skill extends HeyApiClient { + /** + * List v2 skills + * + * Retrieve currently registered v2 skills. + */ + public list( + parameters?: { + location?: { + directory?: string + workspace?: string + } + }, + options?: Options, + ) { + const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "location" }] }]) + return (options?.client ?? this.client).get({ + url: "/api/skill", + ...options, + ...params, + }) + } +} + +export class Event2 extends HeyApiClient { + /** + * Subscribe to v2 events + * + * Subscribe to native EventV2 payloads for a location. + */ + public subscribe( + parameters?: { + location?: { + directory?: string + workspace?: string + } + }, + options?: Options, + ) { + const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "location" }] }]) + return (options?.client ?? this.client).sse.get({ + url: "/api/event", + ...options, + ...params, + }) + } +} + export class V2 extends HeyApiClient { private _session?: Session3 get session(): Session3 { @@ -5015,6 +5093,21 @@ export class V2 extends HeyApiClient { get fs(): Fs { return (this._fs ??= new Fs({ client: this.client })) } + + private _command?: Command2 + get command(): Command2 { + return (this._command ??= new Command2({ client: this.client })) + } + + private _skill?: Skill + get skill(): Skill { + return (this._skill ??= new Skill({ client: this.client })) + } + + private _event?: Event2 + get event(): Event2 { + return (this._event ??= new Event2({ client: this.client })) + } } export class Control extends HeyApiClient { diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index c738c387105..9a809fdc439 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -1789,6 +1789,7 @@ export type Config = { description?: string agent?: string model?: string + variant?: string subtask?: boolean } } @@ -2856,429 +2857,516 @@ export type EventServerInstanceDisposed = { export type SyncEventSessionCreated = { type: "sync" - name: "session.created.1" id: string - seq: number - aggregateID: "sessionID" - data: { - sessionID: string - info: Session + syncEvent: { + type: "session.created.1" + id: string + seq: number + aggregateID: string + data: { + sessionID: string + info: Session + } } } export type SyncEventSessionUpdated = { type: "sync" - name: "session.updated.1" id: string - seq: number - aggregateID: "sessionID" - data: { - sessionID: string - info: Session + syncEvent: { + type: "session.updated.1" + id: string + seq: number + aggregateID: string + data: { + sessionID: string + info: Session + } } } export type SyncEventSessionDeleted = { type: "sync" - name: "session.deleted.1" id: string - seq: number - aggregateID: "sessionID" - data: { - sessionID: string - info: Session + syncEvent: { + type: "session.deleted.1" + id: string + seq: number + aggregateID: string + data: { + sessionID: string + info: Session + } } } export type SyncEventMessageUpdated = { type: "sync" - name: "message.updated.1" id: string - seq: number - aggregateID: "sessionID" - data: { - sessionID: string - info: Message + syncEvent: { + type: "message.updated.1" + id: string + seq: number + aggregateID: string + data: { + sessionID: string + info: Message + } } } export type SyncEventMessageRemoved = { type: "sync" - name: "message.removed.1" id: string - seq: number - aggregateID: "sessionID" - data: { - sessionID: string - messageID: string + syncEvent: { + type: "message.removed.1" + id: string + seq: number + aggregateID: string + data: { + sessionID: string + messageID: string + } } } export type SyncEventMessagePartUpdated = { type: "sync" - name: "message.part.updated.1" id: string - seq: number - aggregateID: "sessionID" - data: { - sessionID: string - part: Part - time: number + syncEvent: { + type: "message.part.updated.1" + id: string + seq: number + aggregateID: string + data: { + sessionID: string + part: Part + time: number + } } } export type SyncEventMessagePartRemoved = { type: "sync" - name: "message.part.removed.1" id: string - seq: number - aggregateID: "sessionID" - data: { - sessionID: string - messageID: string - partID: string + syncEvent: { + type: "message.part.removed.1" + id: string + seq: number + aggregateID: string + data: { + sessionID: string + messageID: string + partID: string + } } } export type SyncEventSessionNextAgentSwitched = { type: "sync" - name: "session.next.agent.switched.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - agent: string + syncEvent: { + type: "session.next.agent.switched.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + agent: string + } } } export type SyncEventSessionNextModelSwitched = { type: "sync" - name: "session.next.model.switched.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - model: { - id: string - providerID: string - variant?: string + syncEvent: { + type: "session.next.model.switched.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + model: { + id: string + providerID: string + variant?: string + } } } } export type SyncEventSessionNextPrompted = { type: "sync" - name: "session.next.prompted.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - prompt: Prompt + syncEvent: { + type: "session.next.prompted.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + prompt: Prompt + } } } export type SyncEventSessionNextSynthetic = { type: "sync" - name: "session.next.synthetic.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - text: string + syncEvent: { + type: "session.next.synthetic.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + text: string + } } } export type SyncEventSessionNextShellStarted = { type: "sync" - name: "session.next.shell.started.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - callID: string - command: string + syncEvent: { + type: "session.next.shell.started.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + callID: string + command: string + } } } export type SyncEventSessionNextShellEnded = { type: "sync" - name: "session.next.shell.ended.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - callID: string - output: string + syncEvent: { + type: "session.next.shell.ended.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + callID: string + output: string + } } } export type SyncEventSessionNextStepStarted = { type: "sync" - name: "session.next.step.started.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - agent: string - model: { - id: string - providerID: string - variant?: string + syncEvent: { + type: "session.next.step.started.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + agent: string + model: { + id: string + providerID: string + variant?: string + } + snapshot?: string } - snapshot?: string } } export type SyncEventSessionNextStepEnded = { type: "sync" - name: "session.next.step.ended.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - finish: string - cost: number - tokens: { - input: number - output: number - reasoning: number - cache: { - read: number - write: number + syncEvent: { + type: "session.next.step.ended.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + finish: string + cost: number + tokens: { + input: number + output: number + reasoning: number + cache: { + read: number + write: number + } } + snapshot?: string } - snapshot?: string } } export type SyncEventSessionNextStepFailed = { type: "sync" - name: "session.next.step.failed.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - error: SessionErrorUnknown + syncEvent: { + type: "session.next.step.failed.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + error: SessionErrorUnknown + } } } export type SyncEventSessionNextTextStarted = { type: "sync" - name: "session.next.text.started.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string + syncEvent: { + type: "session.next.text.started.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + } } } export type SyncEventSessionNextTextDelta = { type: "sync" - name: "session.next.text.delta.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - delta: string + syncEvent: { + type: "session.next.text.delta.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + delta: string + } } } export type SyncEventSessionNextTextEnded = { type: "sync" - name: "session.next.text.ended.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - text: string + syncEvent: { + type: "session.next.text.ended.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + text: string + } } } export type SyncEventSessionNextReasoningStarted = { type: "sync" - name: "session.next.reasoning.started.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - reasoningID: string + syncEvent: { + type: "session.next.reasoning.started.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + reasoningID: string + } } } export type SyncEventSessionNextReasoningDelta = { type: "sync" - name: "session.next.reasoning.delta.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - reasoningID: string - delta: string + syncEvent: { + type: "session.next.reasoning.delta.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + reasoningID: string + delta: string + } } } export type SyncEventSessionNextReasoningEnded = { type: "sync" - name: "session.next.reasoning.ended.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - reasoningID: string - text: string + syncEvent: { + type: "session.next.reasoning.ended.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + reasoningID: string + text: string + } } } export type SyncEventSessionNextToolInputStarted = { type: "sync" - name: "session.next.tool.input.started.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - callID: string - name: string + syncEvent: { + type: "session.next.tool.input.started.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + callID: string + name: string + } } } export type SyncEventSessionNextToolInputDelta = { type: "sync" - name: "session.next.tool.input.delta.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - callID: string - delta: string + syncEvent: { + type: "session.next.tool.input.delta.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + callID: string + delta: string + } } } export type SyncEventSessionNextToolInputEnded = { type: "sync" - name: "session.next.tool.input.ended.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - callID: string - text: string + syncEvent: { + type: "session.next.tool.input.ended.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + callID: string + text: string + } } } export type SyncEventSessionNextToolCalled = { type: "sync" - name: "session.next.tool.called.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - callID: string - tool: string - input: { - [key: string]: unknown - } - provider: { - executed: boolean - metadata?: { + syncEvent: { + type: "session.next.tool.called.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + callID: string + tool: string + input: { [key: string]: unknown } + provider: { + executed: boolean + metadata?: { + [key: string]: unknown + } + } } } } export type SyncEventSessionNextToolProgress = { type: "sync" - name: "session.next.tool.progress.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - callID: string - structured: { - [key: string]: unknown + syncEvent: { + type: "session.next.tool.progress.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + callID: string + structured: { + [key: string]: unknown + } + content: Array } - content: Array } } export type SyncEventSessionNextToolSuccess = { type: "sync" - name: "session.next.tool.success.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - callID: string - structured: { - [key: string]: unknown - } - content: Array - provider: { - executed: boolean - metadata?: { + syncEvent: { + type: "session.next.tool.success.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + callID: string + structured: { [key: string]: unknown } + content: Array + provider: { + executed: boolean + metadata?: { + [key: string]: unknown + } + } } } } export type SyncEventSessionNextToolFailed = { type: "sync" - name: "session.next.tool.failed.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - callID: string - error: SessionErrorUnknown - provider: { - executed: boolean - metadata?: { - [key: string]: unknown + syncEvent: { + type: "session.next.tool.failed.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + callID: string + error: SessionErrorUnknown + provider: { + executed: boolean + metadata?: { + [key: string]: unknown + } } } } @@ -3286,55 +3374,67 @@ export type SyncEventSessionNextToolFailed = { export type SyncEventSessionNextRetried = { type: "sync" - name: "session.next.retried.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - attempt: number - error: SessionNextRetryError + syncEvent: { + type: "session.next.retried.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + attempt: number + error: SessionNextRetryError + } } } export type SyncEventSessionNextCompactionStarted = { type: "sync" - name: "session.next.compaction.started.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - reason: "auto" | "manual" + syncEvent: { + type: "session.next.compaction.started.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + reason: "auto" | "manual" + } } } export type SyncEventSessionNextCompactionDelta = { type: "sync" - name: "session.next.compaction.delta.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - text: string + syncEvent: { + type: "session.next.compaction.delta.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + text: string + } } } export type SyncEventSessionNextCompactionEnded = { type: "sync" - name: "session.next.compaction.ended.1" id: string - seq: number - aggregateID: "sessionID" - data: { - timestamp: number - sessionID: string - text: string - include?: string + syncEvent: { + type: "session.next.compaction.ended.1" + id: string + seq: number + aggregateID: string + data: { + timestamp: number + sessionID: string + text: string + include?: string + } } } @@ -3592,6 +3692,15 @@ export type SessionMessage = | SessionMessageAssistant | SessionMessageCompaction +export type LocationInfo = { + directory: string + workspaceID?: string + project: { + id: string + directory: string + } +} + export type ProviderV2Info = { id: string name: string @@ -3677,6 +3786,27 @@ export type LocationFileSystemEntry = { mime: string } +export type CommandV2Info = { + name: string + template: string + description?: string + agent?: string + model?: { + id: string + providerID: string + variant?: string + } + subtask?: boolean +} + +export type SkillV2Info = { + name: string + description?: string + slash?: boolean + location: string + content: string +} + export type EventModelsDevRefreshed = { id: string type: "models-dev.refreshed" @@ -8092,9 +8222,11 @@ export type V2SessionListError = V2SessionListErrors[keyof V2SessionListErrors] export type V2SessionListResponses = { /** - * V2SessionsResponse + * Success */ - 200: V2SessionsResponse + 200: { + data: V2SessionsResponse + } } export type V2SessionListResponse = V2SessionListResponses[keyof V2SessionListResponses] @@ -8137,9 +8269,11 @@ export type V2SessionPromptError = V2SessionPromptErrors[keyof V2SessionPromptEr export type V2SessionPromptResponses = { /** - * Session.Message + * Success */ - 200: SessionMessage + 200: { + data: SessionMessage + } } export type V2SessionPromptResponse = V2SessionPromptResponses[keyof V2SessionPromptResponses] @@ -8265,7 +8399,9 @@ export type V2SessionContextResponses = { /** * Success */ - 200: Array + 200: { + data: Array + } } export type V2SessionContextResponse = V2SessionContextResponses[keyof V2SessionContextResponses] @@ -8311,9 +8447,11 @@ export type V2SessionMessagesError = V2SessionMessagesErrors[keyof V2SessionMess export type V2SessionMessagesResponses = { /** - * V2SessionMessagesResponse + * Success */ - 200: V2SessionMessagesResponse + 200: { + data: V2SessionMessagesResponse + } } export type V2SessionMessagesResponse2 = V2SessionMessagesResponses[keyof V2SessionMessagesResponses] @@ -8351,7 +8489,10 @@ export type V2ModelListResponses = { /** * Success */ - 200: Array + 200: { + location: LocationInfo + data: Array + } } export type V2ModelListResponse = V2ModelListResponses[keyof V2ModelListResponses] @@ -8389,7 +8530,10 @@ export type V2ProviderListResponses = { /** * Success */ - 200: Array + 200: { + location: LocationInfo + data: Array + } } export type V2ProviderListResponse = V2ProviderListResponses[keyof V2ProviderListResponses] @@ -8431,9 +8575,12 @@ export type V2ProviderGetError = V2ProviderGetErrors[keyof V2ProviderGetErrors] export type V2ProviderGetResponses = { /** - * ProviderV2.Info + * Success */ - 200: ProviderV2Info + 200: { + location: LocationInfo + data: ProviderV2Info + } } export type V2ProviderGetResponse = V2ProviderGetResponses[keyof V2ProviderGetResponses] @@ -8467,7 +8614,10 @@ export type V2PermissionRequestListResponses = { /** * Success */ - 200: Array + 200: { + location: LocationInfo + data: Array + } } export type V2PermissionRequestListResponse = V2PermissionRequestListResponses[keyof V2PermissionRequestListResponses] @@ -8502,7 +8652,9 @@ export type V2SessionPermissionListResponses = { /** * Success */ - 200: Array + 200: { + data: Array + } } export type V2SessionPermissionListResponse = V2SessionPermissionListResponses[keyof V2SessionPermissionListResponses] @@ -8573,7 +8725,9 @@ export type V2PermissionSavedListResponses = { /** * Success */ - 200: Array + 200: { + data: Array + } } export type V2PermissionSavedListResponse = V2PermissionSavedListResponses[keyof V2PermissionSavedListResponses] @@ -8640,7 +8794,10 @@ export type V2FsReadResponses = { /** * Success */ - 200: LocationFileSystemTextContent | LocationFileSystemBinaryContent + 200: { + location: LocationInfo + data: LocationFileSystemTextContent | LocationFileSystemBinaryContent + } } export type V2FsReadResponse = V2FsReadResponses[keyof V2FsReadResponses] @@ -8676,11 +8833,122 @@ export type V2FsListResponses = { /** * Success */ - 200: Array + 200: { + location: LocationInfo + data: Array + } } export type V2FsListResponse = V2FsListResponses[keyof V2FsListResponses] +export type V2CommandListData = { + body?: never + path?: never + query?: { + location?: { + directory?: string + workspace?: string + } + } + url: "/api/command" +} + +export type V2CommandListErrors = { + /** + * InvalidRequestError + */ + 400: InvalidRequestError + /** + * UnauthorizedError + */ + 401: UnauthorizedError +} + +export type V2CommandListError = V2CommandListErrors[keyof V2CommandListErrors] + +export type V2CommandListResponses = { + /** + * Success + */ + 200: { + location: LocationInfo + data: Array + } +} + +export type V2CommandListResponse = V2CommandListResponses[keyof V2CommandListResponses] + +export type V2SkillListData = { + body?: never + path?: never + query?: { + location?: { + directory?: string + workspace?: string + } + } + url: "/api/skill" +} + +export type V2SkillListErrors = { + /** + * InvalidRequestError + */ + 400: InvalidRequestError + /** + * UnauthorizedError + */ + 401: UnauthorizedError +} + +export type V2SkillListError = V2SkillListErrors[keyof V2SkillListErrors] + +export type V2SkillListResponses = { + /** + * Success + */ + 200: { + location: LocationInfo + data: Array + } +} + +export type V2SkillListResponse = V2SkillListResponses[keyof V2SkillListResponses] + +export type V2EventSubscribeData = { + body?: never + path?: never + query?: { + location?: { + directory?: string + workspace?: string + } + } + url: "/api/event" +} + +export type V2EventSubscribeErrors = { + /** + * InvalidRequestError + */ + 400: InvalidRequestError + /** + * UnauthorizedError + */ + 401: UnauthorizedError +} + +export type V2EventSubscribeError = V2EventSubscribeErrors[keyof V2EventSubscribeErrors] + +export type V2EventSubscribeResponses = { + /** + * Success + */ + 200: string +} + +export type V2EventSubscribeResponse = V2EventSubscribeResponses[keyof V2EventSubscribeResponses] + export type TuiAppendPromptData = { body?: { text: string