opencode-mux 0.1.0

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.
@@ -0,0 +1,10 @@
1
+ export declare const BUILTIN_THEME_BORDERS: Record<string, {
2
+ dark: {
3
+ inactive: string;
4
+ active: string;
5
+ };
6
+ light: {
7
+ inactive: string;
8
+ active: string;
9
+ };
10
+ }>;
@@ -0,0 +1,39 @@
1
+ // Generated by scripts/generate-theme-table.mjs — do not edit by hand.
2
+ // Source: anomalyco/opencode@v2.0.5, packages/tui/src/theme/assets/*.json (MIT).
3
+ // Regenerate: node scripts/generate-theme-table.mjs
4
+ export const BUILTIN_THEME_BORDERS = {
5
+ "aura": { "dark": { "inactive": "#2d2d2d", "active": "#6d6d6d" }, "light": { "inactive": "#2d2d2d", "active": "#6d6d6d" } },
6
+ "ayu": { "dark": { "inactive": "#6c7380", "active": "#6c7380" }, "light": { "inactive": "#6c7380", "active": "#6c7380" } },
7
+ "carbonfox": { "dark": { "inactive": "#303030", "active": "#33b1ff" }, "light": { "inactive": "#dcdcdc", "active": "#0043ce" } },
8
+ "catppuccin": { "dark": { "inactive": "#313244", "active": "#45475a" }, "light": { "inactive": "#ccd0da", "active": "#bcc0cc" } },
9
+ "catppuccin-frappe": { "dark": { "inactive": "#414559", "active": "#51576d" }, "light": { "inactive": "#414559", "active": "#51576d" } },
10
+ "catppuccin-macchiato": { "dark": { "inactive": "#363a4f", "active": "#494d64" }, "light": { "inactive": "#363a4f", "active": "#494d64" } },
11
+ "cobalt2": { "dark": { "inactive": "#1f4662", "active": "#0088ff" }, "light": { "inactive": "#d3dae3", "active": "#0066cc" } },
12
+ "cursor": { "dark": { "inactive": "#e4e4e4", "active": "#88c0d0" }, "light": { "inactive": "#141414", "active": "#6f9ba6" } },
13
+ "dracula": { "dark": { "inactive": "#44475a", "active": "#bd93f9" }, "light": { "inactive": "#c8c8c2", "active": "#bd93f9" } },
14
+ "everforest": { "dark": { "inactive": "#859289", "active": "#9da9a0" }, "light": { "inactive": "#939f91", "active": "#829181" } },
15
+ "flexoki": { "dark": { "inactive": "#575653", "active": "#6f6e69" }, "light": { "inactive": "#b7b5ac", "active": "#878580" } },
16
+ "github": { "dark": { "inactive": "#30363d", "active": "#58a6ff" }, "light": { "inactive": "#d0d7de", "active": "#0969da" } },
17
+ "gruvbox": { "dark": { "inactive": "#665c54", "active": "#ebdbb2" }, "light": { "inactive": "#bdae93", "active": "#3c3836" } },
18
+ "kanagawa": { "dark": { "inactive": "#54546d", "active": "#c38d9d" }, "light": { "inactive": "#d4cbbf", "active": "#c38d9d" } },
19
+ "lucent-orng": { "dark": { "inactive": "#ec5b2b", "active": "#ee7948" }, "light": { "inactive": "#ec5b2b", "active": "#c94d24" } },
20
+ "material": { "dark": { "inactive": "#37474f", "active": "#82aaff" }, "light": { "inactive": "#e0e0e0", "active": "#6182b8" } },
21
+ "matrix": { "dark": { "inactive": "#1e2a1b", "active": "#2eff6a" }, "light": { "inactive": "#748476", "active": "#1cc24b" } },
22
+ "mercury": { "dark": { "inactive": "#b4b7c8", "active": "#8da4f5" }, "light": { "inactive": "#707393", "active": "#5266eb" } },
23
+ "monokai": { "dark": { "inactive": "#3e3d32", "active": "#66d9ef" }, "light": { "inactive": "#d0d0d0", "active": "#66d9ef" } },
24
+ "nightowl": { "dark": { "inactive": "#5f7e97", "active": "#82aaff" }, "light": { "inactive": "#5f7e97", "active": "#82aaff" } },
25
+ "nord": { "dark": { "inactive": "#434c5e", "active": "#4c566a" }, "light": { "inactive": "#4c566a", "active": "#434c5e" } },
26
+ "one-dark": { "dark": { "inactive": "#393f4a", "active": "#61afef" }, "light": { "inactive": "#d1d1d2", "active": "#4078f2" } },
27
+ "opencode": { "dark": { "inactive": "#484848", "active": "#606060" }, "light": { "inactive": "#b8b8b8", "active": "#a0a0a0" } },
28
+ "orng": { "dark": { "inactive": "#ec5b2b", "active": "#ee7948" }, "light": { "inactive": "#ec5b2b", "active": "#c94d24" } },
29
+ "osaka-jade": { "dark": { "inactive": "#3d4a44", "active": "#2dd5b7" }, "light": { "inactive": "#a8a78c", "active": "#1faa90" } },
30
+ "palenight": { "dark": { "inactive": "#32364a", "active": "#82aaff" }, "light": { "inactive": "#e0e0e0", "active": "#4976eb" } },
31
+ "rosepine": { "dark": { "inactive": "#403d52", "active": "#9ccfd8" }, "light": { "inactive": "#dfdad9", "active": "#31748f" } },
32
+ "solarized": { "dark": { "inactive": "#073642", "active": "#586e75" }, "light": { "inactive": "#eee8d5", "active": "#93a1a1" } },
33
+ "synthwave84": { "dark": { "inactive": "#495495", "active": "#36f9f6" }, "light": { "inactive": "#e0e0e0", "active": "#00bcd4" } },
34
+ "tokyonight": { "dark": { "inactive": "#737aa2", "active": "#9099b2" }, "light": { "inactive": "#737a8c", "active": "#5a607d" } },
35
+ "vercel": { "dark": { "inactive": "#1f1f1f", "active": "#454545" }, "light": { "inactive": "#eaeaea", "active": "#999999" } },
36
+ "vesper": { "dark": { "inactive": "#282828", "active": "#ffc799" }, "light": { "inactive": "#d0d0d0", "active": "#ffc799" } },
37
+ "zenburn": { "dark": { "inactive": "#5f5f5f", "active": "#8cd0d3" }, "light": { "inactive": "#d0d0c0", "active": "#5f7f8f" } },
38
+ };
39
+ //# sourceMappingURL=builtin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtin.js","sourceRoot":"","sources":["../../src/theme/builtin.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,iFAAiF;AACjF,oDAAoD;AAEpD,MAAM,CAAC,MAAM,qBAAqB,GAG9B;IACF,MAAM,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAC5G,KAAK,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAC3G,WAAW,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IACjH,YAAY,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAClH,mBAAmB,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IACzH,sBAAsB,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAC5H,SAAS,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAC/G,QAAQ,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAC9G,SAAS,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAC/G,YAAY,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAClH,SAAS,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAC/G,QAAQ,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAC9G,SAAS,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAC/G,UAAU,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAChH,aAAa,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IACnH,UAAU,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAChH,QAAQ,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAC9G,SAAS,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAC/G,SAAS,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAC/G,UAAU,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAChH,MAAM,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAC5G,UAAU,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAChH,UAAU,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAChH,MAAM,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAC5G,YAAY,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAClH,WAAW,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IACjH,UAAU,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAChH,WAAW,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IACjH,aAAa,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IACnH,YAAY,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAClH,QAAQ,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAC9G,QAAQ,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;IAC9G,SAAS,EAAE,EAAC,MAAM,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC,OAAO,EAAC,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,EAAC,SAAS,EAAC,EAAC;CAChH,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { BorderStyles } from "./tmux.js";
2
+ /**
3
+ * Resolves the active opencode theme into tmux border style fragments
4
+ * (`fg=<color>`), or null when the theme is `system`, unknown, or unresolvable.
5
+ * Precedence: project cli.json → project tui.json → global cli.json → global
6
+ * tui.json; the first file that names a theme wins. Never throws.
7
+ */
8
+ export declare function resolveThemeStyles(opts: {
9
+ env: NodeJS.ProcessEnv;
10
+ cwd: string;
11
+ }): BorderStyles | null;
12
+ export interface ThemeStylesProvider {
13
+ /**
14
+ * Current border styles, re-resolved only when a watched file's mtime
15
+ * changes (the four config candidates plus the resolved custom theme file).
16
+ */
17
+ current(): BorderStyles | null;
18
+ }
19
+ /**
20
+ * Mtime-cached theme styles provider; cheap enough for per-tick polling.
21
+ * Never throws.
22
+ */
23
+ export declare function createThemeStyles(opts: {
24
+ env: NodeJS.ProcessEnv;
25
+ cwd: string;
26
+ }): ThemeStylesProvider;
package/dist/theme.js ADDED
@@ -0,0 +1,250 @@
1
+ import { existsSync, readFileSync, statSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { BUILTIN_THEME_BORDERS } from "./theme/builtin.js";
5
+ function configBase(env) {
6
+ const xdg = env.XDG_CONFIG_HOME;
7
+ return xdg !== undefined && xdg !== "" ? xdg : join(homedir(), ".config");
8
+ }
9
+ /** The four opencode config files in resolution precedence order. */
10
+ function configCandidates(opts) {
11
+ return [
12
+ join(opts.cwd, ".opencode", "cli.json"),
13
+ join(opts.cwd, ".opencode", "tui.json"),
14
+ join(configBase(opts.env), "opencode", "cli.json"),
15
+ join(configBase(opts.env), "opencode", "tui.json"),
16
+ ];
17
+ }
18
+ /** Parses a JSON file, returning null for missing or malformed files. */
19
+ function readJson(path) {
20
+ try {
21
+ return JSON.parse(readFileSync(path, "utf8"));
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ }
27
+ /** Theme name from a config doc: cli.json object form or legacy string form. */
28
+ function themeName(doc) {
29
+ if (typeof doc !== "object" || doc === null)
30
+ return null;
31
+ const theme = doc.theme;
32
+ if (typeof theme === "string" && theme !== "")
33
+ return theme;
34
+ if (typeof theme === "object" && theme !== null) {
35
+ const name = theme.name;
36
+ if (typeof name === "string" && name !== "")
37
+ return name;
38
+ }
39
+ return null;
40
+ }
41
+ /** Mode from a config doc; system/absent modes resolve as dark. */
42
+ function themeMode(doc) {
43
+ if (typeof doc !== "object" || doc === null)
44
+ return "dark";
45
+ const theme = doc.theme;
46
+ if (typeof theme === "object" && theme !== null && theme.mode === "light")
47
+ return "light";
48
+ return "dark";
49
+ }
50
+ function pickTheme(opts) {
51
+ for (const file of configCandidates(opts)) {
52
+ const doc = readJson(file);
53
+ if (doc === null)
54
+ continue;
55
+ const name = themeName(doc);
56
+ if (name === null)
57
+ continue;
58
+ return { name, mode: themeMode(doc) };
59
+ }
60
+ return { name: "opencode", mode: "dark" };
61
+ }
62
+ /** Custom theme file for a name: project dir first, then the global config dir. */
63
+ function customThemePath(opts, name) {
64
+ const project = join(opts.cwd, ".opencode", "themes", `${name}.json`);
65
+ if (existsSync(project))
66
+ return project;
67
+ const global = join(configBase(opts.env), "themes", `${name}.json`);
68
+ if (existsSync(global))
69
+ return global;
70
+ return null;
71
+ }
72
+ const isHex = (value) => /^#[0-9a-fA-F]{3,8}$/.test(value);
73
+ /** Normalizes #RGB/#RGBA/#RRGGBB/#RRGGBBAA to lowercase #rrggbb, or null. */
74
+ function normHex(value) {
75
+ let h = value.slice(1);
76
+ if (h.length === 3)
77
+ h = h.split("").map((c) => c + c).join("");
78
+ else if (h.length === 4)
79
+ h = h.slice(0, 3).split("").map((c) => c + c).join("");
80
+ else if (h.length === 8)
81
+ h = h.slice(0, 6);
82
+ return h.length === 6 ? `#${h.toLowerCase()}` : null;
83
+ }
84
+ /** Resolves a v1 flat theme value: hex | ansi | "none" | ref into defs/theme | {dark,light}. */
85
+ function resolveV1Value(value, theme, defs, mode, depth = 0) {
86
+ if (depth > 8 || value === null || value === undefined)
87
+ return null;
88
+ if (typeof value === "number") {
89
+ return Number.isInteger(value) && value >= 0 && value <= 255 ? { ansi: value } : null;
90
+ }
91
+ if (typeof value !== "string")
92
+ return null;
93
+ if (isHex(value)) {
94
+ const hex = normHex(value);
95
+ return hex === null ? null : { hex };
96
+ }
97
+ if (value === "none" || value === "transparent")
98
+ return null;
99
+ const next = defs[value] ?? theme[value];
100
+ if (next === undefined)
101
+ return null;
102
+ if (typeof next === "object" && next !== null && ("dark" in next || "light" in next)) {
103
+ const variant = next[mode] ?? next.dark;
104
+ return resolveV1Value(variant, theme, defs, mode, depth + 1);
105
+ }
106
+ return resolveV1Value(next, theme, defs, mode, depth + 1);
107
+ }
108
+ function pickV1(value, theme, defs, mode) {
109
+ if (value === null || value === undefined)
110
+ return null;
111
+ if (typeof value === "object" && !Array.isArray(value)) {
112
+ const variant = value[mode] ?? value.dark;
113
+ return resolveV1Value(variant, theme, defs, mode);
114
+ }
115
+ return resolveV1Value(value, theme, defs, mode);
116
+ }
117
+ function toStyleColor(resolved) {
118
+ if (resolved === null)
119
+ return null;
120
+ return "hex" in resolved ? resolved.hex : `colour${resolved.ansi}`;
121
+ }
122
+ /** Dotted-path lookup into a token document. */
123
+ function readPath(doc, path) {
124
+ let value = doc;
125
+ for (const key of path.split(".")) {
126
+ if (typeof value !== "object" || value === null)
127
+ return undefined;
128
+ value = value[key];
129
+ }
130
+ return value;
131
+ }
132
+ /** Resolves a v2 ColorValue: hex | "transparent" | "$path" token reference. */
133
+ function resolveV2Color(value, scope, seen) {
134
+ if (typeof value === "number") {
135
+ return Number.isInteger(value) && value >= 0 && value <= 255 ? `colour${value}` : null;
136
+ }
137
+ if (typeof value !== "string")
138
+ return null;
139
+ if (value === "none" || value === "transparent")
140
+ return null;
141
+ if (isHex(value))
142
+ return normHex(value);
143
+ if (!value.startsWith("$"))
144
+ return null;
145
+ if (seen.has(value))
146
+ return null;
147
+ seen.add(value);
148
+ return resolveV2Color(readPath(scope, value.slice(1)), scope, seen);
149
+ }
150
+ /** Resolves a custom theme document: v1 flat fully, v2 minimally via border.default. */
151
+ function resolveCustomDoc(doc, mode) {
152
+ const docObj = doc;
153
+ if (docObj === null || typeof docObj !== "object")
154
+ return null;
155
+ if (docObj.version === 2) {
156
+ const palette = docObj[mode] ?? {};
157
+ const border = palette.border;
158
+ // v2 token refs resolve against the palette merged with the doc's hue table.
159
+ const scope = { ...docObj, ...palette };
160
+ const color = resolveV2Color(border?.default, scope, new Set());
161
+ if (color === null)
162
+ return null;
163
+ // v2 has no borderActive: the border colour drives both pane states.
164
+ return { inactive: `fg=${color}`, active: `fg=${color}` };
165
+ }
166
+ const theme = (docObj.theme ?? docObj) ?? {};
167
+ const defs = docObj.defs ?? {};
168
+ const styles = {};
169
+ const inactive = toStyleColor(pickV1(theme.border, theme, defs, mode));
170
+ if (inactive !== null)
171
+ styles.inactive = `fg=${inactive}`;
172
+ // Absent borderActive falls back to the border colour; a present-but-unresolvable
173
+ // one drops the field instead.
174
+ const active = toStyleColor(pickV1(theme.borderActive ?? theme.border, theme, defs, mode));
175
+ if (active !== null)
176
+ styles.active = `fg=${active}`;
177
+ return styles.inactive === undefined && styles.active === undefined ? null : styles;
178
+ }
179
+ function resolveStyles(opts) {
180
+ const pick = pickTheme(opts);
181
+ if (pick.name === "system")
182
+ return { styles: null, customFile: null };
183
+ const custom = customThemePath(opts, pick.name);
184
+ if (custom !== null) {
185
+ const doc = readJson(custom);
186
+ return { styles: doc === null ? null : resolveCustomDoc(doc, pick.mode), customFile: custom };
187
+ }
188
+ const builtin = BUILTIN_THEME_BORDERS[pick.name];
189
+ const colors = builtin?.[pick.mode];
190
+ if (colors === undefined)
191
+ return { styles: null, customFile: null };
192
+ return {
193
+ styles: { inactive: `fg=${colors.inactive}`, active: `fg=${colors.active}` },
194
+ customFile: null,
195
+ };
196
+ }
197
+ /**
198
+ * Resolves the active opencode theme into tmux border style fragments
199
+ * (`fg=<color>`), or null when the theme is `system`, unknown, or unresolvable.
200
+ * Precedence: project cli.json → project tui.json → global cli.json → global
201
+ * tui.json; the first file that names a theme wins. Never throws.
202
+ */
203
+ export function resolveThemeStyles(opts) {
204
+ try {
205
+ return resolveStyles(opts).styles;
206
+ }
207
+ catch {
208
+ return null;
209
+ }
210
+ }
211
+ /**
212
+ * Mtime-cached theme styles provider; cheap enough for per-tick polling.
213
+ * Never throws.
214
+ */
215
+ export function createThemeStyles(opts) {
216
+ let cached = null;
217
+ let cachedSig = "";
218
+ let themeFile = null;
219
+ const statSig = (path) => {
220
+ try {
221
+ return `${path}:${statSync(path).mtimeMs}`;
222
+ }
223
+ catch {
224
+ return `${path}:missing`;
225
+ }
226
+ };
227
+ const composeSig = () => {
228
+ let sig = configCandidates(opts).map(statSig).join(";");
229
+ sig += themeFile === null ? ";theme:none" : `;theme:${statSig(themeFile)}`;
230
+ return sig;
231
+ };
232
+ return {
233
+ current() {
234
+ try {
235
+ const sig = composeSig();
236
+ if (sig === cachedSig)
237
+ return cached;
238
+ const { styles, customFile } = resolveStyles(opts);
239
+ cached = styles;
240
+ themeFile = customFile;
241
+ cachedSig = composeSig();
242
+ return cached;
243
+ }
244
+ catch {
245
+ return cached;
246
+ }
247
+ },
248
+ };
249
+ }
250
+ //# sourceMappingURL=theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"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"}
package/dist/tmux.d.ts ADDED
@@ -0,0 +1,37 @@
1
+ import type { Layout } from "./config.js";
2
+ import type { Exec } from "./exec.js";
3
+ export interface TmuxSplitInput {
4
+ targetPane: string;
5
+ layout: Layout;
6
+ /** Main pane size in percent (20-80) for main-* layouts; other layouts ignore it. */
7
+ mainPaneSize?: number;
8
+ argv: string[];
9
+ }
10
+ export interface TmuxResult {
11
+ ok: boolean;
12
+ error: string | null;
13
+ paneId: string | null;
14
+ }
15
+ export interface TmuxApplyResult {
16
+ ok: boolean;
17
+ error: string | null;
18
+ }
19
+ /** Window-scoped pane border styles, keyed by tmux option name. */
20
+ export interface BorderStyles {
21
+ inactive?: string;
22
+ active?: string;
23
+ }
24
+ export interface Tmux {
25
+ splitPane(input: TmuxSplitInput): Promise<TmuxResult>;
26
+ killPane(paneId: string): Promise<{
27
+ ok: boolean;
28
+ error: string | null;
29
+ }>;
30
+ applyBorderStyles(targetPane: string, styles: BorderStyles): Promise<TmuxApplyResult>;
31
+ clearBorderStyles(targetPane: string): Promise<TmuxApplyResult>;
32
+ }
33
+ /** Pane id from the environment, or null when not inside tmux. */
34
+ export declare function currentPane(env: NodeJS.ProcessEnv): string | null;
35
+ /** Shell-safe single-argument quoting (tmux joins trailing args into `sh -c`). */
36
+ export declare function shellQuote(arg: string): string;
37
+ export declare function tmuxAdapter(exec: Exec): Tmux;
package/dist/tmux.js ADDED
@@ -0,0 +1,108 @@
1
+ /** Pane id from the environment, or null when not inside tmux. */
2
+ export function currentPane(env) {
3
+ const pane = env.TMUX_PANE;
4
+ return pane !== undefined && pane !== "" ? pane : null;
5
+ }
6
+ /** Shell-safe single-argument quoting (tmux joins trailing args into `sh -c`). */
7
+ export function shellQuote(arg) {
8
+ if (/^[A-Za-z0-9_./:@%+-]+$/.test(arg))
9
+ return arg;
10
+ return `'${arg.replaceAll("'", "'\\''")}'`;
11
+ }
12
+ export function tmuxAdapter(exec) {
13
+ return {
14
+ async splitPane({ targetPane, layout, argv, mainPaneSize }) {
15
+ const args = [
16
+ "split-window",
17
+ "-P",
18
+ "-F",
19
+ "#{pane_id}",
20
+ "-t",
21
+ targetPane,
22
+ ...argv.map(shellQuote),
23
+ ];
24
+ const result = await exec.run("tmux", args);
25
+ const raw = result.stdout.trim().split("\n")[0];
26
+ const paneId = raw === undefined || raw === "" ? null : raw;
27
+ const paneOk = paneId !== null && paneId !== "";
28
+ if (result.ok && paneOk) {
29
+ // Shape the whole window into the requested named layout (e.g. the main
30
+ // pane left with subagents stacked in a right column for main-vertical).
31
+ // tmux keeps re-arranging into this layout as panes are added or removed,
32
+ // so repeated splits no longer cascade or exhaust pane space.
33
+ //
34
+ // main-* layouts size their main pane from the window options
35
+ // main-pane-width / main-pane-height, which accept a percentage.
36
+ // select-layout itself rejects a "layout,size" suffix ("invalid layout"),
37
+ // so set the matching option first, then apply the plain preset layout.
38
+ // Non-main layouts have no main pane and ignore the size entirely.
39
+ if (mainPaneSize !== undefined && layout.startsWith("main-")) {
40
+ const option = layout === "main-horizontal" ? "main-pane-height" : "main-pane-width";
41
+ await exec.run("tmux", ["set-option", "-w", "-t", targetPane, option, `${mainPaneSize}%`]);
42
+ }
43
+ await exec.run("tmux", ["select-layout", "-t", targetPane, layout]);
44
+ }
45
+ return {
46
+ ok: result.ok && paneOk,
47
+ error: result.ok ? (paneOk ? null : "no pane id returned") : result.stderr.trim() || result.error || "tmux failed",
48
+ paneId,
49
+ };
50
+ },
51
+ async killPane(paneId) {
52
+ const result = await exec.run("tmux", ["kill-pane", "-t", paneId]);
53
+ return {
54
+ ok: result.ok,
55
+ error: result.ok ? null : result.stderr.trim() || result.error || "tmux failed",
56
+ };
57
+ },
58
+ /**
59
+ * Applies border styles to the target pane's window via window options (-w,
60
+ * never the server-wide -g), so only that window is affected. Best-effort:
61
+ * each defined style is attempted sequentially; a failure does not stop the
62
+ * remaining styles and the first failure is reported.
63
+ */
64
+ async applyBorderStyles(targetPane, styles) {
65
+ const commands = [];
66
+ if (styles.inactive !== undefined)
67
+ commands.push({ option: "pane-border-style", value: styles.inactive });
68
+ if (styles.active !== undefined)
69
+ commands.push({ option: "pane-active-border-style", value: styles.active });
70
+ let firstError = null;
71
+ try {
72
+ for (const { option, value } of commands) {
73
+ const result = await exec.run("tmux", ["set-option", "-w", "-t", targetPane, option, value]);
74
+ if (!result.ok && firstError === null) {
75
+ firstError = result.stderr.trim() || result.error || "tmux failed";
76
+ }
77
+ }
78
+ }
79
+ catch (error) {
80
+ return { ok: false, error: firstError ?? String(error) };
81
+ }
82
+ return { ok: firstError === null, error: firstError };
83
+ },
84
+ /**
85
+ * Unsets the window's border style options (-w -u), restoring inherited
86
+ * defaults on the target pane's window only — never the server-wide -g.
87
+ * Best-effort: a failure does not stop the second unset and the first
88
+ * failure is reported.
89
+ */
90
+ async clearBorderStyles(targetPane) {
91
+ const options = ["pane-border-style", "pane-active-border-style"];
92
+ let firstError = null;
93
+ try {
94
+ for (const option of options) {
95
+ const result = await exec.run("tmux", ["set-option", "-w", "-u", "-t", targetPane, option]);
96
+ if (!result.ok && firstError === null) {
97
+ firstError = result.stderr.trim() || result.error || "tmux failed";
98
+ }
99
+ }
100
+ }
101
+ catch (error) {
102
+ return { ok: false, error: firstError ?? String(error) };
103
+ }
104
+ return { ok: firstError === null, error: firstError };
105
+ },
106
+ };
107
+ }
108
+ //# sourceMappingURL=tmux.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tmux.js","sourceRoot":"","sources":["../src/tmux.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import type { ClosePanes } from "./config.js";
2
+ export type PaneState = {
3
+ phase: "pending";
4
+ terminal: boolean;
5
+ } | {
6
+ phase: "open";
7
+ paneId: string;
8
+ closeAt: number | null;
9
+ } | {
10
+ phase: "closing";
11
+ paneId: string;
12
+ closeAt: number;
13
+ } | {
14
+ phase: "kept";
15
+ paneId: string;
16
+ };
17
+ export type TrackerAction = {
18
+ kind: "open";
19
+ sessionID: string;
20
+ paneId: string;
21
+ } | {
22
+ kind: "close";
23
+ sessionID: string;
24
+ paneId: string;
25
+ };
26
+ export interface PaneTrackerOptions {
27
+ graceMs: number;
28
+ closePanes: ClosePanes;
29
+ }
30
+ /** Pure session→pane state machine; time is injected. */
31
+ export declare class PaneTracker {
32
+ private readonly opts;
33
+ private readonly states;
34
+ constructor(opts: PaneTrackerOptions);
35
+ /** Copy of the current states (read-only view for tests and the watcher). */
36
+ snapshot(): ReadonlyMap<string, PaneState>;
37
+ /** Creates a pending entry for a session whose pane does not exist yet. */
38
+ reserve(sessionID: string): boolean;
39
+ /** Drops any state, e.g. when the pane could not be opened. */
40
+ remove(sessionID: string): void;
41
+ /** Resolves a pending session into an open pane. Returns the open action. */
42
+ open(sessionID: string, paneId: string, now: number): TrackerAction | null;
43
+ /** Marks a session terminal (idle or deleted). Never returns an action. */
44
+ markTerminal(sessionID: string, now: number): TrackerAction | null;
45
+ /** Cancels a pending close when the session comes back busy. Never returns an action. */
46
+ markBusy(sessionID: string): TrackerAction | null;
47
+ /** Emits due close actions and forgets those sessions. */
48
+ tick(now: number): TrackerAction[];
49
+ }
@@ -0,0 +1,75 @@
1
+ /** Pure session→pane state machine; time is injected. */
2
+ export class PaneTracker {
3
+ opts;
4
+ states = new Map();
5
+ constructor(opts) {
6
+ this.opts = opts;
7
+ }
8
+ /** Copy of the current states (read-only view for tests and the watcher). */
9
+ snapshot() {
10
+ return new Map(this.states);
11
+ }
12
+ /** Creates a pending entry for a session whose pane does not exist yet. */
13
+ reserve(sessionID) {
14
+ if (this.states.has(sessionID))
15
+ return false;
16
+ this.states.set(sessionID, { phase: "pending", terminal: false });
17
+ return true;
18
+ }
19
+ /** Drops any state, e.g. when the pane could not be opened. */
20
+ remove(sessionID) {
21
+ this.states.delete(sessionID);
22
+ }
23
+ /** Resolves a pending session into an open pane. Returns the open action. */
24
+ open(sessionID, paneId, now) {
25
+ const st = this.states.get(sessionID);
26
+ if (st === undefined || st.phase !== "pending")
27
+ return null;
28
+ if (st.terminal) {
29
+ this.states.set(sessionID, { phase: "closing", paneId, closeAt: now });
30
+ }
31
+ else {
32
+ this.states.set(sessionID, { phase: "open", paneId, closeAt: null });
33
+ }
34
+ return { kind: "open", sessionID, paneId };
35
+ }
36
+ /** Marks a session terminal (idle or deleted). Never returns an action. */
37
+ markTerminal(sessionID, now) {
38
+ const st = this.states.get(sessionID);
39
+ if (st === undefined)
40
+ return null;
41
+ if (st.phase === "pending") {
42
+ this.states.set(sessionID, { phase: "pending", terminal: true });
43
+ return null;
44
+ }
45
+ if (st.phase === "open") {
46
+ if (this.opts.closePanes === "auto") {
47
+ this.states.set(sessionID, { phase: "closing", paneId: st.paneId, closeAt: now + this.opts.graceMs });
48
+ }
49
+ else {
50
+ this.states.set(sessionID, { phase: "kept", paneId: st.paneId });
51
+ }
52
+ }
53
+ return null;
54
+ }
55
+ /** Cancels a pending close when the session comes back busy. Never returns an action. */
56
+ markBusy(sessionID) {
57
+ const st = this.states.get(sessionID);
58
+ if (st !== undefined && st.phase === "closing") {
59
+ this.states.set(sessionID, { phase: "open", paneId: st.paneId, closeAt: null });
60
+ }
61
+ return null;
62
+ }
63
+ /** Emits due close actions and forgets those sessions. */
64
+ tick(now) {
65
+ const actions = [];
66
+ for (const [sessionID, st] of this.states) {
67
+ if (st.phase === "closing" && st.closeAt <= now) {
68
+ this.states.delete(sessionID);
69
+ actions.push({ kind: "close", sessionID, paneId: st.paneId });
70
+ }
71
+ }
72
+ return actions;
73
+ }
74
+ }
75
+ //# sourceMappingURL=tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracker.js","sourceRoot":"","sources":["../src/tracker.ts"],"names":[],"mappings":"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"}