Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/opencode/src/cli/cmd/attach.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ export const AttachCommand = cmd({
type: "boolean",
describe: "fork the session when continuing (use with --continue or --session)",
})
.option("client", {
type: "string",
describe: "id that /tui/select-session can target so only this TUI switches sessions",
})
.option("password", {
alias: ["p"],
type: "string",
Expand Down Expand Up @@ -139,6 +143,7 @@ export const AttachCommand = cmd({
continue: args.continue,
sessionID: args.session,
fork: args.fork,
client: args.client,
},
directory,
headers,
Expand Down
5 changes: 5 additions & 0 deletions packages/opencode/src/cli/cmd/tui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ export const TuiThreadCommand = cmd({
type: "boolean",
describe: "fork the session when continuing (use with --continue or --session)",
})
.option("client", {
type: "string",
describe: "id that /tui/select-session can target so only this TUI switches sessions",
})
.option("prompt", {
type: "string",
describe: "prompt to use",
Expand Down Expand Up @@ -292,6 +296,7 @@ export const TuiThreadCommand = cmd({
prompt,
fork: args.fork,
auto: args.auto || args.yolo || args["dangerously-skip-permissions"],
client: args.client,
},
}),
)
Expand Down
26 changes: 26 additions & 0 deletions packages/opencode/test/server/session-select.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { describe, expect } from "bun:test"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Effect, Layer } from "effect"
import { GlobalBus, type GlobalEvent } from "@/bus/global"
import { Session } from "@/session/session"
import { TestInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
Expand Down Expand Up @@ -29,6 +30,31 @@ describe("tui.selectSession endpoint", () => {
{ git: true },
)

it.instance(
"should publish the target client with the select event",
() =>
Effect.gen(function* () {
const tmp = yield* TestInstance
const session = yield* Session.use.create({})
const seen: unknown[] = []
const on = (event: GlobalEvent) => {
if (event.payload.type === "tui.session.select") seen.push(event.payload.properties)
}
GlobalBus.on("event", on)
yield* Effect.addFinalizer(() => Effect.sync(() => GlobalBus.off("event", on)))

const response = yield* requestInDirectory("/tui/select-session", tmp.directory, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ sessionID: session.id, client: "pane-2" }),
})

expect(response.status).toBe(200)
expect(seen).toEqual([{ sessionID: session.id, client: "pane-2" }])
}),
{ git: true },
)

it.instance(
"should return 404 when session does not exist",
() =>
Expand Down
5 changes: 5 additions & 0 deletions packages/schema/src/tui-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ export const SessionSelect = Event.define({
type: "tui.session.select",
schema: {
sessionID: SessionID.annotate({ description: "Session ID to navigate to" }),
client: optional(
Schema.String.annotate({
description: "Only the TUI started with this --client id navigates. Omit to navigate every attached TUI.",
}),
),
},
})

Expand Down
2 changes: 2 additions & 0 deletions packages/sdk/js/src/v2/gen/sdk.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4988,6 +4988,7 @@ export class Tui extends HeyApiClient {
directory?: string
workspace?: string
sessionID?: string
client?: string
},
options?: Options<never, ThrowOnError>,
) {
Expand All @@ -4999,6 +5000,7 @@ export class Tui extends HeyApiClient {
{ in: "query", key: "directory" },
{ in: "query", key: "workspace" },
{ in: "body", key: "sessionID" },
{ in: "body", key: "client" },
],
},
],
Expand Down
20 changes: 20 additions & 0 deletions packages/sdk/js/src/v2/gen/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1449,6 +1449,10 @@ export type GlobalEvent = {
* Session ID to navigate to
*/
sessionID: string
/**
* Only the TUI started with this --client id navigates. Omit to navigate every attached TUI.
*/
client?: string
}
}
| {
Expand Down Expand Up @@ -2652,6 +2656,10 @@ export type EventTuiSessionSelect = {
* Session ID to navigate to
*/
sessionID: string
/**
* Only the TUI started with this --client id navigates. Omit to navigate every attached TUI.
*/
client?: string
}
}

Expand Down Expand Up @@ -3016,6 +3024,10 @@ export type EventTuiSessionSelect2 = {
* Session ID to navigate to
*/
sessionID: string
/**
* Only the TUI started with this --client id navigates. Omit to navigate every attached TUI.
*/
client?: string
}
}

Expand Down Expand Up @@ -5831,6 +5843,10 @@ export type TuiSessionSelect = {
* Session ID to navigate to
*/
sessionID: string
/**
* Only the TUI started with this --client id navigates. Omit to navigate every attached TUI.
*/
client?: string
}
}

Expand Down Expand Up @@ -10913,6 +10929,10 @@ export type TuiSelectSessionData = {
* Session ID to navigate to
*/
sessionID: string
/**
* Only the TUI started with this --client id navigates. Omit to navigate every attached TUI.
*/
client?: string
}
path?: never
query?: {
Expand Down
1 change: 1 addition & 0 deletions packages/tui/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,7 @@ function App(props: { onSnapshot?: () => Promise<string[]>; pluginHost: TuiPlugi

event.on("tui.session.select", (evt, { workspace }) => {
if (workspace !== project.workspace.current()) return
if (evt.properties.client !== undefined && evt.properties.client !== args.client) return
route.navigate({
type: "session",
sessionID: evt.properties.sessionID,
Expand Down
1 change: 1 addition & 0 deletions packages/tui/src/context/args.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface Args {
sessionID?: string
fork?: boolean
auto?: boolean
client?: string
}

export const { use: useArgs, provider: ArgsProvider } = createSimpleContext({
Expand Down
Loading