opencode-zellij 0.0.2 → 0.0.3
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/README.md +3 -0
- package/README.zh.md +3 -0
- package/dist/index.mjs +160 -26
- package/dist/index.mjs.map +1 -1
- package/dist/pane-watchdog-runner.mjs +1 -1
- package/package.json +7 -5
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# opencode-zellij
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/opencode-zellij)
|
|
4
|
+
[](https://github.com/maou-shonen/opencode-zellij/actions/workflows/ci.yml)
|
|
5
|
+
|
|
3
6
|
[正體中文](README.zh.md)
|
|
4
7
|
|
|
5
8
|
Give OpenCode a way to use visible Zellij panes for work that should not disappear into a one-shot tool call.
|
package/README.zh.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# opencode-zellij
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/opencode-zellij)
|
|
4
|
+
[](https://github.com/maou-shonen/opencode-zellij/actions/workflows/ci.yml)
|
|
5
|
+
|
|
3
6
|
[English](README.md)
|
|
4
7
|
|
|
5
8
|
讓 OpenCode 可以使用可見的 Zellij panes,處理不適合消失在一次性 tool call 裡的工作。
|
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,131 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { homedir, tmpdir } from "node:os";
|
|
5
|
+
import path, { join } from "node:path";
|
|
6
|
+
import { parseJSON, parseJSONC } from "confbox";
|
|
7
|
+
import { z } from "zod";
|
|
2
8
|
import { randomUUID } from "node:crypto";
|
|
3
9
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
4
10
|
import { tool } from "@opencode-ai/plugin";
|
|
5
11
|
import { execFile, spawn, spawnSync } from "node:child_process";
|
|
6
12
|
import { promisify } from "node:util";
|
|
7
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
8
|
-
import { tmpdir } from "node:os";
|
|
9
|
-
import path from "node:path";
|
|
10
13
|
import { fileURLToPath } from "node:url";
|
|
11
14
|
import { Buffer } from "node:buffer";
|
|
15
|
+
//#region src/config.ts
|
|
16
|
+
const sudoPaneSchema = z.enum([
|
|
17
|
+
"allow",
|
|
18
|
+
"deny",
|
|
19
|
+
"hide"
|
|
20
|
+
]);
|
|
21
|
+
const configFilenames = ["opencode-zellij.config.jsonc", "opencode-zellij.config.json"];
|
|
22
|
+
const tabTitleLayerSchema = z.object({
|
|
23
|
+
enabled: z.boolean().optional().describe("Enable dynamic Zellij tab title updates."),
|
|
24
|
+
emojiIdle: z.string().optional().describe("Prefix used when OpenCode is idle."),
|
|
25
|
+
emojiRunning: z.string().optional().describe("Prefix used while OpenCode is running work."),
|
|
26
|
+
emojiNeedsInput: z.string().optional().describe("Prefix used when OpenCode is waiting for human input."),
|
|
27
|
+
emojiBranch: z.string().optional().describe("Prefix used before the current git branch name."),
|
|
28
|
+
debounceMs: z.number().finite().min(0).optional().describe("Debounce time for tab title updates in milliseconds.")
|
|
29
|
+
}).strict();
|
|
30
|
+
const ptyLayerSchema = z.object({
|
|
31
|
+
enabled: z.boolean().optional().describe("Enable Zellij-backed PTY tools."),
|
|
32
|
+
sudoPane: sudoPaneSchema.optional().describe("Controls whether the sudo pane tool is available, denied, or hidden.")
|
|
33
|
+
}).strict();
|
|
34
|
+
const sidecarConfigSchema = z.object({
|
|
35
|
+
$schema: z.string().optional().describe("JSON Schema URI for editor completion."),
|
|
36
|
+
tabTitle: tabTitleLayerSchema.optional(),
|
|
37
|
+
pty: ptyLayerSchema.optional()
|
|
38
|
+
}).strict();
|
|
39
|
+
const defaultConfig = {
|
|
40
|
+
tabTitle: {
|
|
41
|
+
enabled: true,
|
|
42
|
+
emojiIdle: "🟢",
|
|
43
|
+
emojiRunning: "⚡",
|
|
44
|
+
emojiNeedsInput: "💬",
|
|
45
|
+
emojiBranch: "🌱",
|
|
46
|
+
debounceMs: 300
|
|
47
|
+
},
|
|
48
|
+
pty: {
|
|
49
|
+
enabled: true,
|
|
50
|
+
sudoPane: "allow"
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
function validConfigLayer(value) {
|
|
54
|
+
const result = sidecarConfigSchema.safeParse(value);
|
|
55
|
+
if (!result.success) return void 0;
|
|
56
|
+
return {
|
|
57
|
+
tabTitle: result.data.tabTitle,
|
|
58
|
+
pty: result.data.pty
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function mergeConfig(user, project) {
|
|
62
|
+
return {
|
|
63
|
+
tabTitle: {
|
|
64
|
+
enabled: project?.tabTitle?.enabled ?? user?.tabTitle?.enabled ?? defaultConfig.tabTitle.enabled,
|
|
65
|
+
emojiIdle: project?.tabTitle?.emojiIdle ?? user?.tabTitle?.emojiIdle ?? defaultConfig.tabTitle.emojiIdle,
|
|
66
|
+
emojiRunning: project?.tabTitle?.emojiRunning ?? user?.tabTitle?.emojiRunning ?? defaultConfig.tabTitle.emojiRunning,
|
|
67
|
+
emojiNeedsInput: project?.tabTitle?.emojiNeedsInput ?? user?.tabTitle?.emojiNeedsInput ?? defaultConfig.tabTitle.emojiNeedsInput,
|
|
68
|
+
emojiBranch: project?.tabTitle?.emojiBranch ?? user?.tabTitle?.emojiBranch ?? defaultConfig.tabTitle.emojiBranch,
|
|
69
|
+
debounceMs: project?.tabTitle?.debounceMs ?? user?.tabTitle?.debounceMs ?? defaultConfig.tabTitle.debounceMs
|
|
70
|
+
},
|
|
71
|
+
pty: {
|
|
72
|
+
enabled: project?.pty?.enabled ?? user?.pty?.enabled ?? defaultConfig.pty.enabled,
|
|
73
|
+
sudoPane: project?.pty?.sudoPane ?? user?.pty?.sudoPane ?? defaultConfig.pty.sudoPane
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
async function loadConfigLayer(directory, warnings) {
|
|
78
|
+
const configFile = detectConfigFile(directory);
|
|
79
|
+
if (!configFile) return {};
|
|
80
|
+
try {
|
|
81
|
+
const text = await readFile(configFile, "utf8");
|
|
82
|
+
const layer = validConfigLayer(configFile.endsWith(".jsonc") ? parseJSONC(text) : parseJSON(text));
|
|
83
|
+
if (!layer) {
|
|
84
|
+
warnings.push(`Ignoring invalid config shape in ${configFile}.`);
|
|
85
|
+
return { source: configFile };
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
layer,
|
|
89
|
+
source: configFile
|
|
90
|
+
};
|
|
91
|
+
} catch (cause) {
|
|
92
|
+
warnings.push(`Ignoring unreadable or invalid config file ${configFile}: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
93
|
+
return {};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function detectConfigFile(directory) {
|
|
97
|
+
return configFilenames.map((filename) => join(directory, filename)).find((path) => existsSync(path));
|
|
98
|
+
}
|
|
99
|
+
function userConfigDir() {
|
|
100
|
+
return process.env.XDG_CONFIG_HOME ? join(process.env.XDG_CONFIG_HOME, "opencode") : join(homedir(), ".config", "opencode");
|
|
101
|
+
}
|
|
102
|
+
function projectConfigDirs(input) {
|
|
103
|
+
const dirs = [];
|
|
104
|
+
if (input.worktree) dirs.push(join(input.worktree, ".opencode"));
|
|
105
|
+
if (input.directory && input.directory !== input.worktree) dirs.push(join(input.directory, ".opencode"));
|
|
106
|
+
return dirs;
|
|
107
|
+
}
|
|
108
|
+
async function loadConfig(input) {
|
|
109
|
+
const warnings = [];
|
|
110
|
+
const sources = {};
|
|
111
|
+
const userResult = await loadConfigLayer(userConfigDir(), warnings);
|
|
112
|
+
const userLayer = userResult.layer;
|
|
113
|
+
if (userResult.source && userLayer) sources.user = userResult.source;
|
|
114
|
+
let projectLayer;
|
|
115
|
+
for (const projectDir of projectConfigDirs(input)) {
|
|
116
|
+
const projectResult = await loadConfigLayer(projectDir, warnings);
|
|
117
|
+
if (!projectResult.source) continue;
|
|
118
|
+
projectLayer = projectResult.layer;
|
|
119
|
+
if (projectLayer) sources.project = projectResult.source;
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
config: mergeConfig(userLayer, projectLayer),
|
|
124
|
+
sources,
|
|
125
|
+
warnings
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
//#endregion
|
|
12
129
|
//#region src/utils/shell-args.ts
|
|
13
130
|
const directCommandExitWrapper = "token=\"$1\"; shift; set +e; \"$@\"; code=$?; printf \"\\n[zellij-pty:%s] exit-code=%s\\n\" \"$token\" \"$code\"; exit \"$code\"";
|
|
14
131
|
const shellCommandExitWrapper = "token=\"$1\"; command=\"$2\"; set +e; bash -lc \"$command\"; code=$?; printf \"\\n[zellij-pty:%s] exit-code=%s\\n\" \"$token\" \"$code\"; exit \"$code\"";
|
|
@@ -67,6 +184,9 @@ function wildcardMatches(pattern, commandLine) {
|
|
|
67
184
|
return new RegExp(`^${pattern.split("*").map(escapeRegex).join(".*")}$`).test(commandLine);
|
|
68
185
|
}
|
|
69
186
|
function configurePolicy(config) {
|
|
187
|
+
configuredDenyCommands = [];
|
|
188
|
+
configuredAllowCommands = [];
|
|
189
|
+
allowSudoPane = true;
|
|
70
190
|
if (!config || typeof config !== "object") return;
|
|
71
191
|
const object = config;
|
|
72
192
|
if (isStringArray(object.denyCommands)) configuredDenyCommands = object.denyCommands;
|
|
@@ -79,7 +199,7 @@ function assertCommandAllowed(input) {
|
|
|
79
199
|
for (const pattern of configuredDenyCommands) if (wildcardMatches(pattern, commandLine)) throw new Error(`Command denied by zellij-pty configured deny rule: ${commandLine}`);
|
|
80
200
|
if (configuredAllowCommands.length > 0 && !configuredAllowCommands.some((pattern) => wildcardMatches(pattern, commandLine))) throw new Error(`Command denied by zellij-pty allow list: ${commandLine}`);
|
|
81
201
|
if (!input.humanInputOnly && sudoPattern.test(commandLine)) throw new Error("sudo commands must use zellij_pty_request_sudo so credentials stay human-input-only and never pass through agent tool input.");
|
|
82
|
-
if (input.humanInputOnly &&
|
|
202
|
+
if (input.humanInputOnly && !allowSudoPane) throw new Error("sudo pane is disabled by zellij-pty policy.");
|
|
83
203
|
}
|
|
84
204
|
//#endregion
|
|
85
205
|
//#region src/utils/ids.ts
|
|
@@ -1180,6 +1300,12 @@ const zellijPtyWriteTool = tool({
|
|
|
1180
1300
|
}
|
|
1181
1301
|
});
|
|
1182
1302
|
//#endregion
|
|
1303
|
+
//#region src/utils/debug.ts
|
|
1304
|
+
function debug(message, ...details) {
|
|
1305
|
+
if (!process.env.ZELLIJ_PTY_DEBUG) return;
|
|
1306
|
+
console.warn(`[opencode-zellij] ${message}`, ...details);
|
|
1307
|
+
}
|
|
1308
|
+
//#endregion
|
|
1183
1309
|
//#region src/zellij/shutdown-cleanup.ts
|
|
1184
1310
|
let registered = false;
|
|
1185
1311
|
let cleanedUp = false;
|
|
@@ -1305,12 +1431,6 @@ function handleTabTitleEvent(tabTitleManager, event) {
|
|
|
1305
1431
|
}
|
|
1306
1432
|
}
|
|
1307
1433
|
//#endregion
|
|
1308
|
-
//#region src/utils/debug.ts
|
|
1309
|
-
function debug(message, ...details) {
|
|
1310
|
-
if (!process.env.ZELLIJ_PTY_DEBUG) return;
|
|
1311
|
-
console.warn(`[opencode-zellij] ${message}`, ...details);
|
|
1312
|
-
}
|
|
1313
|
-
//#endregion
|
|
1314
1434
|
//#region src/zellij/tab-title.ts
|
|
1315
1435
|
const defaultTabTitleEmojis = {
|
|
1316
1436
|
idle: "🟢",
|
|
@@ -1456,26 +1576,44 @@ var TabTitleManager = class {
|
|
|
1456
1576
|
};
|
|
1457
1577
|
//#endregion
|
|
1458
1578
|
//#region src/plugin.ts
|
|
1579
|
+
const ptyTools = {
|
|
1580
|
+
zellij_pty_spawn: zellijPtySpawnTool,
|
|
1581
|
+
zellij_pty_list: zellijPtyListTool,
|
|
1582
|
+
zellij_pty_write: zellijPtyWriteTool,
|
|
1583
|
+
zellij_pty_read: zellijPtyReadTool,
|
|
1584
|
+
zellij_pty_kill: zellijPtyKillTool
|
|
1585
|
+
};
|
|
1459
1586
|
function getProjectName(path) {
|
|
1460
1587
|
return path.split(/[/\\]/).filter(Boolean).pop() || "opencode";
|
|
1461
1588
|
}
|
|
1462
1589
|
function getWorkspaceRoot(input) {
|
|
1463
1590
|
return input.worktree || input.directory || process.cwd();
|
|
1464
1591
|
}
|
|
1465
|
-
const ZellijPtyPlugin = async (input
|
|
1466
|
-
|
|
1592
|
+
const ZellijPtyPlugin = async (input) => {
|
|
1593
|
+
const { config, warnings } = await loadConfig(input);
|
|
1594
|
+
for (const warning of warnings) debug(warning);
|
|
1595
|
+
configurePolicy({ allowSudoPane: config.pty.sudoPane === "allow" });
|
|
1467
1596
|
cleanupStaleWatchdogRegistries();
|
|
1468
1597
|
registerShutdownCleanup();
|
|
1469
1598
|
const workspaceRoot = getWorkspaceRoot(input);
|
|
1470
|
-
const
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1599
|
+
const projectName = getProjectName(workspaceRoot);
|
|
1600
|
+
const branchName = config.tabTitle.enabled && shouldReadInitialBranch(process.env.ZELLIJ) ? await getInitialBranch(workspaceRoot) : void 0;
|
|
1601
|
+
const tabTitleManager = config.tabTitle.enabled ? new TabTitleManager({
|
|
1602
|
+
projectName,
|
|
1603
|
+
branchName,
|
|
1604
|
+
debounceMs: config.tabTitle.debounceMs,
|
|
1605
|
+
emojis: {
|
|
1606
|
+
idle: config.tabTitle.emojiIdle,
|
|
1607
|
+
running: config.tabTitle.emojiRunning,
|
|
1608
|
+
needsInput: config.tabTitle.emojiNeedsInput,
|
|
1609
|
+
branch: config.tabTitle.emojiBranch
|
|
1610
|
+
}
|
|
1611
|
+
}) : void 0;
|
|
1612
|
+
tabTitleManager?.renderImmediate().catch(() => {});
|
|
1475
1613
|
return {
|
|
1476
1614
|
async event(input) {
|
|
1477
1615
|
const event = input.event;
|
|
1478
|
-
handleTabTitleEvent(tabTitleManager, event);
|
|
1616
|
+
if (tabTitleManager) handleTabTitleEvent(tabTitleManager, event);
|
|
1479
1617
|
if (event.type === "session.deleted") {
|
|
1480
1618
|
const sessionID = deletedSessionID(event);
|
|
1481
1619
|
if (!sessionID) return;
|
|
@@ -1488,14 +1626,10 @@ const ZellijPtyPlugin = async (input, options) => {
|
|
|
1488
1626
|
}));
|
|
1489
1627
|
}
|
|
1490
1628
|
},
|
|
1491
|
-
tool: {
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
zellij_pty_read: zellijPtyReadTool,
|
|
1496
|
-
zellij_pty_kill: zellijPtyKillTool,
|
|
1497
|
-
zellij_pty_request_sudo: requestSudoTool
|
|
1498
|
-
}
|
|
1629
|
+
tool: config.pty.enabled ? {
|
|
1630
|
+
...ptyTools,
|
|
1631
|
+
...config.pty.sudoPane === "hide" ? {} : { zellij_pty_request_sudo: requestSudoTool }
|
|
1632
|
+
} : {}
|
|
1499
1633
|
};
|
|
1500
1634
|
};
|
|
1501
1635
|
//#endregion
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["execFileAsync","ansiPattern","schema","delay","schema","schema","delay","schema","delay"],"sources":["../src/utils/shell-args.ts","../src/permissions/policy.ts","../src/utils/ids.ts","../src/pty/manager.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/utils/debug.ts","../src/zellij/tab-title.ts","../src/plugin.ts"],"sourcesContent":["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\nexport function commandLineForPolicy(input: CommandInput): string {\n if (!input.args || input.args.length === 0)\n return input.command.trim()\n return [input.command, ...input.args].join(' ').trim()\n}\n","import type { CommandInput } from '../utils/shell-args.js'\nimport { commandLineForPolicy } from '../utils/shell-args.js'\n\nexport interface PolicyConfig {\n denyCommands?: string[] | undefined\n allowCommands?: string[] | undefined\n allowSudoPane?: boolean | undefined\n}\n\nconst denyPatterns: RegExp[] = [\n /(^|\\s)rm\\s+-[^\\n&;r|]*r[^\\n&;|]*f\\s+\\//,\n /(^|\\s)mkfs(?:\\s|$)/,\n /(^|\\s)dd\\s+(?:[^\\s&;|][^\\n;|&]*)?\\bof=\\/dev\\//,\n /:\\(\\)\\s*\\{\\s*:\\|:\\s*&\\s*\\}\\s*;/,\n]\n\nconst sudoPattern = /(?:^|[\\s;&|])sudo(?:[\\s;&|]|$)/\n\nlet configuredDenyCommands: string[] = []\nlet configuredAllowCommands: string[] = []\nlet allowSudoPane = true\n\nexport type PolicyCheckInput = CommandInput & {\n humanInputOnly?: boolean | undefined\n}\n\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every(item => typeof item === 'string')\n}\n\nfunction escapeRegex(value: string): string {\n return value.replace(/[|\\\\{}()[\\]^$+?.]/g, '\\\\$&')\n}\n\nfunction wildcardMatches(pattern: string, commandLine: string): boolean {\n const regex = new RegExp(`^${pattern.split('*').map(escapeRegex).join('.*')}$`)\n return regex.test(commandLine)\n}\n\nexport function configurePolicy(config: unknown): void {\n if (!config || typeof config !== 'object')\n return\n const object = config as Record<string, unknown>\n if (isStringArray(object.denyCommands))\n configuredDenyCommands = object.denyCommands\n if (isStringArray(object.allowCommands))\n configuredAllowCommands = object.allowCommands\n if (typeof object.allowSudoPane === 'boolean')\n allowSudoPane = object.allowSudoPane\n}\n\nexport function assertCommandAllowed(input: PolicyCheckInput): void {\n const commandLine = commandLineForPolicy(input)\n for (const pattern of denyPatterns) {\n if (pattern.test(commandLine)) {\n throw new Error(`Command denied by zellij-pty policy: ${commandLine}`)\n }\n }\n\n for (const pattern of configuredDenyCommands) {\n if (wildcardMatches(pattern, commandLine)) {\n throw new Error(`Command denied by zellij-pty configured deny rule: ${commandLine}`)\n }\n }\n\n if (configuredAllowCommands.length > 0 && !configuredAllowCommands.some(pattern => wildcardMatches(pattern, commandLine))) {\n throw new Error(`Command denied by zellij-pty allow list: ${commandLine}`)\n }\n\n if (!input.humanInputOnly && sudoPattern.test(commandLine)) {\n throw new Error('sudo commands must use zellij_pty_request_sudo so credentials stay human-input-only and never pass through agent tool input.')\n }\n\n if (input.humanInputOnly && sudoPattern.test(commandLine) && !allowSudoPane) {\n throw new Error('sudo pane is disabled by zellij-pty policy.')\n }\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 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","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): string[] {\n return ['action', 'rename-tab', title]\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 renameTab(title: string): Promise<void> {\n await runZellij(buildRenameTabActionArgs(title))\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\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)\n return\n watchdogStarted = true\n\n const child = spawn('node', [watchdogRunnerPath(), watchdogRegistryPath()], {\n detached: true,\n stdio: 'ignore',\n env: process.env,\n })\n child.unref()\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}\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\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 ensureZellijTarget()\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 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 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 state.child = child\n state.lastExitedAt = null\n\n child.stdout.setEncoding('utf8')\n child.stdout.on('data', (chunk: string) => this.handleStdout(session.id, chunk))\n child.stderr.setEncoding('utf8')\n child.stderr.on('data', (chunk: string) => this.handleStderr(session.id, chunk))\n child.on('exit', () => this.handleSubscriberExit(session.id))\n child.on('error', error => this.handleSubscriberError(session.id, 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, chunk: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state)\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, part)\n }\n }\n\n private handleJsonLine(sessionId: string, line: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state)\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 const session = this.sessions.get(sessionId)\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, chunk: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state)\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): void {\n const state = this.subscribers.get(sessionId)\n if (!state)\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, error: Error): void {\n const state = this.subscribers.get(sessionId)\n if (state)\n state.stderr.push(error.message)\n this.sessions.updateStatus(sessionId, 'unknown')\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 { 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 error instanceof Error ? error.message : String(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 if (!subscriberManager.has(session.id)) {\n await subscriberManager.start(session)\n }\n const subscriberStatus = 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 (!subscriberStatus.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: subscriberStatus.active,\n subscriberLastExitedAt: subscriberStatus.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 { assertCommandAllowed } from '../permissions/policy.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 for (const script of args.scripts) {\n assertCommandAllowed({ command: script.command, humanInputOnly: true })\n }\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 { assertCommandAllowed } from '../permissions/policy.js'\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 assertCommandAllowed({ command: args.command, args: args.args, humanInputOnly: false })\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 { 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.get(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 return jsonResponse({\n session: publicSession(session),\n output: readOutputSnapshot(session.id, { maxLines: args.maxLines }),\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}\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\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 'vcs.branch.updated': {\n tabTitleManager.setBranch(stringProperty(properties, 'branch'))\n break\n }\n case 'question.asked':\n case 'permission.asked':\n case 'permission.updated': {\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 '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 }\n}\n","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 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}\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 syncInFlight = false\n private readonly debounceMs: number\n private readonly projectName: string\n private readonly cli: TabTitleCli\n private readonly emojis: TabTitleEmojis\n private readonly enabled: boolean\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.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)\n return\n this.desiredTitle = this.buildTitle()\n this.clearDebounceTimer()\n await this.syncDesiredTitle()\n }\n\n scheduleUpdate(): void {\n if (!this.enabled)\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.clearDebounceTimer()\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = undefined\n this.syncDesiredTitle().catch(() => {})\n }, this.debounceMs)\n }\n\n private async syncDesiredTitle(): Promise<void> {\n if (!this.enabled)\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 }\n catch (cause) {\n debug('Failed to rename Zellij tab.', cause)\n break\n }\n }\n }\n finally {\n this.syncInFlight = false\n }\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.clearDebounceTimer()\n }\n}\n","import type { Plugin } from '@opencode-ai/plugin'\nimport type { OpenCodeEventLike } from './zellij/tab-title-events.js'\nimport process from 'node:process'\nimport { configurePolicy } from './permissions/policy.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 { 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\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 const ZellijPtyPlugin: Plugin = async (input, options) => {\n configurePolicy(options?.zellijPty ?? options)\n cleanupStaleWatchdogRegistries()\n registerShutdownCleanup()\n\n const workspaceRoot = getWorkspaceRoot(input)\n const projectName = getProjectName(workspaceRoot)\n const branchName = shouldReadInitialBranch(process.env.ZELLIJ) ? await getInitialBranch(workspaceRoot) : undefined\n const tabTitleManager = new TabTitleManager({ projectName, branchName })\n\n // Best-effort initial render; no-op when not inside a real Zellij pane.\n tabTitleManager.renderImmediate().catch(() => {})\n\n return {\n async event(input) {\n const event: OpenCodeEventLike = input.event\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(\n sessions.map(async (session) => {\n await subscriberManager.closeSessionPane(session.id)\n subscriberManager.forget(session.id)\n unregisterPaneFromWatchdog(session.id)\n sessionManager.remove(session.id)\n }),\n )\n }\n },\n tool: {\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 zellij_pty_request_sudo: requestSudoTool,\n },\n }\n}\n\nexport default ZellijPtyPlugin\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["execFileAsync","ansiPattern","schema","delay","schema","schema","delay","schema","delay"],"sources":["../src/config.ts","../src/utils/shell-args.ts","../src/permissions/policy.ts","../src/utils/ids.ts","../src/pty/manager.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/utils/debug.ts","../src/zellij/shutdown-cleanup.ts","../src/zellij/tab-title-events.ts","../src/zellij/tab-title.ts","../src/plugin.ts"],"sourcesContent":["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 ZellijPluginConfig {\n tabTitle: TabTitleConfig\n pty: PtyConfig\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\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}).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}\n\ntype ConfigLayer = Pick<z.infer<typeof sidecarConfigSchema>, 'tabTitle' | 'pty'>\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 }\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 }\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\nfunction userConfigDir(): string {\n return process.env.XDG_CONFIG_HOME ? join(process.env.XDG_CONFIG_HOME, 'opencode') : join(homedir(), '.config', 'opencode')\n}\n\nfunction 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","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\nexport function commandLineForPolicy(input: CommandInput): string {\n if (!input.args || input.args.length === 0)\n return input.command.trim()\n return [input.command, ...input.args].join(' ').trim()\n}\n","import type { CommandInput } from '../utils/shell-args.js'\nimport { commandLineForPolicy } from '../utils/shell-args.js'\n\nexport interface PolicyConfig {\n denyCommands?: string[] | undefined\n allowCommands?: string[] | undefined\n allowSudoPane?: boolean | undefined\n}\n\nconst denyPatterns: RegExp[] = [\n /(^|\\s)rm\\s+-[^\\n&;r|]*r[^\\n&;|]*f\\s+\\//,\n /(^|\\s)mkfs(?:\\s|$)/,\n /(^|\\s)dd\\s+(?:[^\\s&;|][^\\n;|&]*)?\\bof=\\/dev\\//,\n /:\\(\\)\\s*\\{\\s*:\\|:\\s*&\\s*\\}\\s*;/,\n]\n\nconst sudoPattern = /(?:^|[\\s;&|])sudo(?:[\\s;&|]|$)/\n\nlet configuredDenyCommands: string[] = []\nlet configuredAllowCommands: string[] = []\nlet allowSudoPane = true\n\nexport type PolicyCheckInput = CommandInput & {\n humanInputOnly?: boolean | undefined\n}\n\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every(item => typeof item === 'string')\n}\n\nfunction escapeRegex(value: string): string {\n return value.replace(/[|\\\\{}()[\\]^$+?.]/g, '\\\\$&')\n}\n\nfunction wildcardMatches(pattern: string, commandLine: string): boolean {\n const regex = new RegExp(`^${pattern.split('*').map(escapeRegex).join('.*')}$`)\n return regex.test(commandLine)\n}\n\nexport function configurePolicy(config: unknown): void {\n configuredDenyCommands = []\n configuredAllowCommands = []\n allowSudoPane = true\n\n if (!config || typeof config !== 'object')\n return\n const object = config as Record<string, unknown>\n if (isStringArray(object.denyCommands))\n configuredDenyCommands = object.denyCommands\n if (isStringArray(object.allowCommands))\n configuredAllowCommands = object.allowCommands\n if (typeof object.allowSudoPane === 'boolean')\n allowSudoPane = object.allowSudoPane\n}\n\nexport function assertCommandAllowed(input: PolicyCheckInput): void {\n const commandLine = commandLineForPolicy(input)\n for (const pattern of denyPatterns) {\n if (pattern.test(commandLine)) {\n throw new Error(`Command denied by zellij-pty policy: ${commandLine}`)\n }\n }\n\n for (const pattern of configuredDenyCommands) {\n if (wildcardMatches(pattern, commandLine)) {\n throw new Error(`Command denied by zellij-pty configured deny rule: ${commandLine}`)\n }\n }\n\n if (configuredAllowCommands.length > 0 && !configuredAllowCommands.some(pattern => wildcardMatches(pattern, commandLine))) {\n throw new Error(`Command denied by zellij-pty allow list: ${commandLine}`)\n }\n\n if (!input.humanInputOnly && sudoPattern.test(commandLine)) {\n throw new Error('sudo commands must use zellij_pty_request_sudo so credentials stay human-input-only and never pass through agent tool input.')\n }\n\n if (input.humanInputOnly && !allowSudoPane) {\n throw new Error('sudo pane is disabled by zellij-pty policy.')\n }\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 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","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): string[] {\n return ['action', 'rename-tab', title]\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 renameTab(title: string): Promise<void> {\n await runZellij(buildRenameTabActionArgs(title))\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\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)\n return\n watchdogStarted = true\n\n const child = spawn('node', [watchdogRunnerPath(), watchdogRegistryPath()], {\n detached: true,\n stdio: 'ignore',\n env: process.env,\n })\n child.unref()\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}\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\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 ensureZellijTarget()\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 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 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 state.child = child\n state.lastExitedAt = null\n\n child.stdout.setEncoding('utf8')\n child.stdout.on('data', (chunk: string) => this.handleStdout(session.id, chunk))\n child.stderr.setEncoding('utf8')\n child.stderr.on('data', (chunk: string) => this.handleStderr(session.id, chunk))\n child.on('exit', () => this.handleSubscriberExit(session.id))\n child.on('error', error => this.handleSubscriberError(session.id, 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, chunk: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state)\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, part)\n }\n }\n\n private handleJsonLine(sessionId: string, line: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state)\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 const session = this.sessions.get(sessionId)\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, chunk: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state)\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): void {\n const state = this.subscribers.get(sessionId)\n if (!state)\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, error: Error): void {\n const state = this.subscribers.get(sessionId)\n if (state)\n state.stderr.push(error.message)\n this.sessions.updateStatus(sessionId, 'unknown')\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 { 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 error instanceof Error ? error.message : String(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 if (!subscriberManager.has(session.id)) {\n await subscriberManager.start(session)\n }\n const subscriberStatus = 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 (!subscriberStatus.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: subscriberStatus.active,\n subscriberLastExitedAt: subscriberStatus.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 { assertCommandAllowed } from '../permissions/policy.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 for (const script of args.scripts) {\n assertCommandAllowed({ command: script.command, humanInputOnly: true })\n }\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 { assertCommandAllowed } from '../permissions/policy.js'\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 assertCommandAllowed({ command: args.command, args: args.args, humanInputOnly: false })\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 { 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.get(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 return jsonResponse({\n session: publicSession(session),\n output: readOutputSnapshot(session.id, { maxLines: args.maxLines }),\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 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 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}\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\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 'vcs.branch.updated': {\n tabTitleManager.setBranch(stringProperty(properties, 'branch'))\n break\n }\n case 'question.asked':\n case 'permission.asked':\n case 'permission.updated': {\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 '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 }\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}\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 syncInFlight = false\n private readonly debounceMs: number\n private readonly projectName: string\n private readonly cli: TabTitleCli\n private readonly emojis: TabTitleEmojis\n private readonly enabled: boolean\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.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)\n return\n this.desiredTitle = this.buildTitle()\n this.clearDebounceTimer()\n await this.syncDesiredTitle()\n }\n\n scheduleUpdate(): void {\n if (!this.enabled)\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.clearDebounceTimer()\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = undefined\n this.syncDesiredTitle().catch(() => {})\n }, this.debounceMs)\n }\n\n private async syncDesiredTitle(): Promise<void> {\n if (!this.enabled)\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 }\n catch (cause) {\n debug('Failed to rename Zellij tab.', cause)\n break\n }\n }\n }\n finally {\n this.syncInFlight = false\n }\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.clearDebounceTimer()\n }\n}\n","import type { Plugin } from '@opencode-ai/plugin'\nimport type { OpenCodeEventLike } from './zellij/tab-title-events.js'\nimport process from 'node:process'\nimport { loadConfig } from './config.js'\nimport { configurePolicy } from './permissions/policy.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 { 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 const ZellijPtyPlugin: Plugin = async (input) => {\n const { config, warnings } = await loadConfig(input)\n for (const warning of warnings) {\n debug(warning)\n }\n configurePolicy({ allowSudoPane: 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 return {\n async event(input) {\n const event: OpenCodeEventLike = input.event\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(\n sessions.map(async (session) => {\n await subscriberManager.closeSessionPane(session.id)\n subscriberManager.forget(session.id)\n unregisterPaneFromWatchdog(session.id)\n sessionManager.remove(session.id)\n }),\n )\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\nexport default ZellijPtyPlugin\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
|
-
import { spawnSync } from "node:child_process";
|
|
3
2
|
import { appendFileSync, existsSync, readFileSync, rmSync } from "node:fs";
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
4
|
//#region src/zellij/pane-watchdog-runner.ts
|
|
5
5
|
const registryPath = process.argv[2];
|
|
6
6
|
const pollIntervalMs = 1e3;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-zellij",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.3",
|
|
5
5
|
"description": "OpenCode plugin for Zellij-backed panes and workflow integrations.",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -11,8 +11,7 @@
|
|
|
11
11
|
".": {
|
|
12
12
|
"types": "./dist/index.d.mts",
|
|
13
13
|
"default": "./dist/index.mjs"
|
|
14
|
-
}
|
|
15
|
-
"./source": "./src/plugin.ts"
|
|
14
|
+
}
|
|
16
15
|
},
|
|
17
16
|
"main": "./dist/index.mjs",
|
|
18
17
|
"types": "./dist/index.d.mts",
|
|
@@ -20,7 +19,8 @@
|
|
|
20
19
|
"dist"
|
|
21
20
|
],
|
|
22
21
|
"scripts": {
|
|
23
|
-
"
|
|
22
|
+
"generate:schema": "bun run scripts/generate-schema.ts",
|
|
23
|
+
"build": "bun run generate:schema && tsdown",
|
|
24
24
|
"typecheck": "tsc --noEmit",
|
|
25
25
|
"lint": "eslint .",
|
|
26
26
|
"lint:fix": "eslint . --fix",
|
|
@@ -30,7 +30,9 @@
|
|
|
30
30
|
"prepack": "bun run build"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@opencode-ai/plugin": "latest"
|
|
33
|
+
"@opencode-ai/plugin": "latest",
|
|
34
|
+
"confbox": "^0.2.4",
|
|
35
|
+
"zod": "^4.4.3"
|
|
34
36
|
},
|
|
35
37
|
"devDependencies": {
|
|
36
38
|
"@antfu/eslint-config": "^8.2.0",
|