opencode-zellij 0.0.8 → 0.0.9
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.
- package/LICENSE +21 -0
- package/README.md +18 -0
- package/README.zh.md +18 -0
- package/dist/index.mjs +57 -36
- package/dist/index.mjs.map +1 -1
- package/dist/pane-watchdog-runner.mjs +13 -4
- package/dist/pane-watchdog-runner.mjs.map +1 -1
- package/package.json +2 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 maou-shonen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -69,6 +69,24 @@ Close the dev server pane.
|
|
|
69
69
|
|
|
70
70
|
`zellij_pty_request_sudo` opens a review pane, shows what will run, and waits for the user to type `YES`. The agent cannot type into that pane, so passwords and credentials stay in Zellij instead of entering prompts or tool arguments.
|
|
71
71
|
|
|
72
|
+
## Configuration
|
|
73
|
+
|
|
74
|
+
Optional sidecar config files are loaded from `~/.config/opencode/opencode-zellij.config.jsonc` and from `.opencode/opencode-zellij.config.jsonc` in the current project. Project config overrides user config.
|
|
75
|
+
|
|
76
|
+
```jsonc
|
|
77
|
+
{
|
|
78
|
+
"$schema": "https://raw.githubusercontent.com/maou-shonen/opencode-zellij/main/opencode-zellij.schema.json",
|
|
79
|
+
"autoUpdate": true,
|
|
80
|
+
"pty": {
|
|
81
|
+
"enabled": true,
|
|
82
|
+
"sudoPane": "allow" // allow, deny, or hide
|
|
83
|
+
},
|
|
84
|
+
"tabTitle": { "enabled": true }
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Set `autoUpdate`, `pty.enabled`, or `tabTitle.enabled` to `false` to turn those features off.
|
|
89
|
+
|
|
72
90
|
## Dynamic tab title
|
|
73
91
|
|
|
74
92
|
When OpenCode runs inside Zellij, the plugin updates the current tab title to show the project, branch, and current OpenCode state:
|
package/README.zh.md
CHANGED
|
@@ -69,6 +69,24 @@ OpenCode 會在啟動時自動安裝 npm plugins。Zellij 也必須已安裝,
|
|
|
69
69
|
|
|
70
70
|
`zellij_pty_request_sudo` 會開啟 review pane、顯示即將執行的內容,並等待使用者輸入 `YES`。Agent 不能在該 pane 中輸入,因此 passwords 與 credentials 會留在 Zellij,而不是進入 prompts 或 tool arguments。
|
|
71
71
|
|
|
72
|
+
## 設定
|
|
73
|
+
|
|
74
|
+
可選的 sidecar config 會從 `~/.config/opencode/opencode-zellij.config.jsonc` 以及目前 project 的 `.opencode/opencode-zellij.config.jsonc` 載入。Project config 會覆蓋 user config。
|
|
75
|
+
|
|
76
|
+
```jsonc
|
|
77
|
+
{
|
|
78
|
+
"$schema": "https://raw.githubusercontent.com/maou-shonen/opencode-zellij/main/opencode-zellij.schema.json",
|
|
79
|
+
"autoUpdate": true,
|
|
80
|
+
"pty": {
|
|
81
|
+
"enabled": true,
|
|
82
|
+
"sudoPane": "allow" // allow, deny, or hide
|
|
83
|
+
},
|
|
84
|
+
"tabTitle": { "enabled": true }
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
將 `autoUpdate`、`pty.enabled` 或 `tabTitle.enabled` 設為 `false` 可關閉對應功能。
|
|
89
|
+
|
|
72
90
|
## 動態 tab title
|
|
73
91
|
|
|
74
92
|
當 OpenCode 在 Zellij 中執行時,plugin 會更新目前 tab title,顯示 project、branch 與目前 OpenCode 狀態:
|
package/dist/index.mjs
CHANGED
|
@@ -18,6 +18,11 @@ function debug(message, ...details) {
|
|
|
18
18
|
console.warn(`[opencode-zellij] ${message}`, ...details);
|
|
19
19
|
}
|
|
20
20
|
//#endregion
|
|
21
|
+
//#region src/utils/errors.ts
|
|
22
|
+
function errorMessage(error) {
|
|
23
|
+
return error instanceof Error ? error.message : String(error);
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
21
26
|
//#region src/auto-update.ts
|
|
22
27
|
const PACKAGE_NAME = "opencode-zellij";
|
|
23
28
|
const NPM_REGISTRY_URL = "https://registry.npmjs.org/-/package/opencode-zellij/dist-tags";
|
|
@@ -39,7 +44,9 @@ async function installedPackageMetadata(installRoot) {
|
|
|
39
44
|
version: typeof pkg.version === "string" ? pkg.version : void 0,
|
|
40
45
|
main: typeof pkg.main === "string" ? pkg.main : void 0
|
|
41
46
|
};
|
|
42
|
-
} catch {
|
|
47
|
+
} catch (error) {
|
|
48
|
+
debug("installedPackageMetadata failed", errorMessage(error));
|
|
49
|
+
}
|
|
43
50
|
}
|
|
44
51
|
function isExpectedPackage(metadata, version) {
|
|
45
52
|
return metadata?.name === "opencode-zellij" && metadata.version === version;
|
|
@@ -108,7 +115,9 @@ async function findInstallContext(importMetaUrl) {
|
|
|
108
115
|
currentVersion: pkg.version
|
|
109
116
|
};
|
|
110
117
|
}
|
|
111
|
-
} catch {
|
|
118
|
+
} catch (error) {
|
|
119
|
+
debug("findInstallContext package.json read failed", errorMessage(error));
|
|
120
|
+
}
|
|
112
121
|
}
|
|
113
122
|
const parent = dirname(dir);
|
|
114
123
|
if (parent === dir) break;
|
|
@@ -254,7 +263,7 @@ const ptyLayerSchema = z.object({
|
|
|
254
263
|
enabled: z.boolean().optional().describe("Enable Zellij-backed PTY tools."),
|
|
255
264
|
sudoPane: sudoPaneSchema.optional().describe("Controls whether the sudo pane tool is available, denied, or hidden.")
|
|
256
265
|
}).strict();
|
|
257
|
-
const autoUpdateLayerSchema = z.
|
|
266
|
+
const autoUpdateLayerSchema = z.boolean().optional().describe("Enable automatic update checks for the opencode-zellij plugin.");
|
|
258
267
|
const sidecarConfigSchema = z.object({
|
|
259
268
|
$schema: z.string().optional().describe("JSON Schema URI for editor completion."),
|
|
260
269
|
tabTitle: tabTitleLayerSchema.optional(),
|
|
@@ -274,7 +283,7 @@ const defaultConfig = {
|
|
|
274
283
|
enabled: true,
|
|
275
284
|
sudoPane: "allow"
|
|
276
285
|
},
|
|
277
|
-
autoUpdate:
|
|
286
|
+
autoUpdate: true
|
|
278
287
|
};
|
|
279
288
|
function validConfigLayer(value) {
|
|
280
289
|
const result = sidecarConfigSchema.safeParse(value);
|
|
@@ -299,7 +308,7 @@ function mergeConfig(user, project) {
|
|
|
299
308
|
enabled: project?.pty?.enabled ?? user?.pty?.enabled ?? defaultConfig.pty.enabled,
|
|
300
309
|
sudoPane: project?.pty?.sudoPane ?? user?.pty?.sudoPane ?? defaultConfig.pty.sudoPane
|
|
301
310
|
},
|
|
302
|
-
autoUpdate:
|
|
311
|
+
autoUpdate: project?.autoUpdate ?? user?.autoUpdate ?? defaultConfig.autoUpdate
|
|
303
312
|
};
|
|
304
313
|
}
|
|
305
314
|
async function loadConfigLayer(directory, warnings) {
|
|
@@ -559,7 +568,8 @@ function parseCurrentPaneTabId(listPanesJson, paneId) {
|
|
|
559
568
|
if (!Number.isInteger(parsedPaneId)) return void 0;
|
|
560
569
|
try {
|
|
561
570
|
return findPaneTabId(JSON.parse(listPanesJson), parsedPaneId);
|
|
562
|
-
} catch {
|
|
571
|
+
} catch (error) {
|
|
572
|
+
debug("parseCurrentPaneTabId failed", errorMessage(error));
|
|
563
573
|
return;
|
|
564
574
|
}
|
|
565
575
|
}
|
|
@@ -656,7 +666,8 @@ function parseLinuxProcessStartTime(stat) {
|
|
|
656
666
|
function linuxProcessStartTime(pid) {
|
|
657
667
|
try {
|
|
658
668
|
return parseLinuxProcessStartTime(readFileSync(`/proc/${pid}/stat`, "utf8"));
|
|
659
|
-
} catch {
|
|
669
|
+
} catch (error) {
|
|
670
|
+
debug("linuxProcessStartTime failed", errorMessage(error));
|
|
660
671
|
return null;
|
|
661
672
|
}
|
|
662
673
|
}
|
|
@@ -677,7 +688,8 @@ function readRegistry() {
|
|
|
677
688
|
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
678
689
|
if (parsed.version !== 1 || parsed.instanceId !== instanceId || parsed.ownerPid !== process.pid || !Array.isArray(parsed.panes)) return emptyRegistry();
|
|
679
690
|
return parsed;
|
|
680
|
-
} catch {
|
|
691
|
+
} catch (error) {
|
|
692
|
+
debug("readRegistry failed", errorMessage(error));
|
|
681
693
|
return emptyRegistry();
|
|
682
694
|
}
|
|
683
695
|
}
|
|
@@ -725,7 +737,8 @@ function cleanupStaleWatchdogRegistries() {
|
|
|
725
737
|
if (registry.version !== 1 || ownerStillMatches(registry)) continue;
|
|
726
738
|
closeRegistryPanes(registry);
|
|
727
739
|
rmSync(file, { force: true });
|
|
728
|
-
} catch {
|
|
740
|
+
} catch (error) {
|
|
741
|
+
debug("cleanupStaleWatchdogRegistries failed", errorMessage(error));
|
|
729
742
|
rmSync(file, { force: true });
|
|
730
743
|
}
|
|
731
744
|
}
|
|
@@ -733,7 +746,8 @@ function cleanupStaleWatchdogRegistries() {
|
|
|
733
746
|
function ownerStillMatches(registry) {
|
|
734
747
|
try {
|
|
735
748
|
process.kill(registry.ownerPid, 0);
|
|
736
|
-
} catch {
|
|
749
|
+
} catch (error) {
|
|
750
|
+
debug("ownerStillMatches kill check failed", errorMessage(error));
|
|
737
751
|
return false;
|
|
738
752
|
}
|
|
739
753
|
return !registry.ownerStartTime || linuxProcessStartTime(registry.ownerPid) === registry.ownerStartTime;
|
|
@@ -785,7 +799,9 @@ function unregisterPaneFromWatchdog(sessionId) {
|
|
|
785
799
|
function removeWatchdogRegistry() {
|
|
786
800
|
try {
|
|
787
801
|
rmSync(watchdogRegistryPath(), { force: true });
|
|
788
|
-
} catch {
|
|
802
|
+
} catch (error) {
|
|
803
|
+
debug("removeWatchdogRegistry failed", errorMessage(error));
|
|
804
|
+
}
|
|
789
805
|
if (!watchdogChild) watchdogStarted = false;
|
|
790
806
|
}
|
|
791
807
|
//#endregion
|
|
@@ -959,14 +975,7 @@ var SubscriberManager = class {
|
|
|
959
975
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
960
976
|
lastExitedAt: null
|
|
961
977
|
};
|
|
962
|
-
if (!existing)
|
|
963
|
-
this.subscribers.set(session.id, state);
|
|
964
|
-
try {
|
|
965
|
-
state.buffer.appendSnapshot(await zellijCli.dumpScreen(session.paneId));
|
|
966
|
-
this.sessions.updateLineCount(session.id, state.buffer.lineCount);
|
|
967
|
-
} catch {}
|
|
968
|
-
if (this.subscribers.get(session.id) !== state) return;
|
|
969
|
-
}
|
|
978
|
+
if (!existing) this.subscribers.set(session.id, state);
|
|
970
979
|
const child = spawn("zellij", zellijCommandArgs([
|
|
971
980
|
"subscribe",
|
|
972
981
|
"--pane-id",
|
|
@@ -993,6 +1002,14 @@ var SubscriberManager = class {
|
|
|
993
1002
|
child.stderr.on("data", (chunk) => this.handleStderr(session.id, child, chunk));
|
|
994
1003
|
child.on("exit", () => this.handleSubscriberExit(session.id, child));
|
|
995
1004
|
child.on("error", (error) => this.handleSubscriberError(session.id, child, error));
|
|
1005
|
+
if (!existing) try {
|
|
1006
|
+
const snapshot = await zellijCli.dumpScreen(session.paneId);
|
|
1007
|
+
if (this.subscribers.get(session.id) !== state || state.child !== child) return;
|
|
1008
|
+
state.buffer.appendSnapshot(snapshot);
|
|
1009
|
+
this.sessions.updateLineCount(session.id, state.buffer.lineCount);
|
|
1010
|
+
} catch (error) {
|
|
1011
|
+
debug("dumpScreen failed", errorMessage(error));
|
|
1012
|
+
}
|
|
996
1013
|
}
|
|
997
1014
|
read(sessionId, input) {
|
|
998
1015
|
const state = this.subscribers.get(sessionId);
|
|
@@ -1032,7 +1049,9 @@ var SubscriberManager = class {
|
|
|
1032
1049
|
this.stop(sessionId);
|
|
1033
1050
|
try {
|
|
1034
1051
|
await zellijCli.closePane(session.paneId);
|
|
1035
|
-
} catch {
|
|
1052
|
+
} catch (error) {
|
|
1053
|
+
debug("closePane failed", errorMessage(error));
|
|
1054
|
+
}
|
|
1036
1055
|
}
|
|
1037
1056
|
handleStdout(sessionId, child, chunk) {
|
|
1038
1057
|
const state = this.subscribers.get(sessionId);
|
|
@@ -1051,16 +1070,18 @@ var SubscriberManager = class {
|
|
|
1051
1070
|
const parsed = JSON.parse(trimmed);
|
|
1052
1071
|
if (!parsed || typeof parsed !== "object") return;
|
|
1053
1072
|
event = parsed;
|
|
1054
|
-
} catch {
|
|
1073
|
+
} catch (error) {
|
|
1055
1074
|
state.buffer.append(trimmed);
|
|
1056
1075
|
this.sessions.updateLineCount(sessionId, state.buffer.lineCount);
|
|
1076
|
+
debug("JSON parse of subscriber event failed, treating as raw text", errorMessage(error));
|
|
1057
1077
|
return;
|
|
1058
1078
|
}
|
|
1059
1079
|
let session;
|
|
1060
1080
|
try {
|
|
1061
1081
|
session = this.sessions.get(sessionId);
|
|
1062
|
-
} catch {
|
|
1082
|
+
} catch (error) {
|
|
1063
1083
|
this.forget(sessionId);
|
|
1084
|
+
debug("session lookup by id failed", errorMessage(error));
|
|
1064
1085
|
return;
|
|
1065
1086
|
}
|
|
1066
1087
|
const paneId = eventPaneId(event);
|
|
@@ -1146,11 +1167,6 @@ function jsonResponse(value) {
|
|
|
1146
1167
|
return JSON.stringify(value, null, 2);
|
|
1147
1168
|
}
|
|
1148
1169
|
//#endregion
|
|
1149
|
-
//#region src/utils/errors.ts
|
|
1150
|
-
function errorMessage(error) {
|
|
1151
|
-
return error instanceof Error ? error.message : String(error);
|
|
1152
|
-
}
|
|
1153
|
-
//#endregion
|
|
1154
1170
|
//#region src/tools/output.ts
|
|
1155
1171
|
function emptyOutputSnapshot(lineCount = 0) {
|
|
1156
1172
|
return {
|
|
@@ -1609,11 +1625,15 @@ function cleanupPanesOnShutdown(sessions = sessionManager, subscribers = subscri
|
|
|
1609
1625
|
for (const session of sessions.list()) {
|
|
1610
1626
|
try {
|
|
1611
1627
|
zellijCli.closePaneSync(session.paneId);
|
|
1612
|
-
} catch {
|
|
1628
|
+
} catch (error) {
|
|
1629
|
+
debug("cleanupPanesOnShutdown closePane failed", errorMessage(error));
|
|
1630
|
+
}
|
|
1613
1631
|
subscribers.forget(session.id);
|
|
1614
1632
|
try {
|
|
1615
1633
|
sessions.remove(session.id);
|
|
1616
|
-
} catch {
|
|
1634
|
+
} catch (error) {
|
|
1635
|
+
debug("cleanupPanesOnShutdown sessions.remove failed", errorMessage(error));
|
|
1636
|
+
}
|
|
1617
1637
|
}
|
|
1618
1638
|
}
|
|
1619
1639
|
function registerShutdownCleanup() {
|
|
@@ -1683,7 +1703,8 @@ async function readGitBranch(worktree) {
|
|
|
1683
1703
|
async function getInitialBranch(worktree, readBranch = readGitBranch) {
|
|
1684
1704
|
try {
|
|
1685
1705
|
return (await readBranch(worktree)).trim() || void 0;
|
|
1686
|
-
} catch {
|
|
1706
|
+
} catch (error) {
|
|
1707
|
+
debug("getInitialBranch failed", errorMessage(error));
|
|
1687
1708
|
return;
|
|
1688
1709
|
}
|
|
1689
1710
|
}
|
|
@@ -1868,7 +1889,7 @@ var TabTitleManager = class {
|
|
|
1868
1889
|
this.clearDebounceTimer();
|
|
1869
1890
|
this.debounceTimer = setTimeout(() => {
|
|
1870
1891
|
this.debounceTimer = void 0;
|
|
1871
|
-
this.syncDesiredTitle().catch(() =>
|
|
1892
|
+
this.syncDesiredTitle().catch((error) => debug("debounced tab title sync failed", errorMessage(error)));
|
|
1872
1893
|
}, this.debounceMs);
|
|
1873
1894
|
this.unrefTimer(this.debounceTimer);
|
|
1874
1895
|
}
|
|
@@ -1900,7 +1921,7 @@ var TabTitleManager = class {
|
|
|
1900
1921
|
this.retryAttempt += 1;
|
|
1901
1922
|
this.retryTimer = setTimeout(() => {
|
|
1902
1923
|
this.retryTimer = void 0;
|
|
1903
|
-
this.syncDesiredTitle().catch(() =>
|
|
1924
|
+
this.syncDesiredTitle().catch((error) => debug("retry tab title sync failed", errorMessage(error)));
|
|
1904
1925
|
}, delay);
|
|
1905
1926
|
this.unrefTimer(this.retryTimer);
|
|
1906
1927
|
}
|
|
@@ -1942,13 +1963,13 @@ function showUpdateToast(client, result) {
|
|
|
1942
1963
|
message: `Updated to ${result.toVersion}. Restart OpenCode to apply the changes.`,
|
|
1943
1964
|
variant: "success",
|
|
1944
1965
|
duration: 1e4
|
|
1945
|
-
} }).catch(() =>
|
|
1966
|
+
} }).catch((error) => debug("show update toast for successful update failed", errorMessage(error)));
|
|
1946
1967
|
else if (result.type === "failed") client.tui.showToast({ body: {
|
|
1947
1968
|
title: "opencode-zellij update failed",
|
|
1948
1969
|
message: `Failed to update to ${result.latestVersion}.`,
|
|
1949
1970
|
variant: "error",
|
|
1950
1971
|
duration: 8e3
|
|
1951
|
-
} }).catch(() =>
|
|
1972
|
+
} }).catch((error) => debug("show update toast for failed update failed", errorMessage(error)));
|
|
1952
1973
|
}
|
|
1953
1974
|
function startAutoUpdateCheck(client, importMetaUrl, check = checkAndUpdate) {
|
|
1954
1975
|
(async () => {
|
|
@@ -1993,9 +2014,9 @@ function createZellijPtyPlugin(dependencies = {}) {
|
|
|
1993
2014
|
branch: config.tabTitle.emojiBranch
|
|
1994
2015
|
}
|
|
1995
2016
|
}) : void 0;
|
|
1996
|
-
tabTitleManager?.renderImmediate().catch(() =>
|
|
2017
|
+
tabTitleManager?.renderImmediate().catch((error) => debug("initial tab title render failed", errorMessage(error)));
|
|
1997
2018
|
const client = input.client;
|
|
1998
|
-
if (config.autoUpdate
|
|
2019
|
+
if (config.autoUpdate) (dependencies.startAutoUpdateCheck ?? startAutoUpdateCheck)(client, dependencies.importMetaUrl ?? import.meta.url);
|
|
1999
2020
|
return {
|
|
2000
2021
|
async event(input) {
|
|
2001
2022
|
const event = input.event;
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["isRecord","execFileAsync","ansiPattern","schema","delay","schema","schema","delay","schema","delay"],"sources":["../src/utils/debug.ts","../src/auto-update.ts","../src/config.ts","../src/permissions/sudo-pane.ts","../src/utils/ids.ts","../src/pty/manager.ts","../src/utils/shell-args.ts","../src/zellij/cli.ts","../src/zellij/pane-watchdog.ts","../src/pty/ring-buffer.ts","../src/utils/exit-code.ts","../src/zellij/subscribe.ts","../src/tools/format.ts","../src/utils/errors.ts","../src/tools/output.ts","../src/tools/kill.ts","../src/tools/list.ts","../src/tools/read.ts","../src/utils/pane-title.ts","../src/tools/request-sudo.ts","../src/pty/probe.ts","../src/tools/spawn.ts","../src/pty/write-data.ts","../src/tools/write.ts","../src/zellij/shutdown-cleanup.ts","../src/zellij/tab-title-events.ts","../src/zellij/tab-title.ts","../src/plugin.ts"],"sourcesContent":["import process from 'node:process'\n\nexport function debug(message: string, ...details: unknown[]): void {\n if (!process.env.ZELLIJ_PTY_DEBUG)\n return\n\n console.warn(`[opencode-zellij] ${message}`, ...details)\n}\n","import { execFile } from 'node:child_process'\nimport { existsSync } from 'node:fs'\nimport { readFile, rename, rm } from 'node:fs/promises'\nimport { basename, dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { promisify } from 'node:util'\nimport { debug } from './utils/debug.js'\n\nexport const PACKAGE_NAME = 'opencode-zellij'\n\nconst NPM_REGISTRY_URL = 'https://registry.npmjs.org/-/package/opencode-zellij/dist-tags'\nconst FETCH_TIMEOUT_MS = 5_000\nconst INSTALL_TIMEOUT_MS = 60_000\n\nconst defaultExecFile = promisify(execFile)\n\nfunction packageDir(installRoot: string): string {\n return join(installRoot, 'node_modules', PACKAGE_NAME)\n}\n\nfunction backupDir(installRoot: string): string {\n return join(installRoot, 'node_modules', `${PACKAGE_NAME}.update-backup`)\n}\n\ninterface InstalledPackageMetadata {\n name: string | undefined\n version: string | undefined\n main: string | undefined\n}\n\nasync function installedPackageMetadata(installRoot: string): Promise<InstalledPackageMetadata | undefined> {\n try {\n const content = await readFile(join(packageDir(installRoot), 'package.json'), 'utf8')\n const pkg: unknown = JSON.parse(content)\n if (isRecord(pkg)) {\n return {\n name: typeof pkg.name === 'string' ? pkg.name : undefined,\n version: typeof pkg.version === 'string' ? pkg.version : undefined,\n main: typeof pkg.main === 'string' ? pkg.main : undefined,\n }\n }\n }\n catch {\n // Missing or unreadable package metadata is handled by the caller.\n }\n return undefined\n}\n\nfunction isExpectedPackage(metadata: InstalledPackageMetadata | undefined, version: string): boolean {\n return metadata?.name === PACKAGE_NAME && metadata.version === version\n}\n\nfunction hasRunnableEntry(installRoot: string, metadata: InstalledPackageMetadata | undefined): boolean {\n if (!metadata)\n return false\n const dir = packageDir(installRoot)\n if (metadata.main && existsSync(join(dir, metadata.main)))\n return true\n return existsSync(join(dir, 'dist', 'index.mjs'))\n}\n\nasync function isVerifiedInstall(installRoot: string, version: string): Promise<boolean> {\n const metadata = await installedPackageMetadata(installRoot)\n return isExpectedPackage(metadata, version) && hasRunnableEntry(installRoot, metadata)\n}\n\nasync function removeInstalledPackage(installRoot: string): Promise<void> {\n await rm(packageDir(installRoot), { force: true, recursive: true })\n}\n\nasync function backupInstalledPackage(installRoot: string): Promise<string | undefined> {\n const source = packageDir(installRoot)\n if (!existsSync(source))\n return undefined\n const backup = backupDir(installRoot)\n await rm(backup, { force: true, recursive: true })\n await rename(source, backup)\n return backup\n}\n\nasync function restoreInstalledPackage(installRoot: string, backup: string | undefined): Promise<void> {\n if (!backup || !existsSync(backup))\n return\n await rm(packageDir(installRoot), { force: true, recursive: true })\n await rename(backup, packageDir(installRoot))\n}\n\nasync function discardBackup(backup: string | undefined): Promise<void> {\n if (backup)\n await rm(backup, { force: true, recursive: true })\n}\n\nexport interface InstallContext {\n installRoot: string\n cacheSpec: string\n currentVersion: string\n}\n\nexport async function findInstallContext(importMetaUrl: string): Promise<InstallContext | undefined> {\n let startPath: string\n try {\n startPath = fileURLToPath(importMetaUrl)\n }\n catch (cause) {\n debug('invalid import.meta.url', cause instanceof Error ? cause.message : String(cause))\n return undefined\n }\n\n let dir = dirname(startPath)\n\n while (true) {\n const isPluginDir = dir.endsWith(`/node_modules/${PACKAGE_NAME}`) || dir.endsWith(`\\\\node_modules\\\\${PACKAGE_NAME}`)\n if (isPluginDir) {\n const packageJsonPath = join(dir, 'package.json')\n try {\n const content = await readFile(packageJsonPath, 'utf8')\n const pkg: unknown = JSON.parse(content)\n if (\n isRecord(pkg)\n && pkg.name === PACKAGE_NAME\n && typeof pkg.version === 'string'\n && pkg.version.length > 0\n ) {\n const installRoot = dirname(dirname(dir))\n const rootPackageJson = join(installRoot, 'package.json')\n if (existsSync(rootPackageJson)) {\n return { installRoot, cacheSpec: basename(installRoot), currentVersion: pkg.version }\n }\n }\n }\n catch {\n // ignore unreadable or invalid package.json\n }\n }\n\n const parent = dirname(dir)\n if (parent === dir)\n break\n dir = parent\n }\n\n return undefined\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null\n}\n\nexport function isAutoUpdatableSpec(spec: string | undefined): boolean {\n if (spec === PACKAGE_NAME)\n return true\n if (spec === `${PACKAGE_NAME}@latest`)\n return true\n return false\n}\n\nexport async function fetchLatestVersion(fetchImpl: typeof fetch = globalThis.fetch): Promise<string | undefined> {\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS)\n\n try {\n const response = await fetchImpl(NPM_REGISTRY_URL, { signal: controller.signal })\n clearTimeout(timeout)\n if (!response.ok) {\n debug(`npm registry returned ${response.status}`)\n return undefined\n }\n const data: unknown = await response.json()\n if (isRecord(data) && typeof data.latest === 'string') {\n return data.latest\n }\n debug('npm registry response missing latest tag')\n return undefined\n }\n catch (cause) {\n clearTimeout(timeout)\n debug('failed to fetch latest version', cause instanceof Error ? cause.message : String(cause))\n return undefined\n }\n}\n\nexport type ExecFileLike = (\n file: string,\n args: string[],\n options: { cwd: string, timeout?: number },\n) => Promise<{ stdout: string, stderr: string }>\n\nexport async function runNpmInstall(\n installRoot: string,\n version: string,\n execImpl: ExecFileLike = defaultExecFile as ExecFileLike,\n): Promise<boolean> {\n debug(`updating ${PACKAGE_NAME} to ${version} in ${installRoot}`)\n\n try {\n const install = () => execImpl(\n 'npm',\n ['install', `${PACKAGE_NAME}@${version}`, '--save-exact', '--ignore-scripts', '--no-audit', '--no-fund', '--prefer-online'],\n { cwd: installRoot, timeout: INSTALL_TIMEOUT_MS },\n )\n\n await install()\n\n if (await isVerifiedInstall(installRoot, version)) {\n debug(`updated ${PACKAGE_NAME} to ${version}`)\n return true\n }\n\n const installedPackage = await installedPackageMetadata(installRoot)\n debug(`npm install left stale or invalid ${PACKAGE_NAME} (${installedPackage?.name ?? '<missing>'}@${installedPackage?.version ?? '<missing>'}); reinstalling ${version}`)\n const backup = await backupInstalledPackage(installRoot)\n try {\n await removeInstalledPackage(installRoot)\n await install()\n\n if (await isVerifiedInstall(installRoot, version)) {\n await discardBackup(backup)\n debug(`updated ${PACKAGE_NAME} to ${version}`)\n return true\n }\n\n const reinstalledPackage = await installedPackageMetadata(installRoot)\n debug(`npm install verification failed: expected ${PACKAGE_NAME}@${version}, found ${reinstalledPackage?.name ?? '<missing>'}@${reinstalledPackage?.version ?? '<missing>'}`)\n await restoreInstalledPackage(installRoot, backup)\n return false\n }\n catch (cause) {\n await restoreInstalledPackage(installRoot, backup)\n throw cause\n }\n }\n catch (cause) {\n debug('npm install failed', cause instanceof Error ? cause.message : String(cause))\n return false\n }\n}\n\nexport interface CheckOptions {\n importMetaUrl: string\n fetchImpl?: typeof fetch\n execImpl?: ExecFileLike\n}\n\nexport type UpdateResult\n = | { type: 'skipped', reason: string }\n | { type: 'up-to-date', currentVersion: string }\n | { type: 'updated', fromVersion: string, toVersion: string }\n | { type: 'failed', currentVersion: string, latestVersion: string, reason: string }\n\nexport async function checkAndUpdate(options: CheckOptions): Promise<UpdateResult> {\n const context = await findInstallContext(options.importMetaUrl)\n if (!context) {\n debug('skipping auto-update: not installed from npm')\n return { type: 'skipped', reason: 'not installed from npm' }\n }\n\n if (!isAutoUpdatableSpec(context.cacheSpec)) {\n debug(`skipping auto-update: cache spec is pinned or unknown (${context.cacheSpec})`)\n return { type: 'skipped', reason: `cache spec is pinned or unknown (${context.cacheSpec})` }\n }\n\n const latest = await fetchLatestVersion(options.fetchImpl)\n if (!latest) {\n debug('skipping auto-update: could not determine latest version')\n return { type: 'skipped', reason: 'could not determine latest version' }\n }\n\n const installedVersion = (await installedPackageMetadata(context.installRoot))?.version ?? context.currentVersion\n if (latest === installedVersion) {\n debug(`auto-update: already on latest ${latest}`)\n return { type: 'up-to-date', currentVersion: installedVersion }\n }\n\n const success = await runNpmInstall(context.installRoot, latest, options.execImpl)\n if (success) {\n debug(`updated ${PACKAGE_NAME} from ${installedVersion} to ${latest}`)\n return { type: 'updated', fromVersion: installedVersion, toVersion: latest }\n }\n\n return { type: 'failed', currentVersion: installedVersion, latestVersion: latest, reason: 'npm install failed' }\n}\n","import { existsSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport process from 'node:process'\nimport { parseJSON, parseJSONC } from 'confbox'\nimport { z } from 'zod'\n\nconst sudoPaneSchema = z.enum(['allow', 'deny', 'hide'])\n\nexport interface TabTitleConfig {\n enabled: boolean\n emojiIdle: string\n emojiRunning: string\n emojiNeedsInput: string\n emojiBranch: string\n debounceMs: number\n}\n\nexport interface PtyConfig {\n enabled: boolean\n sudoPane: SudoPaneMode\n}\n\nexport type SudoPaneMode = z.infer<typeof sudoPaneSchema>\n\nexport interface AutoUpdateConfig {\n enabled: boolean\n}\n\nexport interface ZellijPluginConfig {\n tabTitle: TabTitleConfig\n pty: PtyConfig\n autoUpdate: AutoUpdateConfig\n}\n\nexport interface LoadConfigInput {\n directory?: string | undefined\n worktree?: string | undefined\n}\n\nexport interface LoadConfigResult {\n config: ZellijPluginConfig\n sources: {\n user?: string | undefined\n project?: string | undefined\n }\n warnings: string[]\n}\n\nconst configFilenames = [\n 'opencode-zellij.config.jsonc',\n 'opencode-zellij.config.json',\n] as const\n\nconst tabTitleLayerSchema = z.object({\n enabled: z.boolean().optional().describe('Enable dynamic Zellij tab title updates.'),\n emojiIdle: z.string().optional().describe('Prefix used when OpenCode is idle.'),\n emojiRunning: z.string().optional().describe('Prefix used while OpenCode is running work.'),\n emojiNeedsInput: z.string().optional().describe('Prefix used when OpenCode is waiting for human input.'),\n emojiBranch: z.string().optional().describe('Prefix used before the current git branch name.'),\n debounceMs: z.number().finite().min(0).optional().describe('Debounce time for tab title updates in milliseconds.'),\n}).strict()\n\nconst ptyLayerSchema = z.object({\n enabled: z.boolean().optional().describe('Enable Zellij-backed PTY tools.'),\n sudoPane: sudoPaneSchema.optional().describe('Controls whether the sudo pane tool is available, denied, or hidden.'),\n}).strict()\n\nconst autoUpdateLayerSchema = z.object({\n enabled: z.boolean().optional().describe('Enable automatic update checks for the opencode-zellij plugin.'),\n}).strict()\n\nexport const sidecarConfigSchema = z.object({\n $schema: z.string().optional().describe('JSON Schema URI for editor completion.'),\n tabTitle: tabTitleLayerSchema.optional(),\n pty: ptyLayerSchema.optional(),\n autoUpdate: autoUpdateLayerSchema.optional(),\n}).strict()\n\nexport const defaultConfig: ZellijPluginConfig = {\n tabTitle: {\n enabled: true,\n emojiIdle: '🟢',\n emojiRunning: '⚡',\n emojiNeedsInput: '💬',\n emojiBranch: '🌱',\n debounceMs: 300,\n },\n pty: {\n enabled: true,\n sudoPane: 'allow',\n },\n autoUpdate: {\n enabled: true,\n },\n}\n\ntype ConfigLayer = Pick<z.infer<typeof sidecarConfigSchema>, 'tabTitle' | 'pty' | 'autoUpdate'>\n\nfunction validConfigLayer(value: unknown): ConfigLayer | undefined {\n const result = sidecarConfigSchema.safeParse(value)\n if (!result.success)\n return undefined\n\n return {\n tabTitle: result.data.tabTitle,\n pty: result.data.pty,\n autoUpdate: result.data.autoUpdate,\n }\n}\n\nfunction mergeConfig(user?: ConfigLayer | undefined, project?: ConfigLayer | undefined): ZellijPluginConfig {\n return {\n tabTitle: {\n enabled: project?.tabTitle?.enabled ?? user?.tabTitle?.enabled ?? defaultConfig.tabTitle.enabled,\n emojiIdle: project?.tabTitle?.emojiIdle ?? user?.tabTitle?.emojiIdle ?? defaultConfig.tabTitle.emojiIdle,\n emojiRunning: project?.tabTitle?.emojiRunning ?? user?.tabTitle?.emojiRunning ?? defaultConfig.tabTitle.emojiRunning,\n emojiNeedsInput: project?.tabTitle?.emojiNeedsInput ?? user?.tabTitle?.emojiNeedsInput ?? defaultConfig.tabTitle.emojiNeedsInput,\n emojiBranch: project?.tabTitle?.emojiBranch ?? user?.tabTitle?.emojiBranch ?? defaultConfig.tabTitle.emojiBranch,\n debounceMs: project?.tabTitle?.debounceMs ?? user?.tabTitle?.debounceMs ?? defaultConfig.tabTitle.debounceMs,\n },\n pty: {\n enabled: project?.pty?.enabled ?? user?.pty?.enabled ?? defaultConfig.pty.enabled,\n sudoPane: project?.pty?.sudoPane ?? user?.pty?.sudoPane ?? defaultConfig.pty.sudoPane,\n },\n autoUpdate: {\n enabled: project?.autoUpdate?.enabled ?? user?.autoUpdate?.enabled ?? defaultConfig.autoUpdate.enabled,\n },\n }\n}\n\nasync function loadConfigLayer(directory: string, warnings: string[]): Promise<{ layer?: ConfigLayer | undefined, source?: string | undefined }> {\n const configFile = detectConfigFile(directory)\n if (!configFile)\n return {}\n\n try {\n const text = await readFile(configFile, 'utf8')\n const parsed = configFile.endsWith('.jsonc') ? parseJSONC(text) : parseJSON(text)\n const layer = validConfigLayer(parsed)\n if (!layer) {\n warnings.push(`Ignoring invalid config shape in ${configFile}.`)\n return { source: configFile }\n }\n return { layer, source: configFile }\n }\n catch (cause) {\n warnings.push(`Ignoring unreadable or invalid config file ${configFile}: ${cause instanceof Error ? cause.message : String(cause)}`)\n return {}\n }\n}\n\nfunction detectConfigFile(directory: string): string | undefined {\n return configFilenames\n .map(filename => join(directory, filename))\n .find(path => existsSync(path))\n}\n\nexport function userConfigDir(): string {\n return process.env.XDG_CONFIG_HOME ? join(process.env.XDG_CONFIG_HOME, 'opencode') : join(homedir(), '.config', 'opencode')\n}\n\nexport function projectConfigDirs(input: LoadConfigInput): string[] {\n const dirs: string[] = []\n if (input.worktree)\n dirs.push(join(input.worktree, '.opencode'))\n if (input.directory && input.directory !== input.worktree)\n dirs.push(join(input.directory, '.opencode'))\n return dirs\n}\n\nexport async function loadConfig(input: LoadConfigInput): Promise<LoadConfigResult> {\n const warnings: string[] = []\n const sources: LoadConfigResult['sources'] = {}\n\n const userResult = await loadConfigLayer(userConfigDir(), warnings)\n const userLayer = userResult.layer\n if (userResult.source && userLayer)\n sources.user = userResult.source\n\n let projectLayer: ConfigLayer | undefined\n for (const projectDir of projectConfigDirs(input)) {\n const projectResult = await loadConfigLayer(projectDir, warnings)\n if (!projectResult.source)\n continue\n projectLayer = projectResult.layer\n if (projectLayer)\n sources.project = projectResult.source\n break\n }\n\n return {\n config: mergeConfig(userLayer, projectLayer),\n sources,\n warnings,\n }\n}\n","let sudoPaneAllowed = true\n\nexport function configureSudoPane(allowed: boolean): void {\n sudoPaneAllowed = allowed\n}\n\nexport function assertSudoPaneAllowed(): void {\n if (!sudoPaneAllowed)\n throw new Error('sudo pane is disabled by zellij-pty config.')\n}\n","import { randomUUID } from 'node:crypto'\n\nconst paneIdPattern = /\\b(?:terminal_)?(\\d+)\\b/\n\nexport function createSessionId(): string {\n return `zpty_${randomUUID().replaceAll('-', '').slice(0, 10)}`\n}\n\nexport function normalizePaneId(rawPaneId: string): string {\n const trimmed = rawPaneId.trim()\n if (/^terminal_\\d+$/.test(trimmed))\n return trimmed\n if (/^\\d+$/.test(trimmed))\n return `terminal_${trimmed}`\n throw new Error(`Invalid Zellij terminal pane id: ${rawPaneId}`)\n}\n\nexport function parsePaneId(output: string): string {\n const match = output.match(paneIdPattern)\n if (!match?.[1]) {\n throw new Error(`Unable to parse Zellij pane id from output: ${output.trim() || '<empty>'}`)\n }\n return normalizePaneId(match[1])\n}\n","import type { CreateSessionInput, PtySession, SessionStatus } from './session.js'\nimport { createSessionId } from '../utils/ids.js'\n\nexport class SessionManager {\n private readonly sessions = new Map<string, PtySession>()\n\n create(input: CreateSessionInput): PtySession {\n const now = new Date().toISOString()\n const session: PtySession = {\n id: createSessionId(),\n openCodeSessionId: input.openCodeSessionId ?? null,\n paneId: input.paneId,\n title: input.title,\n command: input.command,\n args: input.args ?? [],\n cwd: input.cwd,\n status: 'running',\n lineCount: 0,\n createdAt: now,\n updatedAt: now,\n allowAgentInput: input.allowAgentInput,\n humanInputOnly: input.humanInputOnly,\n exitCode: null,\n exitedAt: null,\n exitCodeToken: input.exitCodeToken ?? null,\n }\n this.sessions.set(session.id, session)\n return session\n }\n\n get(id: string): PtySession {\n const session = this.sessions.get(id)\n if (!session)\n throw new Error(`Unknown zellij PTY session: ${id}`)\n return session\n }\n\n find(id: string): PtySession | undefined {\n return this.sessions.get(id)\n }\n\n list(): PtySession[] {\n return Array.from(this.sessions.values()).sort((a, b) => a.createdAt.localeCompare(b.createdAt))\n }\n\n updateLineCount(id: string, lineCount: number): PtySession {\n const session = this.get(id)\n session.lineCount = lineCount\n session.updatedAt = new Date().toISOString()\n return session\n }\n\n updateStatus(id: string, status: SessionStatus): PtySession {\n const session = this.get(id)\n session.status = status\n session.updatedAt = new Date().toISOString()\n return session\n }\n\n markExited(id: string, exitCode: number): PtySession {\n const session = this.get(id)\n session.status = 'exited'\n session.exitCode = exitCode\n session.exitedAt = new Date().toISOString()\n session.updatedAt = session.exitedAt\n return session\n }\n\n listByOpenCodeSession(openCodeSessionId: string): PtySession[] {\n return this.list().filter(session => session.openCodeSessionId === openCodeSessionId)\n }\n\n remove(id: string): void {\n if (!this.sessions.delete(id))\n throw new Error(`Unknown zellij PTY session: ${id}`)\n }\n}\n\nexport const sessionManager = new SessionManager()\n","export interface CommandInput {\n command: string\n args?: string[] | undefined\n}\n\nexport interface BuildCommandArgvOptions {\n exitCodeToken?: string | undefined\n}\n\nconst directCommandExitWrapper = 'token=\"$1\"; shift; set +e; \"$@\"; code=$?; printf \"\\\\n[zellij-pty:%s] exit-code=%s\\\\n\" \"$token\" \"$code\"; exit \"$code\"'\nconst shellCommandExitWrapper = 'token=\"$1\"; command=\"$2\"; set +e; bash -lc \"$command\"; code=$?; printf \"\\\\n[zellij-pty:%s] exit-code=%s\\\\n\" \"$token\" \"$code\"; exit \"$code\"'\n\nexport function buildCommandArgv(input: CommandInput, options: BuildCommandArgvOptions = {}): string[] {\n const command = input.command.trim()\n if (!command)\n throw new Error('command is required')\n\n if (options.exitCodeToken) {\n if (input.args && input.args.length > 0) {\n return ['bash', '-lc', directCommandExitWrapper, 'zellij-pty', options.exitCodeToken, command, ...input.args]\n }\n\n return ['bash', '-lc', shellCommandExitWrapper, 'zellij-pty', options.exitCodeToken, command]\n }\n\n if (input.args && input.args.length > 0) {\n return [command, ...input.args]\n }\n\n return ['bash', '-lc', command]\n}\n","import type { CommandInput } from '../utils/shell-args.js'\nimport { execFile, spawnSync } from 'node:child_process'\nimport process from 'node:process'\nimport { promisify } from 'node:util'\nimport { parsePaneId } from '../utils/ids.js'\nimport { buildCommandArgv } from '../utils/shell-args.js'\n\nconst execFileAsync = promisify(execFile)\n\nexport type NewPaneOptions = CommandInput & {\n cwd?: string | undefined\n title?: string | undefined\n floating?: boolean | undefined\n exitCodeToken?: string | undefined\n}\n\nexport interface ZellijRunOptions {\n timeoutMs?: number | undefined\n}\n\ninterface ZellijResult {\n stdout: string\n stderr: string\n}\n\nexport function zellijCommandArgs(actionArgs: string[]): string[] {\n const sessionName = process.env.ZELLIJ_SESSION_NAME?.trim()\n if (sessionName)\n return ['--session', sessionName, ...actionArgs]\n return actionArgs\n}\n\nexport function zellijActionArgs(action: string, args: string[] = []): string[] {\n return ['action', action, ...args]\n}\n\nexport function buildNewPaneActionArgs(options: NewPaneOptions): string[] {\n const args = ['action', 'new-pane']\n if (process.env.ZELLIJ)\n args.push('--near-current-pane')\n\n if (options.title)\n args.push('--name', options.title)\n if (options.cwd)\n args.push('--cwd', options.cwd)\n if (options.floating)\n args.push('--floating')\n\n args.push('--', ...buildCommandArgv(options, { exitCodeToken: options.exitCodeToken }))\n return args\n}\n\nexport function buildRenameTabActionArgs(title: string, options: { tabId?: number } = {}): string[] {\n if (options.tabId !== undefined)\n return ['action', 'rename-tab', '--tab-id', String(options.tabId), title]\n return ['action', 'rename-tab', title]\n}\n\nfunction numericProperty(object: Record<string, unknown>, keys: string[]): number | undefined {\n for (const key of keys) {\n const value = object[key]\n if (typeof value === 'number' && Number.isFinite(value))\n return value\n if (typeof value === 'string') {\n const parsed = Number(value)\n if (Number.isInteger(parsed))\n return parsed\n }\n }\n return undefined\n}\n\nfunction paneMatches(object: Record<string, unknown>, paneId: number): boolean {\n const candidate = numericProperty(object, ['id', 'pane_id', 'paneId'])\n return candidate === paneId && object.is_plugin !== true\n}\n\nfunction findPaneTabId(value: unknown, paneId: number): number | undefined {\n if (Array.isArray(value)) {\n for (const item of value) {\n const found = findPaneTabId(item, paneId)\n if (found !== undefined)\n return found\n }\n return undefined\n }\n\n if (typeof value !== 'object' || value === null)\n return undefined\n\n const object = value as Record<string, unknown>\n if (paneMatches(object, paneId))\n return numericProperty(object, ['tab_id', 'tabId'])\n\n for (const nested of Object.values(object)) {\n const found = findPaneTabId(nested, paneId)\n if (found !== undefined)\n return found\n }\n return undefined\n}\n\nexport function parseCurrentPaneTabId(listPanesJson: string, paneId: string | undefined): number | undefined {\n if (!paneId)\n return undefined\n const parsedPaneId = Number(paneId)\n if (!Number.isInteger(parsedPaneId))\n return undefined\n\n try {\n return findPaneTabId(JSON.parse(listPanesJson), parsedPaneId)\n }\n catch {\n return undefined\n }\n}\n\nexport function ensureZellijTarget(): void {\n if (process.env.ZELLIJ || process.env.ZELLIJ_SESSION_NAME)\n return\n throw new Error('Zellij context not found. Run OpenCode inside Zellij or set ZELLIJ_SESSION_NAME to an existing session.')\n}\n\nasync function runZellij(actionArgs: string[], options: ZellijRunOptions = {}): Promise<ZellijResult> {\n ensureZellijTarget()\n try {\n const result = await execFileAsync('zellij', zellijCommandArgs(actionArgs), {\n encoding: 'utf8',\n timeout: options.timeoutMs ?? 10_000,\n maxBuffer: 20 * 1024 * 1024,\n })\n\n return {\n stdout: result.stdout ?? '',\n stderr: result.stderr ?? '',\n }\n }\n catch (cause) {\n const error = cause as { message?: string, stdout?: string, stderr?: string }\n const stderr = error.stderr?.trim()\n const stdout = error.stdout?.trim()\n const detail = stderr || stdout || error.message || 'unknown error'\n throw new Error(`zellij ${actionArgs.join(' ')} failed: ${detail}`)\n }\n}\n\nexport class ZellijCli {\n async newPane(options: NewPaneOptions): Promise<string> {\n const result = await runZellij(buildNewPaneActionArgs(options))\n return parsePaneId(result.stdout)\n }\n\n async writeChars(paneId: string, data: string): Promise<void> {\n await runZellij(zellijActionArgs('write-chars', ['--pane-id', paneId, data]))\n }\n\n async sendCtrlC(paneId: string): Promise<void> {\n await runZellij(zellijActionArgs('send-keys', ['--pane-id', paneId, 'Ctrl c']))\n }\n\n async closePane(paneId: string): Promise<void> {\n await runZellij(zellijActionArgs('close-pane', ['--pane-id', paneId]))\n }\n\n closePaneSync(paneId: string): void {\n ensureZellijTarget()\n spawnSync('zellij', zellijCommandArgs(zellijActionArgs('close-pane', ['--pane-id', paneId])), {\n encoding: 'utf8',\n stdio: 'ignore',\n timeout: 2_000,\n })\n }\n\n async focusPane(paneId: string): Promise<void> {\n await runZellij(zellijActionArgs('focus-pane-id', [paneId]))\n }\n\n async dumpScreen(paneId: string): Promise<string> {\n const result = await runZellij(zellijActionArgs('dump-screen', ['--pane-id', paneId, '--full']), { timeoutMs: 10_000 })\n return result.stdout\n }\n\n async currentPaneTabId(): Promise<number | undefined> {\n const paneId = process.env.ZELLIJ_PANE_ID\n if (!paneId)\n return undefined\n\n const result = await runZellij(zellijActionArgs('list-panes', ['--json']), { timeoutMs: 5_000 })\n return parseCurrentPaneTabId(result.stdout, paneId)\n }\n\n async renameTab(title: string): Promise<void> {\n const tabId = await this.currentPaneTabId()\n if (tabId === undefined && process.env.ZELLIJ)\n throw new Error(`Could not resolve Zellij tab id for pane ${process.env.ZELLIJ_PANE_ID ?? '<missing>'}`)\n await runZellij(tabId === undefined ? buildRenameTabActionArgs(title) : buildRenameTabActionArgs(title, { tabId }))\n }\n}\n\nexport const zellijCli = new ZellijCli()\n","import type { PtySession } from '../pty/session.js'\nimport { spawn } from 'node:child_process'\nimport { randomUUID } from 'node:crypto'\nimport { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { fileURLToPath } from 'node:url'\n\nexport interface WatchdogPane {\n sessionId: string\n paneId: string\n title: string\n openCodeSessionId: string | null\n createdAt: string\n}\n\nexport interface WatchdogRegistry {\n version: 1\n instanceId: string\n ownerPid: number\n ownerStartTime: string | null\n zellijSessionName: string | null\n panes: WatchdogPane[]\n}\n\nconst instanceId = randomUUID()\nlet watchdogStarted = false\nlet watchdogChild: ReturnType<typeof spawn> | null = null\n\nfunction registryDirectory(): string {\n const base = process.env.XDG_RUNTIME_DIR || tmpdir()\n return path.join(base, `opencode-zellij-${process.getuid?.() ?? 'user'}`)\n}\n\nexport function watchdogRegistryPath(): string {\n return path.join(registryDirectory(), `panes-${process.pid}-${instanceId}.json`)\n}\n\nexport function parseLinuxProcessStartTime(stat: string): string | null {\n const fieldsAfterCommand = stat.slice(stat.lastIndexOf(')') + 2).trim().split(/\\s+/)\n return fieldsAfterCommand[19] ?? null\n}\n\nfunction linuxProcessStartTime(pid: number): string | null {\n try {\n return parseLinuxProcessStartTime(readFileSync(`/proc/${pid}/stat`, 'utf8'))\n }\n catch {\n // Missing /proc data is expected when the owner has exited or on non-Linux systems.\n return null\n }\n}\n\nfunction emptyRegistry(): WatchdogRegistry {\n return {\n version: 1,\n instanceId,\n ownerPid: process.pid,\n ownerStartTime: linuxProcessStartTime(process.pid),\n zellijSessionName: process.env.ZELLIJ_SESSION_NAME?.trim() || null,\n panes: [],\n }\n}\n\nfunction readRegistry(): WatchdogRegistry {\n const file = watchdogRegistryPath()\n if (!existsSync(file))\n return emptyRegistry()\n\n try {\n const parsed = JSON.parse(readFileSync(file, 'utf8')) as WatchdogRegistry\n if (parsed.version !== 1 || parsed.instanceId !== instanceId || parsed.ownerPid !== process.pid || !Array.isArray(parsed.panes))\n return emptyRegistry()\n return parsed\n }\n catch {\n // The current instance registry is corrupt or unreadable; start from an empty registry.\n return emptyRegistry()\n }\n}\n\nfunction writeRegistry(registry: WatchdogRegistry): void {\n const directory = registryDirectory()\n mkdirSync(directory, { recursive: true, mode: 0o700 })\n const file = watchdogRegistryPath()\n const tempFile = `${file}.tmp-${process.pid}`\n writeFileSync(tempFile, JSON.stringify(registry, null, 2), { mode: 0o600 })\n renameSync(tempFile, file)\n}\n\nfunction ensureWatchdog(): void {\n if (watchdogStarted && watchdogChild)\n return\n watchdogStarted = true\n\n const child = spawn(process.execPath, [watchdogRunnerPath(), watchdogRegistryPath()], {\n detached: true,\n stdio: 'ignore',\n env: process.env,\n })\n watchdogChild = child\n child.unref()\n child.on('error', () => {\n // Child failed early or was killed; allow watchdog to be restarted on next pane registration.\n watchdogStarted = false\n if (watchdogChild === child)\n watchdogChild = null\n })\n child.on('exit', () => {\n watchdogStarted = false\n if (watchdogChild === child)\n watchdogChild = null\n if (existsSync(watchdogRegistryPath()))\n ensureWatchdog()\n })\n}\n\nfunction watchdogRunnerPath(): string {\n return fileURLToPath(new URL('./pane-watchdog-runner.mjs', import.meta.url))\n}\n\nexport function cleanupStaleWatchdogRegistries(): void {\n const directory = registryDirectory()\n if (!existsSync(directory))\n return\n\n for (const fileName of readdirSync(directory)) {\n if (!fileName.startsWith('panes-') || !fileName.endsWith('.json'))\n continue\n\n const file = path.join(directory, fileName)\n try {\n const registry = JSON.parse(readFileSync(file, 'utf8')) as WatchdogRegistry\n if (registry.version !== 1 || ownerStillMatches(registry))\n continue\n closeRegistryPanes(registry)\n rmSync(file, { force: true })\n }\n catch {\n // Corrupt stale registries cannot be used safely and would otherwise fail every startup.\n rmSync(file, { force: true })\n }\n }\n}\n\nfunction ownerStillMatches(registry: WatchdogRegistry): boolean {\n try {\n process.kill(registry.ownerPid, 0)\n }\n catch {\n // process.kill(pid, 0) throws when the owner is gone or inaccessible.\n return false\n }\n\n return !registry.ownerStartTime || linuxProcessStartTime(registry.ownerPid) === registry.ownerStartTime\n}\n\nfunction closeRegistryPanes(registry: WatchdogRegistry): void {\n for (const pane of registry.panes) {\n const args = []\n if (registry.zellijSessionName)\n args.push('--session', registry.zellijSessionName)\n args.push('action', 'close-pane', '--pane-id', pane.paneId)\n spawn('zellij', args, { detached: true, stdio: 'ignore', env: process.env }).unref()\n }\n}\n\nexport function upsertWatchdogPane(registry: WatchdogRegistry, session: PtySession): WatchdogRegistry {\n return {\n ...registry,\n panes: [\n ...registry.panes.filter(pane => pane.sessionId !== session.id && pane.paneId !== session.paneId),\n {\n sessionId: session.id,\n paneId: session.paneId,\n title: session.title,\n openCodeSessionId: session.openCodeSessionId,\n createdAt: session.createdAt,\n },\n ],\n }\n}\n\nexport function removeWatchdogPane(registry: WatchdogRegistry, sessionId: string): WatchdogRegistry {\n return {\n ...registry,\n panes: registry.panes.filter(pane => pane.sessionId !== sessionId),\n }\n}\n\nexport function registerPaneForWatchdog(session: PtySession): void {\n writeRegistry(upsertWatchdogPane(readRegistry(), session))\n ensureWatchdog()\n}\n\nexport function unregisterPaneFromWatchdog(sessionId: string): void {\n const registry = readRegistry()\n const updated = removeWatchdogPane(registry, sessionId)\n if (updated.panes.length === registry.panes.length)\n return\n if (updated.panes.length === 0) {\n removeWatchdogRegistry()\n return\n }\n writeRegistry(updated)\n}\n\nexport function removeWatchdogRegistry(): void {\n try {\n rmSync(watchdogRegistryPath(), { force: true })\n }\n catch {\n // Watchdog registry cleanup is best effort.\n }\n if (!watchdogChild)\n watchdogStarted = false\n}\n","export interface ReadLinesInput {\n offset?: number | undefined\n limit?: number | undefined\n grep?: string | undefined\n ignoreCase?: boolean | undefined\n}\n\nexport interface ReadLinesResult {\n offset: number\n returned: number\n lineCount: number\n lines: string[]\n}\n\nconst escapeCharacter = String.fromCharCode(27)\nconst ansiPattern = new RegExp(`${escapeCharacter}\\\\[[0-9;?]*[a-z]`, 'gi')\n\nfunction normalizeLines(input: string | string[]): string[] {\n const lines = Array.isArray(input) ? input : input.replace(/\\r\\n/g, '\\n').split('\\n')\n if (lines.at(-1) === '')\n return lines.slice(0, -1)\n return lines\n}\n\nfunction stripAnsi(line: string): string {\n return line.replace(ansiPattern, '')\n}\n\nfunction overlapSize(existing: string[], incoming: string[]): number {\n const max = Math.min(existing.length, incoming.length)\n for (let size = max; size > 0; size -= 1) {\n const existingStart = existing.length - size\n let matches = true\n for (let index = 0; index < size; index += 1) {\n if (existing[existingStart + index] !== incoming[index]) {\n matches = false\n break\n }\n }\n if (matches)\n return size\n }\n return 0\n}\n\nexport class RingBuffer {\n private readonly maxLines: number\n private lines: string[] = []\n private totalAppended = 0\n\n constructor(maxLines = 50_000) {\n this.maxLines = Math.max(1, maxLines)\n }\n\n get lineCount(): number {\n return this.totalAppended\n }\n\n get startOffset(): number {\n return Math.max(0, this.totalAppended - this.lines.length)\n }\n\n append(input: string | string[]): number {\n const incoming = normalizeLines(input)\n if (incoming.length === 0)\n return 0\n this.lines.push(...incoming)\n this.totalAppended += incoming.length\n this.trim()\n return incoming.length\n }\n\n appendSnapshot(input: string | string[]): number {\n const incoming = normalizeLines(input)\n if (incoming.length === 0)\n return 0\n const overlap = overlapSize(this.lines, incoming)\n return this.append(incoming.slice(overlap))\n }\n\n read(input: ReadLinesInput = {}): ReadLinesResult {\n const limit = Math.max(1, Math.min(input.limit ?? 200, 5_000))\n const firstReadableOffset = this.startOffset\n const defaultOffset = Math.max(firstReadableOffset, this.lineCount - limit)\n const requestedOffset = input.offset ?? defaultOffset\n const offset = Math.max(firstReadableOffset, Math.min(requestedOffset, this.lineCount))\n const relativeOffset = offset - firstReadableOffset\n const unfiltered = this.lines.slice(relativeOffset, relativeOffset + limit)\n const pattern = input.grep ? new RegExp(input.grep, input.ignoreCase ? 'i' : '') : undefined\n const lines = unfiltered\n .map(stripAnsi)\n .filter(line => (pattern ? pattern.test(line) : true))\n\n return {\n offset,\n returned: lines.length,\n lineCount: this.lineCount,\n lines,\n }\n }\n\n clear(): void {\n this.lines = []\n this.totalAppended = 0\n }\n\n private trim(): void {\n if (this.lines.length <= this.maxLines)\n return\n this.lines = this.lines.slice(this.lines.length - this.maxLines)\n }\n}\n","import { randomUUID } from 'node:crypto'\n\nexport interface ExitCodeMarker {\n token: string\n exitCode: number\n}\n\nconst markerPattern = /^\\[zellij-pty:([a-f0-9]+)\\] exit-code=(\\d+)$/\nconst escapeCharacter = String.fromCharCode(27)\nconst ansiPattern = new RegExp(`${escapeCharacter}\\\\[[0-9;?]*[a-z]`, 'gi')\n\nexport function createExitCodeToken(): string {\n return randomUUID().replaceAll('-', '')\n}\n\nexport function parseExitCodeMarker(line: string): ExitCodeMarker | null {\n const match = line.replace(ansiPattern, '').trim().match(markerPattern)\n if (!match?.[1] || !match[2])\n return null\n return {\n token: match[1],\n exitCode: Number(match[2]),\n }\n}\n","import type { ChildProcessWithoutNullStreams } from 'node:child_process'\nimport type { SessionManager } from '../pty/manager.js'\nimport type { ReadLinesInput, ReadLinesResult } from '../pty/ring-buffer.js'\nimport type { PtySession } from '../pty/session.js'\nimport { spawn } from 'node:child_process'\nimport process from 'node:process'\nimport { sessionManager } from '../pty/manager.js'\nimport { RingBuffer } from '../pty/ring-buffer.js'\nimport { parseExitCodeMarker } from '../utils/exit-code.js'\nimport { ensureZellijTarget, zellijCli, zellijCommandArgs } from './cli.js'\nimport { unregisterPaneFromWatchdog } from './pane-watchdog.js'\n\ninterface SubscriberState {\n child: ChildProcessWithoutNullStreams | null\n buffer: RingBuffer\n stderr: string[]\n stdoutRemainder: string\n startedAt: string\n lastExitedAt: string | null\n}\n\ntype JsonObject = Record<string, unknown>\n\nexport interface SubscriberStatus {\n hasBuffer: boolean\n active: boolean\n lastExitedAt: string | null\n}\n\nconst maxStderrLines = 200\n\nfunction splitLines(input: string): string[] {\n const lines = input.replace(/\\r\\n/g, '\\n').split('\\n')\n if (lines.at(-1) === '')\n return lines.slice(0, -1)\n return lines\n}\n\nfunction textFromCell(cell: unknown): string {\n if (typeof cell === 'string')\n return cell\n if (!cell || typeof cell !== 'object')\n return ''\n const object = cell as JsonObject\n const value = object.text ?? object.character ?? object.ch ?? object.content\n return typeof value === 'string' ? value : ''\n}\n\nfunction linesFromRows(rows: unknown[]): string[] {\n return rows.map((row) => {\n if (typeof row === 'string')\n return row\n if (Array.isArray(row))\n return row.map(textFromCell).join('')\n return textFromCell(row)\n })\n}\n\nfunction eventPaneId(event: JsonObject): string | undefined {\n const paneId = event.pane_id ?? event.paneId\n return typeof paneId === 'string' ? paneId : undefined\n}\n\nfunction eventType(event: JsonObject): string | undefined {\n const type = event.event ?? event.type\n return typeof type === 'string' ? type : undefined\n}\n\nfunction extractRenderedLines(event: JsonObject): string[] {\n for (const key of ['viewport', 'scrollback', 'lines'] as const) {\n const value = event[key]\n if (Array.isArray(value))\n return linesFromRows(value)\n }\n\n for (const key of ['text', 'output', 'content'] as const) {\n const value = event[key]\n if (typeof value === 'string')\n return splitLines(value)\n }\n\n return []\n}\n\nexport class SubscriberManager {\n private readonly subscribers = new Map<string, SubscriberState>()\n // Per-session start promises to prevent concurrent spawn races\n private readonly startingSessions = new Map<string, Promise<void>>()\n\n constructor(\n private readonly sessions: SessionManager,\n private readonly maxBufferLines = Number(process.env.PTY_MAX_BUFFER_LINES ?? 50_000),\n ) {}\n\n async start(session: PtySession): Promise<void> {\n const existing = this.subscribers.get(session.id)\n if (existing?.child)\n return\n\n // Prevent concurrent start races for the same session\n const inProgress = this.startingSessions.get(session.id)\n if (inProgress)\n return inProgress\n\n ensureZellijTarget()\n\n const startPromise = this.doStart(session)\n this.startingSessions.set(session.id, startPromise)\n try {\n await startPromise\n }\n finally {\n this.startingSessions.delete(session.id)\n }\n }\n\n private async doStart(session: PtySession): Promise<void> {\n const existing = this.subscribers.get(session.id)\n\n const state: SubscriberState\n = existing\n ?? {\n child: null,\n buffer: new RingBuffer(this.maxBufferLines),\n stderr: [],\n stdoutRemainder: '',\n startedAt: new Date().toISOString(),\n lastExitedAt: null,\n }\n\n if (!existing) {\n this.subscribers.set(session.id, state)\n try {\n state.buffer.appendSnapshot(await zellijCli.dumpScreen(session.paneId))\n this.sessions.updateLineCount(session.id, state.buffer.lineCount)\n }\n catch {\n // dump-screen may race with pane creation; subscribe will still collect future output.\n }\n if (this.subscribers.get(session.id) !== state)\n return\n }\n\n const child = spawn('zellij', zellijCommandArgs(['subscribe', '--pane-id', session.paneId, '--scrollback', '--format', 'json', '--ansi']), {\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n child.stdin.end()\n // Only assign child if state is still the same (no concurrent restart)\n const currentState = this.subscribers.get(session.id)\n if (currentState !== state) {\n child.kill('SIGTERM')\n return\n }\n state.child = child\n state.lastExitedAt = null\n\n child.stdout.setEncoding('utf8')\n child.stdout.on('data', (chunk: string) => this.handleStdout(session.id, child, chunk))\n child.stderr.setEncoding('utf8')\n child.stderr.on('data', (chunk: string) => this.handleStderr(session.id, child, chunk))\n child.on('exit', () => this.handleSubscriberExit(session.id, child))\n child.on('error', error => this.handleSubscriberError(session.id, child, error))\n }\n\n read(sessionId: string, input: ReadLinesInput): ReadLinesResult {\n const state = this.subscribers.get(sessionId)\n if (!state)\n throw new Error(`No subscriber buffer exists for session: ${sessionId}`)\n return state.buffer.read(input)\n }\n\n has(sessionId: string): boolean {\n return this.subscribers.has(sessionId)\n }\n\n status(sessionId: string): SubscriberStatus {\n const state = this.subscribers.get(sessionId)\n return {\n hasBuffer: Boolean(state),\n active: Boolean(state?.child),\n lastExitedAt: state?.lastExitedAt ?? null,\n }\n }\n\n stderr(sessionId: string): string[] {\n return this.subscribers.get(sessionId)?.stderr ?? []\n }\n\n stop(sessionId: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state)\n return\n state.child?.kill('SIGTERM')\n state.child = null\n state.lastExitedAt = new Date().toISOString()\n }\n\n forget(sessionId: string): void {\n this.stop(sessionId)\n this.subscribers.delete(sessionId)\n }\n\n stopAll(): void {\n for (const sessionId of this.subscribers.keys()) {\n this.forget(sessionId)\n }\n }\n\n async closeSessionPane(sessionId: string): Promise<void> {\n const session = this.sessions.get(sessionId)\n this.stop(sessionId)\n try {\n await zellijCli.closePane(session.paneId)\n }\n catch {\n // Pane may already be closed by the user or command exit.\n }\n }\n\n private handleStdout(sessionId: string, child: ChildProcessWithoutNullStreams, chunk: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state || state.child !== child)\n return\n\n const parts = `${state.stdoutRemainder}${chunk}`.split('\\n')\n state.stdoutRemainder = parts.pop() ?? ''\n for (const part of parts) {\n this.handleJsonLine(sessionId, child, part)\n }\n }\n\n private handleJsonLine(sessionId: string, child: ChildProcessWithoutNullStreams, line: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state || state.child !== child)\n return\n const trimmed = line.trim()\n if (!trimmed)\n return\n\n let event: JsonObject\n try {\n const parsed: unknown = JSON.parse(trimmed)\n if (!parsed || typeof parsed !== 'object')\n return\n event = parsed as JsonObject\n }\n catch {\n state.buffer.append(trimmed)\n this.sessions.updateLineCount(sessionId, state.buffer.lineCount)\n return\n }\n\n let session: PtySession\n try {\n session = this.sessions.get(sessionId)\n }\n catch {\n this.forget(sessionId)\n return\n }\n const paneId = eventPaneId(event)\n if (paneId && paneId !== session.paneId)\n return\n\n const type = eventType(event)\n if (type === 'pane_closed' || type === 'PaneClosed') {\n state.buffer.append(`[zellij-pty] Pane ${session.paneId} closed at ${new Date().toISOString()}`)\n this.sessions.updateLineCount(sessionId, state.buffer.lineCount)\n this.sessions.updateStatus(sessionId, session.status === 'killed' ? 'killed' : 'exited')\n unregisterPaneFromWatchdog(sessionId)\n this.stop(sessionId)\n return\n }\n\n const lines = extractRenderedLines(event)\n if (lines.length === 0)\n return\n state.buffer.appendSnapshot(lines)\n this.captureExitCode(sessionId, lines)\n this.sessions.updateLineCount(sessionId, state.buffer.lineCount)\n }\n\n private captureExitCode(sessionId: string, lines: string[]): void {\n const session = this.sessions.get(sessionId)\n if (!session.exitCodeToken)\n return\n\n for (const line of lines) {\n const marker = parseExitCodeMarker(line)\n if (!marker || marker.token !== session.exitCodeToken)\n continue\n this.sessions.markExited(sessionId, marker.exitCode)\n return\n }\n }\n\n private handleStderr(sessionId: string, child: ChildProcessWithoutNullStreams, chunk: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state || state.child !== child)\n return\n state.stderr.push(...splitLines(chunk))\n if (state.stderr.length > maxStderrLines) {\n state.stderr = state.stderr.slice(state.stderr.length - maxStderrLines)\n }\n }\n\n private handleSubscriberExit(sessionId: string, child: ChildProcessWithoutNullStreams): void {\n const state = this.subscribers.get(sessionId)\n if (!state)\n return\n if (state.child !== child)\n return\n state.child = null\n state.lastExitedAt = new Date().toISOString()\n state.stderr.push(`[zellij-pty] subscriber exited at ${state.lastExitedAt}; last buffered output is retained.`)\n if (state.stderr.length > maxStderrLines) {\n state.stderr = state.stderr.slice(state.stderr.length - maxStderrLines)\n }\n }\n\n private handleSubscriberError(sessionId: string, child: ChildProcessWithoutNullStreams, error: Error): void {\n const state = this.subscribers.get(sessionId)\n if (state?.child === child) {\n state.stderr.push(error.message)\n state.child = null\n state.lastExitedAt = new Date().toISOString()\n this.sessions.updateStatus(sessionId, 'unknown')\n }\n }\n}\n\nexport const subscriberManager = new SubscriberManager(sessionManager)\n","import type { PtySession } from '../pty/session.js'\n\nexport function publicSession(session: PtySession): Record<string, unknown> {\n return {\n id: session.id,\n paneId: session.paneId,\n title: session.title,\n command: session.command,\n args: session.args,\n cwd: session.cwd,\n status: session.status,\n lineCount: session.lineCount,\n createdAt: session.createdAt,\n updatedAt: session.updatedAt,\n agentWritable: session.allowAgentInput,\n humanInputOnly: session.humanInputOnly,\n exitCode: session.exitCode,\n exitedAt: session.exitedAt,\n }\n}\n\nexport interface NextAdvice {\n retryable: boolean\n reason: string\n}\n\nexport function nextAdvice(retryable: boolean, reason: string): NextAdvice {\n return { retryable, reason }\n}\n\nexport function jsonResponse(value: unknown): string {\n return JSON.stringify(value, null, 2)\n}\n","export function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n","import { sessionManager } from '../pty/manager.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\n\nexport interface OutputSnapshot {\n text: string\n lines: string[]\n lineCount: number\n returned: number\n truncated: boolean\n}\n\nexport function emptyOutputSnapshot(lineCount = 0): OutputSnapshot {\n return { text: '', lines: [], lineCount, returned: 0, truncated: false }\n}\n\nexport interface OutputOptions {\n maxLines?: number | undefined\n grep?: string | undefined\n ignoreCase?: boolean | undefined\n}\n\nexport function validateGrep(grep: string | undefined): string | null {\n if (!grep)\n return null\n try {\n new RegExp(grep).test('')\n return null\n }\n catch (error) {\n return errorMessage(error)\n }\n}\n\nexport function readOutputSnapshot(sessionId: string, options: OutputOptions = {}): OutputSnapshot {\n const grepError = validateGrep(options.grep)\n if (grepError)\n throw new Error(`Invalid grep regex: ${grepError}`)\n\n const buffered = subscriberManager.read(sessionId, {\n limit: options.maxLines,\n grep: options.grep,\n ignoreCase: options.ignoreCase,\n })\n sessionManager.updateLineCount(sessionId, buffered.lineCount)\n\n return {\n text: buffered.lines.join('\\n'),\n lines: buffered.lines,\n lineCount: buffered.lineCount,\n returned: buffered.returned,\n truncated: buffered.offset > 0,\n }\n}\n\nexport function outputMatches(sessionId: string, grep: string, ignoreCase?: boolean | undefined): boolean {\n return readOutputSnapshot(sessionId, { maxLines: 5_000, grep, ignoreCase }).returned > 0\n}\n","import { setTimeout as delay } from 'node:timers/promises'\nimport { tool } from '@opencode-ai/plugin'\nimport { sessionManager } from '../pty/manager.js'\nimport { zellijCli } from '../zellij/cli.js'\nimport { unregisterPaneFromWatchdog } from '../zellij/pane-watchdog.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { readOutputSnapshot } from './output.js'\n\nconst schema = tool.schema\n\nexport function closeFailureMeansGone(message: string): boolean {\n return /not found|no such|does not exist|already closed|already gone|unknown pane/i.test(message)\n}\n\nexport const zellijPtyKillTool = tool({\n description: 'Terminate a known Zellij PTY session by sending Ctrl-C, then closing its pane.',\n args: {\n id: schema.string().describe('zellij-pty session id.'),\n },\n async execute(args) {\n const session = sessionManager.get(args.id)\n const warnings: string[] = []\n const output = subscriberManager.has(session.id) ? readOutputSnapshot(session.id) : undefined\n try {\n await zellijCli.sendCtrlC(session.paneId)\n await delay(500)\n }\n catch (error) {\n warnings.push(`Ctrl-C failed or pane was already gone: ${error instanceof Error ? error.message : String(error)}`)\n }\n\n try {\n await zellijCli.closePane(session.paneId)\n }\n catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n warnings.push(`close-pane failed: ${message}`)\n if (!closeFailureMeansGone(message)) {\n const updated = sessionManager.updateStatus(session.id, 'unknown')\n return jsonResponse({\n killed: false,\n cleanedUp: false,\n session: publicSession(updated),\n output,\n next: nextAdvice(true, 'close-pane failed and the pane may still be running; the session was kept so kill can be retried.'),\n warnings,\n })\n }\n }\n subscriberManager.stop(session.id)\n subscriberManager.forget(session.id)\n unregisterPaneFromWatchdog(session.id)\n sessionManager.remove(session.id)\n return jsonResponse({ killed: true, cleanedUp: true, id: session.id, paneId: session.paneId, output, next: nextAdvice(false, 'Session was closed and removed from the in-memory registry.'), warnings })\n },\n})\n","import { tool } from '@opencode-ai/plugin'\nimport { sessionManager } from '../pty/manager.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, publicSession } from './format.js'\n\nexport const zellijPtyListTool = tool({\n description: 'List known Zellij pane-backed PTY sessions created by this plugin process for the current OpenCode session.',\n args: {},\n async execute(_args, context) {\n const sessions = sessionManager.listByOpenCodeSession(context.sessionID).map(session => ({\n ...publicSession(session),\n subscriber: subscriberManager.status(session.id),\n }))\n return jsonResponse({ sessions })\n },\n})\n","import { tool } from '@opencode-ai/plugin'\nimport { sessionManager } from '../pty/manager.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { readOutputSnapshot, validateGrep } from './output.js'\n\nconst schema = tool.schema\n\nexport const zellijPtyReadTool = tool({\n description: 'Read recent rendered output from a Zellij PTY session. Supports regex grep filtering.',\n args: {\n id: schema.string().describe('zellij-pty session id.'),\n maxLines: schema.number().int().positive().max(5_000).optional().describe('Maximum recent output lines to return. Defaults to 200.'),\n grep: schema.string().optional().describe('Regex used to filter returned lines.'),\n ignoreCase: schema.boolean().optional().describe('Use case-insensitive regex matching.'),\n },\n async execute(args) {\n const session = sessionManager.get(args.id)\n const grepError = validateGrep(args.grep)\n if (grepError) {\n return jsonResponse({\n session: publicSession(session),\n output: { text: '', lines: [], lineCount: session.lineCount, returned: 0, truncated: false },\n next: nextAdvice(false, `Invalid grep regex: ${grepError}`),\n warnings: [],\n })\n }\n\n const subscriberStatus = subscriberManager.status(session.id)\n if (!subscriberStatus.hasBuffer || (!subscriberStatus.active && (session.status === 'running' || session.status === 'unknown'))) {\n await subscriberManager.start(session)\n }\n const statusAfterStart = subscriberManager.status(session.id)\n const warnings: string[] = []\n if (session.humanInputOnly) {\n warnings.push('This pane is human-input-only: agent writes are forbidden, but rendered output is visible to the agent.')\n }\n if (!statusAfterStart.active) {\n warnings.push('Subscriber is inactive; returned output may be stale.')\n if (session.status === 'running') {\n sessionManager.updateStatus(session.id, 'unknown')\n }\n }\n\n const output = readOutputSnapshot(session.id, { maxLines: args.maxLines, grep: args.grep, ignoreCase: args.ignoreCase })\n\n return jsonResponse({\n session: publicSession(session),\n output,\n next: nextAdvice(session.status !== 'exited' && session.status !== 'killed', nextReadReason(session.status)),\n subscriberActive: statusAfterStart.active,\n subscriberLastExitedAt: statusAfterStart.lastExitedAt,\n subscriberErrors: subscriberManager.stderr(session.id),\n warnings,\n })\n },\n})\n\nfunction nextReadReason(status: string): string {\n if (status === 'running')\n return 'Session is still running; read again later if more output is expected.'\n if (status === 'unknown')\n return 'Session state is unknown because the subscriber is inactive; output may be stale, but retrying read may restart observation.'\n return 'Session is no longer running.'\n}\n","import { randomUUID } from 'node:crypto'\n\nconst generatedInstanceId = randomUUID().replaceAll('-', '').slice(0, 8)\nconst existingOpenCodePrefixPattern = /^oc:[a-z0-9]{4,16}:/i\n\nexport function createOpenCodePaneTitle(title: string, instanceId = generatedInstanceId): string {\n const trimmedTitle = title.trim() || 'opencode'\n if (existingOpenCodePrefixPattern.test(trimmedTitle))\n return trimmedTitle\n\n const safeInstanceId = instanceId.replace(/[^a-z0-9]/gi, '').slice(0, 8) || generatedInstanceId\n return `oc:${safeInstanceId}:${trimmedTitle}`\n}\n","import { tool } from '@opencode-ai/plugin'\nimport { assertSudoPaneAllowed } from '../permissions/sudo-pane.js'\nimport { sessionManager } from '../pty/manager.js'\nimport { createExitCodeToken } from '../utils/exit-code.js'\nimport { createOpenCodePaneTitle } from '../utils/pane-title.js'\nimport { zellijCli } from '../zellij/cli.js'\nimport { registerPaneForWatchdog } from '../zellij/pane-watchdog.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { readOutputSnapshot } from './output.js'\n\nconst schema = tool.schema\n\nexport function shellQuote(value: string): string {\n return `'${value.replaceAll('\\'', `'\"'\"'`)}'`\n}\n\nexport function buildReviewScript(summary: string, scripts: Array<{ command: string, description: string }>): string {\n const lines = [\n 'set +e',\n 'printf \\'%s\\\\n\\' \\'=== OpenCode sudo request ===\\'',\n `printf '%s\\\\n' ${shellQuote(summary)}`,\n 'printf \\'\\\\n%s\\\\n\\' \\'Commands to review:\\'',\n ]\n\n scripts.forEach((script, index) => {\n const number = index + 1\n lines.push(`printf '\\\\n[%s/%s] %s\\\\n' ${shellQuote(String(number))} ${shellQuote(String(scripts.length))} ${shellQuote(script.description)}`)\n lines.push(`printf ' $ %s\\\\n' ${shellQuote(script.command)}`)\n })\n\n lines.push(\n 'printf \\'\\\\n%s\\\\n\\' \\'This pane is human-input-only. The agent cannot type here.\\'',\n 'read -r -p \\'Type YES to run these commands, anything else to cancel: \\' answer',\n 'if [ \"$answer\" != YES ]; then printf \\'%s\\\\n\\' \\'Cancelled by user.\\'; exit 130; fi',\n 'status=0',\n )\n\n scripts.forEach((script, index) => {\n const number = index + 1\n lines.push(`printf '\\\\n[%s/%s] %s\\\\n' ${shellQuote(String(number))} ${shellQuote(String(scripts.length))} ${shellQuote(script.description)}`)\n lines.push(`printf '$ %s\\\\n' ${shellQuote(script.command)}`)\n lines.push(`bash -lc ${shellQuote(script.command)}`)\n lines.push('code=$?')\n lines.push('if [ $code -ne 0 ]; then status=$code; printf \\'Command failed with exit code %s\\\\n\\' \"$code\"; break; fi')\n })\n\n lines.push('exit $status')\n return lines.join('\\n')\n}\n\nexport const requestSudoTool = tool({\n description: 'Open a human-reviewed, human-input-only Zellij pane for sudo or other privileged commands.',\n args: {\n summary: schema.string().min(1).describe('TL;DR of why privileged or human-reviewed execution is needed.'),\n scripts: schema\n .array(\n schema.object({\n command: schema.string().min(1).describe('Command or script to run after the user explicitly approves in the pane.'),\n description: schema.string().min(1).describe('Why this command is needed and what it is expected to change.'),\n }),\n )\n .min(1)\n .describe('Commands shown to the user for review before execution.'),\n },\n async execute(args, context) {\n const cwd = context.directory\n const exitCodeToken = createExitCodeToken()\n assertSudoPaneAllowed()\n\n const command = buildReviewScript(args.summary, args.scripts)\n const title = createOpenCodePaneTitle('zellij_pty_request_sudo')\n const paneId = await zellijCli.newPane({\n command: 'bash',\n args: ['-lc', command],\n cwd,\n title,\n floating: true,\n exitCodeToken,\n })\n\n const warnings: string[] = []\n try {\n await zellijCli.focusPane(paneId)\n }\n catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n if (!message.includes('already focused'))\n throw error\n warnings.push('Pane was already focused after creation.')\n }\n\n const session = sessionManager.create({\n openCodeSessionId: context.sessionID,\n paneId,\n title,\n command: 'zellij_pty_request_sudo',\n args: [],\n cwd,\n allowAgentInput: false,\n humanInputOnly: true,\n exitCodeToken,\n })\n registerPaneForWatchdog(session)\n await subscriberManager.start(session)\n\n return jsonResponse({\n session: publicSession(session),\n output: readOutputSnapshot(session.id),\n next: nextAdvice(false, 'The user must review the summary and commands in Zellij, then type YES and any required credentials directly in the pane.'),\n warnings,\n })\n },\n})\n","import { setTimeout as delay } from 'node:timers/promises'\n\nexport type Probe\n = | { type: 'sleep', seconds?: number | undefined }\n | { type: 'http', url: string, expectStatus?: number | undefined, timeoutSeconds?: number | undefined }\n | { type: 'output', grep: string, ignoreCase?: boolean | undefined, timeoutSeconds?: number | undefined }\n\nexport interface ProbeResult {\n type: Probe['type']\n ok: boolean\n message: string\n elapsedMs: number\n}\n\nexport type OutputProbeReader = (grep: string, ignoreCase: boolean | undefined) => boolean\n\nconst defaultSleepSeconds = 1\nconst defaultProbeTimeoutSeconds = 20\nconst pollIntervalMs = 250\n\nexport async function runProbe(probe: Probe | undefined, outputReader: OutputProbeReader): Promise<ProbeResult> {\n const startedAt = Date.now()\n const effectiveProbe = probe ?? { type: 'sleep', seconds: defaultSleepSeconds }\n\n if (effectiveProbe.type === 'sleep') {\n const seconds = effectiveProbe.seconds ?? defaultSleepSeconds\n await delay(seconds * 1_000)\n return result(effectiveProbe.type, true, `Slept for ${seconds}s.`, startedAt)\n }\n\n if (effectiveProbe.type === 'output') {\n const timeoutSeconds = effectiveProbe.timeoutSeconds ?? defaultProbeTimeoutSeconds\n const deadline = Date.now() + timeoutSeconds * 1_000\n while (Date.now() <= deadline) {\n if (outputReader(effectiveProbe.grep, effectiveProbe.ignoreCase)) {\n return result(effectiveProbe.type, true, `Observed output matching /${effectiveProbe.grep}/.`, startedAt)\n }\n await delay(pollIntervalMs)\n }\n return result(effectiveProbe.type, false, `Timed out after ${timeoutSeconds}s waiting for output matching /${effectiveProbe.grep}/.`, startedAt)\n }\n\n const timeoutSeconds = effectiveProbe.timeoutSeconds ?? defaultProbeTimeoutSeconds\n const deadline = Date.now() + timeoutSeconds * 1_000\n const expectStatus = effectiveProbe.expectStatus\n let lastError = 'no response'\n\n while (Date.now() <= deadline) {\n try {\n const remainingMs = Math.max(1, deadline - Date.now())\n const response = await fetch(effectiveProbe.url, { signal: AbortSignal.timeout(Math.min(remainingMs, 3_000)) })\n const ok = expectStatus === undefined ? response.status >= 200 && response.status < 400 : response.status === expectStatus\n if (ok) {\n const expected = expectStatus === undefined ? '2xx/3xx' : String(expectStatus)\n return result(effectiveProbe.type, true, `HTTP probe ${effectiveProbe.url} returned expected status ${expected}.`, startedAt)\n }\n lastError = `HTTP ${response.status}`\n }\n catch (error) {\n lastError = error instanceof Error ? error.message : String(error)\n }\n await delay(pollIntervalMs)\n }\n\n return result(effectiveProbe.type, false, `Timed out after ${timeoutSeconds}s probing ${effectiveProbe.url}: ${lastError}.`, startedAt)\n}\n\nfunction result(type: Probe['type'], ok: boolean, message: string, startedAt: number): ProbeResult {\n return { type, ok, message, elapsedMs: Date.now() - startedAt }\n}\n","import type { Probe } from '../pty/probe.js'\nimport { tool } from '@opencode-ai/plugin'\nimport { sessionManager } from '../pty/manager.js'\nimport { runProbe } from '../pty/probe.js'\nimport { createExitCodeToken } from '../utils/exit-code.js'\nimport { createOpenCodePaneTitle } from '../utils/pane-title.js'\nimport { zellijCli } from '../zellij/cli.js'\nimport { registerPaneForWatchdog } from '../zellij/pane-watchdog.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { outputMatches, readOutputSnapshot, validateGrep } from './output.js'\n\nconst schema = tool.schema\n\nconst probeSchema = schema.discriminatedUnion('type', [\n schema.object({\n type: schema.literal('sleep'),\n seconds: schema.number().positive().max(300).optional().describe('Seconds to wait before returning initial output. Defaults to 1.'),\n }),\n schema.object({\n type: schema.literal('http'),\n url: schema.string().url().describe('HTTP URL to poll until it returns the expected status.'),\n expectStatus: schema.number().int().min(100).max(599).optional().describe('Expected HTTP status. Defaults to any 2xx/3xx response.'),\n timeoutSeconds: schema.number().positive().max(300).optional().describe('How long to poll before returning a failed probe result. Defaults to 20.'),\n }),\n schema.object({\n type: schema.literal('output'),\n grep: schema.string().describe('Regex to search for in observed pane output.'),\n ignoreCase: schema.boolean().optional().describe('Use case-insensitive regex matching.'),\n timeoutSeconds: schema.number().positive().max(300).optional().describe('How long to wait for matching output. Defaults to 20.'),\n }),\n])\n\nexport const zellijPtySpawnTool = tool({\n description: 'Create a visible Zellij pane and run a command in it.',\n args: {\n command: schema.string().describe('Command to run. Without args, it is executed through bash -lc.'),\n args: schema.array(schema.string()).optional().describe('Optional argv. When provided, command is executed directly without shell parsing.'),\n cwd: schema.string().optional().describe('Working directory for the new pane.'),\n title: schema.string().optional().describe('Pane title/name.'),\n probe: probeSchema.optional().describe('Optional readiness probe. Defaults to a short sleep before returning output.'),\n maxLines: schema.number().int().positive().max(5_000).optional().describe('Maximum recent output lines to return. Defaults to 200.'),\n },\n async execute(args, context) {\n const cwd = args.cwd ?? context.directory\n const exitCodeToken = createExitCodeToken()\n const grepError = args.probe?.type === 'output' ? validateGrep(args.probe.grep) : null\n if (grepError)\n throw new Error(`Invalid probe.grep regex: ${grepError}`)\n const title = createOpenCodePaneTitle(args.title ?? args.command)\n\n const paneId = await zellijCli.newPane({\n command: args.command,\n args: args.args,\n cwd,\n title,\n floating: false,\n exitCodeToken,\n })\n\n const session = sessionManager.create({\n openCodeSessionId: context.sessionID,\n paneId,\n title,\n command: args.command,\n args: args.args,\n cwd,\n allowAgentInput: true,\n humanInputOnly: false,\n exitCodeToken,\n })\n registerPaneForWatchdog(session)\n await subscriberManager.start(session)\n const probe = await runProbe(args.probe as Probe | undefined, (grep, ignoreCase) => outputMatches(session.id, grep, ignoreCase))\n const output = readOutputSnapshot(session.id, { maxLines: args.maxLines })\n\n return jsonResponse({\n session: publicSession(session),\n output,\n probe,\n next: nextAdvice(probe.ok, probe.ok ? 'Probe completed; continue with this session or read later for long-running output.' : probe.message),\n warnings: ['Registry remains in-memory; restarting OpenCode loses plugin session records.'],\n })\n },\n})\n","import { Buffer } from 'node:buffer'\nimport process from 'node:process'\n\nconst defaultMaxWriteBytes = 64 * 1024\nconst defaultChunkBytes = 8 * 1024\n\nexport function maxWriteBytes(): number {\n const configured = Number(process.env.ZELLIJ_PTY_MAX_WRITE_BYTES ?? defaultMaxWriteBytes)\n return Number.isFinite(configured) && configured > 0 ? configured : defaultMaxWriteBytes\n}\n\nexport function assertWriteSizeAllowed(data: string): void {\n const bytes = Buffer.byteLength(data, 'utf8')\n const maxBytes = maxWriteBytes()\n if (bytes > maxBytes) {\n throw new Error(`Write payload is too large: ${bytes} bytes exceeds ${maxBytes} bytes. Split the input into smaller writes.`)\n }\n}\n\nexport function chunkWriteData(data: string, maxChunkBytes = defaultChunkBytes): string[] {\n const chunks: string[] = []\n let current = ''\n let currentBytes = 0\n\n for (const character of data) {\n const characterBytes = Buffer.byteLength(character, 'utf8')\n if (current && currentBytes + characterBytes > maxChunkBytes) {\n chunks.push(current)\n current = ''\n currentBytes = 0\n }\n current += character\n currentBytes += characterBytes\n }\n\n if (current)\n chunks.push(current)\n return chunks\n}\n","import { setTimeout as delay } from 'node:timers/promises'\nimport { tool } from '@opencode-ai/plugin'\nimport { sessionManager } from '../pty/manager.js'\nimport { assertWriteSizeAllowed, chunkWriteData } from '../pty/write-data.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { zellijCli } from '../zellij/cli.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { emptyOutputSnapshot, readOutputSnapshot } from './output.js'\n\nconst schema = tool.schema\n\nexport const zellijPtyWriteTool = tool({\n description: 'Write stdin to a Zellij PTY session. Refuses human-input-only sessions.',\n args: {\n id: schema.string().describe('zellij-pty session id returned by zellij_pty_spawn or zellij_pty_request_sudo.'),\n data: schema.string().describe('Text to write. Use \\u0003 to send Ctrl-C.'),\n maxLines: schema.number().int().positive().max(5_000).optional().describe('Maximum recent output lines to return. Defaults to 200.'),\n interruptAfterSeconds: schema.number().positive().max(300).optional().describe('Blindly send Ctrl-C after this many seconds if the pane is still running; keeps the pane alive.'),\n },\n async execute(args) {\n const session = sessionManager.get(args.id)\n if (session.humanInputOnly || !session.allowAgentInput) {\n return jsonResponse({\n session: publicSession(session),\n output: subscriberManager.has(session.id) ? readOutputSnapshot(session.id, { maxLines: args.maxLines }) : emptyOutputSnapshot(session.lineCount),\n next: nextAdvice(false, 'This session is human-input-only; the user must type directly in the Zellij pane.'),\n warnings: ['Agent writes to human-input-only sessions are forbidden.'],\n })\n }\n\n if (args.data === '\\u0003' || args.data === '\\x03') {\n await zellijCli.sendCtrlC(session.paneId)\n }\n else {\n assertWriteSizeAllowed(args.data)\n for (const chunk of chunkWriteData(args.data)) {\n await zellijCli.writeChars(session.paneId, chunk)\n }\n }\n\n session.updatedAt = new Date().toISOString()\n if (args.interruptAfterSeconds) {\n await delay(args.interruptAfterSeconds * 1_000)\n if (sessionManager.find(session.id)?.status === 'running') {\n await zellijCli.sendCtrlC(session.paneId)\n await delay(500)\n }\n }\n else {\n await delay(1_000)\n }\n\n const warnings: string[] = []\n let output = emptyOutputSnapshot(session.lineCount)\n try {\n output = readOutputSnapshot(session.id, { maxLines: args.maxLines })\n }\n catch (error) {\n warnings.push(`Session output was unavailable before the write response completed: ${errorMessage(error)}`)\n }\n\n return jsonResponse({\n session: publicSession(session),\n output,\n next: nextAdvice(true, args.interruptAfterSeconds ? 'Input was sent; Ctrl-C was sent after the requested interrupt timeout if the session was still running.' : 'Input was sent and recent output was observed.'),\n warnings,\n })\n },\n})\n","import type { SessionManager } from '../pty/manager.js'\nimport type { SubscriberManager } from './subscribe.js'\nimport process from 'node:process'\nimport { sessionManager } from '../pty/manager.js'\nimport { zellijCli } from './cli.js'\nimport { subscriberManager } from './subscribe.js'\n\nlet registered = false\nlet cleanedUp = false\n\nexport function cleanupPanesOnShutdown(\n sessions: SessionManager = sessionManager,\n subscribers: SubscriberManager = subscriberManager,\n): void {\n if (cleanedUp)\n return\n cleanedUp = true\n\n for (const session of sessions.list()) {\n try {\n zellijCli.closePaneSync(session.paneId)\n }\n catch {\n // Shutdown cleanup is only a fast best-effort path; the watchdog registry remains as fallback.\n }\n\n subscribers.forget(session.id)\n try {\n sessions.remove(session.id)\n }\n catch {\n // Another cleanup path may have already removed it.\n }\n }\n}\n\nexport function registerShutdownCleanup(): void {\n if (registered)\n return\n registered = true\n\n process.once('exit', () => cleanupPanesOnShutdown())\n process.once('SIGINT', () => exitAfterCleanup('SIGINT', 130))\n process.once('SIGTERM', () => exitAfterCleanup('SIGTERM', 143))\n process.once('SIGHUP', () => exitAfterCleanup('SIGHUP', 129))\n}\n\nfunction exitAfterCleanup(signal: NodeJS.Signals, code: number): void {\n cleanupPanesOnShutdown()\n process.removeAllListeners(signal)\n process.exit(code)\n}\n","import type { SessionStatus as OpenCodeSessionStatus } from '@opencode-ai/sdk'\nimport { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\n\nconst execFileAsync = promisify(execFile)\n\nexport interface OpenCodeEventLike {\n type: string\n properties: unknown\n}\n\nexport interface TabTitleEventManager {\n updateSessionStatus: (sessionID: string, status: OpenCodeSessionStatus) => void\n markSessionIdle: (sessionID: string) => void\n removeSession: (sessionID: string) => void\n markNeedsInput: (id: string, sessionID: string) => void\n clearNeedsInput: (id: string) => void\n setBranch: (branch: string | undefined) => void\n destroy?: () => void\n}\n\nexport type BranchReader = (worktree: string) => Promise<string>\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null\n}\n\nfunction stringProperty(object: Record<string, unknown>, key: string): string | undefined {\n const value = object[key]\n return typeof value === 'string' ? value : undefined\n}\n\nfunction nestedStringProperty(object: Record<string, unknown>, key: string, nestedKey: string): string | undefined {\n const nested = object[key]\n if (!isRecord(nested))\n return undefined\n return stringProperty(nested, nestedKey)\n}\n\nfunction sessionStatusProperty(object: Record<string, unknown>): OpenCodeSessionStatus | undefined {\n const status = object.status\n if (!isRecord(status))\n return undefined\n\n if (status.type === 'idle' || status.type === 'busy')\n return { type: status.type }\n\n if (status.type === 'retry') {\n return {\n type: 'retry',\n attempt: typeof status.attempt === 'number' ? status.attempt : 0,\n message: typeof status.message === 'string' ? status.message : '',\n next: typeof status.next === 'number' ? status.next : 0,\n }\n }\n\n return undefined\n}\n\nfunction inputRequestID(object: Record<string, unknown>): string | undefined {\n return stringProperty(object, 'id') ?? stringProperty(object, 'requestID') ?? stringProperty(object, 'permissionID')\n}\n\nfunction inputState(object: Record<string, unknown>): string | undefined {\n return (stringProperty(object, 'status') ?? stringProperty(object, 'state') ?? stringProperty(object, 'type'))?.toLowerCase()\n}\n\nfunction isResolvedInputState(state: string | undefined): boolean {\n return state === 'approved' || state === 'denied' || state === 'rejected' || state === 'resolved' || state === 'replied'\n}\n\nexport function deletedSessionID(event: OpenCodeEventLike): string | undefined {\n if (!isRecord(event.properties))\n return undefined\n return nestedStringProperty(event.properties, 'info', 'id') ?? stringProperty(event.properties, 'sessionID')\n}\n\nasync function readGitBranch(worktree: string): Promise<string> {\n const result = await execFileAsync('git', ['-C', worktree, 'branch', '--show-current'], {\n encoding: 'utf8',\n timeout: 1_000,\n maxBuffer: 1024 * 1024,\n })\n return result.stdout\n}\n\nexport async function getInitialBranch(worktree: string, readBranch: BranchReader = readGitBranch): Promise<string | undefined> {\n try {\n return (await readBranch(worktree)).trim() || undefined\n }\n catch {\n return undefined\n }\n}\n\nexport function shouldReadInitialBranch(zellij: string | undefined): boolean {\n return Boolean(zellij)\n}\n\nexport function handleTabTitleEvent(tabTitleManager: TabTitleEventManager, event: OpenCodeEventLike): void {\n if (!isRecord(event.properties))\n return\n\n const properties = event.properties\n\n switch (event.type) {\n case 'session.status': {\n const sessionID = stringProperty(properties, 'sessionID')\n const status = sessionStatusProperty(properties)\n if (sessionID && status)\n tabTitleManager.updateSessionStatus(sessionID, status)\n break\n }\n case 'session.idle': {\n const sessionID = stringProperty(properties, 'sessionID')\n if (sessionID)\n tabTitleManager.markSessionIdle(sessionID)\n break\n }\n case 'session.error': {\n const sessionID = stringProperty(properties, 'sessionID')\n if (sessionID)\n tabTitleManager.markSessionIdle(sessionID)\n break\n }\n case 'vcs.branch.updated': {\n tabTitleManager.setBranch(stringProperty(properties, 'branch'))\n break\n }\n case 'question.asked':\n case 'permission.asked': {\n const id = inputRequestID(properties)\n const sessionID = stringProperty(properties, 'sessionID')\n if (id && sessionID)\n tabTitleManager.markNeedsInput(id, sessionID)\n break\n }\n case 'permission.updated': {\n const id = inputRequestID(properties)\n const sessionID = stringProperty(properties, 'sessionID')\n const state = inputState(properties)\n if (id && isResolvedInputState(state))\n tabTitleManager.clearNeedsInput(id)\n else if (id && sessionID)\n tabTitleManager.markNeedsInput(id, sessionID)\n break\n }\n case 'question.replied':\n case 'question.rejected':\n case 'permission.replied': {\n const id = inputRequestID(properties)\n if (id)\n tabTitleManager.clearNeedsInput(id)\n break\n }\n case 'session.deleted': {\n const sessionID = deletedSessionID(event)\n if (sessionID)\n tabTitleManager.removeSession(sessionID)\n break\n }\n case 'server.instance.disposed':\n case 'global.disposed': {\n tabTitleManager.destroy?.()\n break\n }\n }\n}\n","import type { SessionStatus as OpenCodeSessionStatus } from '@opencode-ai/sdk'\nimport process from 'node:process'\nimport { debug } from '../utils/debug.js'\nimport { ZellijCli } from './cli.js'\n\nexport interface TabTitleCli {\n renameTab: (title: string) => Promise<void>\n}\n\nexport type TabTitleStatus = 'idle' | 'running' | 'needs-input'\n\ntype SessionActivity = 'idle' | 'running'\n\nexport interface TabTitleEmojis {\n idle: string\n running: string\n needsInput: string\n branch: string\n}\n\nexport const defaultTabTitleEmojis: TabTitleEmojis = {\n idle: '🟢',\n running: '⚡',\n needsInput: '💬',\n branch: '🌱',\n}\n\nexport interface TitleContext {\n projectName: string\n branchName: string | undefined\n status: TabTitleStatus\n emojis: TabTitleEmojis\n}\n\nexport function formatTabTitle(context: TitleContext): string {\n const branch = context.branchName ? ` ${context.emojis.branch} ${context.branchName}` : ''\n const emoji = context.emojis[context.status === 'needs-input' ? 'needsInput' : context.status]\n return `${emoji} ${context.projectName}${branch}`\n}\n\nexport function sanitizeTitle(title: string, maxLength = 90): string {\n let cleaned = title\n .replace(/[\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}]/gu, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n\n const chars = Array.from(cleaned)\n if (chars.length > maxLength) {\n cleaned = `${chars.slice(0, maxLength - 1).join('')}…`\n }\n\n return cleaned\n}\n\nexport interface TabTitleManagerOptions {\n projectName: string\n branchName?: string | undefined\n cli?: TabTitleCli\n emojis?: Partial<TabTitleEmojis> | undefined\n debounceMs?: number\n retryInitialMs?: number\n retryMaxMs?: number\n}\n\nexport class TabTitleManager {\n private readonly sessionStatuses = new Map<string, SessionActivity>()\n private readonly pendingInputs = new Map<string, string>()\n private branchName: string | undefined\n private desiredTitle: string | undefined\n private lastSyncedTitle: string | undefined\n private debounceTimer: ReturnType<typeof setTimeout> | undefined\n private retryTimer: ReturnType<typeof setTimeout> | undefined\n private retryAttempt = 0\n private syncInFlight = false\n private readonly debounceMs: number\n private readonly retryInitialMs: number\n private readonly retryMaxMs: number\n private readonly projectName: string\n private readonly cli: TabTitleCli\n private readonly emojis: TabTitleEmojis\n private readonly enabled: boolean\n private destroyed = false\n\n constructor(options: TabTitleManagerOptions) {\n this.projectName = options.projectName\n this.branchName = options.branchName?.trim() || undefined\n this.cli = options.cli ?? new ZellijCli()\n this.emojis = { ...defaultTabTitleEmojis, ...options.emojis }\n this.debounceMs = options.debounceMs ?? 300\n this.retryInitialMs = options.retryInitialMs ?? 250\n this.retryMaxMs = options.retryMaxMs ?? 5_000\n this.enabled = Boolean(process.env.ZELLIJ)\n }\n\n setBranch(branch: string | undefined): void {\n const trimmed = branch?.trim() || undefined\n if (this.branchName === trimmed)\n return\n this.branchName = trimmed\n this.scheduleUpdate()\n }\n\n updateSessionStatus(sessionID: string, status: OpenCodeSessionStatus): void {\n const activity: SessionActivity = status.type === 'idle' ? 'idle' : 'running'\n const existing = this.sessionStatuses.get(sessionID)\n if (existing === activity)\n return\n this.sessionStatuses.set(sessionID, activity)\n this.scheduleUpdate()\n }\n\n markSessionIdle(sessionID: string): void {\n this.updateSessionStatus(sessionID, { type: 'idle' })\n }\n\n removeSession(sessionID: string): void {\n const hadSessionStatus = this.sessionStatuses.delete(sessionID)\n let hadPendingInput = false\n for (const [id, pendingSessionID] of this.pendingInputs) {\n if (pendingSessionID === sessionID) {\n this.pendingInputs.delete(id)\n hadPendingInput = true\n }\n }\n\n if (!hadSessionStatus && !hadPendingInput)\n return\n this.scheduleUpdate()\n }\n\n markNeedsInput(id: string, sessionID: string): void {\n if (this.pendingInputs.get(id) === sessionID)\n return\n this.pendingInputs.set(id, sessionID)\n this.scheduleUpdate()\n }\n\n clearNeedsInput(id: string): void {\n if (!this.pendingInputs.delete(id))\n return\n this.scheduleUpdate()\n }\n\n private get isBusy(): boolean {\n for (const activity of this.sessionStatuses.values()) {\n if (activity === 'running')\n return true\n }\n return false\n }\n\n private get needsInput(): boolean {\n return this.pendingInputs.size > 0\n }\n\n private get status(): TabTitleStatus {\n if (this.needsInput)\n return 'needs-input'\n if (this.isBusy)\n return 'running'\n return 'idle'\n }\n\n private buildTitle(): string {\n const context: TitleContext = {\n projectName: this.projectName,\n branchName: this.branchName,\n status: this.status,\n emojis: this.emojis,\n }\n return sanitizeTitle(formatTabTitle(context))\n }\n\n getCurrentTitle(): string {\n return this.buildTitle()\n }\n\n async renderImmediate(): Promise<void> {\n if (!this.enabled || this.destroyed)\n return\n this.desiredTitle = this.buildTitle()\n this.clearDebounceTimer()\n await this.syncDesiredTitle()\n }\n\n scheduleUpdate(): void {\n if (!this.enabled || this.destroyed)\n return\n const title = this.buildTitle()\n if (title === this.desiredTitle && title === this.lastSyncedTitle)\n return\n this.desiredTitle = title\n\n if (this.syncInFlight)\n return\n\n this.clearRetryTimer()\n this.clearDebounceTimer()\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = undefined\n this.syncDesiredTitle().catch(() => {})\n }, this.debounceMs)\n this.unrefTimer(this.debounceTimer)\n }\n\n private async syncDesiredTitle(): Promise<void> {\n if (!this.enabled || this.destroyed)\n return\n if (this.syncInFlight)\n return\n\n this.syncInFlight = true\n try {\n while (this.desiredTitle && this.desiredTitle !== this.lastSyncedTitle) {\n const title = this.desiredTitle\n try {\n await this.cli.renameTab(title)\n this.lastSyncedTitle = title\n this.retryAttempt = 0\n this.clearRetryTimer()\n }\n catch (cause) {\n debug('Failed to rename Zellij tab.', cause)\n this.scheduleRetry()\n break\n }\n }\n }\n finally {\n this.syncInFlight = false\n }\n }\n\n private scheduleRetry(): void {\n if (!this.enabled || this.destroyed || this.retryTimer || this.desiredTitle === this.lastSyncedTitle)\n return\n\n const delay = Math.min(this.retryMaxMs, this.retryInitialMs * 2 ** this.retryAttempt)\n this.retryAttempt += 1\n this.retryTimer = setTimeout(() => {\n this.retryTimer = undefined\n this.syncDesiredTitle().catch(() => {})\n }, delay)\n this.unrefTimer(this.retryTimer)\n }\n\n private clearRetryTimer(): void {\n if (this.retryTimer)\n clearTimeout(this.retryTimer)\n this.retryTimer = undefined\n }\n\n private unrefTimer(timer: ReturnType<typeof setTimeout>): void {\n if (typeof timer === 'object' && timer && 'unref' in timer && typeof timer.unref === 'function')\n timer.unref()\n }\n\n private clearDebounceTimer(): void {\n if (this.debounceTimer)\n clearTimeout(this.debounceTimer)\n this.debounceTimer = undefined\n }\n\n destroy(): void {\n this.destroyed = true\n this.clearDebounceTimer()\n this.clearRetryTimer()\n }\n}\n","import type { Plugin } from '@opencode-ai/plugin'\nimport type { UpdateResult } from './auto-update.js'\nimport type { OpenCodeEventLike } from './zellij/tab-title-events.js'\nimport process from 'node:process'\nimport { checkAndUpdate } from './auto-update.js'\nimport { loadConfig } from './config.js'\nimport { configureSudoPane } from './permissions/sudo-pane.js'\nimport { sessionManager } from './pty/manager.js'\nimport { zellijPtyKillTool } from './tools/kill.js'\nimport { zellijPtyListTool } from './tools/list.js'\nimport { zellijPtyReadTool } from './tools/read.js'\nimport { requestSudoTool } from './tools/request-sudo.js'\nimport { zellijPtySpawnTool } from './tools/spawn.js'\nimport { zellijPtyWriteTool } from './tools/write.js'\nimport { debug } from './utils/debug.js'\nimport { errorMessage } from './utils/errors.js'\nimport { cleanupStaleWatchdogRegistries, unregisterPaneFromWatchdog } from './zellij/pane-watchdog.js'\nimport { registerShutdownCleanup } from './zellij/shutdown-cleanup.js'\nimport { subscriberManager } from './zellij/subscribe.js'\nimport { deletedSessionID, getInitialBranch, handleTabTitleEvent, shouldReadInitialBranch } from './zellij/tab-title-events.js'\nimport { TabTitleManager } from './zellij/tab-title.js'\n\nconst ptyTools = {\n zellij_pty_spawn: zellijPtySpawnTool,\n zellij_pty_list: zellijPtyListTool,\n zellij_pty_write: zellijPtyWriteTool,\n zellij_pty_read: zellijPtyReadTool,\n zellij_pty_kill: zellijPtyKillTool,\n}\n\nfunction getProjectName(path: string): string {\n return path.split(/[/\\\\]/).filter(Boolean).pop() || 'opencode'\n}\n\nfunction getWorkspaceRoot(input: { directory?: string | undefined, worktree?: string | undefined }): string {\n return input.worktree || input.directory || process.cwd()\n}\n\nexport interface ToastClient {\n tui: {\n showToast: (options: {\n body: {\n title: string\n message: string\n variant: 'success' | 'error'\n duration: number\n }\n }) => Promise<unknown>\n }\n}\n\nexport function showUpdateToast(client: ToastClient, result: UpdateResult): void {\n if (result.type === 'updated') {\n client.tui.showToast({\n body: {\n title: 'opencode-zellij updated',\n message: `Updated to ${result.toVersion}. Restart OpenCode to apply the changes.`,\n variant: 'success',\n duration: 10_000,\n },\n }).catch(() => {})\n }\n else if (result.type === 'failed') {\n client.tui.showToast({\n body: {\n title: 'opencode-zellij update failed',\n message: `Failed to update to ${result.latestVersion}.`,\n variant: 'error',\n duration: 8_000,\n },\n }).catch(() => {})\n }\n}\n\nexport function startAutoUpdateCheck(\n client: ToastClient,\n importMetaUrl: string,\n check: typeof checkAndUpdate = checkAndUpdate,\n): void {\n ;(async () => {\n try {\n showUpdateToast(client, await check({ importMetaUrl }))\n }\n catch (cause) {\n debug('auto-update check failed', errorMessage(cause))\n }\n })()\n}\n\nasync function cleanupStep(stepName: string, sessionId: string, step: () => void | Promise<void>): Promise<void> {\n try {\n await step()\n }\n catch (error) {\n debug(`session.deleted cleanup failed: ${stepName} for ${sessionId}`, errorMessage(error))\n }\n}\n\nasync function cleanupDeletedSession(sessionId: string): Promise<void> {\n await cleanupStep('close pane', sessionId, () => subscriberManager.closeSessionPane(sessionId))\n await cleanupStep('forget subscriber', sessionId, () => subscriberManager.forget(sessionId))\n await cleanupStep('unregister watchdog', sessionId, () => unregisterPaneFromWatchdog(sessionId))\n await cleanupStep('remove session', sessionId, () => sessionManager.remove(sessionId))\n}\n\nexport interface ZellijPtyPluginDependencies {\n importMetaUrl?: string | undefined\n startAutoUpdateCheck?: typeof startAutoUpdateCheck | undefined\n}\n\nexport function createZellijPtyPlugin(dependencies: ZellijPtyPluginDependencies = {}): Plugin {\n return async (input) => {\n const { config, warnings } = await loadConfig(input)\n for (const warning of warnings) {\n debug(warning)\n }\n configureSudoPane(config.pty.sudoPane === 'allow')\n cleanupStaleWatchdogRegistries()\n registerShutdownCleanup()\n\n const workspaceRoot = getWorkspaceRoot(input)\n const projectName = getProjectName(workspaceRoot)\n const branchName = config.tabTitle.enabled && shouldReadInitialBranch(process.env.ZELLIJ) ? await getInitialBranch(workspaceRoot) : undefined\n const tabTitleManager = config.tabTitle.enabled\n ? new TabTitleManager({\n projectName,\n branchName,\n debounceMs: config.tabTitle.debounceMs,\n emojis: {\n idle: config.tabTitle.emojiIdle,\n running: config.tabTitle.emojiRunning,\n needsInput: config.tabTitle.emojiNeedsInput,\n branch: config.tabTitle.emojiBranch,\n },\n })\n : undefined\n\n // Best-effort initial render; no-op when not inside a real Zellij pane.\n tabTitleManager?.renderImmediate().catch(() => {})\n\n const client = input.client\n\n if (config.autoUpdate.enabled)\n (dependencies.startAutoUpdateCheck ?? startAutoUpdateCheck)(client, dependencies.importMetaUrl ?? import.meta.url)\n\n return {\n async event(input) {\n const event: OpenCodeEventLike = input.event\n\n if (tabTitleManager)\n handleTabTitleEvent(tabTitleManager, event)\n\n if (event.type === 'session.deleted') {\n const sessionID = deletedSessionID(event)\n if (!sessionID)\n return\n\n const sessions = sessionManager.listByOpenCodeSession(sessionID)\n await Promise.all(sessions.map(session => cleanupDeletedSession(session.id)))\n }\n },\n tool: config.pty.enabled\n ? {\n ...ptyTools,\n ...(config.pty.sudoPane === 'hide' ? {} : { zellij_pty_request_sudo: requestSudoTool }),\n }\n : {},\n }\n }\n}\n\nexport const ZellijPtyPlugin: Plugin = createZellijPtyPlugin()\n\nexport default ZellijPtyPlugin\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["isRecord","execFileAsync","ansiPattern","schema","delay","schema","schema","delay","schema","delay"],"sources":["../src/utils/debug.ts","../src/utils/errors.ts","../src/auto-update.ts","../src/config.ts","../src/permissions/sudo-pane.ts","../src/utils/ids.ts","../src/pty/manager.ts","../src/utils/shell-args.ts","../src/zellij/cli.ts","../src/zellij/pane-watchdog.ts","../src/pty/ring-buffer.ts","../src/utils/exit-code.ts","../src/zellij/subscribe.ts","../src/tools/format.ts","../src/tools/output.ts","../src/tools/kill.ts","../src/tools/list.ts","../src/tools/read.ts","../src/utils/pane-title.ts","../src/tools/request-sudo.ts","../src/pty/probe.ts","../src/tools/spawn.ts","../src/pty/write-data.ts","../src/tools/write.ts","../src/zellij/shutdown-cleanup.ts","../src/zellij/tab-title-events.ts","../src/zellij/tab-title.ts","../src/plugin.ts"],"sourcesContent":["import process from 'node:process'\n\nexport function debug(message: string, ...details: unknown[]): void {\n if (!process.env.ZELLIJ_PTY_DEBUG)\n return\n\n console.warn(`[opencode-zellij] ${message}`, ...details)\n}\n","export function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n","import { execFile } from 'node:child_process'\nimport { existsSync } from 'node:fs'\nimport { readFile, rename, rm } from 'node:fs/promises'\nimport { basename, dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { promisify } from 'node:util'\nimport { debug } from './utils/debug.js'\nimport { errorMessage } from './utils/errors.js'\n\nexport const PACKAGE_NAME = 'opencode-zellij'\n\nconst NPM_REGISTRY_URL = 'https://registry.npmjs.org/-/package/opencode-zellij/dist-tags'\nconst FETCH_TIMEOUT_MS = 5_000\nconst INSTALL_TIMEOUT_MS = 60_000\n\nconst defaultExecFile = promisify(execFile)\n\nfunction packageDir(installRoot: string): string {\n return join(installRoot, 'node_modules', PACKAGE_NAME)\n}\n\nfunction backupDir(installRoot: string): string {\n return join(installRoot, 'node_modules', `${PACKAGE_NAME}.update-backup`)\n}\n\ninterface InstalledPackageMetadata {\n name: string | undefined\n version: string | undefined\n main: string | undefined\n}\n\nasync function installedPackageMetadata(installRoot: string): Promise<InstalledPackageMetadata | undefined> {\n try {\n const content = await readFile(join(packageDir(installRoot), 'package.json'), 'utf8')\n const pkg: unknown = JSON.parse(content)\n if (isRecord(pkg)) {\n return {\n name: typeof pkg.name === 'string' ? pkg.name : undefined,\n version: typeof pkg.version === 'string' ? pkg.version : undefined,\n main: typeof pkg.main === 'string' ? pkg.main : undefined,\n }\n }\n }\n catch (error) {\n // Missing or unreadable package metadata is handled by the caller.\n debug('installedPackageMetadata failed', errorMessage(error))\n }\n return undefined\n}\n\nfunction isExpectedPackage(metadata: InstalledPackageMetadata | undefined, version: string): boolean {\n return metadata?.name === PACKAGE_NAME && metadata.version === version\n}\n\nfunction hasRunnableEntry(installRoot: string, metadata: InstalledPackageMetadata | undefined): boolean {\n if (!metadata)\n return false\n const dir = packageDir(installRoot)\n if (metadata.main && existsSync(join(dir, metadata.main)))\n return true\n return existsSync(join(dir, 'dist', 'index.mjs'))\n}\n\nasync function isVerifiedInstall(installRoot: string, version: string): Promise<boolean> {\n const metadata = await installedPackageMetadata(installRoot)\n return isExpectedPackage(metadata, version) && hasRunnableEntry(installRoot, metadata)\n}\n\nasync function removeInstalledPackage(installRoot: string): Promise<void> {\n await rm(packageDir(installRoot), { force: true, recursive: true })\n}\n\nasync function backupInstalledPackage(installRoot: string): Promise<string | undefined> {\n const source = packageDir(installRoot)\n if (!existsSync(source))\n return undefined\n const backup = backupDir(installRoot)\n await rm(backup, { force: true, recursive: true })\n await rename(source, backup)\n return backup\n}\n\nasync function restoreInstalledPackage(installRoot: string, backup: string | undefined): Promise<void> {\n if (!backup || !existsSync(backup))\n return\n await rm(packageDir(installRoot), { force: true, recursive: true })\n await rename(backup, packageDir(installRoot))\n}\n\nasync function discardBackup(backup: string | undefined): Promise<void> {\n if (backup)\n await rm(backup, { force: true, recursive: true })\n}\n\nexport interface InstallContext {\n installRoot: string\n cacheSpec: string\n currentVersion: string\n}\n\nexport async function findInstallContext(importMetaUrl: string): Promise<InstallContext | undefined> {\n let startPath: string\n try {\n startPath = fileURLToPath(importMetaUrl)\n }\n catch (cause) {\n debug('invalid import.meta.url', cause instanceof Error ? cause.message : String(cause))\n return undefined\n }\n\n let dir = dirname(startPath)\n\n while (true) {\n const isPluginDir = dir.endsWith(`/node_modules/${PACKAGE_NAME}`) || dir.endsWith(`\\\\node_modules\\\\${PACKAGE_NAME}`)\n if (isPluginDir) {\n const packageJsonPath = join(dir, 'package.json')\n try {\n const content = await readFile(packageJsonPath, 'utf8')\n const pkg: unknown = JSON.parse(content)\n if (\n isRecord(pkg)\n && pkg.name === PACKAGE_NAME\n && typeof pkg.version === 'string'\n && pkg.version.length > 0\n ) {\n const installRoot = dirname(dirname(dir))\n const rootPackageJson = join(installRoot, 'package.json')\n if (existsSync(rootPackageJson)) {\n return { installRoot, cacheSpec: basename(installRoot), currentVersion: pkg.version }\n }\n }\n }\n catch (error) {\n // ignore unreadable or invalid package.json\n debug('findInstallContext package.json read failed', errorMessage(error))\n }\n }\n\n const parent = dirname(dir)\n if (parent === dir)\n break\n dir = parent\n }\n\n return undefined\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null\n}\n\nexport function isAutoUpdatableSpec(spec: string | undefined): boolean {\n if (spec === PACKAGE_NAME)\n return true\n if (spec === `${PACKAGE_NAME}@latest`)\n return true\n return false\n}\n\nexport async function fetchLatestVersion(fetchImpl: typeof fetch = globalThis.fetch): Promise<string | undefined> {\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS)\n\n try {\n const response = await fetchImpl(NPM_REGISTRY_URL, { signal: controller.signal })\n clearTimeout(timeout)\n if (!response.ok) {\n debug(`npm registry returned ${response.status}`)\n return undefined\n }\n const data: unknown = await response.json()\n if (isRecord(data) && typeof data.latest === 'string') {\n return data.latest\n }\n debug('npm registry response missing latest tag')\n return undefined\n }\n catch (cause) {\n clearTimeout(timeout)\n debug('failed to fetch latest version', cause instanceof Error ? cause.message : String(cause))\n return undefined\n }\n}\n\nexport type ExecFileLike = (\n file: string,\n args: string[],\n options: { cwd: string, timeout?: number },\n) => Promise<{ stdout: string, stderr: string }>\n\nexport async function runNpmInstall(\n installRoot: string,\n version: string,\n execImpl: ExecFileLike = defaultExecFile as ExecFileLike,\n): Promise<boolean> {\n debug(`updating ${PACKAGE_NAME} to ${version} in ${installRoot}`)\n\n try {\n const install = () => execImpl(\n 'npm',\n ['install', `${PACKAGE_NAME}@${version}`, '--save-exact', '--ignore-scripts', '--no-audit', '--no-fund', '--prefer-online'],\n { cwd: installRoot, timeout: INSTALL_TIMEOUT_MS },\n )\n\n await install()\n\n if (await isVerifiedInstall(installRoot, version)) {\n debug(`updated ${PACKAGE_NAME} to ${version}`)\n return true\n }\n\n const installedPackage = await installedPackageMetadata(installRoot)\n debug(`npm install left stale or invalid ${PACKAGE_NAME} (${installedPackage?.name ?? '<missing>'}@${installedPackage?.version ?? '<missing>'}); reinstalling ${version}`)\n const backup = await backupInstalledPackage(installRoot)\n try {\n await removeInstalledPackage(installRoot)\n await install()\n\n if (await isVerifiedInstall(installRoot, version)) {\n await discardBackup(backup)\n debug(`updated ${PACKAGE_NAME} to ${version}`)\n return true\n }\n\n const reinstalledPackage = await installedPackageMetadata(installRoot)\n debug(`npm install verification failed: expected ${PACKAGE_NAME}@${version}, found ${reinstalledPackage?.name ?? '<missing>'}@${reinstalledPackage?.version ?? '<missing>'}`)\n await restoreInstalledPackage(installRoot, backup)\n return false\n }\n catch (cause) {\n await restoreInstalledPackage(installRoot, backup)\n throw cause\n }\n }\n catch (cause) {\n debug('npm install failed', cause instanceof Error ? cause.message : String(cause))\n return false\n }\n}\n\nexport interface CheckOptions {\n importMetaUrl: string\n fetchImpl?: typeof fetch\n execImpl?: ExecFileLike\n}\n\nexport type UpdateResult\n = | { type: 'skipped', reason: string }\n | { type: 'up-to-date', currentVersion: string }\n | { type: 'updated', fromVersion: string, toVersion: string }\n | { type: 'failed', currentVersion: string, latestVersion: string, reason: string }\n\nexport async function checkAndUpdate(options: CheckOptions): Promise<UpdateResult> {\n const context = await findInstallContext(options.importMetaUrl)\n if (!context) {\n debug('skipping auto-update: not installed from npm')\n return { type: 'skipped', reason: 'not installed from npm' }\n }\n\n if (!isAutoUpdatableSpec(context.cacheSpec)) {\n debug(`skipping auto-update: cache spec is pinned or unknown (${context.cacheSpec})`)\n return { type: 'skipped', reason: `cache spec is pinned or unknown (${context.cacheSpec})` }\n }\n\n const latest = await fetchLatestVersion(options.fetchImpl)\n if (!latest) {\n debug('skipping auto-update: could not determine latest version')\n return { type: 'skipped', reason: 'could not determine latest version' }\n }\n\n const installedVersion = (await installedPackageMetadata(context.installRoot))?.version ?? context.currentVersion\n if (latest === installedVersion) {\n debug(`auto-update: already on latest ${latest}`)\n return { type: 'up-to-date', currentVersion: installedVersion }\n }\n\n const success = await runNpmInstall(context.installRoot, latest, options.execImpl)\n if (success) {\n debug(`updated ${PACKAGE_NAME} from ${installedVersion} to ${latest}`)\n return { type: 'updated', fromVersion: installedVersion, toVersion: latest }\n }\n\n return { type: 'failed', currentVersion: installedVersion, latestVersion: latest, reason: 'npm install failed' }\n}\n","import { existsSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport process from 'node:process'\nimport { parseJSON, parseJSONC } from 'confbox'\nimport { z } from 'zod'\n\nconst sudoPaneSchema = z.enum(['allow', 'deny', 'hide'])\n\nexport interface TabTitleConfig {\n enabled: boolean\n emojiIdle: string\n emojiRunning: string\n emojiNeedsInput: string\n emojiBranch: string\n debounceMs: number\n}\n\nexport interface PtyConfig {\n enabled: boolean\n sudoPane: SudoPaneMode\n}\n\nexport type SudoPaneMode = z.infer<typeof sudoPaneSchema>\n\nexport type AutoUpdateConfig = boolean\n\nexport interface ZellijPluginConfig {\n tabTitle: TabTitleConfig\n pty: PtyConfig\n autoUpdate: AutoUpdateConfig\n}\n\nexport interface LoadConfigInput {\n directory?: string | undefined\n worktree?: string | undefined\n}\n\nexport interface LoadConfigResult {\n config: ZellijPluginConfig\n sources: {\n user?: string | undefined\n project?: string | undefined\n }\n warnings: string[]\n}\n\nconst configFilenames = [\n 'opencode-zellij.config.jsonc',\n 'opencode-zellij.config.json',\n] as const\n\nconst tabTitleLayerSchema = z.object({\n enabled: z.boolean().optional().describe('Enable dynamic Zellij tab title updates.'),\n emojiIdle: z.string().optional().describe('Prefix used when OpenCode is idle.'),\n emojiRunning: z.string().optional().describe('Prefix used while OpenCode is running work.'),\n emojiNeedsInput: z.string().optional().describe('Prefix used when OpenCode is waiting for human input.'),\n emojiBranch: z.string().optional().describe('Prefix used before the current git branch name.'),\n debounceMs: z.number().finite().min(0).optional().describe('Debounce time for tab title updates in milliseconds.'),\n}).strict()\n\nconst ptyLayerSchema = z.object({\n enabled: z.boolean().optional().describe('Enable Zellij-backed PTY tools.'),\n sudoPane: sudoPaneSchema.optional().describe('Controls whether the sudo pane tool is available, denied, or hidden.'),\n}).strict()\n\nconst autoUpdateLayerSchema = z.boolean().optional().describe('Enable automatic update checks for the opencode-zellij plugin.')\n\nexport const sidecarConfigSchema = z.object({\n $schema: z.string().optional().describe('JSON Schema URI for editor completion.'),\n tabTitle: tabTitleLayerSchema.optional(),\n pty: ptyLayerSchema.optional(),\n autoUpdate: autoUpdateLayerSchema.optional(),\n}).strict()\n\nexport const defaultConfig: ZellijPluginConfig = {\n tabTitle: {\n enabled: true,\n emojiIdle: '🟢',\n emojiRunning: '⚡',\n emojiNeedsInput: '💬',\n emojiBranch: '🌱',\n debounceMs: 300,\n },\n pty: {\n enabled: true,\n sudoPane: 'allow',\n },\n autoUpdate: true,\n}\n\ntype ConfigLayer = Pick<z.infer<typeof sidecarConfigSchema>, 'tabTitle' | 'pty' | 'autoUpdate'>\n\nfunction validConfigLayer(value: unknown): ConfigLayer | undefined {\n const result = sidecarConfigSchema.safeParse(value)\n if (!result.success)\n return undefined\n\n return {\n tabTitle: result.data.tabTitle,\n pty: result.data.pty,\n autoUpdate: result.data.autoUpdate,\n }\n}\n\nfunction mergeConfig(user?: ConfigLayer | undefined, project?: ConfigLayer | undefined): ZellijPluginConfig {\n return {\n tabTitle: {\n enabled: project?.tabTitle?.enabled ?? user?.tabTitle?.enabled ?? defaultConfig.tabTitle.enabled,\n emojiIdle: project?.tabTitle?.emojiIdle ?? user?.tabTitle?.emojiIdle ?? defaultConfig.tabTitle.emojiIdle,\n emojiRunning: project?.tabTitle?.emojiRunning ?? user?.tabTitle?.emojiRunning ?? defaultConfig.tabTitle.emojiRunning,\n emojiNeedsInput: project?.tabTitle?.emojiNeedsInput ?? user?.tabTitle?.emojiNeedsInput ?? defaultConfig.tabTitle.emojiNeedsInput,\n emojiBranch: project?.tabTitle?.emojiBranch ?? user?.tabTitle?.emojiBranch ?? defaultConfig.tabTitle.emojiBranch,\n debounceMs: project?.tabTitle?.debounceMs ?? user?.tabTitle?.debounceMs ?? defaultConfig.tabTitle.debounceMs,\n },\n pty: {\n enabled: project?.pty?.enabled ?? user?.pty?.enabled ?? defaultConfig.pty.enabled,\n sudoPane: project?.pty?.sudoPane ?? user?.pty?.sudoPane ?? defaultConfig.pty.sudoPane,\n },\n autoUpdate: project?.autoUpdate ?? user?.autoUpdate ?? defaultConfig.autoUpdate,\n }\n}\n\nasync function loadConfigLayer(directory: string, warnings: string[]): Promise<{ layer?: ConfigLayer | undefined, source?: string | undefined }> {\n const configFile = detectConfigFile(directory)\n if (!configFile)\n return {}\n\n try {\n const text = await readFile(configFile, 'utf8')\n const parsed = configFile.endsWith('.jsonc') ? parseJSONC(text) : parseJSON(text)\n const layer = validConfigLayer(parsed)\n if (!layer) {\n warnings.push(`Ignoring invalid config shape in ${configFile}.`)\n return { source: configFile }\n }\n return { layer, source: configFile }\n }\n catch (cause) {\n warnings.push(`Ignoring unreadable or invalid config file ${configFile}: ${cause instanceof Error ? cause.message : String(cause)}`)\n return {}\n }\n}\n\nfunction detectConfigFile(directory: string): string | undefined {\n return configFilenames\n .map(filename => join(directory, filename))\n .find(path => existsSync(path))\n}\n\nexport function userConfigDir(): string {\n return process.env.XDG_CONFIG_HOME ? join(process.env.XDG_CONFIG_HOME, 'opencode') : join(homedir(), '.config', 'opencode')\n}\n\nexport function projectConfigDirs(input: LoadConfigInput): string[] {\n const dirs: string[] = []\n if (input.worktree)\n dirs.push(join(input.worktree, '.opencode'))\n if (input.directory && input.directory !== input.worktree)\n dirs.push(join(input.directory, '.opencode'))\n return dirs\n}\n\nexport async function loadConfig(input: LoadConfigInput): Promise<LoadConfigResult> {\n const warnings: string[] = []\n const sources: LoadConfigResult['sources'] = {}\n\n const userResult = await loadConfigLayer(userConfigDir(), warnings)\n const userLayer = userResult.layer\n if (userResult.source && userLayer)\n sources.user = userResult.source\n\n let projectLayer: ConfigLayer | undefined\n for (const projectDir of projectConfigDirs(input)) {\n const projectResult = await loadConfigLayer(projectDir, warnings)\n if (!projectResult.source)\n continue\n projectLayer = projectResult.layer\n if (projectLayer)\n sources.project = projectResult.source\n break\n }\n\n return {\n config: mergeConfig(userLayer, projectLayer),\n sources,\n warnings,\n }\n}\n","let sudoPaneAllowed = true\n\nexport function configureSudoPane(allowed: boolean): void {\n sudoPaneAllowed = allowed\n}\n\nexport function assertSudoPaneAllowed(): void {\n if (!sudoPaneAllowed)\n throw new Error('sudo pane is disabled by zellij-pty config.')\n}\n","import { randomUUID } from 'node:crypto'\n\nconst paneIdPattern = /\\b(?:terminal_)?(\\d+)\\b/\n\nexport function createSessionId(): string {\n return `zpty_${randomUUID().replaceAll('-', '').slice(0, 10)}`\n}\n\nexport function normalizePaneId(rawPaneId: string): string {\n const trimmed = rawPaneId.trim()\n if (/^terminal_\\d+$/.test(trimmed))\n return trimmed\n if (/^\\d+$/.test(trimmed))\n return `terminal_${trimmed}`\n throw new Error(`Invalid Zellij terminal pane id: ${rawPaneId}`)\n}\n\nexport function parsePaneId(output: string): string {\n const match = output.match(paneIdPattern)\n if (!match?.[1]) {\n throw new Error(`Unable to parse Zellij pane id from output: ${output.trim() || '<empty>'}`)\n }\n return normalizePaneId(match[1])\n}\n","import type { CreateSessionInput, PtySession, SessionStatus } from './session.js'\nimport { createSessionId } from '../utils/ids.js'\n\nexport class SessionManager {\n private readonly sessions = new Map<string, PtySession>()\n\n create(input: CreateSessionInput): PtySession {\n const now = new Date().toISOString()\n const session: PtySession = {\n id: createSessionId(),\n openCodeSessionId: input.openCodeSessionId ?? null,\n paneId: input.paneId,\n title: input.title,\n command: input.command,\n args: input.args ?? [],\n cwd: input.cwd,\n status: 'running',\n lineCount: 0,\n createdAt: now,\n updatedAt: now,\n allowAgentInput: input.allowAgentInput,\n humanInputOnly: input.humanInputOnly,\n exitCode: null,\n exitedAt: null,\n exitCodeToken: input.exitCodeToken ?? null,\n }\n this.sessions.set(session.id, session)\n return session\n }\n\n get(id: string): PtySession {\n const session = this.sessions.get(id)\n if (!session)\n throw new Error(`Unknown zellij PTY session: ${id}`)\n return session\n }\n\n find(id: string): PtySession | undefined {\n return this.sessions.get(id)\n }\n\n list(): PtySession[] {\n return Array.from(this.sessions.values()).sort((a, b) => a.createdAt.localeCompare(b.createdAt))\n }\n\n updateLineCount(id: string, lineCount: number): PtySession {\n const session = this.get(id)\n session.lineCount = lineCount\n session.updatedAt = new Date().toISOString()\n return session\n }\n\n updateStatus(id: string, status: SessionStatus): PtySession {\n const session = this.get(id)\n session.status = status\n session.updatedAt = new Date().toISOString()\n return session\n }\n\n markExited(id: string, exitCode: number): PtySession {\n const session = this.get(id)\n session.status = 'exited'\n session.exitCode = exitCode\n session.exitedAt = new Date().toISOString()\n session.updatedAt = session.exitedAt\n return session\n }\n\n listByOpenCodeSession(openCodeSessionId: string): PtySession[] {\n return this.list().filter(session => session.openCodeSessionId === openCodeSessionId)\n }\n\n remove(id: string): void {\n if (!this.sessions.delete(id))\n throw new Error(`Unknown zellij PTY session: ${id}`)\n }\n}\n\nexport const sessionManager = new SessionManager()\n","export interface CommandInput {\n command: string\n args?: string[] | undefined\n}\n\nexport interface BuildCommandArgvOptions {\n exitCodeToken?: string | undefined\n}\n\nconst directCommandExitWrapper = 'token=\"$1\"; shift; set +e; \"$@\"; code=$?; printf \"\\\\n[zellij-pty:%s] exit-code=%s\\\\n\" \"$token\" \"$code\"; exit \"$code\"'\nconst shellCommandExitWrapper = 'token=\"$1\"; command=\"$2\"; set +e; bash -lc \"$command\"; code=$?; printf \"\\\\n[zellij-pty:%s] exit-code=%s\\\\n\" \"$token\" \"$code\"; exit \"$code\"'\n\nexport function buildCommandArgv(input: CommandInput, options: BuildCommandArgvOptions = {}): string[] {\n const command = input.command.trim()\n if (!command)\n throw new Error('command is required')\n\n if (options.exitCodeToken) {\n if (input.args && input.args.length > 0) {\n return ['bash', '-lc', directCommandExitWrapper, 'zellij-pty', options.exitCodeToken, command, ...input.args]\n }\n\n return ['bash', '-lc', shellCommandExitWrapper, 'zellij-pty', options.exitCodeToken, command]\n }\n\n if (input.args && input.args.length > 0) {\n return [command, ...input.args]\n }\n\n return ['bash', '-lc', command]\n}\n","import type { CommandInput } from '../utils/shell-args.js'\nimport { execFile, spawnSync } from 'node:child_process'\nimport process from 'node:process'\nimport { promisify } from 'node:util'\nimport { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { parsePaneId } from '../utils/ids.js'\nimport { buildCommandArgv } from '../utils/shell-args.js'\n\nconst execFileAsync = promisify(execFile)\n\nexport type NewPaneOptions = CommandInput & {\n cwd?: string | undefined\n title?: string | undefined\n floating?: boolean | undefined\n exitCodeToken?: string | undefined\n}\n\nexport interface ZellijRunOptions {\n timeoutMs?: number | undefined\n}\n\ninterface ZellijResult {\n stdout: string\n stderr: string\n}\n\nexport function zellijCommandArgs(actionArgs: string[]): string[] {\n const sessionName = process.env.ZELLIJ_SESSION_NAME?.trim()\n if (sessionName)\n return ['--session', sessionName, ...actionArgs]\n return actionArgs\n}\n\nexport function zellijActionArgs(action: string, args: string[] = []): string[] {\n return ['action', action, ...args]\n}\n\nexport function buildNewPaneActionArgs(options: NewPaneOptions): string[] {\n const args = ['action', 'new-pane']\n if (process.env.ZELLIJ)\n args.push('--near-current-pane')\n\n if (options.title)\n args.push('--name', options.title)\n if (options.cwd)\n args.push('--cwd', options.cwd)\n if (options.floating)\n args.push('--floating')\n\n args.push('--', ...buildCommandArgv(options, { exitCodeToken: options.exitCodeToken }))\n return args\n}\n\nexport function buildRenameTabActionArgs(title: string, options: { tabId?: number } = {}): string[] {\n if (options.tabId !== undefined)\n return ['action', 'rename-tab', '--tab-id', String(options.tabId), title]\n return ['action', 'rename-tab', title]\n}\n\nfunction numericProperty(object: Record<string, unknown>, keys: string[]): number | undefined {\n for (const key of keys) {\n const value = object[key]\n if (typeof value === 'number' && Number.isFinite(value))\n return value\n if (typeof value === 'string') {\n const parsed = Number(value)\n if (Number.isInteger(parsed))\n return parsed\n }\n }\n return undefined\n}\n\nfunction paneMatches(object: Record<string, unknown>, paneId: number): boolean {\n const candidate = numericProperty(object, ['id', 'pane_id', 'paneId'])\n return candidate === paneId && object.is_plugin !== true\n}\n\nfunction findPaneTabId(value: unknown, paneId: number): number | undefined {\n if (Array.isArray(value)) {\n for (const item of value) {\n const found = findPaneTabId(item, paneId)\n if (found !== undefined)\n return found\n }\n return undefined\n }\n\n if (typeof value !== 'object' || value === null)\n return undefined\n\n const object = value as Record<string, unknown>\n if (paneMatches(object, paneId))\n return numericProperty(object, ['tab_id', 'tabId'])\n\n for (const nested of Object.values(object)) {\n const found = findPaneTabId(nested, paneId)\n if (found !== undefined)\n return found\n }\n return undefined\n}\n\nexport function parseCurrentPaneTabId(listPanesJson: string, paneId: string | undefined): number | undefined {\n if (!paneId)\n return undefined\n const parsedPaneId = Number(paneId)\n if (!Number.isInteger(parsedPaneId))\n return undefined\n\n try {\n return findPaneTabId(JSON.parse(listPanesJson), parsedPaneId)\n }\n catch (error) {\n debug('parseCurrentPaneTabId failed', errorMessage(error))\n return undefined\n }\n}\n\nexport function ensureZellijTarget(): void {\n if (process.env.ZELLIJ || process.env.ZELLIJ_SESSION_NAME)\n return\n throw new Error('Zellij context not found. Run OpenCode inside Zellij or set ZELLIJ_SESSION_NAME to an existing session.')\n}\n\nasync function runZellij(actionArgs: string[], options: ZellijRunOptions = {}): Promise<ZellijResult> {\n ensureZellijTarget()\n try {\n const result = await execFileAsync('zellij', zellijCommandArgs(actionArgs), {\n encoding: 'utf8',\n timeout: options.timeoutMs ?? 10_000,\n maxBuffer: 20 * 1024 * 1024,\n })\n\n return {\n stdout: result.stdout ?? '',\n stderr: result.stderr ?? '',\n }\n }\n catch (cause) {\n const error = cause as { message?: string, stdout?: string, stderr?: string }\n const stderr = error.stderr?.trim()\n const stdout = error.stdout?.trim()\n const detail = stderr || stdout || error.message || 'unknown error'\n throw new Error(`zellij ${actionArgs.join(' ')} failed: ${detail}`)\n }\n}\n\nexport class ZellijCli {\n async newPane(options: NewPaneOptions): Promise<string> {\n const result = await runZellij(buildNewPaneActionArgs(options))\n return parsePaneId(result.stdout)\n }\n\n async writeChars(paneId: string, data: string): Promise<void> {\n await runZellij(zellijActionArgs('write-chars', ['--pane-id', paneId, data]))\n }\n\n async sendCtrlC(paneId: string): Promise<void> {\n await runZellij(zellijActionArgs('send-keys', ['--pane-id', paneId, 'Ctrl c']))\n }\n\n async closePane(paneId: string): Promise<void> {\n await runZellij(zellijActionArgs('close-pane', ['--pane-id', paneId]))\n }\n\n closePaneSync(paneId: string): void {\n ensureZellijTarget()\n spawnSync('zellij', zellijCommandArgs(zellijActionArgs('close-pane', ['--pane-id', paneId])), {\n encoding: 'utf8',\n stdio: 'ignore',\n timeout: 2_000,\n })\n }\n\n async focusPane(paneId: string): Promise<void> {\n await runZellij(zellijActionArgs('focus-pane-id', [paneId]))\n }\n\n async dumpScreen(paneId: string): Promise<string> {\n const result = await runZellij(zellijActionArgs('dump-screen', ['--pane-id', paneId, '--full']), { timeoutMs: 10_000 })\n return result.stdout\n }\n\n async currentPaneTabId(): Promise<number | undefined> {\n const paneId = process.env.ZELLIJ_PANE_ID\n if (!paneId)\n return undefined\n\n const result = await runZellij(zellijActionArgs('list-panes', ['--json']), { timeoutMs: 5_000 })\n return parseCurrentPaneTabId(result.stdout, paneId)\n }\n\n async renameTab(title: string): Promise<void> {\n const tabId = await this.currentPaneTabId()\n if (tabId === undefined && process.env.ZELLIJ)\n throw new Error(`Could not resolve Zellij tab id for pane ${process.env.ZELLIJ_PANE_ID ?? '<missing>'}`)\n await runZellij(tabId === undefined ? buildRenameTabActionArgs(title) : buildRenameTabActionArgs(title, { tabId }))\n }\n}\n\nexport const zellijCli = new ZellijCli()\n","import type { PtySession } from '../pty/session.js'\nimport { spawn } from 'node:child_process'\nimport { randomUUID } from 'node:crypto'\nimport { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { fileURLToPath } from 'node:url'\nimport { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\n\nexport interface WatchdogPane {\n sessionId: string\n paneId: string\n title: string\n openCodeSessionId: string | null\n createdAt: string\n}\n\nexport interface WatchdogRegistry {\n version: 1\n instanceId: string\n ownerPid: number\n ownerStartTime: string | null\n zellijSessionName: string | null\n panes: WatchdogPane[]\n}\n\nconst instanceId = randomUUID()\nlet watchdogStarted = false\nlet watchdogChild: ReturnType<typeof spawn> | null = null\n\nfunction registryDirectory(): string {\n const base = process.env.XDG_RUNTIME_DIR || tmpdir()\n return path.join(base, `opencode-zellij-${process.getuid?.() ?? 'user'}`)\n}\n\nexport function watchdogRegistryPath(): string {\n return path.join(registryDirectory(), `panes-${process.pid}-${instanceId}.json`)\n}\n\nexport function parseLinuxProcessStartTime(stat: string): string | null {\n const fieldsAfterCommand = stat.slice(stat.lastIndexOf(')') + 2).trim().split(/\\s+/)\n return fieldsAfterCommand[19] ?? null\n}\n\nfunction linuxProcessStartTime(pid: number): string | null {\n try {\n return parseLinuxProcessStartTime(readFileSync(`/proc/${pid}/stat`, 'utf8'))\n }\n catch (error) {\n // Missing /proc data is expected when the owner has exited or on non-Linux systems.\n debug('linuxProcessStartTime failed', errorMessage(error))\n return null\n }\n}\n\nfunction emptyRegistry(): WatchdogRegistry {\n return {\n version: 1,\n instanceId,\n ownerPid: process.pid,\n ownerStartTime: linuxProcessStartTime(process.pid),\n zellijSessionName: process.env.ZELLIJ_SESSION_NAME?.trim() || null,\n panes: [],\n }\n}\n\nfunction readRegistry(): WatchdogRegistry {\n const file = watchdogRegistryPath()\n if (!existsSync(file))\n return emptyRegistry()\n\n try {\n const parsed = JSON.parse(readFileSync(file, 'utf8')) as WatchdogRegistry\n if (parsed.version !== 1 || parsed.instanceId !== instanceId || parsed.ownerPid !== process.pid || !Array.isArray(parsed.panes))\n return emptyRegistry()\n return parsed\n }\n catch (error) {\n // The current instance registry is corrupt or unreadable; start from an empty registry.\n debug('readRegistry failed', errorMessage(error))\n return emptyRegistry()\n }\n}\n\nfunction writeRegistry(registry: WatchdogRegistry): void {\n const directory = registryDirectory()\n mkdirSync(directory, { recursive: true, mode: 0o700 })\n const file = watchdogRegistryPath()\n const tempFile = `${file}.tmp-${process.pid}`\n writeFileSync(tempFile, JSON.stringify(registry, null, 2), { mode: 0o600 })\n renameSync(tempFile, file)\n}\n\nfunction ensureWatchdog(): void {\n if (watchdogStarted && watchdogChild)\n return\n watchdogStarted = true\n\n const child = spawn(process.execPath, [watchdogRunnerPath(), watchdogRegistryPath()], {\n detached: true,\n stdio: 'ignore',\n env: process.env,\n })\n watchdogChild = child\n child.unref()\n child.on('error', () => {\n // Child failed early or was killed; allow watchdog to be restarted on next pane registration.\n watchdogStarted = false\n if (watchdogChild === child)\n watchdogChild = null\n })\n child.on('exit', () => {\n watchdogStarted = false\n if (watchdogChild === child)\n watchdogChild = null\n if (existsSync(watchdogRegistryPath()))\n ensureWatchdog()\n })\n}\n\nfunction watchdogRunnerPath(): string {\n return fileURLToPath(new URL('./pane-watchdog-runner.mjs', import.meta.url))\n}\n\nexport function cleanupStaleWatchdogRegistries(): void {\n const directory = registryDirectory()\n if (!existsSync(directory))\n return\n\n for (const fileName of readdirSync(directory)) {\n if (!fileName.startsWith('panes-') || !fileName.endsWith('.json'))\n continue\n\n const file = path.join(directory, fileName)\n try {\n const registry = JSON.parse(readFileSync(file, 'utf8')) as WatchdogRegistry\n if (registry.version !== 1 || ownerStillMatches(registry))\n continue\n closeRegistryPanes(registry)\n rmSync(file, { force: true })\n }\n catch (error) {\n // Corrupt stale registries cannot be used safely and would otherwise fail every startup.\n debug('cleanupStaleWatchdogRegistries failed', errorMessage(error))\n rmSync(file, { force: true })\n }\n }\n}\n\nfunction ownerStillMatches(registry: WatchdogRegistry): boolean {\n try {\n process.kill(registry.ownerPid, 0)\n }\n catch (error) {\n // process.kill(pid, 0) throws when the owner is gone or inaccessible.\n debug('ownerStillMatches kill check failed', errorMessage(error))\n return false\n }\n\n return !registry.ownerStartTime || linuxProcessStartTime(registry.ownerPid) === registry.ownerStartTime\n}\n\nfunction closeRegistryPanes(registry: WatchdogRegistry): void {\n for (const pane of registry.panes) {\n const args = []\n if (registry.zellijSessionName)\n args.push('--session', registry.zellijSessionName)\n args.push('action', 'close-pane', '--pane-id', pane.paneId)\n spawn('zellij', args, { detached: true, stdio: 'ignore', env: process.env }).unref()\n }\n}\n\nexport function upsertWatchdogPane(registry: WatchdogRegistry, session: PtySession): WatchdogRegistry {\n return {\n ...registry,\n panes: [\n ...registry.panes.filter(pane => pane.sessionId !== session.id && pane.paneId !== session.paneId),\n {\n sessionId: session.id,\n paneId: session.paneId,\n title: session.title,\n openCodeSessionId: session.openCodeSessionId,\n createdAt: session.createdAt,\n },\n ],\n }\n}\n\nexport function removeWatchdogPane(registry: WatchdogRegistry, sessionId: string): WatchdogRegistry {\n return {\n ...registry,\n panes: registry.panes.filter(pane => pane.sessionId !== sessionId),\n }\n}\n\nexport function registerPaneForWatchdog(session: PtySession): void {\n writeRegistry(upsertWatchdogPane(readRegistry(), session))\n ensureWatchdog()\n}\n\nexport function unregisterPaneFromWatchdog(sessionId: string): void {\n const registry = readRegistry()\n const updated = removeWatchdogPane(registry, sessionId)\n if (updated.panes.length === registry.panes.length)\n return\n if (updated.panes.length === 0) {\n removeWatchdogRegistry()\n return\n }\n writeRegistry(updated)\n}\n\nexport function removeWatchdogRegistry(): void {\n try {\n rmSync(watchdogRegistryPath(), { force: true })\n }\n catch (error) {\n // Watchdog registry cleanup is best effort.\n debug('removeWatchdogRegistry failed', errorMessage(error))\n }\n if (!watchdogChild)\n watchdogStarted = false\n}\n","export interface ReadLinesInput {\n offset?: number | undefined\n limit?: number | undefined\n grep?: string | undefined\n ignoreCase?: boolean | undefined\n}\n\nexport interface ReadLinesResult {\n offset: number\n returned: number\n lineCount: number\n lines: string[]\n}\n\nconst escapeCharacter = String.fromCharCode(27)\nconst ansiPattern = new RegExp(`${escapeCharacter}\\\\[[0-9;?]*[a-z]`, 'gi')\n\nfunction normalizeLines(input: string | string[]): string[] {\n const lines = Array.isArray(input) ? input : input.replace(/\\r\\n/g, '\\n').split('\\n')\n if (lines.at(-1) === '')\n return lines.slice(0, -1)\n return lines\n}\n\nfunction stripAnsi(line: string): string {\n return line.replace(ansiPattern, '')\n}\n\nfunction overlapSize(existing: string[], incoming: string[]): number {\n const max = Math.min(existing.length, incoming.length)\n for (let size = max; size > 0; size -= 1) {\n const existingStart = existing.length - size\n let matches = true\n for (let index = 0; index < size; index += 1) {\n if (existing[existingStart + index] !== incoming[index]) {\n matches = false\n break\n }\n }\n if (matches)\n return size\n }\n return 0\n}\n\nexport class RingBuffer {\n private readonly maxLines: number\n private lines: string[] = []\n private totalAppended = 0\n\n constructor(maxLines = 50_000) {\n this.maxLines = Math.max(1, maxLines)\n }\n\n get lineCount(): number {\n return this.totalAppended\n }\n\n get startOffset(): number {\n return Math.max(0, this.totalAppended - this.lines.length)\n }\n\n append(input: string | string[]): number {\n const incoming = normalizeLines(input)\n if (incoming.length === 0)\n return 0\n this.lines.push(...incoming)\n this.totalAppended += incoming.length\n this.trim()\n return incoming.length\n }\n\n appendSnapshot(input: string | string[]): number {\n const incoming = normalizeLines(input)\n if (incoming.length === 0)\n return 0\n const overlap = overlapSize(this.lines, incoming)\n return this.append(incoming.slice(overlap))\n }\n\n read(input: ReadLinesInput = {}): ReadLinesResult {\n const limit = Math.max(1, Math.min(input.limit ?? 200, 5_000))\n const firstReadableOffset = this.startOffset\n const defaultOffset = Math.max(firstReadableOffset, this.lineCount - limit)\n const requestedOffset = input.offset ?? defaultOffset\n const offset = Math.max(firstReadableOffset, Math.min(requestedOffset, this.lineCount))\n const relativeOffset = offset - firstReadableOffset\n const unfiltered = this.lines.slice(relativeOffset, relativeOffset + limit)\n const pattern = input.grep ? new RegExp(input.grep, input.ignoreCase ? 'i' : '') : undefined\n const lines = unfiltered\n .map(stripAnsi)\n .filter(line => (pattern ? pattern.test(line) : true))\n\n return {\n offset,\n returned: lines.length,\n lineCount: this.lineCount,\n lines,\n }\n }\n\n clear(): void {\n this.lines = []\n this.totalAppended = 0\n }\n\n private trim(): void {\n if (this.lines.length <= this.maxLines)\n return\n this.lines = this.lines.slice(this.lines.length - this.maxLines)\n }\n}\n","import { randomUUID } from 'node:crypto'\n\nexport interface ExitCodeMarker {\n token: string\n exitCode: number\n}\n\nconst markerPattern = /^\\[zellij-pty:([a-f0-9]+)\\] exit-code=(\\d+)$/\nconst escapeCharacter = String.fromCharCode(27)\nconst ansiPattern = new RegExp(`${escapeCharacter}\\\\[[0-9;?]*[a-z]`, 'gi')\n\nexport function createExitCodeToken(): string {\n return randomUUID().replaceAll('-', '')\n}\n\nexport function parseExitCodeMarker(line: string): ExitCodeMarker | null {\n const match = line.replace(ansiPattern, '').trim().match(markerPattern)\n if (!match?.[1] || !match[2])\n return null\n return {\n token: match[1],\n exitCode: Number(match[2]),\n }\n}\n","import type { ChildProcessWithoutNullStreams } from 'node:child_process'\nimport type { SessionManager } from '../pty/manager.js'\nimport type { ReadLinesInput, ReadLinesResult } from '../pty/ring-buffer.js'\nimport type { PtySession } from '../pty/session.js'\nimport { spawn } from 'node:child_process'\nimport process from 'node:process'\nimport { sessionManager } from '../pty/manager.js'\nimport { RingBuffer } from '../pty/ring-buffer.js'\nimport { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { parseExitCodeMarker } from '../utils/exit-code.js'\nimport { ensureZellijTarget, zellijCli, zellijCommandArgs } from './cli.js'\nimport { unregisterPaneFromWatchdog } from './pane-watchdog.js'\n\ninterface SubscriberState {\n child: ChildProcessWithoutNullStreams | null\n buffer: RingBuffer\n stderr: string[]\n stdoutRemainder: string\n startedAt: string\n lastExitedAt: string | null\n}\n\ntype JsonObject = Record<string, unknown>\n\nexport interface SubscriberStatus {\n hasBuffer: boolean\n active: boolean\n lastExitedAt: string | null\n}\n\nconst maxStderrLines = 200\n\nfunction splitLines(input: string): string[] {\n const lines = input.replace(/\\r\\n/g, '\\n').split('\\n')\n if (lines.at(-1) === '')\n return lines.slice(0, -1)\n return lines\n}\n\nfunction textFromCell(cell: unknown): string {\n if (typeof cell === 'string')\n return cell\n if (!cell || typeof cell !== 'object')\n return ''\n const object = cell as JsonObject\n const value = object.text ?? object.character ?? object.ch ?? object.content\n return typeof value === 'string' ? value : ''\n}\n\nfunction linesFromRows(rows: unknown[]): string[] {\n return rows.map((row) => {\n if (typeof row === 'string')\n return row\n if (Array.isArray(row))\n return row.map(textFromCell).join('')\n return textFromCell(row)\n })\n}\n\nfunction eventPaneId(event: JsonObject): string | undefined {\n const paneId = event.pane_id ?? event.paneId\n return typeof paneId === 'string' ? paneId : undefined\n}\n\nfunction eventType(event: JsonObject): string | undefined {\n const type = event.event ?? event.type\n return typeof type === 'string' ? type : undefined\n}\n\nfunction extractRenderedLines(event: JsonObject): string[] {\n for (const key of ['viewport', 'scrollback', 'lines'] as const) {\n const value = event[key]\n if (Array.isArray(value))\n return linesFromRows(value)\n }\n\n for (const key of ['text', 'output', 'content'] as const) {\n const value = event[key]\n if (typeof value === 'string')\n return splitLines(value)\n }\n\n return []\n}\n\nexport class SubscriberManager {\n private readonly subscribers = new Map<string, SubscriberState>()\n // Per-session start promises to prevent concurrent spawn races\n private readonly startingSessions = new Map<string, Promise<void>>()\n\n constructor(\n private readonly sessions: SessionManager,\n private readonly maxBufferLines = Number(process.env.PTY_MAX_BUFFER_LINES ?? 50_000),\n ) {}\n\n async start(session: PtySession): Promise<void> {\n const existing = this.subscribers.get(session.id)\n if (existing?.child)\n return\n\n // Prevent concurrent start races for the same session\n const inProgress = this.startingSessions.get(session.id)\n if (inProgress)\n return inProgress\n\n ensureZellijTarget()\n\n const startPromise = this.doStart(session)\n this.startingSessions.set(session.id, startPromise)\n try {\n await startPromise\n }\n finally {\n this.startingSessions.delete(session.id)\n }\n }\n\n private async doStart(session: PtySession): Promise<void> {\n const existing = this.subscribers.get(session.id)\n\n const state: SubscriberState\n = existing\n ?? {\n child: null,\n buffer: new RingBuffer(this.maxBufferLines),\n stderr: [],\n stdoutRemainder: '',\n startedAt: new Date().toISOString(),\n lastExitedAt: null,\n }\n\n if (!existing) {\n this.subscribers.set(session.id, state)\n }\n\n const child = spawn('zellij', zellijCommandArgs(['subscribe', '--pane-id', session.paneId, '--scrollback', '--format', 'json', '--ansi']), {\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n child.stdin.end()\n // Only assign child if state is still the same (no concurrent restart)\n const currentState = this.subscribers.get(session.id)\n if (currentState !== state) {\n child.kill('SIGTERM')\n return\n }\n state.child = child\n state.lastExitedAt = null\n\n child.stdout.setEncoding('utf8')\n child.stdout.on('data', (chunk: string) => this.handleStdout(session.id, child, chunk))\n child.stderr.setEncoding('utf8')\n child.stderr.on('data', (chunk: string) => this.handleStderr(session.id, child, chunk))\n child.on('exit', () => this.handleSubscriberExit(session.id, child))\n child.on('error', error => this.handleSubscriberError(session.id, child, error))\n\n if (!existing) {\n try {\n const snapshot = await zellijCli.dumpScreen(session.paneId)\n if (this.subscribers.get(session.id) !== state || state.child !== child)\n return\n state.buffer.appendSnapshot(snapshot)\n this.sessions.updateLineCount(session.id, state.buffer.lineCount)\n }\n catch (error) {\n // dump-screen may race with pane creation; subscribe will still collect future output.\n debug('dumpScreen failed', errorMessage(error))\n }\n }\n }\n\n read(sessionId: string, input: ReadLinesInput): ReadLinesResult {\n const state = this.subscribers.get(sessionId)\n if (!state)\n throw new Error(`No subscriber buffer exists for session: ${sessionId}`)\n return state.buffer.read(input)\n }\n\n has(sessionId: string): boolean {\n return this.subscribers.has(sessionId)\n }\n\n status(sessionId: string): SubscriberStatus {\n const state = this.subscribers.get(sessionId)\n return {\n hasBuffer: Boolean(state),\n active: Boolean(state?.child),\n lastExitedAt: state?.lastExitedAt ?? null,\n }\n }\n\n stderr(sessionId: string): string[] {\n return this.subscribers.get(sessionId)?.stderr ?? []\n }\n\n stop(sessionId: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state)\n return\n state.child?.kill('SIGTERM')\n state.child = null\n state.lastExitedAt = new Date().toISOString()\n }\n\n forget(sessionId: string): void {\n this.stop(sessionId)\n this.subscribers.delete(sessionId)\n }\n\n stopAll(): void {\n for (const sessionId of this.subscribers.keys()) {\n this.forget(sessionId)\n }\n }\n\n async closeSessionPane(sessionId: string): Promise<void> {\n const session = this.sessions.get(sessionId)\n this.stop(sessionId)\n try {\n await zellijCli.closePane(session.paneId)\n }\n catch (error) {\n // Pane may already be closed by the user or command exit.\n debug('closePane failed', errorMessage(error))\n }\n }\n\n private handleStdout(sessionId: string, child: ChildProcessWithoutNullStreams, chunk: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state || state.child !== child)\n return\n\n const parts = `${state.stdoutRemainder}${chunk}`.split('\\n')\n state.stdoutRemainder = parts.pop() ?? ''\n for (const part of parts) {\n this.handleJsonLine(sessionId, child, part)\n }\n }\n\n private handleJsonLine(sessionId: string, child: ChildProcessWithoutNullStreams, line: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state || state.child !== child)\n return\n const trimmed = line.trim()\n if (!trimmed)\n return\n\n let event: JsonObject\n try {\n const parsed: unknown = JSON.parse(trimmed)\n if (!parsed || typeof parsed !== 'object')\n return\n event = parsed as JsonObject\n }\n catch (error) {\n state.buffer.append(trimmed)\n this.sessions.updateLineCount(sessionId, state.buffer.lineCount)\n debug('JSON parse of subscriber event failed, treating as raw text', errorMessage(error))\n return\n }\n\n let session: PtySession\n try {\n session = this.sessions.get(sessionId)\n }\n catch (error) {\n this.forget(sessionId)\n debug('session lookup by id failed', errorMessage(error))\n return\n }\n const paneId = eventPaneId(event)\n if (paneId && paneId !== session.paneId)\n return\n\n const type = eventType(event)\n if (type === 'pane_closed' || type === 'PaneClosed') {\n state.buffer.append(`[zellij-pty] Pane ${session.paneId} closed at ${new Date().toISOString()}`)\n this.sessions.updateLineCount(sessionId, state.buffer.lineCount)\n this.sessions.updateStatus(sessionId, session.status === 'killed' ? 'killed' : 'exited')\n unregisterPaneFromWatchdog(sessionId)\n this.stop(sessionId)\n return\n }\n\n const lines = extractRenderedLines(event)\n if (lines.length === 0)\n return\n state.buffer.appendSnapshot(lines)\n this.captureExitCode(sessionId, lines)\n this.sessions.updateLineCount(sessionId, state.buffer.lineCount)\n }\n\n private captureExitCode(sessionId: string, lines: string[]): void {\n const session = this.sessions.get(sessionId)\n if (!session.exitCodeToken)\n return\n\n for (const line of lines) {\n const marker = parseExitCodeMarker(line)\n if (!marker || marker.token !== session.exitCodeToken)\n continue\n this.sessions.markExited(sessionId, marker.exitCode)\n return\n }\n }\n\n private handleStderr(sessionId: string, child: ChildProcessWithoutNullStreams, chunk: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state || state.child !== child)\n return\n state.stderr.push(...splitLines(chunk))\n if (state.stderr.length > maxStderrLines) {\n state.stderr = state.stderr.slice(state.stderr.length - maxStderrLines)\n }\n }\n\n private handleSubscriberExit(sessionId: string, child: ChildProcessWithoutNullStreams): void {\n const state = this.subscribers.get(sessionId)\n if (!state)\n return\n if (state.child !== child)\n return\n state.child = null\n state.lastExitedAt = new Date().toISOString()\n state.stderr.push(`[zellij-pty] subscriber exited at ${state.lastExitedAt}; last buffered output is retained.`)\n if (state.stderr.length > maxStderrLines) {\n state.stderr = state.stderr.slice(state.stderr.length - maxStderrLines)\n }\n }\n\n private handleSubscriberError(sessionId: string, child: ChildProcessWithoutNullStreams, error: Error): void {\n const state = this.subscribers.get(sessionId)\n if (state?.child === child) {\n state.stderr.push(error.message)\n state.child = null\n state.lastExitedAt = new Date().toISOString()\n this.sessions.updateStatus(sessionId, 'unknown')\n }\n }\n}\n\nexport const subscriberManager = new SubscriberManager(sessionManager)\n","import type { PtySession } from '../pty/session.js'\n\nexport function publicSession(session: PtySession): Record<string, unknown> {\n return {\n id: session.id,\n paneId: session.paneId,\n title: session.title,\n command: session.command,\n args: session.args,\n cwd: session.cwd,\n status: session.status,\n lineCount: session.lineCount,\n createdAt: session.createdAt,\n updatedAt: session.updatedAt,\n agentWritable: session.allowAgentInput,\n humanInputOnly: session.humanInputOnly,\n exitCode: session.exitCode,\n exitedAt: session.exitedAt,\n }\n}\n\nexport interface NextAdvice {\n retryable: boolean\n reason: string\n}\n\nexport function nextAdvice(retryable: boolean, reason: string): NextAdvice {\n return { retryable, reason }\n}\n\nexport function jsonResponse(value: unknown): string {\n return JSON.stringify(value, null, 2)\n}\n","import { sessionManager } from '../pty/manager.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\n\nexport interface OutputSnapshot {\n text: string\n lines: string[]\n lineCount: number\n returned: number\n truncated: boolean\n}\n\nexport function emptyOutputSnapshot(lineCount = 0): OutputSnapshot {\n return { text: '', lines: [], lineCount, returned: 0, truncated: false }\n}\n\nexport interface OutputOptions {\n maxLines?: number | undefined\n grep?: string | undefined\n ignoreCase?: boolean | undefined\n}\n\nexport function validateGrep(grep: string | undefined): string | null {\n if (!grep)\n return null\n try {\n new RegExp(grep).test('')\n return null\n }\n catch (error) {\n return errorMessage(error)\n }\n}\n\nexport function readOutputSnapshot(sessionId: string, options: OutputOptions = {}): OutputSnapshot {\n const grepError = validateGrep(options.grep)\n if (grepError)\n throw new Error(`Invalid grep regex: ${grepError}`)\n\n const buffered = subscriberManager.read(sessionId, {\n limit: options.maxLines,\n grep: options.grep,\n ignoreCase: options.ignoreCase,\n })\n sessionManager.updateLineCount(sessionId, buffered.lineCount)\n\n return {\n text: buffered.lines.join('\\n'),\n lines: buffered.lines,\n lineCount: buffered.lineCount,\n returned: buffered.returned,\n truncated: buffered.offset > 0,\n }\n}\n\nexport function outputMatches(sessionId: string, grep: string, ignoreCase?: boolean | undefined): boolean {\n return readOutputSnapshot(sessionId, { maxLines: 5_000, grep, ignoreCase }).returned > 0\n}\n","import { setTimeout as delay } from 'node:timers/promises'\nimport { tool } from '@opencode-ai/plugin'\nimport { sessionManager } from '../pty/manager.js'\nimport { zellijCli } from '../zellij/cli.js'\nimport { unregisterPaneFromWatchdog } from '../zellij/pane-watchdog.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { readOutputSnapshot } from './output.js'\n\nconst schema = tool.schema\n\nexport function closeFailureMeansGone(message: string): boolean {\n return /not found|no such|does not exist|already closed|already gone|unknown pane/i.test(message)\n}\n\nexport const zellijPtyKillTool = tool({\n description: 'Terminate a known Zellij PTY session by sending Ctrl-C, then closing its pane.',\n args: {\n id: schema.string().describe('zellij-pty session id.'),\n },\n async execute(args) {\n const session = sessionManager.get(args.id)\n const warnings: string[] = []\n const output = subscriberManager.has(session.id) ? readOutputSnapshot(session.id) : undefined\n try {\n await zellijCli.sendCtrlC(session.paneId)\n await delay(500)\n }\n catch (error) {\n warnings.push(`Ctrl-C failed or pane was already gone: ${error instanceof Error ? error.message : String(error)}`)\n }\n\n try {\n await zellijCli.closePane(session.paneId)\n }\n catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n warnings.push(`close-pane failed: ${message}`)\n if (!closeFailureMeansGone(message)) {\n const updated = sessionManager.updateStatus(session.id, 'unknown')\n return jsonResponse({\n killed: false,\n cleanedUp: false,\n session: publicSession(updated),\n output,\n next: nextAdvice(true, 'close-pane failed and the pane may still be running; the session was kept so kill can be retried.'),\n warnings,\n })\n }\n }\n subscriberManager.stop(session.id)\n subscriberManager.forget(session.id)\n unregisterPaneFromWatchdog(session.id)\n sessionManager.remove(session.id)\n return jsonResponse({ killed: true, cleanedUp: true, id: session.id, paneId: session.paneId, output, next: nextAdvice(false, 'Session was closed and removed from the in-memory registry.'), warnings })\n },\n})\n","import { tool } from '@opencode-ai/plugin'\nimport { sessionManager } from '../pty/manager.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, publicSession } from './format.js'\n\nexport const zellijPtyListTool = tool({\n description: 'List known Zellij pane-backed PTY sessions created by this plugin process for the current OpenCode session.',\n args: {},\n async execute(_args, context) {\n const sessions = sessionManager.listByOpenCodeSession(context.sessionID).map(session => ({\n ...publicSession(session),\n subscriber: subscriberManager.status(session.id),\n }))\n return jsonResponse({ sessions })\n },\n})\n","import { tool } from '@opencode-ai/plugin'\nimport { sessionManager } from '../pty/manager.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { readOutputSnapshot, validateGrep } from './output.js'\n\nconst schema = tool.schema\n\nexport const zellijPtyReadTool = tool({\n description: 'Read recent rendered output from a Zellij PTY session. Supports regex grep filtering.',\n args: {\n id: schema.string().describe('zellij-pty session id.'),\n maxLines: schema.number().int().positive().max(5_000).optional().describe('Maximum recent output lines to return. Defaults to 200.'),\n grep: schema.string().optional().describe('Regex used to filter returned lines.'),\n ignoreCase: schema.boolean().optional().describe('Use case-insensitive regex matching.'),\n },\n async execute(args) {\n const session = sessionManager.get(args.id)\n const grepError = validateGrep(args.grep)\n if (grepError) {\n return jsonResponse({\n session: publicSession(session),\n output: { text: '', lines: [], lineCount: session.lineCount, returned: 0, truncated: false },\n next: nextAdvice(false, `Invalid grep regex: ${grepError}`),\n warnings: [],\n })\n }\n\n const subscriberStatus = subscriberManager.status(session.id)\n if (!subscriberStatus.hasBuffer || (!subscriberStatus.active && (session.status === 'running' || session.status === 'unknown'))) {\n await subscriberManager.start(session)\n }\n const statusAfterStart = subscriberManager.status(session.id)\n const warnings: string[] = []\n if (session.humanInputOnly) {\n warnings.push('This pane is human-input-only: agent writes are forbidden, but rendered output is visible to the agent.')\n }\n if (!statusAfterStart.active) {\n warnings.push('Subscriber is inactive; returned output may be stale.')\n if (session.status === 'running') {\n sessionManager.updateStatus(session.id, 'unknown')\n }\n }\n\n const output = readOutputSnapshot(session.id, { maxLines: args.maxLines, grep: args.grep, ignoreCase: args.ignoreCase })\n\n return jsonResponse({\n session: publicSession(session),\n output,\n next: nextAdvice(session.status !== 'exited' && session.status !== 'killed', nextReadReason(session.status)),\n subscriberActive: statusAfterStart.active,\n subscriberLastExitedAt: statusAfterStart.lastExitedAt,\n subscriberErrors: subscriberManager.stderr(session.id),\n warnings,\n })\n },\n})\n\nfunction nextReadReason(status: string): string {\n if (status === 'running')\n return 'Session is still running; read again later if more output is expected.'\n if (status === 'unknown')\n return 'Session state is unknown because the subscriber is inactive; output may be stale, but retrying read may restart observation.'\n return 'Session is no longer running.'\n}\n","import { randomUUID } from 'node:crypto'\n\nconst generatedInstanceId = randomUUID().replaceAll('-', '').slice(0, 8)\nconst existingOpenCodePrefixPattern = /^oc:[a-z0-9]{4,16}:/i\n\nexport function createOpenCodePaneTitle(title: string, instanceId = generatedInstanceId): string {\n const trimmedTitle = title.trim() || 'opencode'\n if (existingOpenCodePrefixPattern.test(trimmedTitle))\n return trimmedTitle\n\n const safeInstanceId = instanceId.replace(/[^a-z0-9]/gi, '').slice(0, 8) || generatedInstanceId\n return `oc:${safeInstanceId}:${trimmedTitle}`\n}\n","import { tool } from '@opencode-ai/plugin'\nimport { assertSudoPaneAllowed } from '../permissions/sudo-pane.js'\nimport { sessionManager } from '../pty/manager.js'\nimport { createExitCodeToken } from '../utils/exit-code.js'\nimport { createOpenCodePaneTitle } from '../utils/pane-title.js'\nimport { zellijCli } from '../zellij/cli.js'\nimport { registerPaneForWatchdog } from '../zellij/pane-watchdog.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { readOutputSnapshot } from './output.js'\n\nconst schema = tool.schema\n\nexport function shellQuote(value: string): string {\n return `'${value.replaceAll('\\'', `'\"'\"'`)}'`\n}\n\nexport function buildReviewScript(summary: string, scripts: Array<{ command: string, description: string }>): string {\n const lines = [\n 'set +e',\n 'printf \\'%s\\\\n\\' \\'=== OpenCode sudo request ===\\'',\n `printf '%s\\\\n' ${shellQuote(summary)}`,\n 'printf \\'\\\\n%s\\\\n\\' \\'Commands to review:\\'',\n ]\n\n scripts.forEach((script, index) => {\n const number = index + 1\n lines.push(`printf '\\\\n[%s/%s] %s\\\\n' ${shellQuote(String(number))} ${shellQuote(String(scripts.length))} ${shellQuote(script.description)}`)\n lines.push(`printf ' $ %s\\\\n' ${shellQuote(script.command)}`)\n })\n\n lines.push(\n 'printf \\'\\\\n%s\\\\n\\' \\'This pane is human-input-only. The agent cannot type here.\\'',\n 'read -r -p \\'Type YES to run these commands, anything else to cancel: \\' answer',\n 'if [ \"$answer\" != YES ]; then printf \\'%s\\\\n\\' \\'Cancelled by user.\\'; exit 130; fi',\n 'status=0',\n )\n\n scripts.forEach((script, index) => {\n const number = index + 1\n lines.push(`printf '\\\\n[%s/%s] %s\\\\n' ${shellQuote(String(number))} ${shellQuote(String(scripts.length))} ${shellQuote(script.description)}`)\n lines.push(`printf '$ %s\\\\n' ${shellQuote(script.command)}`)\n lines.push(`bash -lc ${shellQuote(script.command)}`)\n lines.push('code=$?')\n lines.push('if [ $code -ne 0 ]; then status=$code; printf \\'Command failed with exit code %s\\\\n\\' \"$code\"; break; fi')\n })\n\n lines.push('exit $status')\n return lines.join('\\n')\n}\n\nexport const requestSudoTool = tool({\n description: 'Open a human-reviewed, human-input-only Zellij pane for sudo or other privileged commands.',\n args: {\n summary: schema.string().min(1).describe('TL;DR of why privileged or human-reviewed execution is needed.'),\n scripts: schema\n .array(\n schema.object({\n command: schema.string().min(1).describe('Command or script to run after the user explicitly approves in the pane.'),\n description: schema.string().min(1).describe('Why this command is needed and what it is expected to change.'),\n }),\n )\n .min(1)\n .describe('Commands shown to the user for review before execution.'),\n },\n async execute(args, context) {\n const cwd = context.directory\n const exitCodeToken = createExitCodeToken()\n assertSudoPaneAllowed()\n\n const command = buildReviewScript(args.summary, args.scripts)\n const title = createOpenCodePaneTitle('zellij_pty_request_sudo')\n const paneId = await zellijCli.newPane({\n command: 'bash',\n args: ['-lc', command],\n cwd,\n title,\n floating: true,\n exitCodeToken,\n })\n\n const warnings: string[] = []\n try {\n await zellijCli.focusPane(paneId)\n }\n catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n if (!message.includes('already focused'))\n throw error\n warnings.push('Pane was already focused after creation.')\n }\n\n const session = sessionManager.create({\n openCodeSessionId: context.sessionID,\n paneId,\n title,\n command: 'zellij_pty_request_sudo',\n args: [],\n cwd,\n allowAgentInput: false,\n humanInputOnly: true,\n exitCodeToken,\n })\n registerPaneForWatchdog(session)\n await subscriberManager.start(session)\n\n return jsonResponse({\n session: publicSession(session),\n output: readOutputSnapshot(session.id),\n next: nextAdvice(false, 'The user must review the summary and commands in Zellij, then type YES and any required credentials directly in the pane.'),\n warnings,\n })\n },\n})\n","import { setTimeout as delay } from 'node:timers/promises'\n\nexport type Probe\n = | { type: 'sleep', seconds?: number | undefined }\n | { type: 'http', url: string, expectStatus?: number | undefined, timeoutSeconds?: number | undefined }\n | { type: 'output', grep: string, ignoreCase?: boolean | undefined, timeoutSeconds?: number | undefined }\n\nexport interface ProbeResult {\n type: Probe['type']\n ok: boolean\n message: string\n elapsedMs: number\n}\n\nexport type OutputProbeReader = (grep: string, ignoreCase: boolean | undefined) => boolean\n\nconst defaultSleepSeconds = 1\nconst defaultProbeTimeoutSeconds = 20\nconst pollIntervalMs = 250\n\nexport async function runProbe(probe: Probe | undefined, outputReader: OutputProbeReader): Promise<ProbeResult> {\n const startedAt = Date.now()\n const effectiveProbe = probe ?? { type: 'sleep', seconds: defaultSleepSeconds }\n\n if (effectiveProbe.type === 'sleep') {\n const seconds = effectiveProbe.seconds ?? defaultSleepSeconds\n await delay(seconds * 1_000)\n return result(effectiveProbe.type, true, `Slept for ${seconds}s.`, startedAt)\n }\n\n if (effectiveProbe.type === 'output') {\n const timeoutSeconds = effectiveProbe.timeoutSeconds ?? defaultProbeTimeoutSeconds\n const deadline = Date.now() + timeoutSeconds * 1_000\n while (Date.now() <= deadline) {\n if (outputReader(effectiveProbe.grep, effectiveProbe.ignoreCase)) {\n return result(effectiveProbe.type, true, `Observed output matching /${effectiveProbe.grep}/.`, startedAt)\n }\n await delay(pollIntervalMs)\n }\n return result(effectiveProbe.type, false, `Timed out after ${timeoutSeconds}s waiting for output matching /${effectiveProbe.grep}/.`, startedAt)\n }\n\n const timeoutSeconds = effectiveProbe.timeoutSeconds ?? defaultProbeTimeoutSeconds\n const deadline = Date.now() + timeoutSeconds * 1_000\n const expectStatus = effectiveProbe.expectStatus\n let lastError = 'no response'\n\n while (Date.now() <= deadline) {\n try {\n const remainingMs = Math.max(1, deadline - Date.now())\n const response = await fetch(effectiveProbe.url, { signal: AbortSignal.timeout(Math.min(remainingMs, 3_000)) })\n const ok = expectStatus === undefined ? response.status >= 200 && response.status < 400 : response.status === expectStatus\n if (ok) {\n const expected = expectStatus === undefined ? '2xx/3xx' : String(expectStatus)\n return result(effectiveProbe.type, true, `HTTP probe ${effectiveProbe.url} returned expected status ${expected}.`, startedAt)\n }\n lastError = `HTTP ${response.status}`\n }\n catch (error) {\n lastError = error instanceof Error ? error.message : String(error)\n }\n await delay(pollIntervalMs)\n }\n\n return result(effectiveProbe.type, false, `Timed out after ${timeoutSeconds}s probing ${effectiveProbe.url}: ${lastError}.`, startedAt)\n}\n\nfunction result(type: Probe['type'], ok: boolean, message: string, startedAt: number): ProbeResult {\n return { type, ok, message, elapsedMs: Date.now() - startedAt }\n}\n","import type { Probe } from '../pty/probe.js'\nimport { tool } from '@opencode-ai/plugin'\nimport { sessionManager } from '../pty/manager.js'\nimport { runProbe } from '../pty/probe.js'\nimport { createExitCodeToken } from '../utils/exit-code.js'\nimport { createOpenCodePaneTitle } from '../utils/pane-title.js'\nimport { zellijCli } from '../zellij/cli.js'\nimport { registerPaneForWatchdog } from '../zellij/pane-watchdog.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { outputMatches, readOutputSnapshot, validateGrep } from './output.js'\n\nconst schema = tool.schema\n\nconst probeSchema = schema.discriminatedUnion('type', [\n schema.object({\n type: schema.literal('sleep'),\n seconds: schema.number().positive().max(300).optional().describe('Seconds to wait before returning initial output. Defaults to 1.'),\n }),\n schema.object({\n type: schema.literal('http'),\n url: schema.string().url().describe('HTTP URL to poll until it returns the expected status.'),\n expectStatus: schema.number().int().min(100).max(599).optional().describe('Expected HTTP status. Defaults to any 2xx/3xx response.'),\n timeoutSeconds: schema.number().positive().max(300).optional().describe('How long to poll before returning a failed probe result. Defaults to 20.'),\n }),\n schema.object({\n type: schema.literal('output'),\n grep: schema.string().describe('Regex to search for in observed pane output.'),\n ignoreCase: schema.boolean().optional().describe('Use case-insensitive regex matching.'),\n timeoutSeconds: schema.number().positive().max(300).optional().describe('How long to wait for matching output. Defaults to 20.'),\n }),\n])\n\nexport const zellijPtySpawnTool = tool({\n description: 'Create a visible Zellij pane and run a command in it.',\n args: {\n command: schema.string().describe('Command to run. Without args, it is executed through bash -lc.'),\n args: schema.array(schema.string()).optional().describe('Optional argv. When provided, command is executed directly without shell parsing.'),\n cwd: schema.string().optional().describe('Working directory for the new pane.'),\n title: schema.string().optional().describe('Pane title/name.'),\n probe: probeSchema.optional().describe('Optional readiness probe. Defaults to a short sleep before returning output.'),\n maxLines: schema.number().int().positive().max(5_000).optional().describe('Maximum recent output lines to return. Defaults to 200.'),\n },\n async execute(args, context) {\n const cwd = args.cwd ?? context.directory\n const exitCodeToken = createExitCodeToken()\n const grepError = args.probe?.type === 'output' ? validateGrep(args.probe.grep) : null\n if (grepError)\n throw new Error(`Invalid probe.grep regex: ${grepError}`)\n const title = createOpenCodePaneTitle(args.title ?? args.command)\n\n const paneId = await zellijCli.newPane({\n command: args.command,\n args: args.args,\n cwd,\n title,\n floating: false,\n exitCodeToken,\n })\n\n const session = sessionManager.create({\n openCodeSessionId: context.sessionID,\n paneId,\n title,\n command: args.command,\n args: args.args,\n cwd,\n allowAgentInput: true,\n humanInputOnly: false,\n exitCodeToken,\n })\n registerPaneForWatchdog(session)\n await subscriberManager.start(session)\n const probe = await runProbe(args.probe as Probe | undefined, (grep, ignoreCase) => outputMatches(session.id, grep, ignoreCase))\n const output = readOutputSnapshot(session.id, { maxLines: args.maxLines })\n\n return jsonResponse({\n session: publicSession(session),\n output,\n probe,\n next: nextAdvice(probe.ok, probe.ok ? 'Probe completed; continue with this session or read later for long-running output.' : probe.message),\n warnings: ['Registry remains in-memory; restarting OpenCode loses plugin session records.'],\n })\n },\n})\n","import { Buffer } from 'node:buffer'\nimport process from 'node:process'\n\nconst defaultMaxWriteBytes = 64 * 1024\nconst defaultChunkBytes = 8 * 1024\n\nexport function maxWriteBytes(): number {\n const configured = Number(process.env.ZELLIJ_PTY_MAX_WRITE_BYTES ?? defaultMaxWriteBytes)\n return Number.isFinite(configured) && configured > 0 ? configured : defaultMaxWriteBytes\n}\n\nexport function assertWriteSizeAllowed(data: string): void {\n const bytes = Buffer.byteLength(data, 'utf8')\n const maxBytes = maxWriteBytes()\n if (bytes > maxBytes) {\n throw new Error(`Write payload is too large: ${bytes} bytes exceeds ${maxBytes} bytes. Split the input into smaller writes.`)\n }\n}\n\nexport function chunkWriteData(data: string, maxChunkBytes = defaultChunkBytes): string[] {\n const chunks: string[] = []\n let current = ''\n let currentBytes = 0\n\n for (const character of data) {\n const characterBytes = Buffer.byteLength(character, 'utf8')\n if (current && currentBytes + characterBytes > maxChunkBytes) {\n chunks.push(current)\n current = ''\n currentBytes = 0\n }\n current += character\n currentBytes += characterBytes\n }\n\n if (current)\n chunks.push(current)\n return chunks\n}\n","import { setTimeout as delay } from 'node:timers/promises'\nimport { tool } from '@opencode-ai/plugin'\nimport { sessionManager } from '../pty/manager.js'\nimport { assertWriteSizeAllowed, chunkWriteData } from '../pty/write-data.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { zellijCli } from '../zellij/cli.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { emptyOutputSnapshot, readOutputSnapshot } from './output.js'\n\nconst schema = tool.schema\n\nexport const zellijPtyWriteTool = tool({\n description: 'Write stdin to a Zellij PTY session. Refuses human-input-only sessions.',\n args: {\n id: schema.string().describe('zellij-pty session id returned by zellij_pty_spawn or zellij_pty_request_sudo.'),\n data: schema.string().describe('Text to write. Use \\u0003 to send Ctrl-C.'),\n maxLines: schema.number().int().positive().max(5_000).optional().describe('Maximum recent output lines to return. Defaults to 200.'),\n interruptAfterSeconds: schema.number().positive().max(300).optional().describe('Blindly send Ctrl-C after this many seconds if the pane is still running; keeps the pane alive.'),\n },\n async execute(args) {\n const session = sessionManager.get(args.id)\n if (session.humanInputOnly || !session.allowAgentInput) {\n return jsonResponse({\n session: publicSession(session),\n output: subscriberManager.has(session.id) ? readOutputSnapshot(session.id, { maxLines: args.maxLines }) : emptyOutputSnapshot(session.lineCount),\n next: nextAdvice(false, 'This session is human-input-only; the user must type directly in the Zellij pane.'),\n warnings: ['Agent writes to human-input-only sessions are forbidden.'],\n })\n }\n\n if (args.data === '\\u0003' || args.data === '\\x03') {\n await zellijCli.sendCtrlC(session.paneId)\n }\n else {\n assertWriteSizeAllowed(args.data)\n for (const chunk of chunkWriteData(args.data)) {\n await zellijCli.writeChars(session.paneId, chunk)\n }\n }\n\n session.updatedAt = new Date().toISOString()\n if (args.interruptAfterSeconds) {\n await delay(args.interruptAfterSeconds * 1_000)\n if (sessionManager.find(session.id)?.status === 'running') {\n await zellijCli.sendCtrlC(session.paneId)\n await delay(500)\n }\n }\n else {\n await delay(1_000)\n }\n\n const warnings: string[] = []\n let output = emptyOutputSnapshot(session.lineCount)\n try {\n output = readOutputSnapshot(session.id, { maxLines: args.maxLines })\n }\n catch (error) {\n warnings.push(`Session output was unavailable before the write response completed: ${errorMessage(error)}`)\n }\n\n return jsonResponse({\n session: publicSession(session),\n output,\n next: nextAdvice(true, args.interruptAfterSeconds ? 'Input was sent; Ctrl-C was sent after the requested interrupt timeout if the session was still running.' : 'Input was sent and recent output was observed.'),\n warnings,\n })\n },\n})\n","import type { SessionManager } from '../pty/manager.js'\nimport type { SubscriberManager } from './subscribe.js'\nimport process from 'node:process'\nimport { sessionManager } from '../pty/manager.js'\nimport { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { zellijCli } from './cli.js'\nimport { subscriberManager } from './subscribe.js'\n\nlet registered = false\nlet cleanedUp = false\n\nexport function cleanupPanesOnShutdown(\n sessions: SessionManager = sessionManager,\n subscribers: SubscriberManager = subscriberManager,\n): void {\n if (cleanedUp)\n return\n cleanedUp = true\n\n for (const session of sessions.list()) {\n try {\n zellijCli.closePaneSync(session.paneId)\n }\n catch (error) {\n // Shutdown cleanup is only a fast best-effort path; the watchdog registry remains as fallback.\n debug('cleanupPanesOnShutdown closePane failed', errorMessage(error))\n }\n\n subscribers.forget(session.id)\n try {\n sessions.remove(session.id)\n }\n catch (error) {\n // Another cleanup path may have already removed it.\n debug('cleanupPanesOnShutdown sessions.remove failed', errorMessage(error))\n }\n }\n}\n\nexport function registerShutdownCleanup(): void {\n if (registered)\n return\n registered = true\n\n process.once('exit', () => cleanupPanesOnShutdown())\n process.once('SIGINT', () => exitAfterCleanup('SIGINT', 130))\n process.once('SIGTERM', () => exitAfterCleanup('SIGTERM', 143))\n process.once('SIGHUP', () => exitAfterCleanup('SIGHUP', 129))\n}\n\nfunction exitAfterCleanup(signal: NodeJS.Signals, code: number): void {\n cleanupPanesOnShutdown()\n process.removeAllListeners(signal)\n process.exit(code)\n}\n","import type { SessionStatus as OpenCodeSessionStatus } from '@opencode-ai/sdk'\nimport { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\n\nconst execFileAsync = promisify(execFile)\n\nexport interface OpenCodeEventLike {\n type: string\n properties: unknown\n}\n\nexport interface TabTitleEventManager {\n updateSessionStatus: (sessionID: string, status: OpenCodeSessionStatus) => void\n markSessionIdle: (sessionID: string) => void\n removeSession: (sessionID: string) => void\n markNeedsInput: (id: string, sessionID: string) => void\n clearNeedsInput: (id: string) => void\n setBranch: (branch: string | undefined) => void\n destroy?: () => void\n}\n\nexport type BranchReader = (worktree: string) => Promise<string>\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null\n}\n\nfunction stringProperty(object: Record<string, unknown>, key: string): string | undefined {\n const value = object[key]\n return typeof value === 'string' ? value : undefined\n}\n\nfunction nestedStringProperty(object: Record<string, unknown>, key: string, nestedKey: string): string | undefined {\n const nested = object[key]\n if (!isRecord(nested))\n return undefined\n return stringProperty(nested, nestedKey)\n}\n\nfunction sessionStatusProperty(object: Record<string, unknown>): OpenCodeSessionStatus | undefined {\n const status = object.status\n if (!isRecord(status))\n return undefined\n\n if (status.type === 'idle' || status.type === 'busy')\n return { type: status.type }\n\n if (status.type === 'retry') {\n return {\n type: 'retry',\n attempt: typeof status.attempt === 'number' ? status.attempt : 0,\n message: typeof status.message === 'string' ? status.message : '',\n next: typeof status.next === 'number' ? status.next : 0,\n }\n }\n\n return undefined\n}\n\nfunction inputRequestID(object: Record<string, unknown>): string | undefined {\n return stringProperty(object, 'id') ?? stringProperty(object, 'requestID') ?? stringProperty(object, 'permissionID')\n}\n\nfunction inputState(object: Record<string, unknown>): string | undefined {\n return (stringProperty(object, 'status') ?? stringProperty(object, 'state') ?? stringProperty(object, 'type'))?.toLowerCase()\n}\n\nfunction isResolvedInputState(state: string | undefined): boolean {\n return state === 'approved' || state === 'denied' || state === 'rejected' || state === 'resolved' || state === 'replied'\n}\n\nexport function deletedSessionID(event: OpenCodeEventLike): string | undefined {\n if (!isRecord(event.properties))\n return undefined\n return nestedStringProperty(event.properties, 'info', 'id') ?? stringProperty(event.properties, 'sessionID')\n}\n\nasync function readGitBranch(worktree: string): Promise<string> {\n const result = await execFileAsync('git', ['-C', worktree, 'branch', '--show-current'], {\n encoding: 'utf8',\n timeout: 1_000,\n maxBuffer: 1024 * 1024,\n })\n return result.stdout\n}\n\nexport async function getInitialBranch(worktree: string, readBranch: BranchReader = readGitBranch): Promise<string | undefined> {\n try {\n return (await readBranch(worktree)).trim() || undefined\n }\n catch (error) {\n debug('getInitialBranch failed', errorMessage(error))\n return undefined\n }\n}\n\nexport function shouldReadInitialBranch(zellij: string | undefined): boolean {\n return Boolean(zellij)\n}\n\nexport function handleTabTitleEvent(tabTitleManager: TabTitleEventManager, event: OpenCodeEventLike): void {\n if (!isRecord(event.properties))\n return\n\n const properties = event.properties\n\n switch (event.type) {\n case 'session.status': {\n const sessionID = stringProperty(properties, 'sessionID')\n const status = sessionStatusProperty(properties)\n if (sessionID && status)\n tabTitleManager.updateSessionStatus(sessionID, status)\n break\n }\n case 'session.idle': {\n const sessionID = stringProperty(properties, 'sessionID')\n if (sessionID)\n tabTitleManager.markSessionIdle(sessionID)\n break\n }\n case 'session.error': {\n const sessionID = stringProperty(properties, 'sessionID')\n if (sessionID)\n tabTitleManager.markSessionIdle(sessionID)\n break\n }\n case 'vcs.branch.updated': {\n tabTitleManager.setBranch(stringProperty(properties, 'branch'))\n break\n }\n case 'question.asked':\n case 'permission.asked': {\n const id = inputRequestID(properties)\n const sessionID = stringProperty(properties, 'sessionID')\n if (id && sessionID)\n tabTitleManager.markNeedsInput(id, sessionID)\n break\n }\n case 'permission.updated': {\n const id = inputRequestID(properties)\n const sessionID = stringProperty(properties, 'sessionID')\n const state = inputState(properties)\n if (id && isResolvedInputState(state))\n tabTitleManager.clearNeedsInput(id)\n else if (id && sessionID)\n tabTitleManager.markNeedsInput(id, sessionID)\n break\n }\n case 'question.replied':\n case 'question.rejected':\n case 'permission.replied': {\n const id = inputRequestID(properties)\n if (id)\n tabTitleManager.clearNeedsInput(id)\n break\n }\n case 'session.deleted': {\n const sessionID = deletedSessionID(event)\n if (sessionID)\n tabTitleManager.removeSession(sessionID)\n break\n }\n case 'server.instance.disposed':\n case 'global.disposed': {\n tabTitleManager.destroy?.()\n break\n }\n }\n}\n","import type { SessionStatus as OpenCodeSessionStatus } from '@opencode-ai/sdk'\nimport process from 'node:process'\nimport { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { ZellijCli } from './cli.js'\n\nexport interface TabTitleCli {\n renameTab: (title: string) => Promise<void>\n}\n\nexport type TabTitleStatus = 'idle' | 'running' | 'needs-input'\n\ntype SessionActivity = 'idle' | 'running'\n\nexport interface TabTitleEmojis {\n idle: string\n running: string\n needsInput: string\n branch: string\n}\n\nexport const defaultTabTitleEmojis: TabTitleEmojis = {\n idle: '🟢',\n running: '⚡',\n needsInput: '💬',\n branch: '🌱',\n}\n\nexport interface TitleContext {\n projectName: string\n branchName: string | undefined\n status: TabTitleStatus\n emojis: TabTitleEmojis\n}\n\nexport function formatTabTitle(context: TitleContext): string {\n const branch = context.branchName ? ` ${context.emojis.branch} ${context.branchName}` : ''\n const emoji = context.emojis[context.status === 'needs-input' ? 'needsInput' : context.status]\n return `${emoji} ${context.projectName}${branch}`\n}\n\nexport function sanitizeTitle(title: string, maxLength = 90): string {\n let cleaned = title\n .replace(/[\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}]/gu, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n\n const chars = Array.from(cleaned)\n if (chars.length > maxLength) {\n cleaned = `${chars.slice(0, maxLength - 1).join('')}…`\n }\n\n return cleaned\n}\n\nexport interface TabTitleManagerOptions {\n projectName: string\n branchName?: string | undefined\n cli?: TabTitleCli\n emojis?: Partial<TabTitleEmojis> | undefined\n debounceMs?: number\n retryInitialMs?: number\n retryMaxMs?: number\n}\n\nexport class TabTitleManager {\n private readonly sessionStatuses = new Map<string, SessionActivity>()\n private readonly pendingInputs = new Map<string, string>()\n private branchName: string | undefined\n private desiredTitle: string | undefined\n private lastSyncedTitle: string | undefined\n private debounceTimer: ReturnType<typeof setTimeout> | undefined\n private retryTimer: ReturnType<typeof setTimeout> | undefined\n private retryAttempt = 0\n private syncInFlight = false\n private readonly debounceMs: number\n private readonly retryInitialMs: number\n private readonly retryMaxMs: number\n private readonly projectName: string\n private readonly cli: TabTitleCli\n private readonly emojis: TabTitleEmojis\n private readonly enabled: boolean\n private destroyed = false\n\n constructor(options: TabTitleManagerOptions) {\n this.projectName = options.projectName\n this.branchName = options.branchName?.trim() || undefined\n this.cli = options.cli ?? new ZellijCli()\n this.emojis = { ...defaultTabTitleEmojis, ...options.emojis }\n this.debounceMs = options.debounceMs ?? 300\n this.retryInitialMs = options.retryInitialMs ?? 250\n this.retryMaxMs = options.retryMaxMs ?? 5_000\n this.enabled = Boolean(process.env.ZELLIJ)\n }\n\n setBranch(branch: string | undefined): void {\n const trimmed = branch?.trim() || undefined\n if (this.branchName === trimmed)\n return\n this.branchName = trimmed\n this.scheduleUpdate()\n }\n\n updateSessionStatus(sessionID: string, status: OpenCodeSessionStatus): void {\n const activity: SessionActivity = status.type === 'idle' ? 'idle' : 'running'\n const existing = this.sessionStatuses.get(sessionID)\n if (existing === activity)\n return\n this.sessionStatuses.set(sessionID, activity)\n this.scheduleUpdate()\n }\n\n markSessionIdle(sessionID: string): void {\n this.updateSessionStatus(sessionID, { type: 'idle' })\n }\n\n removeSession(sessionID: string): void {\n const hadSessionStatus = this.sessionStatuses.delete(sessionID)\n let hadPendingInput = false\n for (const [id, pendingSessionID] of this.pendingInputs) {\n if (pendingSessionID === sessionID) {\n this.pendingInputs.delete(id)\n hadPendingInput = true\n }\n }\n\n if (!hadSessionStatus && !hadPendingInput)\n return\n this.scheduleUpdate()\n }\n\n markNeedsInput(id: string, sessionID: string): void {\n if (this.pendingInputs.get(id) === sessionID)\n return\n this.pendingInputs.set(id, sessionID)\n this.scheduleUpdate()\n }\n\n clearNeedsInput(id: string): void {\n if (!this.pendingInputs.delete(id))\n return\n this.scheduleUpdate()\n }\n\n private get isBusy(): boolean {\n for (const activity of this.sessionStatuses.values()) {\n if (activity === 'running')\n return true\n }\n return false\n }\n\n private get needsInput(): boolean {\n return this.pendingInputs.size > 0\n }\n\n private get status(): TabTitleStatus {\n if (this.needsInput)\n return 'needs-input'\n if (this.isBusy)\n return 'running'\n return 'idle'\n }\n\n private buildTitle(): string {\n const context: TitleContext = {\n projectName: this.projectName,\n branchName: this.branchName,\n status: this.status,\n emojis: this.emojis,\n }\n return sanitizeTitle(formatTabTitle(context))\n }\n\n getCurrentTitle(): string {\n return this.buildTitle()\n }\n\n async renderImmediate(): Promise<void> {\n if (!this.enabled || this.destroyed)\n return\n this.desiredTitle = this.buildTitle()\n this.clearDebounceTimer()\n await this.syncDesiredTitle()\n }\n\n scheduleUpdate(): void {\n if (!this.enabled || this.destroyed)\n return\n const title = this.buildTitle()\n if (title === this.desiredTitle && title === this.lastSyncedTitle)\n return\n this.desiredTitle = title\n\n if (this.syncInFlight)\n return\n\n this.clearRetryTimer()\n this.clearDebounceTimer()\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = undefined\n this.syncDesiredTitle()\n .catch(error => debug('debounced tab title sync failed', errorMessage(error)))\n }, this.debounceMs)\n this.unrefTimer(this.debounceTimer)\n }\n\n private async syncDesiredTitle(): Promise<void> {\n if (!this.enabled || this.destroyed)\n return\n if (this.syncInFlight)\n return\n\n this.syncInFlight = true\n try {\n while (this.desiredTitle && this.desiredTitle !== this.lastSyncedTitle) {\n const title = this.desiredTitle\n try {\n await this.cli.renameTab(title)\n this.lastSyncedTitle = title\n this.retryAttempt = 0\n this.clearRetryTimer()\n }\n catch (cause) {\n debug('Failed to rename Zellij tab.', cause)\n this.scheduleRetry()\n break\n }\n }\n }\n finally {\n this.syncInFlight = false\n }\n }\n\n private scheduleRetry(): void {\n if (!this.enabled || this.destroyed || this.retryTimer || this.desiredTitle === this.lastSyncedTitle)\n return\n\n const delay = Math.min(this.retryMaxMs, this.retryInitialMs * 2 ** this.retryAttempt)\n this.retryAttempt += 1\n this.retryTimer = setTimeout(() => {\n this.retryTimer = undefined\n this.syncDesiredTitle()\n .catch(error => debug('retry tab title sync failed', errorMessage(error)))\n }, delay)\n this.unrefTimer(this.retryTimer)\n }\n\n private clearRetryTimer(): void {\n if (this.retryTimer)\n clearTimeout(this.retryTimer)\n this.retryTimer = undefined\n }\n\n private unrefTimer(timer: ReturnType<typeof setTimeout>): void {\n if (typeof timer === 'object' && timer && 'unref' in timer && typeof timer.unref === 'function')\n timer.unref()\n }\n\n private clearDebounceTimer(): void {\n if (this.debounceTimer)\n clearTimeout(this.debounceTimer)\n this.debounceTimer = undefined\n }\n\n destroy(): void {\n this.destroyed = true\n this.clearDebounceTimer()\n this.clearRetryTimer()\n }\n}\n","import type { Plugin } from '@opencode-ai/plugin'\nimport type { UpdateResult } from './auto-update.js'\nimport type { OpenCodeEventLike } from './zellij/tab-title-events.js'\nimport process from 'node:process'\nimport { checkAndUpdate } from './auto-update.js'\nimport { loadConfig } from './config.js'\nimport { configureSudoPane } from './permissions/sudo-pane.js'\nimport { sessionManager } from './pty/manager.js'\nimport { zellijPtyKillTool } from './tools/kill.js'\nimport { zellijPtyListTool } from './tools/list.js'\nimport { zellijPtyReadTool } from './tools/read.js'\nimport { requestSudoTool } from './tools/request-sudo.js'\nimport { zellijPtySpawnTool } from './tools/spawn.js'\nimport { zellijPtyWriteTool } from './tools/write.js'\nimport { debug } from './utils/debug.js'\nimport { errorMessage } from './utils/errors.js'\nimport { cleanupStaleWatchdogRegistries, unregisterPaneFromWatchdog } from './zellij/pane-watchdog.js'\nimport { registerShutdownCleanup } from './zellij/shutdown-cleanup.js'\nimport { subscriberManager } from './zellij/subscribe.js'\nimport { deletedSessionID, getInitialBranch, handleTabTitleEvent, shouldReadInitialBranch } from './zellij/tab-title-events.js'\nimport { TabTitleManager } from './zellij/tab-title.js'\n\nconst ptyTools = {\n zellij_pty_spawn: zellijPtySpawnTool,\n zellij_pty_list: zellijPtyListTool,\n zellij_pty_write: zellijPtyWriteTool,\n zellij_pty_read: zellijPtyReadTool,\n zellij_pty_kill: zellijPtyKillTool,\n}\n\nfunction getProjectName(path: string): string {\n return path.split(/[/\\\\]/).filter(Boolean).pop() || 'opencode'\n}\n\nfunction getWorkspaceRoot(input: { directory?: string | undefined, worktree?: string | undefined }): string {\n return input.worktree || input.directory || process.cwd()\n}\n\nexport interface ToastClient {\n tui: {\n showToast: (options: {\n body: {\n title: string\n message: string\n variant: 'success' | 'error'\n duration: number\n }\n }) => Promise<unknown>\n }\n}\n\nexport function showUpdateToast(client: ToastClient, result: UpdateResult): void {\n if (result.type === 'updated') {\n client.tui.showToast({\n body: {\n title: 'opencode-zellij updated',\n message: `Updated to ${result.toVersion}. Restart OpenCode to apply the changes.`,\n variant: 'success',\n duration: 10_000,\n },\n })\n .catch(error => debug('show update toast for successful update failed', errorMessage(error)))\n }\n else if (result.type === 'failed') {\n client.tui.showToast({\n body: {\n title: 'opencode-zellij update failed',\n message: `Failed to update to ${result.latestVersion}.`,\n variant: 'error',\n duration: 8_000,\n },\n })\n .catch(error => debug('show update toast for failed update failed', errorMessage(error)))\n }\n}\n\nexport function startAutoUpdateCheck(\n client: ToastClient,\n importMetaUrl: string,\n check: typeof checkAndUpdate = checkAndUpdate,\n): void {\n ;(async () => {\n try {\n showUpdateToast(client, await check({ importMetaUrl }))\n }\n catch (cause) {\n debug('auto-update check failed', errorMessage(cause))\n }\n })()\n}\n\nasync function cleanupStep(stepName: string, sessionId: string, step: () => void | Promise<void>): Promise<void> {\n try {\n await step()\n }\n catch (error) {\n debug(`session.deleted cleanup failed: ${stepName} for ${sessionId}`, errorMessage(error))\n }\n}\n\nasync function cleanupDeletedSession(sessionId: string): Promise<void> {\n await cleanupStep('close pane', sessionId, () => subscriberManager.closeSessionPane(sessionId))\n await cleanupStep('forget subscriber', sessionId, () => subscriberManager.forget(sessionId))\n await cleanupStep('unregister watchdog', sessionId, () => unregisterPaneFromWatchdog(sessionId))\n await cleanupStep('remove session', sessionId, () => sessionManager.remove(sessionId))\n}\n\nexport interface ZellijPtyPluginDependencies {\n importMetaUrl?: string | undefined\n startAutoUpdateCheck?: typeof startAutoUpdateCheck | undefined\n}\n\nexport function createZellijPtyPlugin(dependencies: ZellijPtyPluginDependencies = {}): Plugin {\n return async (input) => {\n const { config, warnings } = await loadConfig(input)\n for (const warning of warnings) {\n debug(warning)\n }\n configureSudoPane(config.pty.sudoPane === 'allow')\n cleanupStaleWatchdogRegistries()\n registerShutdownCleanup()\n\n const workspaceRoot = getWorkspaceRoot(input)\n const projectName = getProjectName(workspaceRoot)\n const branchName = config.tabTitle.enabled && shouldReadInitialBranch(process.env.ZELLIJ) ? await getInitialBranch(workspaceRoot) : undefined\n const tabTitleManager = config.tabTitle.enabled\n ? new TabTitleManager({\n projectName,\n branchName,\n debounceMs: config.tabTitle.debounceMs,\n emojis: {\n idle: config.tabTitle.emojiIdle,\n running: config.tabTitle.emojiRunning,\n needsInput: config.tabTitle.emojiNeedsInput,\n branch: config.tabTitle.emojiBranch,\n },\n })\n : undefined\n\n // Best-effort initial render; no-op when not inside a real Zellij pane.\n tabTitleManager?.renderImmediate()\n .catch(error => debug('initial tab title render failed', errorMessage(error)))\n\n const client = input.client\n\n if (config.autoUpdate)\n (dependencies.startAutoUpdateCheck ?? startAutoUpdateCheck)(client, dependencies.importMetaUrl ?? import.meta.url)\n\n return {\n async event(input) {\n const event: OpenCodeEventLike = input.event\n\n if (tabTitleManager)\n handleTabTitleEvent(tabTitleManager, event)\n\n if (event.type === 'session.deleted') {\n const sessionID = deletedSessionID(event)\n if (!sessionID)\n return\n\n const sessions = sessionManager.listByOpenCodeSession(sessionID)\n await Promise.all(sessions.map(session => cleanupDeletedSession(session.id)))\n }\n },\n tool: config.pty.enabled\n ? {\n ...ptyTools,\n ...(config.pty.sudoPane === 'hide' ? {} : { zellij_pty_request_sudo: requestSudoTool }),\n }\n : {},\n }\n }\n}\n\nexport const ZellijPtyPlugin: Plugin = createZellijPtyPlugin()\n\nexport default ZellijPtyPlugin\n"],"mappings":"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"}
|
|
@@ -4,6 +4,12 @@ import { appendFileSync, existsSync, readFileSync, rmSync } from "node:fs";
|
|
|
4
4
|
//#region src/zellij/pane-watchdog-runner.ts
|
|
5
5
|
const registryPath = process.argv[2];
|
|
6
6
|
const pollIntervalMs = 1e3;
|
|
7
|
+
function writeWatchdogDebug(message, error) {
|
|
8
|
+
if (!process.env.ZELLIJ_PTY_DEBUG) return;
|
|
9
|
+
try {
|
|
10
|
+
appendFileSync(`${registryPath}.log`, `${(/* @__PURE__ */ new Date()).toISOString()} ${message}: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
11
|
+
} catch (loggingError) {}
|
|
12
|
+
}
|
|
7
13
|
if (!registryPath) process.exit(1);
|
|
8
14
|
function sleep(ms) {
|
|
9
15
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -12,7 +18,8 @@ function linuxProcessStartTime(pid) {
|
|
|
12
18
|
try {
|
|
13
19
|
const stat = readFileSync(`/proc/${pid}/stat`, "utf8");
|
|
14
20
|
return stat.slice(stat.lastIndexOf(")") + 2).trim().split(/\s+/)[19] || null;
|
|
15
|
-
} catch {
|
|
21
|
+
} catch (error) {
|
|
22
|
+
writeWatchdogDebug("linuxProcessStartTime failed", error);
|
|
16
23
|
return null;
|
|
17
24
|
}
|
|
18
25
|
}
|
|
@@ -20,14 +27,16 @@ function readRegistry() {
|
|
|
20
27
|
try {
|
|
21
28
|
if (!existsSync(registryPath)) return null;
|
|
22
29
|
return JSON.parse(readFileSync(registryPath, "utf8"));
|
|
23
|
-
} catch {
|
|
30
|
+
} catch (error) {
|
|
31
|
+
writeWatchdogDebug("readRegistry failed", error);
|
|
24
32
|
return null;
|
|
25
33
|
}
|
|
26
34
|
}
|
|
27
35
|
function ownerAlive(registry) {
|
|
28
36
|
try {
|
|
29
37
|
process.kill(registry.ownerPid, 0);
|
|
30
|
-
} catch {
|
|
38
|
+
} catch (error) {
|
|
39
|
+
writeWatchdogDebug("ownerAlive kill check failed", error);
|
|
31
40
|
return false;
|
|
32
41
|
}
|
|
33
42
|
return !registry.ownerStartTime || linuxProcessStartTime(registry.ownerPid) === registry.ownerStartTime;
|
|
@@ -57,7 +66,7 @@ async function main() {
|
|
|
57
66
|
function writeFatalError(error) {
|
|
58
67
|
try {
|
|
59
68
|
appendFileSync(`${registryPath}.log`, `${(/* @__PURE__ */ new Date()).toISOString()} ${error instanceof Error ? error.stack || error.message : String(error)}\n`);
|
|
60
|
-
} catch {}
|
|
69
|
+
} catch (loggingError) {}
|
|
61
70
|
}
|
|
62
71
|
main().catch((error) => {
|
|
63
72
|
writeFatalError(error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pane-watchdog-runner.mjs","names":[],"sources":["../src/zellij/pane-watchdog-runner.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process'\nimport { appendFileSync, existsSync, readFileSync, rmSync } from 'node:fs'\nimport process from 'node:process'\n\ninterface WatchdogPane {\n paneId: string\n}\n\ninterface WatchdogRegistry {\n ownerPid: number\n ownerStartTime?: string | null | undefined\n zellijSessionName?: string | null | undefined\n panes?: WatchdogPane[] | undefined\n}\n\
|
|
1
|
+
{"version":3,"file":"pane-watchdog-runner.mjs","names":[],"sources":["../src/zellij/pane-watchdog-runner.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process'\nimport { appendFileSync, existsSync, readFileSync, rmSync } from 'node:fs'\nimport process from 'node:process'\n\nconst registryPath = process.argv[2]\nconst pollIntervalMs = 1_000\n\nfunction writeWatchdogDebug(message: string, error: unknown): void {\n if (!process.env.ZELLIJ_PTY_DEBUG)\n return\n\n try {\n appendFileSync(`${registryPath}.log`, `${new Date().toISOString()} ${message}: ${error instanceof Error ? error.message : String(error)}\\n`)\n }\n catch (loggingError) {\n void loggingError\n // The watchdog has no stderr; if file logging fails, there is nowhere else to report diagnostics.\n }\n}\n\ninterface WatchdogPane {\n paneId: string\n}\n\ninterface WatchdogRegistry {\n ownerPid: number\n ownerStartTime?: string | null | undefined\n zellijSessionName?: string | null | undefined\n panes?: WatchdogPane[] | undefined\n}\n\nif (!registryPath)\n process.exit(1)\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\nfunction linuxProcessStartTime(pid: number): string | null {\n try {\n const stat = readFileSync(`/proc/${pid}/stat`, 'utf8')\n const fieldsAfterCommand = stat.slice(stat.lastIndexOf(')') + 2).trim().split(/\\s+/)\n return fieldsAfterCommand[19] || null\n }\n catch (error) {\n // Missing /proc data is expected when the owner has exited or on non-Linux systems.\n writeWatchdogDebug('linuxProcessStartTime failed', error)\n return null\n }\n}\n\nfunction readRegistry(): WatchdogRegistry | null {\n try {\n if (!existsSync(registryPath!))\n return null\n return JSON.parse(readFileSync(registryPath!, 'utf8')) as WatchdogRegistry\n }\n catch (error) {\n // A missing or corrupt registry cannot be used safely; let the watchdog exit.\n writeWatchdogDebug('readRegistry failed', error)\n return null\n }\n}\n\nfunction ownerAlive(registry: WatchdogRegistry): boolean {\n try {\n process.kill(registry.ownerPid, 0)\n }\n catch (error) {\n // process.kill(pid, 0) throws when the owner is gone or inaccessible.\n writeWatchdogDebug('ownerAlive kill check failed', error)\n return false\n }\n\n return !registry.ownerStartTime || linuxProcessStartTime(registry.ownerPid) === registry.ownerStartTime\n}\n\nfunction closePane(registry: WatchdogRegistry, paneId: string): void {\n const args: string[] = []\n if (registry.zellijSessionName)\n args.push('--session', registry.zellijSessionName)\n args.push('action', 'close-pane', '--pane-id', paneId)\n spawnSync('zellij', args, { stdio: 'ignore', timeout: 2_000 })\n}\n\nasync function main(): Promise<void> {\n for (;;) {\n const registry = readRegistry()\n if (!registry)\n return\n\n if (!ownerAlive(registry)) {\n const finalRegistry = readRegistry() || registry\n for (const pane of finalRegistry.panes || []) {\n closePane(finalRegistry, pane.paneId)\n }\n rmSync(registryPath!, { force: true })\n return\n }\n\n await sleep(pollIntervalMs)\n }\n}\n\nfunction writeFatalError(error: unknown): void {\n try {\n appendFileSync(`${registryPath}.log`, `${new Date().toISOString()} ${error instanceof Error ? error.stack || error.message : String(error)}\\n`)\n }\n catch (loggingError) {\n void loggingError\n // The watchdog has no stderr; if file logging also fails, exiting is the only safe fallback.\n }\n}\n\nmain().catch((error: unknown) => {\n writeFatalError(error)\n process.exit(1)\n})\n"],"mappings":";;;;AAIA,MAAM,eAAe,QAAQ,KAAK;AAClC,MAAM,iBAAiB;AAEvB,SAAS,mBAAmB,SAAiB,OAAsB;AACjE,KAAI,CAAC,QAAQ,IAAI,iBACf;AAEF,KAAI;AACF,iBAAe,GAAG,aAAa,OAAO,oBAAG,IAAI,MAAM,EAAC,aAAa,CAAC,GAAG,QAAQ,IAAI,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,CAAC,IAAI;UAEvI,cAAc;;AAiBvB,IAAI,CAAC,aACH,SAAQ,KAAK,EAAE;AAEjB,SAAS,MAAM,IAA2B;AACxC,QAAO,IAAI,SAAQ,YAAW,WAAW,SAAS,GAAG,CAAC;;AAGxD,SAAS,sBAAsB,KAA4B;AACzD,KAAI;EACF,MAAM,OAAO,aAAa,SAAS,IAAI,QAAQ,OAAO;AAEtD,SAD2B,KAAK,MAAM,KAAK,YAAY,IAAI,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,MACrD,CAAC,OAAO;UAE5B,OAAO;AAEZ,qBAAmB,gCAAgC,MAAM;AACzD,SAAO;;;AAIX,SAAS,eAAwC;AAC/C,KAAI;AACF,MAAI,CAAC,WAAW,aAAc,CAC5B,QAAO;AACT,SAAO,KAAK,MAAM,aAAa,cAAe,OAAO,CAAC;UAEjD,OAAO;AAEZ,qBAAmB,uBAAuB,MAAM;AAChD,SAAO;;;AAIX,SAAS,WAAW,UAAqC;AACvD,KAAI;AACF,UAAQ,KAAK,SAAS,UAAU,EAAE;UAE7B,OAAO;AAEZ,qBAAmB,gCAAgC,MAAM;AACzD,SAAO;;AAGT,QAAO,CAAC,SAAS,kBAAkB,sBAAsB,SAAS,SAAS,KAAK,SAAS;;AAG3F,SAAS,UAAU,UAA4B,QAAsB;CACnE,MAAM,OAAiB,EAAE;AACzB,KAAI,SAAS,kBACX,MAAK,KAAK,aAAa,SAAS,kBAAkB;AACpD,MAAK,KAAK,UAAU,cAAc,aAAa,OAAO;AACtD,WAAU,UAAU,MAAM;EAAE,OAAO;EAAU,SAAS;EAAO,CAAC;;AAGhE,eAAe,OAAsB;AACnC,UAAS;EACP,MAAM,WAAW,cAAc;AAC/B,MAAI,CAAC,SACH;AAEF,MAAI,CAAC,WAAW,SAAS,EAAE;GACzB,MAAM,gBAAgB,cAAc,IAAI;AACxC,QAAK,MAAM,QAAQ,cAAc,SAAS,EAAE,CAC1C,WAAU,eAAe,KAAK,OAAO;AAEvC,UAAO,cAAe,EAAE,OAAO,MAAM,CAAC;AACtC;;AAGF,QAAM,MAAM,eAAe;;;AAI/B,SAAS,gBAAgB,OAAsB;AAC7C,KAAI;AACF,iBAAe,GAAG,aAAa,OAAO,oBAAG,IAAI,MAAM,EAAC,aAAa,CAAC,GAAG,iBAAiB,QAAQ,MAAM,SAAS,MAAM,UAAU,OAAO,MAAM,CAAC,IAAI;UAE1I,cAAc;;AAMvB,MAAM,CAAC,OAAO,UAAmB;AAC/B,iBAAgB,MAAM;AACtB,SAAQ,KAAK,EAAE;EACf"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-zellij",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.9",
|
|
5
5
|
"description": "OpenCode plugin for Zellij-backed panes and workflow integrations.",
|
|
6
|
+
"license": "MIT",
|
|
6
7
|
"repository": {
|
|
7
8
|
"type": "git",
|
|
8
9
|
"url": "https://github.com/maou-shonen/opencode-zellij"
|