oc-bg-color-sync 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +72 -0
  2. package/index.ts +30 -0
  3. package/package.json +24 -0
package/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # oc-bg-color-sync
2
+
3
+ Synchronize the terminal's native background color with OpenTUI's renderer background color. Fixes mismatched border/gutter colors in terminals that draw padding outside the application viewport.
4
+
5
+ ## Why
6
+
7
+ OpenTUI renders its own background, but the terminal emulator may show its own default color in gutters, borders, or padding areas around the app. This plugin emits **OSC 11** whenever the renderer background changes so the terminal stays in sync.
8
+
9
+ On cleanup it emits **OSC 111** to restore the terminal's original background.
10
+
11
+ ## The Bug
12
+
13
+ ### What you see
14
+
15
+ When OpenCode's TUI renders with a dark theme but your terminal profile has a light background (or vice versa), you get visible color mismatches in:
16
+
17
+ - Terminal gutters/padding around the app
18
+ - Border areas not covered by the renderer
19
+ - Scrollback regions showing the "wrong" background
20
+
21
+ ### Root cause
22
+
23
+ This was originally fixed upstream in `@opentui/core` via [PR #951](https://github.com/anomalyco/opentui/pull/951) by having `setBackgroundColor()` emit **OSC 11** to sync the terminal's native background with the renderer's background.
24
+
25
+ However, [PR #969](https://github.com/anomalyco/opentui/pull/969) ("more reliable theme mode") **removed** the OSC 11 emission from `setBackgroundColor()` because it caused issues in Ghostty:
26
+
27
+ > "Do not mirror renderer background to terminal default background via OSC 11 for now. In Ghostty, once OSC 11 has been used, later system light/dark theme changes can leave OSC 11 queries stuck on stale bg values even after OSC 111 resets. Theme detection relies on fresh OSC 10/11 replies, so mutating terminal default bg here breaks that."
28
+
29
+ The PR also disabled the **OSC 111** reset in `terminal.zig`'s `resetState()`:
30
+
31
+ > "OSC 111 is intentionally disabled for now. In Ghostty, sending the reset alone is enough to poison later OSC 11 background reporting for system light/dark theme changes, which breaks theme detection on the next app startup even though the immediate reset appears to work."
32
+
33
+ So after PR #969:
34
+
35
+ - `renderer.setBackgroundColor()` only updates the internal render buffer
36
+ - The terminal's native background stays at its profile default
37
+ - Theme detection is more reliable, but border/gutter colors break
38
+
39
+ This plugin restores the OSC 11 sync as a userland workaround until upstream finds a solution that works for both use cases.
40
+
41
+ ## How it works
42
+
43
+ - Wraps `renderer.setBackgroundColor()`
44
+ - After the native call, converts the RGBA color to hex and writes `OSC 11;rgb:rr/gg/bb\x07` to stdout
45
+ - On plugin dispose, calls `renderer.resetTerminalBgColor()` which writes `OSC 111\x07`
46
+
47
+ ### OSC sequence reference
48
+
49
+ - **OSC 11** — Set terminal background color
50
+ Format: `\x1b]11;rgb:RR/GG/BB\x07`
51
+ - **OSC 111** — Reset terminal background to default
52
+ Format: `\x1b]111\x07`
53
+
54
+ See [VT100.net OSC 11 docs](https://vtdn.dev/docs/osc/osc11) and [OSC 110-112](https://vtdn.dev/docs/osc/osc110-112) for more.
55
+
56
+ ## Install
57
+
58
+ Add the plugin to your OpenCode config (`tui.json` or equivalent):
59
+
60
+ ```json
61
+ {
62
+ "plugin": ["oc-bg-color-sync"]
63
+ }
64
+ ```
65
+
66
+ ## Requirements
67
+
68
+ - A terminal emulator that supports OSC 11/111 (most modern terminals do; Ghostty has quirks with theme detection after OSC 11/111 usage)
69
+
70
+ ## License
71
+
72
+ MIT
package/index.ts ADDED
@@ -0,0 +1,30 @@
1
+ import type { TuiPlugin, TuiPluginModule } from "@opencode-ai/plugin/tui";
2
+ import { hexToRgb } from "@opentui/core";
3
+
4
+ const tui: TuiPlugin = async (api) => {
5
+ const renderer = api.renderer;
6
+ const original = renderer.setBackgroundColor.bind(renderer);
7
+
8
+ renderer.setBackgroundColor = (color) => {
9
+ original(color);
10
+ const rgba = typeof color === "string" ? hexToRgb(color) : color;
11
+
12
+ if (rgba.a > 0) {
13
+ const hex = (n: number) => n.toString(16).padStart(2, "0");
14
+ process.stdout.write(
15
+ `\x1b]11;rgb:${hex(rgba.r)}/${hex(rgba.g)}/${hex(rgba.b)}\x07`,
16
+ );
17
+ }
18
+ };
19
+
20
+ api.lifecycle.onDispose(() => {
21
+ renderer.resetTerminalBgColor();
22
+ });
23
+ };
24
+
25
+ const plugin: TuiPluginModule & { id: string } = {
26
+ id: "bg-sync",
27
+ tui,
28
+ };
29
+
30
+ export default plugin;
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "oc-bg-color-sync",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "main": "index.ts",
6
+ "exports": {
7
+ "./tui": {
8
+ "import": "./index.ts"
9
+ }
10
+ },
11
+ "files": [
12
+ "index.ts"
13
+ ],
14
+ "peerDependencies": {
15
+ "@opencode-ai/plugin": "*",
16
+ "@opentui/core": "*",
17
+ "@opentui/solid": "*",
18
+ "solid-js": "*"
19
+ },
20
+ "devDependencies": {
21
+ "typescript": "^5",
22
+ "@types/bun": "latest"
23
+ }
24
+ }