Skip to content

Commit 27f8662

Browse files
committed
fix(tui): harden scenario preview boundaries
1 parent ad17c00 commit 27f8662

4 files changed

Lines changed: 54 additions & 20 deletions

File tree

packages/opencode/src/cli/cmd/tui/routes/session/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2130,8 +2130,8 @@ function Read(props: ToolProps<typeof ReadTool>) {
21302130
Read {pathFormatter.format(props.input.filePath)} {input(props.input, ["filePath"])}
21312131
</InlineTool>
21322132
<For each={loaded()}>
2133-
{(filepath) => (
2134-
<box paddingLeft={3}>
2133+
{(filepath, index) => (
2134+
<box id={`tool-inline-loaded-${props.part.id}-${index()}`} paddingLeft={3}>
21352135
<text paddingLeft={3} fg={theme.textMuted}>
21362136
↳ Loaded {pathFormatter.format(filepath)}
21372137
</text>

packages/opencode/src/cli/cmd/tui/thread.ts

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,27 @@ export const TuiThreadCommand = cmd({
137137
return
138138
}
139139

140+
const network = resolveNetworkOptionsNoConfig(args)
141+
const external =
142+
process.argv.includes("--port") ||
143+
process.argv.includes("--hostname") ||
144+
process.argv.includes("--mdns") ||
145+
network.mdns ||
146+
network.port !== 0 ||
147+
network.hostname !== "127.0.0.1"
148+
149+
if (args.scenario && external) {
150+
UI.error("--scenario is only available with the internal transport")
151+
process.exitCode = 1
152+
return
153+
}
154+
155+
if (args.scenario && (args.continue || args.session || args.fork)) {
156+
UI.error("--scenario cannot be combined with --continue, --session, or --fork")
157+
process.exitCode = 1
158+
return
159+
}
160+
140161
// Resolve relative --project paths from PWD, then use the real cwd after
141162
// chdir so the thread and worker share the same directory key.
142163
const next = resolveThreadDirectory(args.project)
@@ -199,15 +220,6 @@ export const TuiThreadCommand = cmd({
199220
const prompt = await input(args.prompt)
200221
const config = await TuiConfig.get()
201222

202-
const network = resolveNetworkOptionsNoConfig(args)
203-
const external =
204-
process.argv.includes("--port") ||
205-
process.argv.includes("--hostname") ||
206-
process.argv.includes("--mdns") ||
207-
network.mdns ||
208-
network.port !== 0 ||
209-
network.hostname !== "127.0.0.1"
210-
211223
const transport = external
212224
? {
213225
url: (await client.call("server", network)).url,
@@ -220,12 +232,6 @@ export const TuiThreadCommand = cmd({
220232
events: createEventSource(client),
221233
}
222234

223-
if (args.scenario && external) {
224-
UI.error("--scenario is only available with the internal transport")
225-
process.exitCode = 1
226-
return
227-
}
228-
229235
const scenario = args.scenario
230236
? (await import("./scenario")).createScenario({
231237
name: args.scenario,
@@ -251,9 +257,10 @@ export const TuiThreadCommand = cmd({
251257
return
252258
}
253259

254-
setTimeout(() => {
255-
client.call("checkUpgrade", { directory: cwd }).catch(() => {})
256-
}, 1000).unref?.()
260+
if (!args.scenario)
261+
setTimeout(() => {
262+
client.call("checkUpgrade", { directory: cwd }).catch(() => {})
263+
}, 1000).unref?.()
257264

258265
try {
259266
const { createTuiRenderer, tui } = await import("./app")

packages/opencode/test/cli/tui/__snapshots__/inline-tool-wrap-snapshot.test.tsx.snap

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,10 @@ exports[`TUI inline tool wrapping separates a contiguous task group from inline
6161
6262
→ Read src/cli/cmd/tui/routes/session/index.tsx"
6363
`;
64+
65+
exports[`TUI inline tool wrapping separates a task group after an expanded read 1`] = `
66+
" → Read src/cli/cmd/tui/routes/session/index.tsx
67+
↳ Loaded src/cli/cmd/tui/routes/session/tools.tsx
68+
69+
✓ Explore Task — Inspect active task spacing"
70+
`;

packages/opencode/test/cli/tui/inline-tool-wrap-snapshot.test.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,22 @@ function TaskGroupFixture() {
105105
)
106106
}
107107

108+
function LoadedReadBeforeTaskFixture() {
109+
return (
110+
<box flexDirection="column" width={72}>
111+
<InlineToolRow id="tool-inline-read" icon="→" complete={true} pending="">
112+
Read src/cli/cmd/tui/routes/session/index.tsx
113+
</InlineToolRow>
114+
<box id="tool-inline-loaded-read-child" paddingLeft={3}>
115+
<text paddingLeft={3}>↳ Loaded src/cli/cmd/tui/routes/session/tools.tsx</text>
116+
</box>
117+
<InlineToolRow id="tool-inline-task-after-read" icon="✓" complete={true} pending="" task={true}>
118+
Explore Task — Inspect active task spacing
119+
</InlineToolRow>
120+
</box>
121+
)
122+
}
123+
108124
async function renderFrame(component: () => JSX.Element, options: { width: number; height: number }) {
109125
testSetup = await testRender(component, options)
110126
await testSetup.renderOnce()
@@ -139,4 +155,8 @@ describe("TUI inline tool wrapping", () => {
139155
test("separates a contiguous task group from inline tools", async () => {
140156
expect(await renderFrame(() => <TaskGroupFixture />, { width: 72, height: 10 })).toMatchSnapshot()
141157
})
158+
159+
test("separates a task group after an expanded read", async () => {
160+
expect(await renderFrame(() => <LoadedReadBeforeTaskFixture />, { width: 72, height: 8 })).toMatchSnapshot()
161+
})
142162
})

0 commit comments

Comments
 (0)