mirror of
https://github.com/cline/cline.git
synced 2026-08-29 03:52:41 +08:00
fix(cli): patch @opentui-ui/dialog for opentui 0.4.x remove() contract (#12516)
@opentui-ui/dialog@0.1.2 is built against @opentui/core ^0.1.69, whose Renderable.remove(id) took a string id. Core 0.4.x renamed it to remove(child) and throws when handed anything but a renderable, so the dialog package's removeDialog()/provider teardown aborted before detaching the panel: the React portal content unmounted but the imperative grey box stayed on screen over the chat after every dialog close (model picker, help, command palette, ...). The upstream package is abandoned at 0.1.2, so pin the fix with a bun patch that passes the renderable object on all three bindings (react, solid, core container). A tui-test opens and dismisses the help dialog and asserts the panel's #262626 background is fully gone, not just its text. Fixes #12506 Co-authored-by: Cline Agent <cline-agent@users.noreply.github.com>
This commit is contained in:
@@ -17,14 +17,19 @@
|
||||
// - Auto-approve all (Shift+Tab)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
import { test } from "@microsoft/tui-test";
|
||||
import { expect, test } from "@microsoft/tui-test";
|
||||
import type { Terminal } from "@microsoft/tui-test/lib/terminal/term";
|
||||
import { CLINE_BIN, TERMINAL_WIDE } from "../helpers/constants.js";
|
||||
import { clineEnv } from "../helpers/env.js";
|
||||
import {
|
||||
toggleAutoApproveAll,
|
||||
waitForChatReady,
|
||||
} from "../helpers/page-objects/chat.js";
|
||||
import { expectVisible } from "../helpers/terminal.js";
|
||||
import {
|
||||
expectNotVisible,
|
||||
expectVisible,
|
||||
typeAndSubmit,
|
||||
} from "../helpers/terminal.js";
|
||||
|
||||
test.describe("cline (authenticated) - shows chat view", () => {
|
||||
test.use({
|
||||
@@ -53,3 +58,54 @@ test.describe("Auto-approve all - Shift+Tab toggle", () => {
|
||||
await toggleAutoApproveAll(terminal);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Dialog dismissal - panel is fully removed", () => {
|
||||
test.use({
|
||||
program: { file: CLINE_BIN, args: [] },
|
||||
...TERMINAL_WIDE,
|
||||
env: clineEnv("default"),
|
||||
});
|
||||
|
||||
// The dialog panel's background is @opentui-ui/dialog's DEFAULT_STYLE
|
||||
// (#262626), which xterm reports as this packed 24-bit color.
|
||||
const DIALOG_PANEL_BG = 0x262626;
|
||||
|
||||
const countPanelCells = (terminal: Terminal): number => {
|
||||
let count = 0;
|
||||
for (const shift of terminal.serialize().shifts.values()) {
|
||||
if (shift.bgColor === DIALOG_PANEL_BG) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
// @opentui-ui/dialog is built against @opentui/core ^0.1.69, whose
|
||||
// Renderable.remove(id) took an id. Core 0.4.x renamed it to
|
||||
// remove(child) and throws on a non-renderable argument, so the
|
||||
// package's removeDialog() aborted before detaching its panel — the React
|
||||
// portal content unmounted, but the imperative grey box stayed on screen
|
||||
// over the chat. Asserting on the panel's background (not its text) is what
|
||||
// distinguishes a leaked box from a clean teardown.
|
||||
test("closing the help dialog removes its grey panel", async ({
|
||||
terminal,
|
||||
}) => {
|
||||
await waitForChatReady(terminal);
|
||||
await typeAndSubmit(terminal, "/help");
|
||||
await expectVisible(terminal, "Keyboard Shortcuts");
|
||||
expect(countPanelCells(terminal)).toBeGreaterThan(0);
|
||||
|
||||
terminal.keyEscape();
|
||||
await expectNotVisible(terminal, "Keyboard Shortcuts");
|
||||
|
||||
// The panel unmounts a frame after its content; poll until the
|
||||
// dialog's imperative box is detached rather than sampling once.
|
||||
const deadline = Date.now() + 10_000;
|
||||
let remaining = countPanelCells(terminal);
|
||||
while (remaining > 0 && Date.now() < deadline) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
remaining = countPanelCells(terminal);
|
||||
}
|
||||
expect(remaining).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -772,6 +772,9 @@
|
||||
"better-sqlite3",
|
||||
"grpc-tools",
|
||||
],
|
||||
"patchedDependencies": {
|
||||
"@opentui-ui/dialog@0.1.2": "patches/@opentui-ui%2Fdialog@0.1.2.patch",
|
||||
},
|
||||
"overrides": {
|
||||
"@opentui/core": "0.4.3",
|
||||
"@opentui/react": "0.4.3",
|
||||
|
||||
+4
-1
@@ -86,5 +86,8 @@
|
||||
"better-sqlite3",
|
||||
"grpc-tools"
|
||||
],
|
||||
"packageManager": "bun@1.3.13"
|
||||
"packageManager": "bun@1.3.13",
|
||||
"patchedDependencies": {
|
||||
"@opentui-ui/dialog@0.1.2": "patches/@opentui-ui%2Fdialog@0.1.2.patch"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
diff --git a/dist/dialog-container-Btgzkwy7.mjs b/dist/dialog-container-Btgzkwy7.mjs
|
||||
index fa1f29023479d5df2daf399c42f1d492365365aa..9a576b394c551269e6944bbb08fb43f7a7d3a8ca 100644
|
||||
--- a/dist/dialog-container-Btgzkwy7.mjs
|
||||
+++ b/dist/dialog-container-Btgzkwy7.mjs
|
||||
@@ -677,7 +677,7 @@ var DialogContainerRenderable = class extends BoxRenderable {
|
||||
const renderable = this._dialogRenderables.get(id);
|
||||
if (renderable) {
|
||||
this._dialogRenderables.delete(id);
|
||||
- this.remove(renderable.id);
|
||||
+ this.remove(renderable);
|
||||
renderable.destroyRecursively();
|
||||
this.updateBackdropVisibility();
|
||||
this.updateBackdropStyle();
|
||||
diff --git a/dist/react.mjs b/dist/react.mjs
|
||||
index 157bd9c3ba3101810e02da720b8763425fd7b0fd..70bb55028ff815a82fea84205c61fb85d2aac03a 100644
|
||||
--- a/dist/react.mjs
|
||||
+++ b/dist/react.mjs
|
||||
@@ -169,7 +169,7 @@ function DialogProvider(props) {
|
||||
renderer.root.add(container);
|
||||
return () => {
|
||||
container.destroyRecursively();
|
||||
- renderer.root.remove(container.id);
|
||||
+ renderer.root.remove(container);
|
||||
manager.destroy();
|
||||
};
|
||||
}, [
|
||||
diff --git a/dist/solid.mjs b/dist/solid.mjs
|
||||
index 2aea0ede350d79b5a8e533323fe70480bbd7f3ce..f075087a57c68875f341baa9ada67231fcc9cb10 100644
|
||||
--- a/dist/solid.mjs
|
||||
+++ b/dist/solid.mjs
|
||||
@@ -192,7 +192,7 @@ function DialogProvider(props) {
|
||||
unsubscribe();
|
||||
portalItemCache.clear();
|
||||
container.destroyRecursively();
|
||||
- renderer.root.remove(container.id);
|
||||
+ renderer.root.remove(container);
|
||||
manager.destroy();
|
||||
});
|
||||
createEffect(() => {
|
||||
Reference in New Issue
Block a user