opencode-zellij 0.0.15 → 0.0.17
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 +13 -2
- package/README.zh.md +13 -2
- package/dist/index.d.mts +9 -107
- package/dist/index.mjs +227 -664
- package/dist/index.mjs.map +1 -1
- package/dist/pane-watchdog-runner.mjs +1 -1
- package/package.json +4 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["isRecord","stringProperty","execFileAsync","ansiPattern","schema","delay","schema","schema","delay","schema","delay","isRecord","stringProperty","nestedStringProperty","deletedSessionID","deletedSessionID"],"sources":["../src/utils/debug.ts","../src/utils/errors.ts","../src/auto-update.ts","../src/config.ts","../src/permissions/sudo-pane.ts","../src/utils/ids.ts","../src/pty/manager.ts","../src/utils/shell-args.ts","../src/zellij/parse.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/pane-cleanup.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/completion-notifications.ts","../src/zellij/shutdown-cleanup.ts","../src/zellij/tab-title-events.ts","../src/zellij/tab-title.ts","../src/plugin.ts"],"sourcesContent":["import process from 'node:process'\n\nexport function debug(message: string, ...details: unknown[]): void {\n if (!process.env.ZELLIJ_PTY_DEBUG)\n return\n\n console.warn(`[opencode-zellij] ${message}`, ...details)\n}\n","export function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n","import { execFile } from 'node:child_process'\nimport { existsSync } from 'node:fs'\nimport { readFile, rename, rm } from 'node:fs/promises'\nimport { basename, dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { promisify } from 'node:util'\nimport { debug } from './utils/debug.js'\nimport { errorMessage } from './utils/errors.js'\n\nexport const PACKAGE_NAME = 'opencode-zellij'\n\nconst NPM_REGISTRY_URL = 'https://registry.npmjs.org/-/package/opencode-zellij/dist-tags'\nconst FETCH_TIMEOUT_MS = 5_000\nconst INSTALL_TIMEOUT_MS = 60_000\n\nconst defaultExecFile = promisify(execFile)\n\nfunction packageDir(installRoot: string): string {\n return join(installRoot, 'node_modules', PACKAGE_NAME)\n}\n\nfunction backupDir(installRoot: string): string {\n return join(installRoot, 'node_modules', `${PACKAGE_NAME}.update-backup`)\n}\n\ninterface InstalledPackageMetadata {\n name: string | undefined\n version: string | undefined\n main: string | undefined\n}\n\nasync function installedPackageMetadata(installRoot: string): Promise<InstalledPackageMetadata | undefined> {\n try {\n const content = await readFile(join(packageDir(installRoot), 'package.json'), 'utf8')\n const pkg: unknown = JSON.parse(content)\n if (isRecord(pkg)) {\n return {\n name: typeof pkg.name === 'string' ? pkg.name : undefined,\n version: typeof pkg.version === 'string' ? pkg.version : undefined,\n main: typeof pkg.main === 'string' ? pkg.main : undefined,\n }\n }\n }\n catch (error) {\n // Missing or unreadable package metadata is handled by the caller.\n debug('installedPackageMetadata failed', errorMessage(error))\n }\n return undefined\n}\n\nfunction isExpectedPackage(metadata: InstalledPackageMetadata | undefined, version: string): boolean {\n return metadata?.name === PACKAGE_NAME && metadata.version === version\n}\n\nfunction hasRunnableEntry(installRoot: string, metadata: InstalledPackageMetadata | undefined): boolean {\n if (!metadata)\n return false\n const dir = packageDir(installRoot)\n if (metadata.main && existsSync(join(dir, metadata.main)))\n return true\n return existsSync(join(dir, 'dist', 'index.mjs'))\n}\n\nasync function isVerifiedInstall(installRoot: string, version: string): Promise<boolean> {\n const metadata = await installedPackageMetadata(installRoot)\n return isExpectedPackage(metadata, version) && hasRunnableEntry(installRoot, metadata)\n}\n\nasync function removeInstalledPackage(installRoot: string): Promise<void> {\n await rm(packageDir(installRoot), { force: true, recursive: true })\n}\n\nasync function backupInstalledPackage(installRoot: string): Promise<string | undefined> {\n const source = packageDir(installRoot)\n if (!existsSync(source))\n return undefined\n const backup = backupDir(installRoot)\n await rm(backup, { force: true, recursive: true })\n await rename(source, backup)\n return backup\n}\n\nasync function restoreInstalledPackage(installRoot: string, backup: string | undefined): Promise<void> {\n if (!backup || !existsSync(backup))\n return\n await rm(packageDir(installRoot), { force: true, recursive: true })\n await rename(backup, packageDir(installRoot))\n}\n\nasync function discardBackup(backup: string | undefined): Promise<void> {\n if (backup)\n await rm(backup, { force: true, recursive: true })\n}\n\nexport interface InstallContext {\n installRoot: string\n cacheSpec: string\n currentVersion: string\n}\n\nexport async function findInstallContext(importMetaUrl: string): Promise<InstallContext | undefined> {\n let startPath: string\n try {\n startPath = fileURLToPath(importMetaUrl)\n }\n catch (cause) {\n debug('invalid import.meta.url', cause instanceof Error ? cause.message : String(cause))\n return undefined\n }\n\n let dir = dirname(startPath)\n\n while (true) {\n const isPluginDir = dir.endsWith(`/node_modules/${PACKAGE_NAME}`) || dir.endsWith(`\\\\node_modules\\\\${PACKAGE_NAME}`)\n if (isPluginDir) {\n const packageJsonPath = join(dir, 'package.json')\n try {\n const content = await readFile(packageJsonPath, 'utf8')\n const pkg: unknown = JSON.parse(content)\n if (\n isRecord(pkg)\n && pkg.name === PACKAGE_NAME\n && typeof pkg.version === 'string'\n && pkg.version.length > 0\n ) {\n const installRoot = dirname(dirname(dir))\n const rootPackageJson = join(installRoot, 'package.json')\n if (existsSync(rootPackageJson)) {\n return { installRoot, cacheSpec: basename(installRoot), currentVersion: pkg.version }\n }\n }\n }\n catch (error) {\n // ignore unreadable or invalid package.json\n debug('findInstallContext package.json read failed', errorMessage(error))\n }\n }\n\n const parent = dirname(dir)\n if (parent === dir)\n break\n dir = parent\n }\n\n return undefined\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null\n}\n\nexport function isAutoUpdatableSpec(spec: string | undefined): boolean {\n if (spec === PACKAGE_NAME)\n return true\n if (spec === `${PACKAGE_NAME}@latest`)\n return true\n return false\n}\n\nexport async function fetchLatestVersion(fetchImpl: typeof fetch = globalThis.fetch): Promise<string | undefined> {\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS)\n\n try {\n const response = await fetchImpl(NPM_REGISTRY_URL, { signal: controller.signal })\n clearTimeout(timeout)\n if (!response.ok) {\n debug(`npm registry returned ${response.status}`)\n return undefined\n }\n const data: unknown = await response.json()\n if (isRecord(data) && typeof data.latest === 'string') {\n return data.latest\n }\n debug('npm registry response missing latest tag')\n return undefined\n }\n catch (cause) {\n clearTimeout(timeout)\n debug('failed to fetch latest version', cause instanceof Error ? cause.message : String(cause))\n return undefined\n }\n}\n\nexport type ExecFileLike = (\n file: string,\n args: string[],\n options: { cwd: string, timeout?: number },\n) => Promise<{ stdout: string, stderr: string }>\n\nexport async function runNpmInstall(\n installRoot: string,\n version: string,\n execImpl: ExecFileLike = defaultExecFile as ExecFileLike,\n): Promise<boolean> {\n debug(`updating ${PACKAGE_NAME} to ${version} in ${installRoot}`)\n\n try {\n const install = () => execImpl(\n 'npm',\n ['install', `${PACKAGE_NAME}@${version}`, '--save-exact', '--ignore-scripts', '--no-audit', '--no-fund', '--prefer-online'],\n { cwd: installRoot, timeout: INSTALL_TIMEOUT_MS },\n )\n\n await install()\n\n if (await isVerifiedInstall(installRoot, version)) {\n debug(`updated ${PACKAGE_NAME} to ${version}`)\n return true\n }\n\n const installedPackage = await installedPackageMetadata(installRoot)\n debug(`npm install left stale or invalid ${PACKAGE_NAME} (${installedPackage?.name ?? '<missing>'}@${installedPackage?.version ?? '<missing>'}); reinstalling ${version}`)\n const backup = await backupInstalledPackage(installRoot)\n try {\n await removeInstalledPackage(installRoot)\n await install()\n\n if (await isVerifiedInstall(installRoot, version)) {\n await discardBackup(backup)\n debug(`updated ${PACKAGE_NAME} to ${version}`)\n return true\n }\n\n const reinstalledPackage = await installedPackageMetadata(installRoot)\n debug(`npm install verification failed: expected ${PACKAGE_NAME}@${version}, found ${reinstalledPackage?.name ?? '<missing>'}@${reinstalledPackage?.version ?? '<missing>'}`)\n await restoreInstalledPackage(installRoot, backup)\n return false\n }\n catch (cause) {\n await restoreInstalledPackage(installRoot, backup)\n throw cause\n }\n }\n catch (cause) {\n debug('npm install failed', cause instanceof Error ? cause.message : String(cause))\n return false\n }\n}\n\nexport interface CheckOptions {\n importMetaUrl: string\n fetchImpl?: typeof fetch\n execImpl?: ExecFileLike\n}\n\nexport type UpdateResult\n = | { type: 'skipped', reason: string }\n | { type: 'up-to-date', currentVersion: string }\n | { type: 'updated', fromVersion: string, toVersion: string }\n | { type: 'failed', currentVersion: string, latestVersion: string, reason: string }\n\nexport async function checkAndUpdate(options: CheckOptions): Promise<UpdateResult> {\n const context = await findInstallContext(options.importMetaUrl)\n if (!context) {\n debug('skipping auto-update: not installed from npm')\n return { type: 'skipped', reason: 'not installed from npm' }\n }\n\n if (!isAutoUpdatableSpec(context.cacheSpec)) {\n debug(`skipping auto-update: cache spec is pinned or unknown (${context.cacheSpec})`)\n return { type: 'skipped', reason: `cache spec is pinned or unknown (${context.cacheSpec})` }\n }\n\n const latest = await fetchLatestVersion(options.fetchImpl)\n if (!latest) {\n debug('skipping auto-update: could not determine latest version')\n return { type: 'skipped', reason: 'could not determine latest version' }\n }\n\n const installedVersion = (await installedPackageMetadata(context.installRoot))?.version ?? context.currentVersion\n if (latest === installedVersion) {\n debug(`auto-update: already on latest ${latest}`)\n return { type: 'up-to-date', currentVersion: installedVersion }\n }\n\n const success = await runNpmInstall(context.installRoot, latest, options.execImpl)\n if (success) {\n debug(`updated ${PACKAGE_NAME} from ${installedVersion} to ${latest}`)\n return { type: 'updated', fromVersion: installedVersion, toVersion: latest }\n }\n\n return { type: 'failed', currentVersion: installedVersion, latestVersion: latest, reason: 'npm install failed' }\n}\n","import { existsSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport process from 'node:process'\nimport { parseJSON, parseJSONC } from 'confbox'\nimport { z } from 'zod'\n\nconst sudoPaneSchema = z.enum(['allow', 'deny', 'hide'])\nconst completionNotificationModeSchema = z.enum(['off', 'queue', 'toast', 'queue+toast', 'prompt'])\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 cleanupExitedPaneOnRead: boolean\n sudoPane: SudoPaneMode\n completionNotification: CompletionNotificationConfig\n}\n\nexport interface CompletionNotificationPromptConfig {\n requireIdle: boolean\n cooldownMs: number\n maxAttempts: number\n}\n\nexport interface CompletionNotificationConfig {\n mode: CompletionNotificationMode\n prompt: CompletionNotificationPromptConfig\n}\n\nexport type SudoPaneMode = z.infer<typeof sudoPaneSchema>\n\nexport type CompletionNotificationMode = z.infer<typeof completionNotificationModeSchema>\n\nexport type AutoUpdateConfig = boolean\n\nexport interface ZellijPluginConfig {\n tabTitle: TabTitleConfig\n pty: PtyConfig\n autoUpdate: AutoUpdateConfig\n}\n\nexport interface LoadConfigInput {\n directory?: string | undefined\n worktree?: string | undefined\n}\n\nexport interface LoadConfigResult {\n config: ZellijPluginConfig\n sources: {\n user?: string | undefined\n project?: string | undefined\n }\n warnings: string[]\n}\n\nconst configFilenames = [\n 'opencode-zellij.config.jsonc',\n 'opencode-zellij.config.json',\n] as const\n\nconst tabTitleLayerSchema = z.object({\n enabled: z.boolean().optional().describe('Enable dynamic Zellij tab title updates.'),\n emojiIdle: z.string().optional().describe('Prefix used when OpenCode is idle.'),\n emojiRunning: z.string().optional().describe('Prefix used while OpenCode is running work.'),\n emojiNeedsInput: z.string().optional().describe('Prefix used when OpenCode is waiting for human input.'),\n emojiBranch: z.string().optional().describe('Prefix used before the current git branch name.'),\n debounceMs: z.number().finite().min(0).optional().describe('Debounce time for tab title updates in milliseconds.'),\n}).strict()\n\nconst ptyLayerSchema = z.object({\n enabled: z.boolean().optional().describe('Enable Zellij-backed PTY tools.'),\n cleanupExitedPaneOnRead: z.boolean().optional().describe('Remove exited PTY panes after they are read.'),\n sudoPane: sudoPaneSchema.optional().describe('Controls whether the sudo pane tool is available, denied, or hidden.'),\n completionNotification: z.object({\n mode: completionNotificationModeSchema.optional().describe('Controls how completion notifications are delivered.'),\n prompt: z.object({\n requireIdle: z.boolean().optional().describe('Require the plugin to be idle before prompting.'),\n cooldownMs: z.number().finite().min(0).optional().describe('Cooldown time before prompting again in milliseconds.'),\n maxAttempts: z.number().finite().int().min(0).optional().describe('Maximum prompt attempts before backing off.'),\n }).strict().optional().describe('Prompt-specific completion notification settings.'),\n }).strict().optional().describe('Completion notification delivery settings.'),\n}).strict()\n\nconst autoUpdateLayerSchema = z.boolean().optional().describe('Enable automatic update checks for the opencode-zellij plugin.')\n\nexport const sidecarConfigSchema = z.object({\n $schema: z.string().optional().describe('JSON Schema URI for editor completion.'),\n tabTitle: tabTitleLayerSchema.optional(),\n pty: ptyLayerSchema.optional(),\n autoUpdate: autoUpdateLayerSchema.optional(),\n}).strict()\n\nexport const defaultConfig: ZellijPluginConfig = {\n tabTitle: {\n enabled: true,\n emojiIdle: '🟢',\n emojiRunning: '⚡',\n emojiNeedsInput: '💬',\n emojiBranch: '🌱',\n debounceMs: 300,\n },\n pty: {\n enabled: true,\n cleanupExitedPaneOnRead: true,\n sudoPane: 'allow',\n completionNotification: {\n mode: 'queue+toast',\n prompt: {\n requireIdle: true,\n cooldownMs: 30_000,\n maxAttempts: 1,\n },\n },\n },\n autoUpdate: true,\n}\n\ntype ConfigLayer = Pick<z.infer<typeof sidecarConfigSchema>, 'tabTitle' | 'pty' | 'autoUpdate'>\n\nfunction validConfigLayer(value: unknown): ConfigLayer | undefined {\n const result = sidecarConfigSchema.safeParse(value)\n if (!result.success)\n return undefined\n\n return {\n tabTitle: result.data.tabTitle,\n pty: result.data.pty,\n autoUpdate: result.data.autoUpdate,\n }\n}\n\nfunction mergeConfig(user?: ConfigLayer | undefined, project?: ConfigLayer | undefined): ZellijPluginConfig {\n return {\n tabTitle: {\n enabled: project?.tabTitle?.enabled ?? user?.tabTitle?.enabled ?? defaultConfig.tabTitle.enabled,\n emojiIdle: project?.tabTitle?.emojiIdle ?? user?.tabTitle?.emojiIdle ?? defaultConfig.tabTitle.emojiIdle,\n emojiRunning: project?.tabTitle?.emojiRunning ?? user?.tabTitle?.emojiRunning ?? defaultConfig.tabTitle.emojiRunning,\n emojiNeedsInput: project?.tabTitle?.emojiNeedsInput ?? user?.tabTitle?.emojiNeedsInput ?? defaultConfig.tabTitle.emojiNeedsInput,\n emojiBranch: project?.tabTitle?.emojiBranch ?? user?.tabTitle?.emojiBranch ?? defaultConfig.tabTitle.emojiBranch,\n debounceMs: project?.tabTitle?.debounceMs ?? user?.tabTitle?.debounceMs ?? defaultConfig.tabTitle.debounceMs,\n },\n pty: {\n enabled: project?.pty?.enabled ?? user?.pty?.enabled ?? defaultConfig.pty.enabled,\n cleanupExitedPaneOnRead: project?.pty?.cleanupExitedPaneOnRead ?? user?.pty?.cleanupExitedPaneOnRead ?? defaultConfig.pty.cleanupExitedPaneOnRead,\n sudoPane: project?.pty?.sudoPane ?? user?.pty?.sudoPane ?? defaultConfig.pty.sudoPane,\n completionNotification: {\n mode: project?.pty?.completionNotification?.mode ?? user?.pty?.completionNotification?.mode ?? defaultConfig.pty.completionNotification.mode,\n prompt: {\n requireIdle: project?.pty?.completionNotification?.prompt?.requireIdle ?? user?.pty?.completionNotification?.prompt?.requireIdle ?? defaultConfig.pty.completionNotification.prompt.requireIdle,\n cooldownMs: project?.pty?.completionNotification?.prompt?.cooldownMs ?? user?.pty?.completionNotification?.prompt?.cooldownMs ?? defaultConfig.pty.completionNotification.prompt.cooldownMs,\n maxAttempts: project?.pty?.completionNotification?.prompt?.maxAttempts ?? user?.pty?.completionNotification?.prompt?.maxAttempts ?? defaultConfig.pty.completionNotification.prompt.maxAttempts,\n },\n },\n },\n autoUpdate: project?.autoUpdate ?? user?.autoUpdate ?? defaultConfig.autoUpdate,\n }\n}\n\nasync function loadConfigLayer(directory: string, warnings: string[]): Promise<{ layer?: ConfigLayer | undefined, source?: string | undefined }> {\n const configFile = detectConfigFile(directory)\n if (!configFile)\n return {}\n\n try {\n const text = await readFile(configFile, 'utf8')\n const parsed = configFile.endsWith('.jsonc') ? parseJSONC(text) : parseJSON(text)\n const layer = validConfigLayer(parsed)\n if (!layer) {\n warnings.push(`Ignoring invalid config shape in ${configFile}.`)\n return { source: configFile }\n }\n return { layer, source: configFile }\n }\n catch (cause) {\n warnings.push(`Ignoring unreadable or invalid config file ${configFile}: ${cause instanceof Error ? cause.message : String(cause)}`)\n return {}\n }\n}\n\nfunction detectConfigFile(directory: string): string | undefined {\n return configFilenames\n .map(filename => join(directory, filename))\n .find(path => existsSync(path))\n}\n\nexport function userConfigDir(): string {\n return process.env.XDG_CONFIG_HOME ? join(process.env.XDG_CONFIG_HOME, 'opencode') : join(homedir(), '.config', 'opencode')\n}\n\nexport function projectConfigDirs(input: LoadConfigInput): string[] {\n const dirs: string[] = []\n if (input.worktree)\n dirs.push(join(input.worktree, '.opencode'))\n if (input.directory && input.directory !== input.worktree)\n dirs.push(join(input.directory, '.opencode'))\n return dirs\n}\n\nexport async function loadConfig(input: LoadConfigInput): Promise<LoadConfigResult> {\n const warnings: string[] = []\n const sources: LoadConfigResult['sources'] = {}\n\n const userResult = await loadConfigLayer(userConfigDir(), warnings)\n const userLayer = userResult.layer\n if (userResult.source && userLayer)\n sources.user = userResult.source\n\n let projectLayer: ConfigLayer | undefined\n for (const projectDir of projectConfigDirs(input)) {\n const projectResult = await loadConfigLayer(projectDir, warnings)\n if (!projectResult.source)\n continue\n projectLayer = projectResult.layer\n if (projectLayer)\n sources.project = projectResult.source\n break\n }\n\n return {\n config: mergeConfig(userLayer, projectLayer),\n sources,\n warnings,\n }\n}\n","let sudoPaneAllowed = true\n\nexport function configureSudoPane(allowed: boolean): void {\n sudoPaneAllowed = allowed\n}\n\nexport function assertSudoPaneAllowed(): void {\n if (!sudoPaneAllowed)\n throw new Error('sudo pane is disabled by zellij-pty config.')\n}\n","import { randomUUID } from 'node:crypto'\n\nconst paneIdPattern = /\\b(?:terminal_)?(\\d+)\\b/\n\nexport function createSessionId(): string {\n return `zpty_${randomUUID().replaceAll('-', '').slice(0, 10)}`\n}\n\nexport function normalizePaneId(rawPaneId: string): string {\n const trimmed = rawPaneId.trim()\n if (/^terminal_\\d+$/.test(trimmed))\n return trimmed\n if (/^\\d+$/.test(trimmed))\n return `terminal_${trimmed}`\n throw new Error(`Invalid Zellij terminal pane id: ${rawPaneId}`)\n}\n\nexport function parsePaneId(output: string): string {\n const match = output.match(paneIdPattern)\n if (!match?.[1]) {\n throw new Error(`Unable to parse Zellij pane id from output: ${output.trim() || '<empty>'}`)\n }\n return normalizePaneId(match[1])\n}\n","import type { CreateSessionInput, PtySession, SessionStatus, SessionTerminalReason, SessionTombstone } from './session.js'\nimport { createSessionId } from '../utils/ids.js'\n\nconst tombstoneTailLimit = 200\n\nexport interface MarkTerminalInput {\n reason: SessionTerminalReason\n tail?: string[] | undefined\n exitCode?: number | undefined\n}\n\nexport interface MarkTerminalResult {\n session: PtySession\n created: boolean\n}\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 tombstone: null,\n }\n this.sessions.set(session.id, session)\n return session\n }\n\n get(id: string): PtySession {\n const session = this.sessions.get(id)\n if (!session)\n throw new Error(`Unknown zellij PTY session: ${id}`)\n return session\n }\n\n find(id: string): PtySession | undefined {\n return this.sessions.get(id)\n }\n\n list(): PtySession[] {\n return Array.from(this.sessions.values()).sort((a, b) => a.createdAt.localeCompare(b.createdAt))\n }\n\n updateLineCount(id: string, lineCount: number): PtySession {\n const session = this.get(id)\n session.lineCount = lineCount\n session.updatedAt = new Date().toISOString()\n return session\n }\n\n updateStatus(id: string, status: SessionStatus): PtySession {\n const session = this.get(id)\n if (session.status === 'terminal' && status !== 'terminal')\n return session\n session.status = status\n session.updatedAt = new Date().toISOString()\n return session\n }\n\n markExited(id: string, exitCode: number): PtySession {\n return this.markTerminal(id, { reason: 'exit_marker', exitCode }).session\n }\n\n markTerminal(id: string, input: MarkTerminalInput): MarkTerminalResult {\n const session = this.get(id)\n const now = new Date().toISOString()\n const created = session.status !== 'terminal' || !session.tombstone\n\n if (created) {\n const tombstone: SessionTombstone = {\n reason: input.reason,\n terminalAt: now,\n tail: (input.tail ?? []).slice(-tombstoneTailLimit),\n paneClosedAt: null,\n notificationSentAt: null,\n }\n\n session.status = 'terminal'\n session.tombstone = tombstone\n session.updatedAt = now\n }\n\n if (input.exitCode !== undefined && session.exitCode === null) {\n session.exitCode = input.exitCode\n session.exitedAt = now\n session.updatedAt = now\n }\n\n if (session.tombstone) {\n if (input.tail?.length && session.tombstone.tail.length === 0)\n session.tombstone.tail = input.tail.slice(-tombstoneTailLimit)\n if (!session.tombstone.reason)\n session.tombstone.reason = input.reason\n }\n\n return { session, created }\n }\n\n markTerminalPaneClosed(id: string): PtySession {\n const session = this.get(id)\n const now = new Date().toISOString()\n if (!session.tombstone)\n return session\n if (!session.tombstone.paneClosedAt) {\n session.tombstone.paneClosedAt = now\n session.updatedAt = now\n }\n return session\n }\n\n markTerminalNotificationSent(id: string): PtySession {\n const session = this.get(id)\n const now = new Date().toISOString()\n if (!session.tombstone)\n return session\n if (!session.tombstone.notificationSentAt) {\n session.tombstone.notificationSentAt = now\n session.updatedAt = now\n }\n return session\n }\n\n listByOpenCodeSession(openCodeSessionId: string): PtySession[] {\n return this.list().filter(session => session.openCodeSessionId === openCodeSessionId)\n }\n\n remove(id: string): void {\n if (!this.sessions.delete(id))\n throw new Error(`Unknown zellij PTY session: ${id}`)\n }\n}\n\nexport const sessionManager = new SessionManager()\n","export interface CommandInput {\n command: string\n args?: string[] | undefined\n}\n\nexport interface BuildCommandArgvOptions {\n exitCodeToken?: string | undefined\n}\n\nconst directCommandExitWrapper = 'token=\"$1\"; shift; set +e; \"$@\"; code=$?; printf \"\\\\n[zellij-pty:%s] exit-code=%s\\\\n\" \"$token\" \"$code\"; exit \"$code\"'\nconst shellCommandExitWrapper = 'token=\"$1\"; command=\"$2\"; set +e; bash -lc \"$command\"; code=$?; printf \"\\\\n[zellij-pty:%s] exit-code=%s\\\\n\" \"$token\" \"$code\"; exit \"$code\"'\n\nexport function buildCommandArgv(input: CommandInput, options: BuildCommandArgvOptions = {}): string[] {\n const command = input.command.trim()\n if (!command)\n throw new Error('command is required')\n\n if (options.exitCodeToken) {\n if (input.args && input.args.length > 0) {\n return ['bash', '-lc', directCommandExitWrapper, 'zellij-pty', options.exitCodeToken, command, ...input.args]\n }\n\n return ['bash', '-lc', shellCommandExitWrapper, 'zellij-pty', options.exitCodeToken, command]\n }\n\n if (input.args && input.args.length > 0) {\n return [command, ...input.args]\n }\n\n return ['bash', '-lc', command]\n}\n","import { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { normalizePaneId } from '../utils/ids.js'\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction numericProperty(object: Record<string, unknown>, keys: string[]): number | undefined {\n for (const key of keys) {\n const value = object[key]\n if (typeof value === 'number' && Number.isFinite(value))\n return value\n if (typeof value === 'string') {\n const parsed = Number(value)\n if (Number.isInteger(parsed))\n return parsed\n }\n }\n return undefined\n}\n\nfunction stringProperty(object: Record<string, unknown>, keys: string[]): string | undefined {\n for (const key of keys) {\n const value = object[key]\n if (typeof value === 'string')\n return value\n }\n return undefined\n}\n\n// ---------------------------------------------------------------------------\n// Pane → tab resolution\n// ---------------------------------------------------------------------------\n\nfunction paneMatches(object: Record<string, unknown>, paneId: number): boolean {\n const candidate = numericProperty(object, ['id', 'pane_id', 'paneId'])\n return candidate === paneId && object.is_plugin !== true\n}\n\nfunction findPaneRecord(value: unknown, paneId: number): Record<string, unknown> | undefined {\n if (Array.isArray(value)) {\n for (const item of value) {\n const found = findPaneRecord(item, paneId)\n if (found !== undefined)\n return found\n }\n return undefined\n }\n\n if (typeof value !== 'object' || value === null)\n return undefined\n\n const object = value as Record<string, unknown>\n if (paneMatches(object, paneId))\n return object\n\n for (const nested of Object.values(object)) {\n const found = findPaneRecord(nested, paneId)\n if (found !== undefined)\n return found\n }\n return undefined\n}\n\nexport function parseCurrentPaneTabId(listPanesJson: string, paneId: string | undefined): number | undefined {\n if (!paneId)\n return undefined\n const parsedPaneId = Number(paneId)\n if (!Number.isInteger(parsedPaneId))\n return undefined\n\n try {\n const pane = findPaneRecord(JSON.parse(listPanesJson), parsedPaneId)\n return pane ? numericProperty(pane, ['tab_id', 'tabId']) : undefined\n }\n catch (error) {\n debug('parseCurrentPaneTabId failed', errorMessage(error))\n return undefined\n }\n}\n\nexport function parsePaneExists(listPanesJson: string, paneId: string | undefined): boolean | undefined {\n if (!paneId)\n return undefined\n let parsedPaneId: number\n try {\n parsedPaneId = Number(normalizePaneId(paneId).slice('terminal_'.length))\n }\n catch {\n return undefined\n }\n\n try {\n return findPaneRecord(JSON.parse(listPanesJson), parsedPaneId) !== undefined\n }\n catch (error) {\n debug('parsePaneExists failed', errorMessage(error))\n return undefined\n }\n}\n\n// ---------------------------------------------------------------------------\n// Tab name resolution\n// ---------------------------------------------------------------------------\n\nfunction tabNameProperty(object: Record<string, unknown>, tabId: number | undefined): string | undefined {\n if (tabId === undefined)\n return undefined\n const foundTabId = numericProperty(object, ['tab_id', 'tabId'])\n if (foundTabId !== tabId)\n return undefined\n const name = stringProperty(object, ['name', 'title'])\n return typeof name === 'string' ? name : undefined\n}\n\nfunction findTabName(value: unknown, tabId: number | undefined): string | undefined {\n if (Array.isArray(value)) {\n for (const item of value) {\n const found = findTabName(item, tabId)\n if (found !== undefined)\n return found\n }\n return undefined\n }\n\n if (typeof value !== 'object' || value === null)\n return undefined\n\n const object = value as Record<string, unknown>\n const name = tabNameProperty(object, tabId)\n if (name !== undefined)\n return name\n\n for (const nested of Object.values(object)) {\n const found = findTabName(nested, tabId)\n if (found !== undefined)\n return found\n }\n return undefined\n}\n\nexport function parseTabName(listTabsJson: string, tabId: number | undefined): string | undefined {\n try {\n return findTabName(JSON.parse(listTabsJson), tabId)\n }\n catch (error) {\n debug('parseTabName failed', errorMessage(error))\n return undefined\n }\n}\n","import type { CommandInput } from '../utils/shell-args.js'\nimport { execFile, spawnSync } from 'node:child_process'\nimport process from 'node:process'\nimport { promisify } from 'node:util'\nimport { parsePaneId } from '../utils/ids.js'\nimport { buildCommandArgv } from '../utils/shell-args.js'\nimport { parseCurrentPaneTabId, parsePaneExists, parseTabName } from './parse.js'\n\nconst execFileAsync = promisify(execFile)\n\nexport type NewPaneOptions = CommandInput & {\n cwd?: string | undefined\n title?: string | undefined\n floating?: boolean | undefined\n exitCodeToken?: string | undefined\n}\n\nexport interface ZellijRunOptions {\n timeoutMs?: number | undefined\n}\n\ninterface ZellijResult {\n stdout: string\n stderr: string\n}\n\nexport function zellijCommandArgs(actionArgs: string[]): string[] {\n const sessionName = process.env.ZELLIJ_SESSION_NAME?.trim()\n if (sessionName)\n return ['--session', sessionName, ...actionArgs]\n return actionArgs\n}\n\nexport function zellijActionArgs(action: string, args: string[] = []): string[] {\n return ['action', action, ...args]\n}\n\nexport function buildNewPaneActionArgs(options: NewPaneOptions): string[] {\n const args = ['action', 'new-pane']\n if (process.env.ZELLIJ)\n args.push('--near-current-pane')\n\n if (options.title)\n args.push('--name', options.title)\n if (options.cwd)\n args.push('--cwd', options.cwd)\n if (options.floating)\n args.push('--floating')\n\n args.push('--', ...buildCommandArgv(options, { exitCodeToken: options.exitCodeToken }))\n return args\n}\n\nexport function buildRenameTabActionArgs(title: string, options: { tabId?: number } = {}): string[] {\n if (options.tabId !== undefined)\n return ['action', 'rename-tab', '--tab-id', String(options.tabId), title]\n return ['action', 'rename-tab', title]\n}\n\nexport function ensureZellijTarget(): void {\n if (process.env.ZELLIJ || process.env.ZELLIJ_SESSION_NAME)\n return\n throw new Error('Zellij context not found. Run OpenCode inside Zellij or set ZELLIJ_SESSION_NAME to an existing session.')\n}\n\nasync function runZellij(actionArgs: string[], options: ZellijRunOptions = {}): Promise<ZellijResult> {\n ensureZellijTarget()\n try {\n const result = await execFileAsync('zellij', zellijCommandArgs(actionArgs), {\n encoding: 'utf8',\n timeout: options.timeoutMs ?? 10_000,\n maxBuffer: 20 * 1024 * 1024,\n })\n\n return {\n stdout: result.stdout ?? '',\n stderr: result.stderr ?? '',\n }\n }\n catch (cause) {\n const error = cause as { message?: string, stdout?: string, stderr?: string }\n const stderr = error.stderr?.trim()\n const stdout = error.stdout?.trim()\n const detail = stderr || stdout || error.message || 'unknown error'\n throw new Error(`zellij ${actionArgs.join(' ')} failed: ${detail}`)\n }\n}\n\nexport class ZellijCli {\n async newPane(options: NewPaneOptions): Promise<string> {\n const result = await runZellij(buildNewPaneActionArgs(options))\n return parsePaneId(result.stdout)\n }\n\n async writeChars(paneId: string, data: string): Promise<void> {\n await runZellij(zellijActionArgs('write-chars', ['--pane-id', paneId, data]))\n }\n\n async sendCtrlC(paneId: string): Promise<void> {\n await runZellij(zellijActionArgs('send-keys', ['--pane-id', paneId, 'Ctrl c']))\n }\n\n async closePane(paneId: string): Promise<void> {\n await runZellij(zellijActionArgs('close-pane', ['--pane-id', paneId]))\n }\n\n closePaneSync(paneId: string): void {\n ensureZellijTarget()\n spawnSync('zellij', zellijCommandArgs(zellijActionArgs('close-pane', ['--pane-id', paneId])), {\n encoding: 'utf8',\n stdio: 'ignore',\n timeout: 2_000,\n })\n }\n\n async focusPane(paneId: string): Promise<void> {\n await runZellij(zellijActionArgs('focus-pane-id', [paneId]))\n }\n\n async dumpScreen(paneId: string): Promise<string> {\n const result = await runZellij(zellijActionArgs('dump-screen', ['--pane-id', paneId, '--full']), { timeoutMs: 10_000 })\n return result.stdout\n }\n\n async currentPaneTabId(): Promise<number | undefined> {\n const paneId = process.env.ZELLIJ_PANE_ID\n if (!paneId)\n return undefined\n\n const result = await runZellij(zellijActionArgs('list-panes', ['--json']), { timeoutMs: 5_000 })\n return parseCurrentPaneTabId(result.stdout, paneId)\n }\n\n async paneExists(paneId: string): Promise<boolean | undefined> {\n const result = await runZellij(zellijActionArgs('list-panes', ['--json']), { timeoutMs: 5_000 })\n return parsePaneExists(result.stdout, paneId)\n }\n\n async renameTab(title: string): Promise<void> {\n const tabId = await this.currentPaneTabId()\n if (tabId === undefined && process.env.ZELLIJ)\n throw new Error(`Could not resolve Zellij tab id for pane ${process.env.ZELLIJ_PANE_ID ?? '<missing>'}`)\n await runZellij(tabId === undefined ? buildRenameTabActionArgs(title) : buildRenameTabActionArgs(title, { tabId }))\n }\n\n async currentTabTitle(): Promise<string | undefined> {\n const paneId = process.env.ZELLIJ_PANE_ID\n if (!paneId)\n return undefined\n\n const tabId = await this.currentPaneTabId()\n if (tabId === undefined)\n return undefined\n const result = await runZellij(zellijActionArgs('list-tabs', ['--json']), { timeoutMs: 5_000 })\n return parseTabName(result.stdout, tabId)\n }\n}\n\nexport const zellijCli = new ZellijCli()\n","import type { PtySession } from '../pty/session.js'\nimport { spawn } from 'node:child_process'\nimport { randomUUID } from 'node:crypto'\nimport { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { fileURLToPath } from 'node:url'\nimport { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\n\nexport interface WatchdogPane {\n sessionId: string\n paneId: string\n title: string\n openCodeSessionId: string | null\n createdAt: string\n}\n\nexport interface WatchdogRegistry {\n version: 1\n instanceId: string\n ownerPid: number\n ownerStartTime: string | null\n zellijSessionName: string | null\n panes: WatchdogPane[]\n}\n\nconst instanceId = randomUUID()\nlet watchdogStarted = false\nlet watchdogChild: ReturnType<typeof spawn> | null = null\n\nfunction registryDirectory(): string {\n const base = process.env.XDG_RUNTIME_DIR || tmpdir()\n return path.join(base, `opencode-zellij-${process.getuid?.() ?? 'user'}`)\n}\n\nexport function watchdogRegistryPath(): string {\n return path.join(registryDirectory(), `panes-${process.pid}-${instanceId}.json`)\n}\n\nexport function parseLinuxProcessStartTime(stat: string): string | null {\n const fieldsAfterCommand = stat.slice(stat.lastIndexOf(')') + 2).trim().split(/\\s+/)\n return fieldsAfterCommand[19] ?? null\n}\n\nfunction linuxProcessStartTime(pid: number): string | null {\n try {\n return parseLinuxProcessStartTime(readFileSync(`/proc/${pid}/stat`, 'utf8'))\n }\n catch (error) {\n // Missing /proc data is expected when the owner has exited or on non-Linux systems.\n debug('linuxProcessStartTime failed', errorMessage(error))\n return null\n }\n}\n\nfunction emptyRegistry(): WatchdogRegistry {\n return {\n version: 1,\n instanceId,\n ownerPid: process.pid,\n ownerStartTime: linuxProcessStartTime(process.pid),\n zellijSessionName: process.env.ZELLIJ_SESSION_NAME?.trim() || null,\n panes: [],\n }\n}\n\nfunction readRegistry(): WatchdogRegistry {\n const file = watchdogRegistryPath()\n if (!existsSync(file))\n return emptyRegistry()\n\n try {\n const parsed = JSON.parse(readFileSync(file, 'utf8')) as WatchdogRegistry\n if (parsed.version !== 1 || parsed.instanceId !== instanceId || parsed.ownerPid !== process.pid || !Array.isArray(parsed.panes))\n return emptyRegistry()\n return parsed\n }\n catch (error) {\n // The current instance registry is corrupt or unreadable; start from an empty registry.\n debug('readRegistry failed', errorMessage(error))\n return emptyRegistry()\n }\n}\n\nfunction writeRegistry(registry: WatchdogRegistry): void {\n const directory = registryDirectory()\n mkdirSync(directory, { recursive: true, mode: 0o700 })\n const file = watchdogRegistryPath()\n const tempFile = `${file}.tmp-${process.pid}`\n writeFileSync(tempFile, JSON.stringify(registry, null, 2), { mode: 0o600 })\n renameSync(tempFile, file)\n}\n\nfunction ensureWatchdog(): void {\n if (watchdogStarted && watchdogChild)\n return\n watchdogStarted = true\n\n const child = spawn(process.execPath, [watchdogRunnerPath(), watchdogRegistryPath()], {\n detached: true,\n stdio: 'ignore',\n env: process.env,\n })\n watchdogChild = child\n child.unref()\n child.on('error', () => {\n // Child failed early or was killed; allow watchdog to be restarted on next pane registration.\n watchdogStarted = false\n if (watchdogChild === child)\n watchdogChild = null\n })\n child.on('exit', () => {\n watchdogStarted = false\n if (watchdogChild === child)\n watchdogChild = null\n if (existsSync(watchdogRegistryPath()))\n ensureWatchdog()\n })\n}\n\nfunction watchdogRunnerPath(): string {\n return fileURLToPath(new URL('./pane-watchdog-runner.mjs', import.meta.url))\n}\n\nexport function cleanupStaleWatchdogRegistries(): void {\n const directory = registryDirectory()\n if (!existsSync(directory))\n return\n\n for (const fileName of readdirSync(directory)) {\n if (!fileName.startsWith('panes-') || !fileName.endsWith('.json'))\n continue\n\n const file = path.join(directory, fileName)\n try {\n const registry = JSON.parse(readFileSync(file, 'utf8')) as WatchdogRegistry\n if (registry.version !== 1 || ownerStillMatches(registry))\n continue\n closeRegistryPanes(registry)\n rmSync(file, { force: true })\n }\n catch (error) {\n // Corrupt stale registries cannot be used safely and would otherwise fail every startup.\n debug('cleanupStaleWatchdogRegistries failed', errorMessage(error))\n rmSync(file, { force: true })\n }\n }\n}\n\nfunction ownerStillMatches(registry: WatchdogRegistry): boolean {\n try {\n process.kill(registry.ownerPid, 0)\n }\n catch (error) {\n // process.kill(pid, 0) throws when the owner is gone or inaccessible.\n debug('ownerStillMatches kill check failed', errorMessage(error))\n return false\n }\n\n return !registry.ownerStartTime || linuxProcessStartTime(registry.ownerPid) === registry.ownerStartTime\n}\n\nfunction closeRegistryPanes(registry: WatchdogRegistry): void {\n for (const pane of registry.panes) {\n const args = []\n if (registry.zellijSessionName)\n args.push('--session', registry.zellijSessionName)\n args.push('action', 'close-pane', '--pane-id', pane.paneId)\n spawn('zellij', args, { detached: true, stdio: 'ignore', env: process.env }).unref()\n }\n}\n\nexport function upsertWatchdogPane(registry: WatchdogRegistry, session: PtySession): WatchdogRegistry {\n return {\n ...registry,\n panes: [\n ...registry.panes.filter(pane => pane.sessionId !== session.id && pane.paneId !== session.paneId),\n {\n sessionId: session.id,\n paneId: session.paneId,\n title: session.title,\n openCodeSessionId: session.openCodeSessionId,\n createdAt: session.createdAt,\n },\n ],\n }\n}\n\nexport function removeWatchdogPane(registry: WatchdogRegistry, sessionId: string): WatchdogRegistry {\n return {\n ...registry,\n panes: registry.panes.filter(pane => pane.sessionId !== sessionId),\n }\n}\n\nexport function registerPaneForWatchdog(session: PtySession): void {\n writeRegistry(upsertWatchdogPane(readRegistry(), session))\n ensureWatchdog()\n}\n\nexport function unregisterPaneFromWatchdog(sessionId: string): void {\n const registry = readRegistry()\n const updated = removeWatchdogPane(registry, sessionId)\n if (updated.panes.length === registry.panes.length)\n return\n if (updated.panes.length === 0) {\n removeWatchdogRegistry()\n return\n }\n writeRegistry(updated)\n}\n\nexport function removeWatchdogRegistry(): void {\n try {\n rmSync(watchdogRegistryPath(), { force: true })\n }\n catch (error) {\n // Watchdog registry cleanup is best effort.\n debug('removeWatchdogRegistry failed', errorMessage(error))\n }\n if (!watchdogChild)\n watchdogStarted = false\n}\n","export interface ReadLinesInput {\n offset?: number | undefined\n limit?: number | undefined\n grep?: string | undefined\n ignoreCase?: boolean | undefined\n}\n\nexport interface ReadLinesResult {\n offset: number\n returned: number\n lineCount: number\n lines: string[]\n}\n\nconst escapeCharacter = String.fromCharCode(27)\nconst ansiPattern = new RegExp(`${escapeCharacter}\\\\[[0-9;?]*[a-z]`, 'gi')\n\nfunction normalizeLines(input: string | string[]): string[] {\n const lines = Array.isArray(input) ? input : input.replace(/\\r\\n/g, '\\n').split('\\n')\n if (lines.at(-1) === '')\n return lines.slice(0, -1)\n return lines\n}\n\nfunction stripAnsi(line: string): string {\n return line.replace(ansiPattern, '')\n}\n\nfunction overlapSize(existing: string[], incoming: string[]): number {\n const max = Math.min(existing.length, incoming.length)\n for (let size = max; size > 0; size -= 1) {\n const existingStart = existing.length - size\n let matches = true\n for (let index = 0; index < size; index += 1) {\n if (existing[existingStart + index] !== incoming[index]) {\n matches = false\n break\n }\n }\n if (matches)\n return size\n }\n return 0\n}\n\nexport class RingBuffer {\n private readonly maxLines: number\n private lines: string[] = []\n private totalAppended = 0\n\n constructor(maxLines = 50_000) {\n this.maxLines = Math.max(1, maxLines)\n }\n\n get lineCount(): number {\n return this.totalAppended\n }\n\n get startOffset(): number {\n return Math.max(0, this.totalAppended - this.lines.length)\n }\n\n append(input: string | string[]): number {\n const incoming = normalizeLines(input)\n if (incoming.length === 0)\n return 0\n this.lines.push(...incoming)\n this.totalAppended += incoming.length\n this.trim()\n return incoming.length\n }\n\n appendSnapshot(input: string | string[]): number {\n const incoming = normalizeLines(input)\n if (incoming.length === 0)\n return 0\n const overlap = overlapSize(this.lines, incoming)\n return this.append(incoming.slice(overlap))\n }\n\n read(input: ReadLinesInput = {}): ReadLinesResult {\n const limit = Math.max(1, Math.min(input.limit ?? 200, 5_000))\n const firstReadableOffset = this.startOffset\n const defaultOffset = Math.max(firstReadableOffset, this.lineCount - limit)\n const requestedOffset = input.offset ?? defaultOffset\n const offset = Math.max(firstReadableOffset, Math.min(requestedOffset, this.lineCount))\n const relativeOffset = offset - firstReadableOffset\n const unfiltered = this.lines.slice(relativeOffset, relativeOffset + limit)\n const pattern = input.grep ? new RegExp(input.grep, input.ignoreCase ? 'i' : '') : undefined\n const lines = unfiltered\n .map(stripAnsi)\n .filter(line => (pattern ? pattern.test(line) : true))\n\n return {\n offset,\n returned: lines.length,\n lineCount: this.lineCount,\n lines,\n }\n }\n\n clear(): void {\n this.lines = []\n this.totalAppended = 0\n }\n\n private trim(): void {\n if (this.lines.length <= this.maxLines)\n return\n this.lines = this.lines.slice(this.lines.length - this.maxLines)\n }\n}\n","import { randomUUID } from 'node:crypto'\n\nexport interface ExitCodeMarker {\n token: string\n exitCode: number\n}\n\nconst markerPattern = /^\\[zellij-pty:([a-f0-9]+)\\] exit-code=(\\d+)$/\nconst escapeCharacter = String.fromCharCode(27)\nconst ansiPattern = new RegExp(`${escapeCharacter}\\\\[[0-9;?]*[a-z]`, 'gi')\n\nexport function createExitCodeToken(): string {\n return randomUUID().replaceAll('-', '')\n}\n\nexport function parseExitCodeMarker(line: string): ExitCodeMarker | null {\n const match = line.replace(ansiPattern, '').trim().match(markerPattern)\n if (!match?.[1] || !match[2])\n return null\n return {\n token: match[1],\n exitCode: Number(match[2]),\n }\n}\n","import type { ChildProcessWithoutNullStreams } from 'node:child_process'\nimport type { SessionManager } from '../pty/manager.js'\nimport type { ReadLinesInput, ReadLinesResult } from '../pty/ring-buffer.js'\nimport type { PtySession, SessionTerminalReason } from '../pty/session.js'\nimport { spawn } from 'node:child_process'\nimport process from 'node:process'\nimport { sessionManager } from '../pty/manager.js'\nimport { RingBuffer } from '../pty/ring-buffer.js'\nimport { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { parseExitCodeMarker } from '../utils/exit-code.js'\nimport { ensureZellijTarget, zellijCli, zellijCommandArgs } from './cli.js'\nimport { unregisterPaneFromWatchdog } from './pane-watchdog.js'\n\ninterface SubscriberState {\n child: ChildProcessWithoutNullStreams | null\n buffer: RingBuffer\n stderr: string[]\n stdoutRemainder: string\n startedAt: string\n lastExitedAt: string | null\n}\n\nexport interface SubscriberTerminalEvent {\n sessionId: string\n reason: SessionTerminalReason\n session: PtySession\n}\n\nexport interface SubscriberLifecycleHooks {\n onSessionTerminal?: (event: SubscriberTerminalEvent) => void | Promise<void>\n}\n\nexport interface SubscriberManagerDependencies {\n spawn?: typeof spawn | undefined\n dumpScreen?: typeof zellijCli.dumpScreen | undefined\n paneExists?: typeof zellijCli.paneExists | undefined\n closePane?: typeof zellijCli.closePane | undefined\n lifecycleHooks?: SubscriberLifecycleHooks | undefined\n terminalTailLines?: number | undefined\n}\n\ntype JsonObject = Record<string, unknown>\n\nexport interface SubscriberStatus {\n hasBuffer: boolean\n active: boolean\n lastExitedAt: string | null\n terminal: boolean\n}\n\nconst maxStderrLines = 200\n\nfunction splitLines(input: string): string[] {\n const lines = input.replace(/\\r\\n/g, '\\n').split('\\n')\n if (lines.at(-1) === '')\n return lines.slice(0, -1)\n return lines\n}\n\nfunction textFromCell(cell: unknown): string {\n if (typeof cell === 'string')\n return cell\n if (!cell || typeof cell !== 'object')\n return ''\n const object = cell as JsonObject\n const value = object.text ?? object.character ?? object.ch ?? object.content\n return typeof value === 'string' ? value : ''\n}\n\nfunction linesFromRows(rows: unknown[]): string[] {\n return rows.map((row) => {\n if (typeof row === 'string')\n return row\n if (Array.isArray(row))\n return row.map(textFromCell).join('')\n return textFromCell(row)\n })\n}\n\nfunction eventPaneId(event: JsonObject): string | undefined {\n const paneId = event.pane_id ?? event.paneId\n return typeof paneId === 'string' ? paneId : undefined\n}\n\nfunction eventType(event: JsonObject): string | undefined {\n const type = event.event ?? event.type\n return typeof type === 'string' ? type : undefined\n}\n\nfunction extractRenderedLines(event: JsonObject): string[] {\n for (const key of ['viewport', 'scrollback', 'lines'] as const) {\n const value = event[key]\n if (Array.isArray(value))\n return linesFromRows(value)\n }\n\n for (const key of ['text', 'output', 'content'] as const) {\n const value = event[key]\n if (typeof value === 'string')\n return splitLines(value)\n }\n\n return []\n}\n\nexport class SubscriberManager {\n private readonly subscribers = new Map<string, SubscriberState>()\n // Per-session start promises to prevent concurrent spawn races\n private readonly startingSessions = new Map<string, Promise<void>>()\n private readonly spawnProcess: typeof spawn\n private readonly dumpScreen: typeof zellijCli.dumpScreen\n private readonly paneExists: typeof zellijCli.paneExists\n private readonly closePane: typeof zellijCli.closePane\n private lifecycleHooks: SubscriberLifecycleHooks | undefined\n private readonly terminalTailLines: number\n\n constructor(\n private readonly sessions: SessionManager,\n private readonly maxBufferLines = Number(process.env.PTY_MAX_BUFFER_LINES ?? 50_000),\n dependencies: SubscriberManagerDependencies = {},\n ) {\n this.spawnProcess = dependencies.spawn ?? spawn\n this.dumpScreen = dependencies.dumpScreen ?? zellijCli.dumpScreen\n this.paneExists = dependencies.paneExists ?? zellijCli.paneExists\n this.closePane = dependencies.closePane ?? zellijCli.closePane\n this.lifecycleHooks = dependencies.lifecycleHooks\n this.terminalTailLines = dependencies.terminalTailLines ?? 200\n }\n\n setLifecycleHooks(hooks: SubscriberLifecycleHooks | undefined): void {\n this.lifecycleHooks = hooks\n }\n\n async start(session: PtySession): Promise<void> {\n const currentSession = this.sessions.find(session.id) ?? session\n if (currentSession.status === 'terminal')\n return\n const existing = this.subscribers.get(session.id)\n if (existing?.child)\n return\n\n // Prevent concurrent start races for the same session\n const inProgress = this.startingSessions.get(session.id)\n if (inProgress)\n return inProgress\n\n ensureZellijTarget()\n\n const startPromise = this.doStart(session)\n this.startingSessions.set(session.id, startPromise)\n try {\n await startPromise\n }\n finally {\n this.startingSessions.delete(session.id)\n }\n }\n\n private async doStart(session: PtySession): Promise<void> {\n const existing = this.subscribers.get(session.id)\n\n const state: SubscriberState\n = existing\n ?? {\n child: null,\n buffer: new RingBuffer(this.maxBufferLines),\n stderr: [],\n stdoutRemainder: '',\n startedAt: new Date().toISOString(),\n lastExitedAt: null,\n }\n\n if (!existing) {\n this.subscribers.set(session.id, state)\n }\n\n const child = this.spawnProcess('zellij', zellijCommandArgs(['subscribe', '--pane-id', session.paneId, '--scrollback', '--format', 'json', '--ansi']), {\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n child.stdin.end()\n // Only assign child if state is still the same (no concurrent restart)\n const currentState = this.subscribers.get(session.id)\n if (currentState !== state) {\n child.kill('SIGTERM')\n return\n }\n state.child = child\n state.lastExitedAt = null\n\n child.stdout.setEncoding('utf8')\n child.stdout.on('data', (chunk: string) => this.handleStdout(session.id, child, chunk))\n child.stderr.setEncoding('utf8')\n child.stderr.on('data', (chunk: string) => this.handleStderr(session.id, child, chunk))\n child.on('exit', () => this.handleSubscriberExit(session.id, child))\n child.on('error', error => this.handleSubscriberError(session.id, child, error))\n\n if (!existing) {\n try {\n const snapshot = await this.dumpScreen(session.paneId)\n if (this.subscribers.get(session.id) !== state || state.child !== child)\n return\n state.buffer.appendSnapshot(snapshot)\n this.sessions.updateLineCount(session.id, state.buffer.lineCount)\n }\n catch (error) {\n // dump-screen may race with pane creation; subscribe will still collect future output.\n debug('dumpScreen failed', errorMessage(error))\n }\n }\n }\n\n read(sessionId: string, input: ReadLinesInput): ReadLinesResult {\n const state = this.subscribers.get(sessionId)\n if (!state)\n throw new Error(`No subscriber buffer exists for session: ${sessionId}`)\n return state.buffer.read(input)\n }\n\n has(sessionId: string): boolean {\n return this.subscribers.has(sessionId)\n }\n\n status(sessionId: string): SubscriberStatus {\n const state = this.subscribers.get(sessionId)\n return {\n hasBuffer: Boolean(state),\n active: Boolean(state?.child),\n lastExitedAt: state?.lastExitedAt ?? null,\n terminal: this.sessions.find(sessionId)?.status === 'terminal',\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, options: { throwOnFailure?: boolean } = {}): Promise<void> {\n const session = this.sessions.get(sessionId)\n this.stop(sessionId)\n try {\n await this.closePane(session.paneId)\n }\n catch (error) {\n // Pane may already be closed by the user or command exit.\n debug('closePane failed', errorMessage(error))\n if (options.throwOnFailure)\n throw error\n }\n }\n\n private handleStdout(sessionId: string, child: ChildProcessWithoutNullStreams, chunk: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state || state.child !== child)\n return\n\n const parts = `${state.stdoutRemainder}${chunk}`.split('\\n')\n state.stdoutRemainder = parts.pop() ?? ''\n for (const part of parts) {\n this.handleJsonLine(sessionId, child, part)\n }\n }\n\n private handleJsonLine(sessionId: string, child: ChildProcessWithoutNullStreams, line: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state || state.child !== child)\n return\n const trimmed = line.trim()\n if (!trimmed)\n return\n\n let event: JsonObject\n try {\n const parsed: unknown = JSON.parse(trimmed)\n if (!parsed || typeof parsed !== 'object')\n return\n event = parsed as JsonObject\n }\n catch (error) {\n state.buffer.append(trimmed)\n this.sessions.updateLineCount(sessionId, state.buffer.lineCount)\n debug('JSON parse of subscriber event failed, treating as raw text', errorMessage(error))\n return\n }\n\n let session: PtySession\n try {\n session = this.sessions.get(sessionId)\n }\n catch (error) {\n this.forget(sessionId)\n debug('session lookup by id failed', errorMessage(error))\n return\n }\n const paneId = eventPaneId(event)\n if (paneId && paneId !== session.paneId)\n return\n\n const type = eventType(event)\n if (type === 'pane_closed' || type === 'PaneClosed') {\n this.markSessionTerminal(sessionId, 'pane_closed')\n unregisterPaneFromWatchdog(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.markSessionTerminal(sessionId, 'exit_marker', { exitCode: marker.exitCode })\n return\n }\n }\n\n private handleStderr(sessionId: string, child: ChildProcessWithoutNullStreams, chunk: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state || state.child !== child)\n return\n this.appendStderr(state, ...splitLines(chunk))\n }\n\n private handleSubscriberExit(sessionId: string, child: ChildProcessWithoutNullStreams): void {\n const state = this.subscribers.get(sessionId)\n if (!state)\n return\n if (state.child !== child)\n return\n state.child = null\n state.lastExitedAt = new Date().toISOString()\n if (this.sessions.find(sessionId)?.status !== 'terminal')\n this.appendStderr(state, `[zellij-pty] subscriber exited at ${state.lastExitedAt}; last buffered output is retained.`)\n void this.reconcileSubscriberTermination(sessionId, state, 'subscriber_exit')\n }\n\n private handleSubscriberError(sessionId: string, child: ChildProcessWithoutNullStreams, error: Error): void {\n const state = this.subscribers.get(sessionId)\n if (state?.child === child) {\n this.appendStderr(state, error.message)\n state.child = null\n state.lastExitedAt = new Date().toISOString()\n const session = this.sessions.find(sessionId)\n if (session?.status !== 'terminal')\n this.sessions.updateStatus(sessionId, 'unknown')\n void this.reconcileSubscriberTermination(sessionId, state, 'subscriber_error')\n }\n }\n\n private appendStderr(state: SubscriberState, ...lines: string[]): void {\n state.stderr.push(...lines)\n if (state.stderr.length > maxStderrLines)\n state.stderr = state.stderr.slice(state.stderr.length - maxStderrLines)\n }\n\n private async reconcileSubscriberTermination(\n sessionId: string,\n state: SubscriberState,\n reason: Extract<SessionTerminalReason, 'subscriber_exit' | 'subscriber_error'>,\n ): Promise<void> {\n const session = this.sessions.find(sessionId)\n if (!session || session.status === 'terminal' || this.subscribers.get(sessionId) !== state || state.child)\n return\n\n let paneExists: boolean | undefined\n try {\n paneExists = await this.paneExists(session.paneId)\n }\n catch (error) {\n const latestState = this.subscribers.get(sessionId)\n const latestSession = this.sessions.find(sessionId)\n if (!latestState || latestState !== state || latestState.child || !latestSession || latestSession.status === 'terminal')\n return\n this.appendStderr(latestState, `[zellij-pty] ${reason} reconciliation could not verify pane ${latestSession.paneId}: ${errorMessage(error)}`)\n return\n }\n\n const latestState = this.subscribers.get(sessionId)\n const latestSession = this.sessions.find(sessionId)\n if (!latestState || latestState !== state || latestState.child || !latestSession || latestSession.status === 'terminal')\n return\n\n if (paneExists === false) {\n this.markSessionTerminal(sessionId, reason)\n unregisterPaneFromWatchdog(sessionId)\n return\n }\n\n if (paneExists === undefined) {\n this.appendStderr(latestState, `[zellij-pty] ${reason} reconciliation could not confirm whether pane ${latestSession.paneId} still exists; leaving session non-terminal.`)\n }\n }\n\n private markSessionTerminal(sessionId: string, reason: SessionTerminalReason, input: { exitCode?: number | undefined } = {}): void {\n const state = this.subscribers.get(sessionId)\n if (!state)\n return\n\n const tail = state.buffer.read({ limit: this.terminalTailLines }).lines\n const result = this.sessions.markTerminal(sessionId, {\n reason,\n tail,\n exitCode: input.exitCode,\n })\n\n if (result.created) {\n try {\n const maybePromise = this.lifecycleHooks?.onSessionTerminal?.({\n sessionId,\n reason,\n session: result.session,\n })\n if (maybePromise && typeof maybePromise.then === 'function') {\n void maybePromise.catch((error) => {\n debug('onSessionTerminal hook failed', errorMessage(error))\n })\n }\n }\n catch (error) {\n debug('onSessionTerminal hook failed', errorMessage(error))\n }\n }\n\n this.stop(sessionId)\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 === 'terminal' ? 'exited' : 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 tombstone: session.tombstone\n ? {\n reason: session.tombstone.reason,\n terminalAt: session.tombstone.terminalAt,\n tailLines: session.tombstone.tail.length,\n paneClosedAt: session.tombstone.paneClosedAt,\n notificationSentAt: session.tombstone.notificationSentAt,\n }\n : null,\n }\n}\n\nexport interface NextAdvice {\n retryable: boolean\n reason: string\n}\n\nexport function nextAdvice(retryable: boolean, reason: string): NextAdvice {\n return { retryable, reason }\n}\n\nexport function jsonResponse(value: unknown): string {\n return JSON.stringify(value, null, 2)\n}\n","import { sessionManager } from '../pty/manager.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\n\nexport interface OutputSnapshot {\n text: string\n lines: string[]\n lineCount: number\n returned: number\n truncated: boolean\n}\n\nexport function emptyOutputSnapshot(lineCount = 0): OutputSnapshot {\n return { text: '', lines: [], lineCount, returned: 0, truncated: false }\n}\n\nexport interface OutputOptions {\n maxLines?: number | undefined\n grep?: string | undefined\n ignoreCase?: boolean | undefined\n}\n\nexport function validateGrep(grep: string | undefined): string | null {\n if (!grep)\n return null\n try {\n new RegExp(grep).test('')\n return null\n }\n catch (error) {\n return errorMessage(error)\n }\n}\n\nexport function readOutputSnapshot(sessionId: string, options: OutputOptions = {}): OutputSnapshot {\n const grepError = validateGrep(options.grep)\n if (grepError)\n throw new Error(`Invalid grep regex: ${grepError}`)\n\n const buffered = subscriberManager.read(sessionId, {\n limit: options.maxLines,\n grep: options.grep,\n ignoreCase: options.ignoreCase,\n })\n sessionManager.updateLineCount(sessionId, buffered.lineCount)\n\n return {\n text: buffered.lines.join('\\n'),\n lines: buffered.lines,\n lineCount: buffered.lineCount,\n returned: buffered.returned,\n truncated: buffered.offset > 0,\n }\n}\n\nexport function outputMatches(sessionId: string, grep: string, ignoreCase?: boolean | undefined): boolean {\n return readOutputSnapshot(sessionId, { maxLines: 5_000, grep, ignoreCase }).returned > 0\n}\n","export type PaneExistsFn = (paneId: string) => Promise<boolean | undefined> | boolean | undefined\n\nexport interface ClosePaneOrVerifyGoneInput {\n paneId: string\n closePane: () => Promise<void>\n paneExists?: PaneExistsFn | undefined\n}\n\nexport interface ClosePaneOrVerifyGoneResult {\n cleanupReady: boolean\n alreadyGone: boolean\n closeErrorMessage?: string | undefined\n}\n\nexport async function closePaneOrVerifyGone(input: ClosePaneOrVerifyGoneInput): Promise<ClosePaneOrVerifyGoneResult> {\n try {\n await input.closePane()\n return { cleanupReady: true, alreadyGone: false }\n }\n catch (error) {\n const closeErrorMessage = error instanceof Error ? error.message : String(error)\n const paneGone = await isPaneGone(input.paneId, input.paneExists)\n if (paneGone)\n return { cleanupReady: true, alreadyGone: true, closeErrorMessage }\n return { cleanupReady: false, alreadyGone: false, closeErrorMessage }\n }\n}\n\nasync function isPaneGone(paneId: string, paneExists?: PaneExistsFn | undefined): Promise<boolean> {\n if (!paneExists)\n return false\n\n try {\n return (await paneExists(paneId)) === false\n }\n catch {\n return false\n }\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'\nimport { closePaneOrVerifyGone } from './pane-cleanup.js'\n\nconst schema = tool.schema\n\nexport interface KillToolDependencies {\n zellijCli?: Pick<typeof zellijCli, 'sendCtrlC' | 'closePane' | 'paneExists'> | undefined\n}\n\nexport interface KillToolResult {\n killed: boolean\n cleanedUp: boolean\n id?: string | undefined\n paneId?: string | undefined\n session?: ReturnType<typeof publicSession> | undefined\n output?: ReturnType<typeof readOutputSnapshot> | undefined\n next: ReturnType<typeof nextAdvice>\n warnings: string[]\n}\n\nexport async function executeZellijPtyKill(args: { id: string }, dependencies: KillToolDependencies = {}): Promise<KillToolResult> {\n const zellijCliApi = dependencies.zellijCli ?? zellijCli\n const session = sessionManager.get(args.id)\n const warnings: string[] = []\n const output = subscriberManager.has(session.id) ? readOutputSnapshot(session.id) : undefined\n\n try {\n await zellijCliApi.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 const closeResult = await closePaneOrVerifyGone({\n paneId: session.paneId,\n closePane: () => zellijCliApi.closePane(session.paneId),\n paneExists: zellijCliApi.paneExists,\n })\n\n if (!closeResult.cleanupReady) {\n warnings.push(`close-pane failed: ${closeResult.closeErrorMessage ?? 'unknown error'}`)\n const updated = sessionManager.updateStatus(session.id, 'unknown')\n return {\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 return finalizeKilledSession(session.id, session.paneId, output, warnings)\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 return jsonResponse(await executeZellijPtyKill(args))\n },\n})\n\nasync function finalizeKilledSession(\n sessionId: string,\n paneId: string,\n output: ReturnType<typeof readOutputSnapshot> | undefined,\n warnings: string[],\n): Promise<KillToolResult> {\n subscriberManager.stop(sessionId)\n subscriberManager.forget(sessionId)\n unregisterPaneFromWatchdog(sessionId)\n sessionManager.remove(sessionId)\n return {\n killed: true,\n cleanedUp: true,\n id: sessionId,\n paneId,\n output,\n next: nextAdvice(false, 'Session was closed and removed from the in-memory registry.'),\n 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 type { PaneExistsFn } from './pane-cleanup.js'\nimport { tool } from '@opencode-ai/plugin'\nimport { sessionManager } from '../pty/manager.js'\nimport { zellijCli } from '../zellij/cli.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { readOutputSnapshot, validateGrep } from './output.js'\nimport { closePaneOrVerifyGone } from './pane-cleanup.js'\n\nconst schema = tool.schema\n\nexport interface ReadToolArgs {\n id: string\n maxLines?: number | undefined\n grep?: string | undefined\n ignoreCase?: boolean | undefined\n cleanupExitedPaneOnRead?: boolean | undefined\n}\n\nexport interface ReadCleanupResult {\n requested: boolean\n performed: boolean\n alreadyClosed: boolean\n warning?: string | undefined\n}\n\nexport interface ReadToolResult {\n session: ReturnType<typeof publicSession>\n output: ReturnType<typeof readOutputSnapshot>\n next: ReturnType<typeof nextAdvice>\n subscriberActive: boolean\n subscriberLastExitedAt: string | null\n subscriberErrors: string[]\n warnings: string[]\n cleanup: ReadCleanupResult\n}\n\nexport interface ReadToolDependencies {\n sessionManager?: Pick<typeof sessionManager, 'get' | 'updateStatus' | 'markTerminalPaneClosed'> | undefined\n subscriberManager?: Pick<typeof subscriberManager, 'status' | 'start' | 'stderr' | 'closeSessionPane'> | undefined\n publicSession?: typeof publicSession | undefined\n nextAdvice?: typeof nextAdvice | undefined\n readOutputSnapshot?: typeof readOutputSnapshot | undefined\n validateGrep?: typeof validateGrep | undefined\n paneExists?: PaneExistsFn | undefined\n defaultCleanupExitedPaneOnRead?: boolean | undefined\n}\n\nexport async function executeZellijPtyRead(args: ReadToolArgs, dependencies: ReadToolDependencies = {}): Promise<ReadToolResult> {\n const sessionManagerApi = dependencies.sessionManager ?? sessionManager\n const subscriberManagerApi = dependencies.subscriberManager ?? subscriberManager\n const publicSessionApi = dependencies.publicSession ?? publicSession\n const nextAdviceApi = dependencies.nextAdvice ?? nextAdvice\n const readOutputSnapshotApi = dependencies.readOutputSnapshot ?? readOutputSnapshot\n const validateGrepApi = dependencies.validateGrep ?? validateGrep\n const paneExistsApi = dependencies.paneExists ?? zellijCli.paneExists\n\n const session = sessionManagerApi.get(args.id)\n const grepError = validateGrepApi(args.grep)\n if (grepError) {\n return {\n session: publicSessionApi(session),\n output: { text: '', lines: [], lineCount: session.lineCount, returned: 0, truncated: false },\n next: nextAdviceApi(false, `Invalid grep regex: ${grepError}`),\n subscriberActive: false,\n subscriberLastExitedAt: null,\n subscriberErrors: [],\n warnings: [],\n cleanup: { requested: false, performed: false, alreadyClosed: false },\n }\n }\n\n const subscriberStatus = subscriberManagerApi.status(session.id)\n if (!subscriberStatus.hasBuffer || (!subscriberStatus.active && (session.status === 'running' || session.status === 'unknown')))\n await subscriberManagerApi.start(session)\n\n const statusAfterStart = subscriberManagerApi.status(session.id)\n const warnings: string[] = []\n if (session.humanInputOnly)\n warnings.push('This pane is human-input-only: agent writes are forbidden, but rendered output is visible to the agent.')\n\n if (!statusAfterStart.active && session.status === 'running') {\n warnings.push('Subscriber is inactive; returned output may be stale.')\n sessionManagerApi.updateStatus(session.id, 'unknown')\n }\n\n const output = readOutputSnapshotApi(session.id, { maxLines: args.maxLines, grep: args.grep, ignoreCase: args.ignoreCase })\n const cleanup = await cleanupExitedPaneOnRead(session.id, session.status, args.cleanupExitedPaneOnRead ?? dependencies.defaultCleanupExitedPaneOnRead ?? true, {\n sessionManager: sessionManagerApi,\n subscriberManager: subscriberManagerApi,\n paneExists: paneExistsApi,\n })\n if (cleanup.warning)\n warnings.push(cleanup.warning)\n\n return {\n session: publicSessionApi(session),\n output,\n next: nextAdviceApi(!isCompletedSession(session.status), nextReadReason(session.status)),\n subscriberActive: statusAfterStart.active,\n subscriberLastExitedAt: statusAfterStart.lastExitedAt,\n subscriberErrors: subscriberManagerApi.stderr(session.id),\n warnings,\n cleanup,\n }\n}\n\nasync function cleanupExitedPaneOnRead(\n sessionId: string,\n status: string,\n enabled: boolean,\n dependencies: {\n sessionManager: Pick<typeof sessionManager, 'get' | 'markTerminalPaneClosed'>\n subscriberManager: Pick<typeof subscriberManager, 'closeSessionPane'>\n paneExists: PaneExistsFn\n },\n): Promise<ReadCleanupResult> {\n const requested = enabled && isCompletedSession(status)\n if (!requested)\n return { requested: false, performed: false, alreadyClosed: false }\n\n const session = dependencies.sessionManager.get(sessionId)\n if (session.tombstone?.paneClosedAt)\n return { requested: true, performed: false, alreadyClosed: true }\n\n const closeResult = await closePaneOrVerifyGone({\n paneId: session.paneId,\n closePane: () => dependencies.subscriberManager.closeSessionPane(sessionId, { throwOnFailure: true }),\n paneExists: dependencies.paneExists,\n })\n\n if (closeResult.cleanupReady) {\n dependencies.sessionManager.markTerminalPaneClosed(sessionId)\n return { requested: true, performed: true, alreadyClosed: closeResult.alreadyGone }\n }\n return {\n requested: true,\n performed: false,\n alreadyClosed: false,\n warning: `Completed pane cleanup failed: ${closeResult.closeErrorMessage ?? 'unknown error'}`,\n }\n}\n\nexport function createZellijPtyReadTool(options: { defaultCleanupExitedPaneOnRead?: boolean | undefined, dependencies?: ReadToolDependencies | undefined } = {}) {\n return 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 cleanupExitedPaneOnRead: schema.boolean().optional().describe('Close completed panes after returning the final output. Defaults to true.'),\n },\n async execute(args) {\n return jsonResponse(await executeZellijPtyRead(args, {\n ...options.dependencies,\n defaultCleanupExitedPaneOnRead: options.defaultCleanupExitedPaneOnRead,\n }))\n },\n })\n}\n\nexport const zellijPtyReadTool = createZellijPtyReadTool()\n\nfunction isCompletedSession(status: string): boolean {\n return status === 'terminal' || status === 'exited' || status === 'killed'\n}\n\nfunction nextReadReason(status: string): string {\n if (status === 'terminal')\n return 'Session has finished; the final output is retained until the completed pane is read and cleaned up.'\n if (status === 'running')\n return 'Session is still running; read again later if more output is expected.'\n if (status === 'unknown')\n return 'Session state is unknown because the subscriber is inactive; output may be stale, but retrying read may restart observation.'\n return 'Session is no longer running.'\n}\n","import { randomUUID } from 'node:crypto'\n\nconst generatedInstanceId = randomUUID().replaceAll('-', '').slice(0, 8)\nconst existingOpenCodePrefixPattern = /^oc:[a-z0-9]{4,16}:/i\n\nexport function createOpenCodePaneTitle(title: string, instanceId = generatedInstanceId): string {\n const trimmedTitle = title.trim() || 'opencode'\n if (existingOpenCodePrefixPattern.test(trimmedTitle))\n return trimmedTitle\n\n const safeInstanceId = instanceId.replace(/[^a-z0-9]/gi, '').slice(0, 8) || generatedInstanceId\n return `oc:${safeInstanceId}:${trimmedTitle}`\n}\n","import { tool } from '@opencode-ai/plugin'\nimport { assertSudoPaneAllowed } from '../permissions/sudo-pane.js'\nimport { sessionManager } from '../pty/manager.js'\nimport { createExitCodeToken } from '../utils/exit-code.js'\nimport { createOpenCodePaneTitle } from '../utils/pane-title.js'\nimport { zellijCli } from '../zellij/cli.js'\nimport { registerPaneForWatchdog } from '../zellij/pane-watchdog.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { readOutputSnapshot } from './output.js'\n\nconst schema = tool.schema\n\nexport function shellQuote(value: string): string {\n return `'${value.replaceAll('\\'', `'\"'\"'`)}'`\n}\n\nexport function buildReviewScript(summary: string, scripts: Array<{ command: string, description: string }>): string {\n const lines = [\n 'set +e',\n 'printf \\'%s\\\\n\\' \\'=== OpenCode sudo request ===\\'',\n `printf '%s\\\\n' ${shellQuote(summary)}`,\n 'printf \\'\\\\n%s\\\\n\\' \\'Commands to review:\\'',\n ]\n\n scripts.forEach((script, index) => {\n const number = index + 1\n lines.push(`printf '\\\\n[%s/%s] %s\\\\n' ${shellQuote(String(number))} ${shellQuote(String(scripts.length))} ${shellQuote(script.description)}`)\n lines.push(`printf ' $ %s\\\\n' ${shellQuote(script.command)}`)\n })\n\n lines.push(\n 'printf \\'\\\\n%s\\\\n\\' \\'This pane is human-input-only. The agent cannot type here.\\'',\n 'read -r -p \\'Type YES to run these commands, anything else to cancel: \\' answer',\n 'if [ \"$answer\" != YES ]; then printf \\'%s\\\\n\\' \\'Cancelled by user.\\'; exit 130; fi',\n 'status=0',\n )\n\n scripts.forEach((script, index) => {\n const number = index + 1\n lines.push(`printf '\\\\n[%s/%s] %s\\\\n' ${shellQuote(String(number))} ${shellQuote(String(scripts.length))} ${shellQuote(script.description)}`)\n lines.push(`printf '$ %s\\\\n' ${shellQuote(script.command)}`)\n lines.push(`bash -lc ${shellQuote(script.command)}`)\n lines.push('code=$?')\n lines.push('if [ $code -ne 0 ]; then status=$code; printf \\'Command failed with exit code %s\\\\n\\' \"$code\"; break; fi')\n })\n\n lines.push('exit $status')\n return lines.join('\\n')\n}\n\nexport const requestSudoTool = tool({\n description: 'Open a human-reviewed, human-input-only Zellij pane for sudo or other privileged commands.',\n args: {\n summary: schema.string().min(1).describe('TL;DR of why privileged or human-reviewed execution is needed.'),\n scripts: schema\n .array(\n schema.object({\n command: schema.string().min(1).describe('Command or script to run after the user explicitly approves in the pane.'),\n description: schema.string().min(1).describe('Why this command is needed and what it is expected to change.'),\n }),\n )\n .min(1)\n .describe('Commands shown to the user for review before execution.'),\n },\n async execute(args, context) {\n const cwd = context.directory\n const exitCodeToken = createExitCodeToken()\n assertSudoPaneAllowed()\n\n const command = buildReviewScript(args.summary, args.scripts)\n const title = createOpenCodePaneTitle('zellij_pty_request_sudo')\n const paneId = await zellijCli.newPane({\n command: 'bash',\n args: ['-lc', command],\n cwd,\n title,\n floating: true,\n exitCodeToken,\n })\n\n const warnings: string[] = []\n try {\n await zellijCli.focusPane(paneId)\n }\n catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n if (!message.includes('already focused'))\n throw error\n warnings.push('Pane was already focused after creation.')\n }\n\n const session = sessionManager.create({\n openCodeSessionId: context.sessionID,\n paneId,\n title,\n command: 'zellij_pty_request_sudo',\n args: [],\n cwd,\n allowAgentInput: false,\n humanInputOnly: true,\n exitCodeToken,\n })\n registerPaneForWatchdog(session)\n await subscriberManager.start(session)\n\n return jsonResponse({\n session: publicSession(session),\n output: readOutputSnapshot(session.id),\n next: nextAdvice(false, 'The user must review the summary and commands in Zellij, then type YES and any required credentials directly in the pane.'),\n warnings,\n })\n },\n})\n","import { setTimeout as delay } from 'node:timers/promises'\n\nexport type Probe\n = | { type: 'sleep', seconds?: number | undefined }\n | { type: 'http', url: string, expectStatus?: number | undefined, timeoutSeconds?: number | undefined }\n | { type: 'output', grep: string, ignoreCase?: boolean | undefined, timeoutSeconds?: number | undefined }\n\nexport interface ProbeResult {\n type: Probe['type']\n ok: boolean\n message: string\n elapsedMs: number\n}\n\nexport type OutputProbeReader = (grep: string, ignoreCase: boolean | undefined) => boolean\n\nconst defaultSleepSeconds = 1\nconst defaultProbeTimeoutSeconds = 20\nconst pollIntervalMs = 250\n\nexport async function runProbe(probe: Probe | undefined, outputReader: OutputProbeReader): Promise<ProbeResult> {\n const startedAt = Date.now()\n const effectiveProbe = probe ?? { type: 'sleep', seconds: defaultSleepSeconds }\n\n if (effectiveProbe.type === 'sleep') {\n const seconds = effectiveProbe.seconds ?? defaultSleepSeconds\n await delay(seconds * 1_000)\n return result(effectiveProbe.type, true, `Slept for ${seconds}s.`, startedAt)\n }\n\n if (effectiveProbe.type === 'output') {\n const timeoutSeconds = effectiveProbe.timeoutSeconds ?? defaultProbeTimeoutSeconds\n const deadline = Date.now() + timeoutSeconds * 1_000\n while (Date.now() <= deadline) {\n if (outputReader(effectiveProbe.grep, effectiveProbe.ignoreCase)) {\n return result(effectiveProbe.type, true, `Observed output matching /${effectiveProbe.grep}/.`, startedAt)\n }\n await delay(pollIntervalMs)\n }\n return result(effectiveProbe.type, false, `Timed out after ${timeoutSeconds}s waiting for output matching /${effectiveProbe.grep}/.`, startedAt)\n }\n\n const timeoutSeconds = effectiveProbe.timeoutSeconds ?? defaultProbeTimeoutSeconds\n const deadline = Date.now() + timeoutSeconds * 1_000\n const expectStatus = effectiveProbe.expectStatus\n let lastError = 'no response'\n\n while (Date.now() <= deadline) {\n try {\n const remainingMs = Math.max(1, deadline - Date.now())\n const response = await fetch(effectiveProbe.url, { signal: AbortSignal.timeout(Math.min(remainingMs, 3_000)) })\n const ok = expectStatus === undefined ? response.status >= 200 && response.status < 400 : response.status === expectStatus\n if (ok) {\n const expected = expectStatus === undefined ? '2xx/3xx' : String(expectStatus)\n return result(effectiveProbe.type, true, `HTTP probe ${effectiveProbe.url} returned expected status ${expected}.`, startedAt)\n }\n lastError = `HTTP ${response.status}`\n }\n catch (error) {\n lastError = error instanceof Error ? error.message : String(error)\n }\n await delay(pollIntervalMs)\n }\n\n return result(effectiveProbe.type, false, `Timed out after ${timeoutSeconds}s probing ${effectiveProbe.url}: ${lastError}.`, startedAt)\n}\n\nfunction result(type: Probe['type'], ok: boolean, message: string, startedAt: number): ProbeResult {\n return { type, ok, message, elapsedMs: Date.now() - startedAt }\n}\n","import type { Probe } from '../pty/probe.js'\nimport { tool } from '@opencode-ai/plugin'\nimport { sessionManager } from '../pty/manager.js'\nimport { runProbe } from '../pty/probe.js'\nimport { createExitCodeToken } from '../utils/exit-code.js'\nimport { createOpenCodePaneTitle } from '../utils/pane-title.js'\nimport { zellijCli } from '../zellij/cli.js'\nimport { registerPaneForWatchdog } from '../zellij/pane-watchdog.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { outputMatches, readOutputSnapshot, validateGrep } from './output.js'\n\nconst schema = tool.schema\n\nconst probeSchema = schema.discriminatedUnion('type', [\n schema.object({\n type: schema.literal('sleep'),\n seconds: schema.number().positive().max(300).optional().describe('Seconds to wait before returning initial output. Defaults to 1.'),\n }),\n schema.object({\n type: schema.literal('http'),\n url: schema.string().url().describe('HTTP URL to poll until it returns the expected status.'),\n expectStatus: schema.number().int().min(100).max(599).optional().describe('Expected HTTP status. Defaults to any 2xx/3xx response.'),\n timeoutSeconds: schema.number().positive().max(300).optional().describe('How long to poll before returning a failed probe result. Defaults to 20.'),\n }),\n schema.object({\n type: schema.literal('output'),\n grep: schema.string().describe('Regex to search for in observed pane output.'),\n ignoreCase: schema.boolean().optional().describe('Use case-insensitive regex matching.'),\n timeoutSeconds: schema.number().positive().max(300).optional().describe('How long to wait for matching output. Defaults to 20.'),\n }),\n])\n\nexport const zellijPtySpawnTool = tool({\n description: 'Create a visible Zellij pane and run a command in it.',\n args: {\n command: schema.string().describe('Command to run. Without args, it is executed through bash -lc.'),\n args: schema.array(schema.string()).optional().describe('Optional argv. When provided, command is executed directly without shell parsing.'),\n cwd: schema.string().optional().describe('Working directory for the new pane.'),\n title: schema.string().optional().describe('Pane title/name.'),\n probe: probeSchema.optional().describe('Optional readiness probe. Defaults to a short sleep before returning output.'),\n maxLines: schema.number().int().positive().max(5_000).optional().describe('Maximum recent output lines to return. Defaults to 200.'),\n },\n async execute(args, context) {\n const cwd = args.cwd ?? context.directory\n const exitCodeToken = createExitCodeToken()\n const grepError = args.probe?.type === 'output' ? validateGrep(args.probe.grep) : null\n if (grepError)\n throw new Error(`Invalid probe.grep regex: ${grepError}`)\n const title = createOpenCodePaneTitle(args.title ?? args.command)\n\n const paneId = await zellijCli.newPane({\n command: args.command,\n args: args.args,\n cwd,\n title,\n floating: false,\n exitCodeToken,\n })\n\n const session = sessionManager.create({\n openCodeSessionId: context.sessionID,\n paneId,\n title,\n command: args.command,\n args: args.args,\n cwd,\n allowAgentInput: true,\n humanInputOnly: false,\n exitCodeToken,\n })\n registerPaneForWatchdog(session)\n await subscriberManager.start(session)\n const probe = await runProbe(args.probe as Probe | undefined, (grep, ignoreCase) => outputMatches(session.id, grep, ignoreCase))\n const output = readOutputSnapshot(session.id, { maxLines: args.maxLines })\n\n return jsonResponse({\n session: publicSession(session),\n output,\n probe,\n next: nextAdvice(probe.ok, probe.ok ? 'Probe completed; continue with this session or read later for long-running output.' : probe.message),\n warnings: ['Registry remains in-memory; restarting OpenCode loses plugin session records.'],\n })\n },\n})\n","import { Buffer } from 'node:buffer'\nimport process from 'node:process'\n\nconst defaultMaxWriteBytes = 64 * 1024\nconst defaultChunkBytes = 8 * 1024\n\nexport function maxWriteBytes(): number {\n const configured = Number(process.env.ZELLIJ_PTY_MAX_WRITE_BYTES ?? defaultMaxWriteBytes)\n return Number.isFinite(configured) && configured > 0 ? configured : defaultMaxWriteBytes\n}\n\nexport function assertWriteSizeAllowed(data: string): void {\n const bytes = Buffer.byteLength(data, 'utf8')\n const maxBytes = maxWriteBytes()\n if (bytes > maxBytes) {\n throw new Error(`Write payload is too large: ${bytes} bytes exceeds ${maxBytes} bytes. Split the input into smaller writes.`)\n }\n}\n\nexport function chunkWriteData(data: string, maxChunkBytes = defaultChunkBytes): string[] {\n const chunks: string[] = []\n let current = ''\n let currentBytes = 0\n\n for (const character of data) {\n const characterBytes = Buffer.byteLength(character, 'utf8')\n if (current && currentBytes + characterBytes > maxChunkBytes) {\n chunks.push(current)\n current = ''\n currentBytes = 0\n }\n current += character\n currentBytes += characterBytes\n }\n\n if (current)\n chunks.push(current)\n return chunks\n}\n","import { setTimeout as delay } from 'node:timers/promises'\nimport { tool } from '@opencode-ai/plugin'\nimport { sessionManager } from '../pty/manager.js'\nimport { assertWriteSizeAllowed, chunkWriteData } from '../pty/write-data.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { zellijCli } from '../zellij/cli.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { emptyOutputSnapshot, readOutputSnapshot } from './output.js'\n\nconst schema = tool.schema\n\nexport const zellijPtyWriteTool = tool({\n description: 'Write stdin to a Zellij PTY session. Refuses human-input-only sessions.',\n args: {\n id: schema.string().describe('zellij-pty session id returned by zellij_pty_spawn or zellij_pty_request_sudo.'),\n data: schema.string().describe('Text to write. Use \\u0003 to send Ctrl-C.'),\n maxLines: schema.number().int().positive().max(5_000).optional().describe('Maximum recent output lines to return. Defaults to 200.'),\n interruptAfterSeconds: schema.number().positive().max(300).optional().describe('Blindly send Ctrl-C after this many seconds if the pane is still running; keeps the pane alive.'),\n },\n async execute(args) {\n const session = sessionManager.get(args.id)\n if (session.humanInputOnly || !session.allowAgentInput) {\n return jsonResponse({\n session: publicSession(session),\n output: subscriberManager.has(session.id) ? readOutputSnapshot(session.id, { maxLines: args.maxLines }) : emptyOutputSnapshot(session.lineCount),\n next: nextAdvice(false, 'This session is human-input-only; the user must type directly in the Zellij pane.'),\n warnings: ['Agent writes to human-input-only sessions are forbidden.'],\n })\n }\n\n if (args.data === '\\u0003' || args.data === '\\x03') {\n await zellijCli.sendCtrlC(session.paneId)\n }\n else {\n assertWriteSizeAllowed(args.data)\n for (const chunk of chunkWriteData(args.data)) {\n await zellijCli.writeChars(session.paneId, chunk)\n }\n }\n\n session.updatedAt = new Date().toISOString()\n if (args.interruptAfterSeconds) {\n await delay(args.interruptAfterSeconds * 1_000)\n if (sessionManager.find(session.id)?.status === 'running') {\n await zellijCli.sendCtrlC(session.paneId)\n await delay(500)\n }\n }\n else {\n await delay(1_000)\n }\n\n const warnings: string[] = []\n let output = emptyOutputSnapshot(session.lineCount)\n try {\n output = readOutputSnapshot(session.id, { maxLines: args.maxLines })\n }\n catch (error) {\n warnings.push(`Session output was unavailable before the write response completed: ${errorMessage(error)}`)\n }\n\n return jsonResponse({\n session: publicSession(session),\n output,\n next: nextAdvice(true, args.interruptAfterSeconds ? 'Input was sent; Ctrl-C was sent after the requested interrupt timeout if the session was still running.' : 'Input was sent and recent output was observed.'),\n warnings,\n })\n },\n})\n","import type { SessionStatus as OpenCodeSessionStatus } from '@opencode-ai/sdk'\nimport type { CompletionNotificationConfig } from '../config.js'\nimport type { PtySession, SessionTerminalReason } from '../pty/session.js'\nimport { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\n\ninterface PromptIdleStatusClient {\n session?: {\n status?: (options: { query: { directory: string } }) => Promise<unknown>\n }\n}\n\n/** Fetches the prompt-mode idle guard status; unrelated to tab title state. */\nasync function fetchPromptIdleStatusSnapshot(\n client: PromptIdleStatusClient,\n workspaceRoot: string,\n): Promise<Record<string, OpenCodeSessionStatus> | undefined> {\n try {\n if (!client.session?.status) {\n debug('fetchPromptIdleStatusSnapshot: client.session.status not available')\n return undefined\n }\n\n const result = await client.session.status({ query: { directory: workspaceRoot } })\n const payload = result && typeof result === 'object' && 'data' in result\n ? (result as { data: unknown }).data\n : result\n\n if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n debug('fetchPromptIdleStatusSnapshot received non-object payload')\n return undefined\n }\n\n const entries = Object.entries(payload)\n if (entries.length === 0)\n return {}\n\n const snapshot: Record<string, OpenCodeSessionStatus> = {}\n for (const [sessionID, status] of entries) {\n const parsed = parseSessionStatus(status)\n if (parsed === undefined) {\n debug('fetchPromptIdleStatusSnapshot received invalid status entry, rejecting entire snapshot')\n return undefined\n }\n snapshot[sessionID] = parsed\n }\n\n return snapshot\n }\n catch (err) {\n debug('fetchPromptIdleStatusSnapshot failed', errorMessage(err))\n return undefined\n }\n}\n\nfunction parseSessionStatus(value: unknown): OpenCodeSessionStatus | undefined {\n if (!value || typeof value !== 'object' || !('type' in value))\n return undefined\n\n const status = value as Record<string, unknown>\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\nexport interface CompletionNotificationToastClient {\n tui?: {\n showToast?: (options: {\n body: {\n title: string\n message: string\n variant: 'success' | 'error'\n duration: number\n }\n }) => Promise<unknown>\n }\n}\n\nexport interface CompletionNotificationPromptClient {\n session?: {\n status?: (options: { query: { directory: string } }) => Promise<unknown>\n prompt?: (request: CompletionPromptRequest) => Promise<unknown>\n promptAsync?: (request: CompletionPromptRequest) => Promise<unknown>\n }\n}\n\nexport interface CompletionNotificationClient extends CompletionNotificationToastClient, CompletionNotificationPromptClient {}\n\nexport interface CompletionNotificationContext {\n client: CompletionNotificationClient\n workspaceRoot: string\n config: CompletionNotificationConfig\n markSent: (sessionId: string) => void\n}\n\nexport interface CompletionNotificationHooks {\n prompt?: (event: SubscriberTerminalEvent) => void | Promise<void>\n}\n\nexport interface CompletionNotificationManager {\n handleSessionTerminal: (event: SubscriberTerminalEvent) => Promise<void>\n injectQueuedChatMessage: (input: unknown) => unknown\n clearSession: (sessionId: string) => void\n clearAll: () => void\n dispose: () => void\n}\n\nexport interface SubscriberTerminalEvent {\n sessionId: string\n reason: SessionTerminalReason\n session: PtySession\n}\n\nexport interface CompletionPromptRequest {\n path: {\n id: string\n }\n body: {\n parts: Array<{\n type: 'text'\n text: string\n }>\n }\n}\n\ninterface CompletionNotificationState {\n event: SubscriberTerminalEvent\n queued: boolean\n toastSent: boolean\n promptAttempts: number\n promptAttemptedAt: number | null\n}\n\ninterface CompletionNotificationDecision {\n shouldPrompt: boolean\n shouldQueue: boolean\n reason: string\n}\n\nconst completionTitle = 'Zellij PTY session completed'\nconst completionMessage = 'A Zellij PTY session completed. Review the finished pane if needed.'\nconst queuedNoticeHeader = '[OpenCode] Zellij PTY completion notice'\n\nexport function buildQueuedCompletionNotice(events: SubscriberTerminalEvent[]): string {\n const lines = events.map(event => `- ${event.session.id} (${event.session.paneId}) 已完成,請使用 zellij_pty_read 讀取最終輸出並清理 pane。`)\n return [queuedNoticeHeader, ...lines].join('\\n')\n}\n\nexport function buildCompletionPromptRequest(event: SubscriberTerminalEvent): CompletionPromptRequest {\n return {\n path: {\n id: event.session.openCodeSessionId!,\n },\n body: {\n parts: [{ type: 'text', text: completionMessage }],\n },\n }\n}\n\nexport function injectQueuedCompletionNotice(input: unknown, notice: string): unknown {\n if (typeof input === 'string')\n return `${notice}\\n\\n${input}`\n\n if (!input || typeof input !== 'object')\n return input\n\n const record = input as Record<string, unknown>\n\n if (Array.isArray(record.parts)) {\n return {\n ...record,\n parts: [{ type: 'text', text: notice }, ...record.parts],\n }\n }\n\n if (typeof record.message === 'string') {\n return {\n ...record,\n message: `${notice}\\n\\n${record.message}`,\n }\n }\n\n if (typeof record.content === 'string') {\n return {\n ...record,\n content: `${notice}\\n\\n${record.content}`,\n }\n }\n\n if (typeof record.text === 'string') {\n return {\n ...record,\n text: `${notice}\\n\\n${record.text}`,\n }\n }\n\n return {\n ...record,\n message: notice,\n }\n}\n\nexport function evaluateCompletionPromptDecision(input: {\n event: SubscriberTerminalEvent\n config: Pick<CompletionNotificationConfig, 'mode' | 'prompt'>\n snapshot?: Record<string, OpenCodeSessionStatus> | undefined\n snapshotAvailable: boolean\n now: number\n lastPromptAttemptAt: number | null\n promptAttemptCount: number\n promptClientAvailable: boolean\n}): CompletionNotificationDecision {\n if (input.config.mode !== 'prompt')\n return { shouldPrompt: false, shouldQueue: false, reason: 'prompt mode disabled' }\n\n if (input.event.session.humanInputOnly || !input.event.session.allowAgentInput)\n return { shouldPrompt: false, shouldQueue: true, reason: 'human-input-only session' }\n\n if (!input.promptClientAvailable)\n return { shouldPrompt: false, shouldQueue: true, reason: 'prompt client unavailable' }\n\n if (!input.event.session.openCodeSessionId)\n return { shouldPrompt: false, shouldQueue: true, reason: 'session id unavailable' }\n\n if (!input.snapshotAvailable)\n return { shouldPrompt: false, shouldQueue: true, reason: 'session status snapshot unavailable' }\n\n if (input.config.prompt.maxAttempts <= 0 || input.promptAttemptCount >= input.config.prompt.maxAttempts)\n return { shouldPrompt: false, shouldQueue: true, reason: 'prompt max attempts reached' }\n\n if (input.config.prompt.cooldownMs > 0 && input.lastPromptAttemptAt !== null && input.now - input.lastPromptAttemptAt < input.config.prompt.cooldownMs)\n return { shouldPrompt: false, shouldQueue: true, reason: 'prompt cooldown active' }\n\n if (input.config.prompt.requireIdle) {\n const sessionId = input.event.session.openCodeSessionId\n if (!sessionId)\n return { shouldPrompt: false, shouldQueue: true, reason: 'session status unavailable' }\n const status = sessionId ? input.snapshot?.[sessionId] : undefined\n if (!status)\n return { shouldPrompt: false, shouldQueue: true, reason: 'session status unavailable' }\n if (status && status.type !== 'idle')\n return { shouldPrompt: false, shouldQueue: true, reason: 'session not idle' }\n }\n\n return { shouldPrompt: true, shouldQueue: false, reason: 'prompt allowed' }\n}\n\nexport class SessionCompletionNotificationQueue implements CompletionNotificationManager {\n private readonly states = new Map<string, CompletionNotificationState>()\n\n constructor(\n private readonly context: CompletionNotificationContext,\n private readonly hooks: CompletionNotificationHooks = {},\n private readonly clock: () => number = () => Date.now(),\n ) {}\n\n hasPending(sessionId: string): boolean {\n return this.states.get(sessionId)?.queued ?? false\n }\n\n clearSession(sessionId: string): void {\n this.states.delete(sessionId)\n }\n\n clearAll(): void {\n this.states.clear()\n }\n\n dispose(): void {\n this.clearAll()\n }\n\n async handleSessionTerminal(event: SubscriberTerminalEvent): Promise<void> {\n if (this.context.config.mode === 'off')\n return\n\n if (this.states.has(event.sessionId) || event.session.tombstone?.notificationSentAt)\n return\n\n const state: CompletionNotificationState = {\n event,\n queued: false,\n toastSent: false,\n promptAttempts: 0,\n promptAttemptedAt: null,\n }\n\n this.states.set(event.sessionId, state)\n\n switch (this.context.config.mode) {\n case 'queue':\n state.queued = true\n return\n case 'toast':\n await this.sendToast(state)\n this.finalize(state)\n return\n case 'queue+toast':\n state.queued = true\n await this.sendToast(state)\n return\n case 'prompt':\n await this.tryPromptOrQueue(state)\n break\n default:\n }\n }\n\n injectQueuedChatMessage(input: unknown): unknown {\n const pending = [...this.states.values()].filter(state => state.queued)\n if (pending.length === 0)\n return input\n\n const notice = buildQueuedCompletionNotice(pending.map(state => state.event))\n for (const state of pending) {\n if (!state.toastSent)\n this.context.markSent(state.event.sessionId)\n this.finalize(state)\n }\n\n return injectQueuedCompletionNotice(input, notice)\n }\n\n private async tryPromptOrQueue(state: CompletionNotificationState): Promise<void> {\n if (!state.event.session.openCodeSessionId) {\n state.queued = true\n return\n }\n\n const session = this.context.client.session\n const prompt = session?.prompt ?? session?.promptAsync\n const statusSnapshot = await fetchPromptIdleStatusSnapshot(this.context.client, this.context.workspaceRoot)\n const decision = evaluateCompletionPromptDecision({\n event: state.event,\n config: this.context.config,\n snapshot: statusSnapshot,\n snapshotAvailable: statusSnapshot !== undefined,\n now: this.clock(),\n lastPromptAttemptAt: state.promptAttemptedAt,\n promptAttemptCount: state.promptAttempts,\n promptClientAvailable: Boolean(prompt),\n })\n\n if (!decision.shouldPrompt) {\n state.queued = decision.shouldQueue\n return\n }\n\n if (this.hooks.prompt) {\n try {\n const maybePromise = this.hooks.prompt(state.event)\n if (maybePromise && typeof maybePromise.then === 'function')\n await maybePromise\n }\n catch (error) {\n debug('completion notification prompt hook failed', errorMessage(error))\n }\n }\n\n if (!session || !prompt) {\n state.queued = true\n return\n }\n\n state.promptAttempts += 1\n state.promptAttemptedAt = this.clock()\n\n try {\n if (session.prompt) {\n await session.prompt(buildCompletionPromptRequest(state.event))\n }\n else if (session.promptAsync) {\n await session.promptAsync(buildCompletionPromptRequest(state.event))\n }\n else {\n state.queued = true\n return\n }\n this.context.markSent(state.event.sessionId)\n this.finalize(state)\n }\n catch (error) {\n debug('completion notification prompt failed', errorMessage(error))\n state.queued = true\n }\n }\n\n private async sendToast(state: CompletionNotificationState): Promise<void> {\n const toast = this.context.client.tui?.showToast\n if (!toast) {\n debug('completion notification toast skipped: client.tui.showToast unavailable')\n return\n }\n\n try {\n await toast({\n body: {\n title: completionTitle,\n message: completionMessage,\n variant: 'success',\n duration: 10_000,\n },\n })\n state.toastSent = true\n this.context.markSent(state.event.sessionId)\n if (!state.queued)\n this.finalize(state)\n }\n catch (error) {\n debug('completion notification toast failed', errorMessage(error))\n }\n }\n\n private finalize(state: CompletionNotificationState): void {\n this.states.delete(state.event.sessionId)\n }\n}\n","import type { SessionManager } from '../pty/manager.js'\nimport type { SubscriberManager } from './subscribe.js'\nimport process from 'node:process'\nimport { sessionManager } from '../pty/manager.js'\nimport { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { zellijCli } from './cli.js'\nimport { subscriberManager } from './subscribe.js'\n\nlet registered = false\nlet cleanedUp = false\n\nexport function cleanupPanesOnShutdown(\n sessions: SessionManager = sessionManager,\n subscribers: SubscriberManager = subscriberManager,\n): void {\n if (cleanedUp)\n return\n cleanedUp = true\n\n for (const session of sessions.list()) {\n try {\n zellijCli.closePaneSync(session.paneId)\n }\n catch (error) {\n // Shutdown cleanup is only a fast best-effort path; the watchdog registry remains as fallback.\n debug('cleanupPanesOnShutdown closePane failed', errorMessage(error))\n }\n\n subscribers.forget(session.id)\n try {\n sessions.remove(session.id)\n }\n catch (error) {\n // Another cleanup path may have already removed it.\n debug('cleanupPanesOnShutdown sessions.remove failed', errorMessage(error))\n }\n }\n}\n\nexport function registerShutdownCleanup(): void {\n if (registered)\n return\n registered = true\n\n process.once('exit', () => cleanupPanesOnShutdown())\n process.once('SIGINT', () => exitAfterCleanup('SIGINT', 130))\n process.once('SIGTERM', () => exitAfterCleanup('SIGTERM', 143))\n process.once('SIGHUP', () => exitAfterCleanup('SIGHUP', 129))\n}\n\nfunction exitAfterCleanup(signal: NodeJS.Signals, code: number): void {\n cleanupPanesOnShutdown()\n process.removeAllListeners(signal)\n process.exit(code)\n}\n","import { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\n\nconst execFileAsync = promisify(execFile)\n\nexport interface OpenCodeEventLike {\n type: string\n properties: unknown\n}\n\nexport 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\nexport function deletedSessionID(event: OpenCodeEventLike): string | undefined {\n if (!isRecord(event.properties))\n return undefined\n return nestedStringProperty(event.properties, 'info', 'id') ?? stringProperty(event.properties, 'sessionID')\n}\n\nasync function readGitBranch(worktree: string): Promise<string> {\n const result = await execFileAsync('git', ['-C', worktree, 'branch', '--show-current'], {\n encoding: 'utf8',\n timeout: 1_000,\n maxBuffer: 1024 * 1024,\n })\n return result.stdout\n}\n\nexport async function getInitialBranch(worktree: string, readBranch: BranchReader = readGitBranch): Promise<string | undefined> {\n try {\n return (await readBranch(worktree)).trim() || undefined\n }\n catch (error) {\n debug('getInitialBranch failed', errorMessage(error))\n return undefined\n }\n}\n\nexport function shouldReadInitialBranch(zellij: string | undefined): boolean {\n return Boolean(zellij)\n}\n","import process from 'node:process'\nimport { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { ZellijCli } from './cli.js'\n\nexport interface TabTitleCli {\n renameTab: (title: string) => Promise<void>\n currentTabTitle: () => Promise<string | undefined>\n}\n\nexport type TabTitleStatus = 'idle' | 'running' | 'needs-input'\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\n// Helper functions for event parsing (mirrored from tab-title-events.ts)\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 sessionStatusType(properties: Record<string, unknown>): 'idle' | 'busy' | 'retry' | undefined {\n const status = properties.status\n if (!isRecord(status))\n return undefined\n const type = status.type\n if (type === 'idle' || type === 'busy')\n return type\n if (type === 'retry')\n return 'retry'\n return undefined\n}\n\nfunction inputRequestID(properties: Record<string, unknown>): string | undefined {\n return stringProperty(properties, 'id') ?? stringProperty(properties, 'requestID') ?? stringProperty(properties, 'permissionID')\n}\n\nfunction inputState(properties: Record<string, unknown>): string | undefined {\n return (stringProperty(properties, 'status') ?? stringProperty(properties, 'state') ?? stringProperty(properties, 'type'))?.toLowerCase()\n}\n\nfunction isResolvedInputState(state: string | undefined): boolean {\n return state === 'approved' || state === 'denied' || state === 'rejected' || state === 'resolved' || state === 'replied'\n}\n\nfunction deletedSessionID(properties: Record<string, unknown>): string | undefined {\n return nestedStringProperty(properties, 'info', 'id') ?? stringProperty(properties, 'sessionID')\n}\n\ninterface SessionRecord {\n directory: string | undefined\n parentID: string | undefined\n}\n\nexport class TabTitleIdentityModel {\n ready: Promise<void>\n projectName: string\n branchName: string | undefined\n private worktree: string\n private readBranch: (worktree: string) => Promise<string>\n private refreshGeneration = 0\n\n constructor(options: {\n projectName: string\n worktree: string\n readBranch: (worktree: string) => Promise<string>\n }) {\n this.projectName = options.projectName\n this.worktree = options.worktree\n this.readBranch = options.readBranch\n this.ready = this.refreshBranch('initial')\n }\n\n async refreshBranch(_reason?: string): Promise<void> {\n const generation = ++this.refreshGeneration\n try {\n const result = await this.readBranch(this.worktree)\n if (generation !== this.refreshGeneration)\n return\n const trimmed = result.trim() || undefined\n this.branchName = trimmed\n }\n catch (error) {\n if (generation !== this.refreshGeneration)\n return\n debug('refreshBranch failed', errorMessage(error))\n // keep previous branch\n }\n }\n\n handleEvent(event: { type: string, properties?: unknown }): Promise<void> | void {\n if (event.type === 'vcs.branch.updated') {\n return this.refreshBranch('vcs.branch.updated')\n }\n }\n}\n\nexport class TabTitleActivityModel {\n status: 'idle' | 'running' | 'needs-input' = 'idle'\n private worktreeDirectory: string\n private sessions = new Map<string, SessionRecord>()\n private scopedSessions = new Set<string>()\n private runningSessions = new Set<string>()\n private pendingInputs = new Map<string, string>()\n\n constructor(options: { worktreeDirectory: string }) {\n this.worktreeDirectory = options.worktreeDirectory\n }\n\n getSession(sessionID: string): SessionRecord | undefined {\n return this.scopedSessions.has(sessionID) ? this.sessions.get(sessionID) : undefined\n }\n\n hasPendingInput(sessionID: string, requestID: string): boolean {\n return this.pendingInputs.has(`${sessionID}:${requestID}`)\n }\n\n handleEvent(event: { type: string, properties?: unknown }): void {\n if (!isRecord(event.properties))\n return\n\n const properties = event.properties\n\n switch (event.type) {\n case 'session.created':\n case 'session.updated': {\n const info = properties.info\n if (isRecord(info)) {\n const id = stringProperty(info, 'id')\n if (id)\n this.storeSession(id, info)\n }\n break\n }\n case 'session.status': {\n const sessionID = stringProperty(properties, 'sessionID')\n const statusType = sessionStatusType(properties)\n if (sessionID && statusType) {\n if (statusType === 'idle') {\n if (this.runningSessions.has(sessionID)) {\n this.runningSessions.delete(sessionID)\n this.updateStatus()\n }\n }\n else if (statusType === 'busy' || statusType === 'retry') {\n if (this.scopedSessions.has(sessionID)) {\n this.runningSessions.add(sessionID)\n this.updateStatus()\n }\n }\n }\n break\n }\n case 'session.idle':\n case 'session.error': {\n const sessionID = stringProperty(properties, 'sessionID')\n if (sessionID && this.runningSessions.has(sessionID)) {\n this.runningSessions.delete(sessionID)\n this.updateStatus()\n }\n break\n }\n case 'question.asked':\n case 'permission.asked': {\n const id = inputRequestID(properties)\n const sessionID = stringProperty(properties, 'sessionID')\n if (id && sessionID && this.scopedSessions.has(sessionID)) {\n this.pendingInputs.set(`${sessionID}:${id}`, sessionID)\n this.runningSessions.add(sessionID)\n this.updateStatus()\n }\n break\n }\n case 'permission.updated': {\n const id = inputRequestID(properties)\n const sessionID = stringProperty(properties, 'sessionID')\n const state = inputState(properties)\n if (id && isResolvedInputState(state)) {\n this.pendingInputs.delete(`${sessionID}:${id}`)\n if (sessionID && this.runningSessions.has(sessionID))\n this.runningSessions.add(sessionID)\n this.updateStatus()\n }\n else if (id && sessionID && this.scopedSessions.has(sessionID)) {\n this.pendingInputs.set(`${sessionID}:${id}`, sessionID)\n this.runningSessions.add(sessionID)\n this.updateStatus()\n }\n break\n }\n case 'question.replied':\n case 'question.rejected':\n case 'permission.replied': {\n const id = inputRequestID(properties)\n const sessionID = stringProperty(properties, 'sessionID')\n if (id)\n this.pendingInputs.delete(`${sessionID}:${id}`)\n if (sessionID && this.runningSessions.has(sessionID))\n this.runningSessions.add(sessionID)\n this.updateStatus()\n break\n }\n case 'session.deleted': {\n const sessionID = deletedSessionID(properties)\n if (sessionID) {\n this.removeSessionAndDescendants(sessionID)\n this.updateStatus()\n }\n break\n }\n }\n }\n\n private storeSession(id: string, info: Record<string, unknown>): void {\n const directory = stringProperty(info, 'directory')\n const parentID = stringProperty(info, 'parentID')\n this.sessions.set(id, { directory, parentID })\n\n const isDirectlyScoped = directory === this.worktreeDirectory\n const isDescendantScoped = parentID ? this.scopedSessions.has(parentID) : false\n const isKnown = this.scopedSessions.has(id)\n\n if (isKnown || isDirectlyScoped || isDescendantScoped)\n this.scopedSessions.add(id)\n }\n\n private removeSessionAndDescendants(rootID: string): void {\n const toRemove = new Set<string>()\n toRemove.add(rootID)\n\n let changed = true\n while (changed) {\n changed = false\n for (const [id, session] of this.sessions) {\n if (!toRemove.has(id) && session.parentID && toRemove.has(session.parentID)) {\n toRemove.add(id)\n changed = true\n }\n }\n }\n\n for (const id of toRemove) {\n this.sessions.delete(id)\n this.scopedSessions.delete(id)\n this.runningSessions.delete(id)\n }\n\n for (const [key, sessionID] of [...this.pendingInputs.entries()]) {\n if (toRemove.has(sessionID))\n this.pendingInputs.delete(key)\n }\n }\n\n private updateStatus(): void {\n if (this.pendingInputs.size > 0)\n this.status = 'needs-input'\n else if (this.runningSessions.size > 0)\n this.status = 'running'\n else\n this.status = 'idle'\n }\n}\n\nexport class TabTitleActor {\n ready: Promise<void>\n private identity: TabTitleIdentityModel\n private activity: TabTitleActivityModel\n private emojis: TabTitleEmojis\n\n constructor(options: {\n identity: TabTitleIdentityModel\n activity: TabTitleActivityModel\n emojis?: Partial<TabTitleEmojis> | undefined\n }) {\n this.identity = options.identity\n this.activity = options.activity\n this.emojis = { ...defaultTabTitleEmojis, ...options.emojis }\n this.ready = this.identity.ready\n }\n\n get context() {\n return {\n projectName: this.identity.projectName,\n branchName: this.identity.branchName,\n status: this.activity.status,\n }\n }\n\n get title(): string {\n return formatTabTitle({\n ...this.context,\n emojis: this.emojis,\n })\n }\n\n async handleEvent(event: { type: string, properties?: unknown }): Promise<void> {\n this.activity.handleEvent(event)\n\n const identityResult = this.identity.handleEvent(event)\n if (identityResult instanceof Promise)\n await identityResult\n }\n}\n\nexport interface TabTitleManagerOptions {\n cli?: TabTitleCli\n emojis?: Partial<TabTitleEmojis> | undefined\n debounceMs?: number\n retryInitialMs?: number\n retryMaxMs?: number\n actor: TabTitleActor\n}\n\nexport class TabTitleManager {\n private desiredTitle: string | undefined\n private lastSyncedTitle: string | undefined\n private syncGeneration = 0\n private debounceTimer: ReturnType<typeof setTimeout> | undefined\n private retryTimer: ReturnType<typeof setTimeout> | undefined\n private retryAttempt = 0\n private syncInFlight = false\n private syncPromise: Promise<void> | undefined\n private readonly debounceMs: number\n private readonly retryInitialMs: number\n private readonly retryMaxMs: number\n private readonly cli: TabTitleCli\n private readonly emojis: TabTitleEmojis\n private readonly enabled: boolean\n private destroyed = false\n private originalTabTitle: string | undefined\n private originalTabTitleLoaded = false\n private originalTabTitlePromise: Promise<void> | undefined\n private destroyPromise: Promise<void> | undefined\n private readonly actor: TabTitleActor\n\n constructor(options: TabTitleManagerOptions) {\n this.cli = options.cli ?? new ZellijCli()\n this.emojis = { ...defaultTabTitleEmojis, ...options.emojis }\n this.debounceMs = options.debounceMs ?? 300\n this.retryInitialMs = options.retryInitialMs ?? 250\n this.retryMaxMs = options.retryMaxMs ?? 5_000\n this.enabled = Boolean(process.env.ZELLIJ || process.env.ZELLIJ_SESSION_NAME)\n this.actor = options.actor\n }\n\n private buildTitle(): string {\n return sanitizeTitle(formatTabTitle({\n ...this.actor.context,\n emojis: this.emojis,\n }))\n }\n\n getCurrentTitle(): string {\n return this.buildTitle()\n }\n\n async renderImmediate(): Promise<void> {\n if (!this.enabled || this.destroyed)\n return\n await this.ensureOriginalTabTitle()\n if (this.destroyed)\n return\n this.desiredTitle = this.buildTitle()\n this.clearDebounceTimer()\n await this.syncDesiredTitle()\n }\n\n scheduleUpdate(): void {\n if (!this.enabled || this.destroyed)\n return\n const title = this.buildTitle()\n if (title === this.desiredTitle && title === this.lastSyncedTitle)\n return\n this.desiredTitle = title\n\n if (this.syncInFlight)\n return\n\n this.clearRetryTimer()\n this.clearDebounceTimer()\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = undefined\n this.syncDesiredTitle()\n .catch(error => debug('debounced tab title sync failed', errorMessage(error)))\n }, this.debounceMs)\n this.unrefTimer(this.debounceTimer)\n }\n\n private async syncDesiredTitle(): Promise<void> {\n if (!this.enabled || this.destroyed)\n return\n const generation = this.syncGeneration\n await this.ensureOriginalTabTitle()\n if (this.destroyed || generation !== this.syncGeneration)\n return\n if (this.syncInFlight)\n return this.syncPromise\n\n this.syncInFlight = true\n this.syncPromise = this.runTitleSync(generation)\n return this.syncPromise\n }\n\n private async runTitleSync(generation: number): Promise<void> {\n try {\n while (generation === this.syncGeneration && this.desiredTitle && this.desiredTitle !== this.lastSyncedTitle) {\n const title = this.desiredTitle\n try {\n await this.cli.renameTab(title)\n if (generation !== this.syncGeneration || this.destroyed)\n return\n this.lastSyncedTitle = title\n this.retryAttempt = 0\n this.clearRetryTimer()\n }\n catch (cause) {\n debug('Failed to rename Zellij tab.', cause)\n if (generation !== this.syncGeneration || this.destroyed)\n break\n this.scheduleRetry()\n break\n }\n }\n }\n finally {\n this.syncInFlight = false\n this.syncPromise = undefined\n }\n }\n\n private scheduleRetry(): void {\n if (!this.enabled || this.destroyed || this.retryTimer || this.desiredTitle === this.lastSyncedTitle)\n return\n\n const delay = Math.min(this.retryMaxMs, this.retryInitialMs * 2 ** this.retryAttempt)\n this.retryAttempt += 1\n this.retryTimer = setTimeout(() => {\n this.retryTimer = undefined\n this.syncDesiredTitle()\n .catch(error => debug('retry tab title sync failed', errorMessage(error)))\n }, delay)\n this.unrefTimer(this.retryTimer)\n }\n\n private clearRetryTimer(): void {\n if (this.retryTimer)\n clearTimeout(this.retryTimer)\n this.retryTimer = undefined\n }\n\n private unrefTimer(timer: ReturnType<typeof setTimeout>): void {\n if (typeof timer === 'object' && timer && 'unref' in timer && typeof timer.unref === 'function')\n timer.unref()\n }\n\n private clearDebounceTimer(): void {\n if (this.debounceTimer)\n clearTimeout(this.debounceTimer)\n this.debounceTimer = undefined\n }\n\n private async ensureOriginalTabTitle(): Promise<void> {\n if (!this.enabled || this.originalTabTitleLoaded)\n return\n if (this.originalTabTitlePromise)\n return this.originalTabTitlePromise\n\n this.originalTabTitlePromise = this.saveOriginalTabTitle()\n return this.originalTabTitlePromise\n }\n\n private async saveOriginalTabTitle(): Promise<void> {\n try {\n const title = await this.cli.currentTabTitle()\n if (title !== undefined)\n this.originalTabTitle = title\n }\n catch (error) {\n debug('TabTitleManager failed to save original tab title', errorMessage(error))\n }\n finally {\n this.originalTabTitleLoaded = true\n this.originalTabTitlePromise = undefined\n }\n }\n\n destroy(): Promise<void> {\n if (this.destroyed)\n return this.destroyPromise ?? Promise.resolve()\n this.destroyed = true\n this.syncGeneration += 1\n this.desiredTitle = undefined\n this.clearDebounceTimer()\n this.clearRetryTimer()\n\n if (!this.enabled)\n return Promise.resolve()\n\n this.destroyPromise = this.restoreOriginalTabTitle()\n .catch(error => debug('TabTitleManager failed to restore original tab title', errorMessage(error)))\n return this.destroyPromise\n }\n\n private async restoreOriginalTabTitle(): Promise<void> {\n await this.originalTabTitlePromise\n await this.syncPromise\n const originalTitle = this.originalTabTitle\n this.originalTabTitle = undefined\n if (originalTitle === undefined)\n return\n await this.cli.renameTab(originalTitle)\n }\n}\n","import type { Plugin } from '@opencode-ai/plugin'\nimport type { UpdateResult } from './auto-update.js'\nimport type { CompletionNotificationClient, CompletionNotificationContext, CompletionNotificationManager } from './zellij/completion-notifications.js'\nimport type { OpenCodeEventLike } from './zellij/tab-title-events.js'\nimport process from 'node:process'\nimport { checkAndUpdate } from './auto-update.js'\nimport { loadConfig } from './config.js'\nimport { configureSudoPane } from './permissions/sudo-pane.js'\nimport { sessionManager } from './pty/manager.js'\nimport { zellijPtyKillTool } from './tools/kill.js'\nimport { zellijPtyListTool } from './tools/list.js'\nimport { createZellijPtyReadTool } from './tools/read.js'\nimport { requestSudoTool } from './tools/request-sudo.js'\nimport { zellijPtySpawnTool } from './tools/spawn.js'\nimport { zellijPtyWriteTool } from './tools/write.js'\nimport { debug } from './utils/debug.js'\nimport { errorMessage } from './utils/errors.js'\nimport { SessionCompletionNotificationQueue } from './zellij/completion-notifications.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, shouldReadInitialBranch } from './zellij/tab-title-events.js'\nimport { TabTitleActivityModel, TabTitleActor, TabTitleIdentityModel, TabTitleManager } from './zellij/tab-title.js'\n\nfunction createPtyTools(defaultCleanupExitedPaneOnRead: boolean) {\n return {\n zellij_pty_spawn: zellijPtySpawnTool,\n zellij_pty_list: zellijPtyListTool,\n zellij_pty_write: zellijPtyWriteTool,\n zellij_pty_read: createZellijPtyReadTool({ defaultCleanupExitedPaneOnRead }),\n zellij_pty_kill: zellijPtyKillTool,\n }\n}\n\nfunction getProjectName(path: string): string {\n return path.split(/[/\\\\]/).filter(Boolean).pop() || 'opencode'\n}\n\nfunction getWorkspaceRoot(input: { directory?: string | undefined, worktree?: string | undefined }): string {\n return input.worktree || input.directory || process.cwd()\n}\n\nexport interface ToastClient {\n tui: {\n showToast: (options: {\n body: {\n title: string\n message: string\n variant: 'success' | 'error'\n duration: number\n }\n }) => Promise<unknown>\n }\n}\n\nexport function showUpdateToast(client: ToastClient, result: UpdateResult): void {\n if (result.type === 'updated') {\n client.tui.showToast({\n body: {\n title: 'opencode-zellij updated',\n message: `Updated to ${result.toVersion}. Restart OpenCode to apply the changes.`,\n variant: 'success',\n duration: 10_000,\n },\n })\n .catch(error => debug('show update toast for successful update failed', errorMessage(error)))\n }\n else if (result.type === 'failed') {\n client.tui.showToast({\n body: {\n title: 'opencode-zellij update failed',\n message: `Failed to update to ${result.latestVersion}.`,\n variant: 'error',\n duration: 8_000,\n },\n })\n .catch(error => debug('show update toast for failed update failed', errorMessage(error)))\n }\n}\n\nexport function startAutoUpdateCheck(\n client: ToastClient,\n importMetaUrl: string,\n check: typeof checkAndUpdate = checkAndUpdate,\n): void {\n ;(async () => {\n try {\n showUpdateToast(client, await check({ importMetaUrl }))\n }\n catch (cause) {\n debug('auto-update check failed', errorMessage(cause))\n }\n })()\n}\n\nasync function cleanupStep(stepName: string, sessionId: string, step: () => void | Promise<void>): Promise<void> {\n try {\n await step()\n }\n catch (error) {\n debug(`session.deleted cleanup failed: ${stepName} for ${sessionId}`, errorMessage(error))\n }\n}\n\nasync function cleanupDeletedSession(sessionId: string): Promise<void> {\n await cleanupStep('close pane', sessionId, () => subscriberManager.closeSessionPane(sessionId))\n await cleanupStep('forget subscriber', sessionId, () => subscriberManager.forget(sessionId))\n await cleanupStep('unregister watchdog', sessionId, () => unregisterPaneFromWatchdog(sessionId))\n await cleanupStep('remove session', sessionId, () => sessionManager.remove(sessionId))\n}\n\nexport interface ZellijPtyPluginDependencies {\n importMetaUrl?: string | undefined\n startAutoUpdateCheck?: typeof startAutoUpdateCheck | undefined\n createCompletionNotifications?: (context: CompletionNotificationContext) => CompletionNotificationManager | undefined\n}\n\nexport function createZellijPtyPlugin(dependencies: ZellijPtyPluginDependencies = {}): Plugin {\n return async (input) => {\n const { config, warnings } = await loadConfig(input)\n for (const warning of warnings) {\n debug(warning)\n }\n configureSudoPane(config.pty.sudoPane === 'allow')\n cleanupStaleWatchdogRegistries()\n registerShutdownCleanup()\n\n const workspaceRoot = getWorkspaceRoot(input)\n const projectName = getProjectName(workspaceRoot)\n const identityModel = config.tabTitle.enabled\n ? new TabTitleIdentityModel({\n projectName,\n worktree: workspaceRoot,\n readBranch: async worktree => shouldReadInitialBranch(process.env.ZELLIJ || process.env.ZELLIJ_SESSION_NAME) ? (await getInitialBranch(worktree)) ?? '' : '',\n })\n : undefined\n const activityModel = config.tabTitle.enabled\n ? new TabTitleActivityModel({\n worktreeDirectory: workspaceRoot,\n })\n : undefined\n const actor = identityModel && activityModel\n ? new TabTitleActor({\n identity: identityModel,\n activity: activityModel,\n })\n : undefined\n const tabTitleManager = config.tabTitle.enabled && actor\n ? new TabTitleManager({\n actor,\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 const client = input.client\n const completionNotifications = config.pty.completionNotification.mode === 'off'\n ? undefined\n : (dependencies.createCompletionNotifications?.({\n client: client as CompletionNotificationClient,\n workspaceRoot,\n config: config.pty.completionNotification,\n markSent(sessionId) {\n try {\n sessionManager.markTerminalNotificationSent(sessionId)\n }\n catch (error) {\n debug('mark terminal notification sent failed', errorMessage(error))\n }\n },\n }) ?? new SessionCompletionNotificationQueue({\n client: client as CompletionNotificationClient,\n workspaceRoot,\n config: config.pty.completionNotification,\n markSent(sessionId) {\n try {\n sessionManager.markTerminalNotificationSent(sessionId)\n }\n catch (error) {\n debug('mark terminal notification sent failed', errorMessage(error))\n }\n },\n }))\n\n subscriberManager.setLifecycleHooks(completionNotifications\n ? { onSessionTerminal: event => void completionNotifications.handleSessionTerminal(event).catch(error => debug('completion notification lifecycle hook failed', errorMessage(error))) }\n : undefined)\n\n // Best-effort initial render; no-op when not inside a real Zellij pane.\n if (actor) {\n await actor.ready\n }\n tabTitleManager?.renderImmediate()\n .catch(error => debug('initial tab title render failed', errorMessage(error)))\n\n if (config.autoUpdate)\n (dependencies.startAutoUpdateCheck ?? startAutoUpdateCheck)(client, dependencies.importMetaUrl ?? import.meta.url)\n\n return {\n async event(input) {\n const event: OpenCodeEventLike = input.event\n\n if (actor && tabTitleManager) {\n await actor.handleEvent(event)\n if (event.type === 'server.instance.disposed' || event.type === 'global.disposed') {\n await tabTitleManager.destroy()\n }\n else {\n tabTitleManager.scheduleUpdate()\n }\n }\n if (event.type === 'server.instance.disposed' || event.type === 'global.disposed') {\n completionNotifications?.clearAll()\n completionNotifications?.dispose()\n subscriberManager.setLifecycleHooks(undefined)\n }\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 for (const session of sessions)\n completionNotifications?.clearSession(session.id)\n await Promise.all(sessions.map(session => cleanupDeletedSession(session.id)))\n }\n },\n 'chat.message': async (\n _input: unknown,\n output: { message: unknown, parts: Array<Record<string, unknown> & { type: string }> },\n ) => {\n const injected = completionNotifications?.injectQueuedChatMessage(output) ?? output\n if (injected !== output && injected && typeof injected === 'object' && Array.isArray((injected as { parts?: unknown }).parts))\n output.parts = (injected as { parts: Array<Record<string, unknown> & { type: string }> }).parts\n },\n 'tool': config.pty.enabled\n ? {\n ...createPtyTools(config.pty.cleanupExitedPaneOnRead),\n ...(config.pty.sudoPane === 'hide' ? {} : { zellij_pty_request_sudo: requestSudoTool }),\n }\n : {},\n }\n }\n}\n\nexport const ZellijPtyPlugin: Plugin = createZellijPtyPlugin()\n\nexport default ZellijPtyPlugin\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["stringProperty","execFileAsync","ansiPattern","schema","delay","schema","schema","delay","schema","delay","isRecord","stringProperty","nestedStringProperty","deletedSessionID","deletedSessionID"],"sources":["../src/config.ts","../src/permissions/sudo-pane.ts","../src/utils/ids.ts","../src/pty/manager.ts","../src/utils/shell-args.ts","../src/utils/debug.ts","../src/utils/errors.ts","../src/zellij/parse.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/pane-cleanup.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/runtime.ts","../src/utils/logger.ts","../src/zellij/completion-notifications.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 cleanupExitedPaneOnRead: 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 cleanupExitedPaneOnRead: z.boolean().optional().describe('Remove exited PTY panes after they are read.'),\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 cleanupExitedPaneOnRead: 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 cleanupExitedPaneOnRead: project?.pty?.cleanupExitedPaneOnRead ?? user?.pty?.cleanupExitedPaneOnRead ?? defaultConfig.pty.cleanupExitedPaneOnRead,\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\nexport function userConfigDir(): string {\n return process.env.XDG_CONFIG_HOME ? join(process.env.XDG_CONFIG_HOME, 'opencode') : join(homedir(), '.config', 'opencode')\n}\n\nexport function projectConfigDirs(input: LoadConfigInput): string[] {\n const dirs: string[] = []\n if (input.worktree)\n dirs.push(join(input.worktree, '.opencode'))\n if (input.directory && input.directory !== input.worktree)\n dirs.push(join(input.directory, '.opencode'))\n return dirs\n}\n\nexport async function loadConfig(input: LoadConfigInput): Promise<LoadConfigResult> {\n const warnings: string[] = []\n const sources: LoadConfigResult['sources'] = {}\n\n const userResult = await loadConfigLayer(userConfigDir(), warnings)\n const userLayer = userResult.layer\n if (userResult.source && userLayer)\n sources.user = userResult.source\n\n let projectLayer: ConfigLayer | undefined\n for (const projectDir of projectConfigDirs(input)) {\n const projectResult = await loadConfigLayer(projectDir, warnings)\n if (!projectResult.source)\n continue\n projectLayer = projectResult.layer\n if (projectLayer)\n sources.project = projectResult.source\n break\n }\n\n return {\n config: mergeConfig(userLayer, projectLayer),\n sources,\n warnings,\n }\n}\n","let sudoPaneAllowed = true\n\nexport function configureSudoPane(allowed: boolean): void {\n sudoPaneAllowed = allowed\n}\n\nexport function assertSudoPaneAllowed(): void {\n if (!sudoPaneAllowed)\n throw new Error('sudo pane is disabled by zellij-pty config.')\n}\n","import { randomUUID } from 'node:crypto'\n\nconst paneIdPattern = /\\b(?:terminal_)?(\\d+)\\b/\n\nexport function createSessionId(): string {\n return `zpty_${randomUUID().replaceAll('-', '').slice(0, 10)}`\n}\n\nexport function normalizePaneId(rawPaneId: string): string {\n const trimmed = rawPaneId.trim()\n if (/^terminal_\\d+$/.test(trimmed))\n return trimmed\n if (/^\\d+$/.test(trimmed))\n return `terminal_${trimmed}`\n throw new Error(`Invalid Zellij terminal pane id: ${rawPaneId}`)\n}\n\nexport function parsePaneId(output: string): string {\n const match = output.match(paneIdPattern)\n if (!match?.[1]) {\n throw new Error(`Unable to parse Zellij pane id from output: ${output.trim() || '<empty>'}`)\n }\n return normalizePaneId(match[1])\n}\n","import type { CreateSessionInput, PtySession, SessionStatus, SessionTerminalReason, SessionTombstone } from './session.js'\nimport { createSessionId } from '../utils/ids.js'\n\nconst tombstoneTailLimit = 200\n\nexport interface MarkTerminalInput {\n reason: SessionTerminalReason\n tail?: string[] | undefined\n exitCode?: number | undefined\n}\n\nexport interface MarkTerminalResult {\n session: PtySession\n created: boolean\n}\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 tombstone: null,\n }\n this.sessions.set(session.id, session)\n return session\n }\n\n get(id: string): PtySession {\n const session = this.sessions.get(id)\n if (!session)\n throw new Error(`Unknown zellij PTY session: ${id}`)\n return session\n }\n\n find(id: string): PtySession | undefined {\n return this.sessions.get(id)\n }\n\n list(): PtySession[] {\n return Array.from(this.sessions.values()).sort((a, b) => a.createdAt.localeCompare(b.createdAt))\n }\n\n updateLineCount(id: string, lineCount: number): PtySession {\n const session = this.get(id)\n session.lineCount = lineCount\n session.updatedAt = new Date().toISOString()\n return session\n }\n\n updateStatus(id: string, status: SessionStatus): PtySession {\n const session = this.get(id)\n if (session.status === 'terminal' && status !== 'terminal')\n return session\n session.status = status\n session.updatedAt = new Date().toISOString()\n return session\n }\n\n markExited(id: string, exitCode: number): PtySession {\n return this.markTerminal(id, { reason: 'exit_marker', exitCode }).session\n }\n\n markTerminal(id: string, input: MarkTerminalInput): MarkTerminalResult {\n const session = this.get(id)\n const now = new Date().toISOString()\n const created = session.status !== 'terminal' || !session.tombstone\n\n if (created) {\n const tombstone: SessionTombstone = {\n reason: input.reason,\n terminalAt: now,\n tail: (input.tail ?? []).slice(-tombstoneTailLimit),\n paneClosedAt: null,\n }\n\n session.status = 'terminal'\n session.tombstone = tombstone\n session.updatedAt = now\n }\n\n if (input.exitCode !== undefined && session.exitCode === null) {\n session.exitCode = input.exitCode\n session.exitedAt = now\n session.updatedAt = now\n }\n\n if (session.tombstone) {\n if (input.tail?.length && session.tombstone.tail.length === 0)\n session.tombstone.tail = input.tail.slice(-tombstoneTailLimit)\n if (!session.tombstone.reason)\n session.tombstone.reason = input.reason\n }\n\n return { session, created }\n }\n\n markTerminalPaneClosed(id: string): PtySession {\n const session = this.get(id)\n const now = new Date().toISOString()\n if (!session.tombstone)\n return session\n if (!session.tombstone.paneClosedAt) {\n session.tombstone.paneClosedAt = now\n session.updatedAt = now\n }\n return session\n }\n\n listByOpenCodeSession(openCodeSessionId: string): PtySession[] {\n return this.list().filter(session => session.openCodeSessionId === openCodeSessionId)\n }\n\n remove(id: string): void {\n if (!this.sessions.delete(id))\n throw new Error(`Unknown zellij PTY session: ${id}`)\n }\n}\n\nexport const sessionManager = new SessionManager()\n","export interface CommandInput {\n command: string\n args?: string[] | undefined\n}\n\nexport interface BuildCommandArgvOptions {\n exitCodeToken?: string | undefined\n}\n\nconst directCommandExitWrapper = 'token=\"$1\"; shift; set +e; \"$@\"; code=$?; printf \"\\\\n[zellij-pty:%s] exit-code=%s\\\\n\" \"$token\" \"$code\"; exit \"$code\"'\nconst shellCommandExitWrapper = 'token=\"$1\"; command=\"$2\"; set +e; bash -lc \"$command\"; code=$?; printf \"\\\\n[zellij-pty:%s] exit-code=%s\\\\n\" \"$token\" \"$code\"; exit \"$code\"'\n\nexport function buildCommandArgv(input: CommandInput, options: BuildCommandArgvOptions = {}): string[] {\n const command = input.command.trim()\n if (!command)\n throw new Error('command is required')\n\n if (options.exitCodeToken) {\n if (input.args && input.args.length > 0) {\n return ['bash', '-lc', directCommandExitWrapper, 'zellij-pty', options.exitCodeToken, command, ...input.args]\n }\n\n return ['bash', '-lc', shellCommandExitWrapper, 'zellij-pty', options.exitCodeToken, command]\n }\n\n if (input.args && input.args.length > 0) {\n return [command, ...input.args]\n }\n\n return ['bash', '-lc', command]\n}\n","import process from 'node:process'\n\nexport function debug(message: string, ...details: unknown[]): void {\n if (!process.env.ZELLIJ_PTY_DEBUG)\n return\n\n console.warn(`[opencode-zellij] ${message}`, ...details)\n}\n","export function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n","import { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { normalizePaneId } from '../utils/ids.js'\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction numericProperty(object: Record<string, unknown>, keys: string[]): number | undefined {\n for (const key of keys) {\n const value = object[key]\n if (typeof value === 'number' && Number.isFinite(value))\n return value\n if (typeof value === 'string') {\n const parsed = Number(value)\n if (Number.isInteger(parsed))\n return parsed\n }\n }\n return undefined\n}\n\nfunction stringProperty(object: Record<string, unknown>, keys: string[]): string | undefined {\n for (const key of keys) {\n const value = object[key]\n if (typeof value === 'string')\n return value\n }\n return undefined\n}\n\n// ---------------------------------------------------------------------------\n// Pane → tab resolution\n// ---------------------------------------------------------------------------\n\nfunction paneMatches(object: Record<string, unknown>, paneId: number): boolean {\n const candidate = numericProperty(object, ['id', 'pane_id', 'paneId'])\n return candidate === paneId && object.is_plugin !== true\n}\n\nfunction findPaneRecord(value: unknown, paneId: number): Record<string, unknown> | undefined {\n if (Array.isArray(value)) {\n for (const item of value) {\n const found = findPaneRecord(item, paneId)\n if (found !== undefined)\n return found\n }\n return undefined\n }\n\n if (typeof value !== 'object' || value === null)\n return undefined\n\n const object = value as Record<string, unknown>\n if (paneMatches(object, paneId))\n return object\n\n for (const nested of Object.values(object)) {\n const found = findPaneRecord(nested, paneId)\n if (found !== undefined)\n return found\n }\n return undefined\n}\n\nexport function parseCurrentPaneTabId(listPanesJson: string, paneId: string | undefined): number | undefined {\n if (!paneId)\n return undefined\n const parsedPaneId = Number(paneId)\n if (!Number.isInteger(parsedPaneId))\n return undefined\n\n try {\n const pane = findPaneRecord(JSON.parse(listPanesJson), parsedPaneId)\n return pane ? numericProperty(pane, ['tab_id', 'tabId']) : undefined\n }\n catch (error) {\n debug('parseCurrentPaneTabId failed', errorMessage(error))\n return undefined\n }\n}\n\nexport function parsePaneExists(listPanesJson: string, paneId: string | undefined): boolean | undefined {\n if (!paneId)\n return undefined\n let parsedPaneId: number\n try {\n parsedPaneId = Number(normalizePaneId(paneId).slice('terminal_'.length))\n }\n catch {\n return undefined\n }\n\n try {\n return findPaneRecord(JSON.parse(listPanesJson), parsedPaneId) !== undefined\n }\n catch (error) {\n debug('parsePaneExists failed', errorMessage(error))\n return undefined\n }\n}\n\n// ---------------------------------------------------------------------------\n// Tab name resolution\n// ---------------------------------------------------------------------------\n\nfunction tabNameProperty(object: Record<string, unknown>, tabId: number | undefined): string | undefined {\n if (tabId === undefined)\n return undefined\n const foundTabId = numericProperty(object, ['tab_id', 'tabId'])\n if (foundTabId !== tabId)\n return undefined\n const name = stringProperty(object, ['name', 'title'])\n return typeof name === 'string' ? name : undefined\n}\n\nfunction findTabName(value: unknown, tabId: number | undefined): string | undefined {\n if (Array.isArray(value)) {\n for (const item of value) {\n const found = findTabName(item, tabId)\n if (found !== undefined)\n return found\n }\n return undefined\n }\n\n if (typeof value !== 'object' || value === null)\n return undefined\n\n const object = value as Record<string, unknown>\n const name = tabNameProperty(object, tabId)\n if (name !== undefined)\n return name\n\n for (const nested of Object.values(object)) {\n const found = findTabName(nested, tabId)\n if (found !== undefined)\n return found\n }\n return undefined\n}\n\nfunction activeTabNameProperty(object: Record<string, unknown>): string | undefined {\n if (object.active !== true || object.is_plugin === true)\n return undefined\n const name = stringProperty(object, ['name', 'title'])\n return typeof name === 'string' ? name : undefined\n}\n\nfunction findActiveTabName(value: unknown): string | undefined {\n if (Array.isArray(value)) {\n for (const item of value) {\n const found = findActiveTabName(item)\n if (found !== undefined)\n return found\n }\n return undefined\n }\n\n if (typeof value !== 'object' || value === null)\n return undefined\n\n const object = value as Record<string, unknown>\n const name = activeTabNameProperty(object)\n if (name !== undefined)\n return name\n\n for (const nested of Object.values(object)) {\n const found = findActiveTabName(nested)\n if (found !== undefined)\n return found\n }\n return undefined\n}\n\nexport function parseTabName(listTabsJson: string, tabId: number | undefined): string | undefined {\n try {\n return findTabName(JSON.parse(listTabsJson), tabId)\n }\n catch (error) {\n debug('parseTabName failed', errorMessage(error))\n return undefined\n }\n}\n\nexport function parseActiveTabName(listTabsJson: string): string | undefined {\n try {\n return findActiveTabName(JSON.parse(listTabsJson))\n }\n catch (error) {\n debug('parseActiveTabName failed', errorMessage(error))\n return undefined\n }\n}\n","import type { CommandInput } from '../utils/shell-args.js'\nimport { execFile, spawnSync } from 'node:child_process'\nimport process from 'node:process'\nimport { promisify } from 'node:util'\nimport { parsePaneId } from '../utils/ids.js'\nimport { buildCommandArgv } from '../utils/shell-args.js'\nimport { parseActiveTabName, parseCurrentPaneTabId, parsePaneExists, parseTabName } from './parse.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\ntype ZellijRunner = (actionArgs: string[], options?: ZellijRunOptions) => Promise<ZellijResult>\n\nexport function zellijCommandArgs(actionArgs: string[]): string[] {\n const sessionName = process.env.ZELLIJ_SESSION_NAME?.trim()\n if (sessionName)\n return ['--session', sessionName, ...actionArgs]\n return actionArgs\n}\n\nexport function zellijActionArgs(action: string, args: string[] = []): string[] {\n return ['action', action, ...args]\n}\n\nexport function buildNewPaneActionArgs(options: NewPaneOptions): string[] {\n const args = ['action', 'new-pane']\n if (process.env.ZELLIJ)\n args.push('--near-current-pane')\n\n if (options.title)\n args.push('--name', options.title)\n if (options.cwd)\n args.push('--cwd', options.cwd)\n if (options.floating)\n args.push('--floating')\n\n args.push('--', ...buildCommandArgv(options, { exitCodeToken: options.exitCodeToken }))\n return args\n}\n\nexport function buildRenameTabActionArgs(title: string, options: { tabId?: number } = {}): string[] {\n if (options.tabId !== undefined)\n return ['action', 'rename-tab', '--tab-id', String(options.tabId), title]\n return ['action', 'rename-tab', title]\n}\n\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 constructor(private readonly run: ZellijRunner = runZellij) {}\n\n async newPane(options: NewPaneOptions): Promise<string> {\n const result = await this.run(buildNewPaneActionArgs(options))\n return parsePaneId(result.stdout)\n }\n\n async writeChars(paneId: string, data: string): Promise<void> {\n await this.run(zellijActionArgs('write-chars', ['--pane-id', paneId, data]))\n }\n\n async sendCtrlC(paneId: string): Promise<void> {\n await this.run(zellijActionArgs('send-keys', ['--pane-id', paneId, 'Ctrl c']))\n }\n\n async closePane(paneId: string): Promise<void> {\n await this.run(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 this.run(zellijActionArgs('focus-pane-id', [paneId]))\n }\n\n async dumpScreen(paneId: string): Promise<string> {\n const result = await this.run(zellijActionArgs('dump-screen', ['--pane-id', paneId, '--full']), { timeoutMs: 10_000 })\n return result.stdout\n }\n\n async currentPaneTabId(): Promise<number | undefined> {\n const paneId = process.env.ZELLIJ_PANE_ID\n if (!paneId)\n return undefined\n\n const result = await this.run(zellijActionArgs('list-panes', ['--json']), { timeoutMs: 5_000 })\n return parseCurrentPaneTabId(result.stdout, paneId)\n }\n\n async paneExists(paneId: string): Promise<boolean | undefined> {\n const result = await this.run(zellijActionArgs('list-panes', ['--json']), { timeoutMs: 5_000 })\n return parsePaneExists(result.stdout, paneId)\n }\n\n async renameTab(title: string): Promise<void> {\n const tabId = await this.currentPaneTabId()\n if (tabId === undefined && process.env.ZELLIJ)\n throw new Error(`Could not resolve Zellij tab id for pane ${process.env.ZELLIJ_PANE_ID ?? '<missing>'}`)\n await this.run(tabId === undefined ? buildRenameTabActionArgs(title) : buildRenameTabActionArgs(title, { tabId }))\n }\n\n async currentTabTitle(): Promise<string | undefined> {\n const paneId = process.env.ZELLIJ_PANE_ID\n if (!paneId) {\n if (!process.env.ZELLIJ_SESSION_NAME?.trim())\n return undefined\n\n const result = await this.run(zellijActionArgs('list-tabs', ['--json']), { timeoutMs: 5_000 })\n return parseActiveTabName(result.stdout)\n }\n\n const tabId = await this.currentPaneTabId()\n if (tabId === undefined)\n return undefined\n\n const result = await this.run(zellijActionArgs('list-tabs', ['--json']), { timeoutMs: 5_000 })\n return parseTabName(result.stdout, tabId)\n }\n}\n\nexport const zellijCli = new ZellijCli()\n","import type { PtySession } from '../pty/session.js'\nimport { spawn } from 'node:child_process'\nimport { randomUUID } from 'node:crypto'\nimport { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { fileURLToPath } from 'node:url'\nimport { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\n\nexport interface WatchdogPane {\n sessionId: string\n paneId: string\n title: string\n openCodeSessionId: string | null\n createdAt: string\n}\n\nexport interface WatchdogRegistry {\n version: 1\n instanceId: string\n ownerPid: number\n ownerStartTime: string | null\n zellijSessionName: string | null\n panes: WatchdogPane[]\n}\n\nconst instanceId = randomUUID()\nlet watchdogStarted = false\nlet watchdogChild: ReturnType<typeof spawn> | null = null\n\nfunction registryDirectory(): string {\n const base = process.env.XDG_RUNTIME_DIR || tmpdir()\n return path.join(base, `opencode-zellij-${process.getuid?.() ?? 'user'}`)\n}\n\nexport function watchdogRegistryPath(): string {\n return path.join(registryDirectory(), `panes-${process.pid}-${instanceId}.json`)\n}\n\nexport function parseLinuxProcessStartTime(stat: string): string | null {\n const fieldsAfterCommand = stat.slice(stat.lastIndexOf(')') + 2).trim().split(/\\s+/)\n return fieldsAfterCommand[19] ?? null\n}\n\nfunction linuxProcessStartTime(pid: number): string | null {\n try {\n return parseLinuxProcessStartTime(readFileSync(`/proc/${pid}/stat`, 'utf8'))\n }\n catch (error) {\n // Missing /proc data is expected when the owner has exited or on non-Linux systems.\n debug('linuxProcessStartTime failed', errorMessage(error))\n return null\n }\n}\n\nfunction emptyRegistry(): WatchdogRegistry {\n return {\n version: 1,\n instanceId,\n ownerPid: process.pid,\n ownerStartTime: linuxProcessStartTime(process.pid),\n zellijSessionName: process.env.ZELLIJ_SESSION_NAME?.trim() || null,\n panes: [],\n }\n}\n\nfunction readRegistry(): WatchdogRegistry {\n const file = watchdogRegistryPath()\n if (!existsSync(file))\n return emptyRegistry()\n\n try {\n const parsed = JSON.parse(readFileSync(file, 'utf8')) as WatchdogRegistry\n if (parsed.version !== 1 || parsed.instanceId !== instanceId || parsed.ownerPid !== process.pid || !Array.isArray(parsed.panes))\n return emptyRegistry()\n return parsed\n }\n catch (error) {\n // The current instance registry is corrupt or unreadable; start from an empty registry.\n debug('readRegistry failed', errorMessage(error))\n return emptyRegistry()\n }\n}\n\nfunction writeRegistry(registry: WatchdogRegistry): void {\n const directory = registryDirectory()\n mkdirSync(directory, { recursive: true, mode: 0o700 })\n const file = watchdogRegistryPath()\n const tempFile = `${file}.tmp-${process.pid}`\n writeFileSync(tempFile, JSON.stringify(registry, null, 2), { mode: 0o600 })\n renameSync(tempFile, file)\n}\n\nfunction ensureWatchdog(): void {\n if (watchdogStarted && watchdogChild)\n return\n watchdogStarted = true\n\n const child = spawn(process.execPath, [watchdogRunnerPath(), watchdogRegistryPath()], {\n detached: true,\n stdio: 'ignore',\n env: process.env,\n })\n watchdogChild = child\n child.unref()\n child.on('error', () => {\n // Child failed early or was killed; allow watchdog to be restarted on next pane registration.\n watchdogStarted = false\n if (watchdogChild === child)\n watchdogChild = null\n })\n child.on('exit', () => {\n watchdogStarted = false\n if (watchdogChild === child)\n watchdogChild = null\n if (existsSync(watchdogRegistryPath()))\n ensureWatchdog()\n })\n}\n\nfunction watchdogRunnerPath(): string {\n return fileURLToPath(new URL('./pane-watchdog-runner.mjs', import.meta.url))\n}\n\nexport function cleanupStaleWatchdogRegistries(): void {\n const directory = registryDirectory()\n if (!existsSync(directory))\n return\n\n for (const fileName of readdirSync(directory)) {\n if (!fileName.startsWith('panes-') || !fileName.endsWith('.json'))\n continue\n\n const file = path.join(directory, fileName)\n try {\n const registry = JSON.parse(readFileSync(file, 'utf8')) as WatchdogRegistry\n if (registry.version !== 1 || ownerStillMatches(registry))\n continue\n closeRegistryPanes(registry)\n rmSync(file, { force: true })\n }\n catch (error) {\n // Corrupt stale registries cannot be used safely and would otherwise fail every startup.\n debug('cleanupStaleWatchdogRegistries failed', errorMessage(error))\n rmSync(file, { force: true })\n }\n }\n}\n\nfunction ownerStillMatches(registry: WatchdogRegistry): boolean {\n try {\n process.kill(registry.ownerPid, 0)\n }\n catch (error) {\n // process.kill(pid, 0) throws when the owner is gone or inaccessible.\n debug('ownerStillMatches kill check failed', errorMessage(error))\n return false\n }\n\n return !registry.ownerStartTime || linuxProcessStartTime(registry.ownerPid) === registry.ownerStartTime\n}\n\nfunction closeRegistryPanes(registry: WatchdogRegistry): void {\n for (const pane of registry.panes) {\n const args = []\n if (registry.zellijSessionName)\n args.push('--session', registry.zellijSessionName)\n args.push('action', 'close-pane', '--pane-id', pane.paneId)\n spawn('zellij', args, { detached: true, stdio: 'ignore', env: process.env }).unref()\n }\n}\n\nexport function upsertWatchdogPane(registry: WatchdogRegistry, session: PtySession): WatchdogRegistry {\n return {\n ...registry,\n panes: [\n ...registry.panes.filter(pane => pane.sessionId !== session.id && pane.paneId !== session.paneId),\n {\n sessionId: session.id,\n paneId: session.paneId,\n title: session.title,\n openCodeSessionId: session.openCodeSessionId,\n createdAt: session.createdAt,\n },\n ],\n }\n}\n\nexport function removeWatchdogPane(registry: WatchdogRegistry, sessionId: string): WatchdogRegistry {\n return {\n ...registry,\n panes: registry.panes.filter(pane => pane.sessionId !== sessionId),\n }\n}\n\nexport function registerPaneForWatchdog(session: PtySession): void {\n writeRegistry(upsertWatchdogPane(readRegistry(), session))\n ensureWatchdog()\n}\n\nexport function unregisterPaneFromWatchdog(sessionId: string): void {\n const registry = readRegistry()\n const updated = removeWatchdogPane(registry, sessionId)\n if (updated.panes.length === registry.panes.length)\n return\n if (updated.panes.length === 0) {\n removeWatchdogRegistry()\n return\n }\n writeRegistry(updated)\n}\n\nexport function removeWatchdogRegistry(): void {\n try {\n rmSync(watchdogRegistryPath(), { force: true })\n }\n catch (error) {\n // Watchdog registry cleanup is best effort.\n debug('removeWatchdogRegistry failed', errorMessage(error))\n }\n if (!watchdogChild)\n watchdogStarted = false\n}\n","export interface ReadLinesInput {\n offset?: number | undefined\n limit?: number | undefined\n grep?: string | undefined\n ignoreCase?: boolean | undefined\n}\n\nexport interface ReadLinesResult {\n offset: number\n returned: number\n lineCount: number\n lines: string[]\n}\n\nconst escapeCharacter = String.fromCharCode(27)\nconst ansiPattern = new RegExp(`${escapeCharacter}\\\\[[0-9;?]*[a-z]`, 'gi')\n\nfunction normalizeLines(input: string | string[]): string[] {\n const lines = Array.isArray(input) ? input : input.replace(/\\r\\n/g, '\\n').split('\\n')\n if (lines.at(-1) === '')\n return lines.slice(0, -1)\n return lines\n}\n\nfunction stripAnsi(line: string): string {\n return line.replace(ansiPattern, '')\n}\n\nfunction overlapSize(existing: string[], incoming: string[]): number {\n const max = Math.min(existing.length, incoming.length)\n for (let size = max; size > 0; size -= 1) {\n const existingStart = existing.length - size\n let matches = true\n for (let index = 0; index < size; index += 1) {\n if (existing[existingStart + index] !== incoming[index]) {\n matches = false\n break\n }\n }\n if (matches)\n return size\n }\n return 0\n}\n\nexport class RingBuffer {\n private readonly maxLines: number\n private lines: string[] = []\n private totalAppended = 0\n\n constructor(maxLines = 50_000) {\n this.maxLines = Math.max(1, maxLines)\n }\n\n get lineCount(): number {\n return this.totalAppended\n }\n\n get startOffset(): number {\n return Math.max(0, this.totalAppended - this.lines.length)\n }\n\n append(input: string | string[]): number {\n const incoming = normalizeLines(input)\n if (incoming.length === 0)\n return 0\n this.lines.push(...incoming)\n this.totalAppended += incoming.length\n this.trim()\n return incoming.length\n }\n\n appendSnapshot(input: string | string[]): number {\n const incoming = normalizeLines(input)\n if (incoming.length === 0)\n return 0\n const overlap = overlapSize(this.lines, incoming)\n return this.append(incoming.slice(overlap))\n }\n\n read(input: ReadLinesInput = {}): ReadLinesResult {\n const limit = Math.max(1, Math.min(input.limit ?? 200, 5_000))\n const firstReadableOffset = this.startOffset\n const defaultOffset = Math.max(firstReadableOffset, this.lineCount - limit)\n const requestedOffset = input.offset ?? defaultOffset\n const offset = Math.max(firstReadableOffset, Math.min(requestedOffset, this.lineCount))\n const relativeOffset = offset - firstReadableOffset\n const unfiltered = this.lines.slice(relativeOffset, relativeOffset + limit)\n const pattern = input.grep ? new RegExp(input.grep, input.ignoreCase ? 'i' : '') : undefined\n const lines = unfiltered\n .map(stripAnsi)\n .filter(line => (pattern ? pattern.test(line) : true))\n\n return {\n offset,\n returned: lines.length,\n lineCount: this.lineCount,\n lines,\n }\n }\n\n clear(): void {\n this.lines = []\n this.totalAppended = 0\n }\n\n private trim(): void {\n if (this.lines.length <= this.maxLines)\n return\n this.lines = this.lines.slice(this.lines.length - this.maxLines)\n }\n}\n","import { randomUUID } from 'node:crypto'\n\nexport interface ExitCodeMarker {\n token: string\n exitCode: number\n}\n\nconst markerPattern = /^\\[zellij-pty:([a-f0-9]+)\\] exit-code=(\\d+)$/\nconst escapeCharacter = String.fromCharCode(27)\nconst ansiPattern = new RegExp(`${escapeCharacter}\\\\[[0-9;?]*[a-z]`, 'gi')\n\nexport function createExitCodeToken(): string {\n return randomUUID().replaceAll('-', '')\n}\n\nexport function parseExitCodeMarker(line: string): ExitCodeMarker | null {\n const match = line.replace(ansiPattern, '').replace(/\\r?\\n/g, '').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\nexport function parseExitCodeMarkerLines(lines: string[], maxWindowLines = 8): ExitCodeMarker | null {\n for (let start = 0; start < lines.length; start += 1) {\n for (let size = 1; size <= maxWindowLines && start + size <= lines.length; size += 1) {\n const marker = parseExitCodeMarker(lines.slice(start, start + size).join('\\n'))\n if (marker)\n return marker\n }\n }\n\n return null\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, SessionTerminalReason } from '../pty/session.js'\nimport { spawn } from 'node:child_process'\nimport process from 'node:process'\nimport { sessionManager } from '../pty/manager.js'\nimport { RingBuffer } from '../pty/ring-buffer.js'\nimport { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { parseExitCodeMarkerLines } 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\nexport interface SubscriberTerminalEvent {\n sessionId: string\n reason: SessionTerminalReason\n session: PtySession\n}\n\nexport interface SubscriberLifecycleHooks {\n onSessionTerminal?: (event: SubscriberTerminalEvent) => void | Promise<void>\n}\n\nexport interface SubscriberManagerDependencies {\n spawn?: typeof spawn | undefined\n dumpScreen?: typeof zellijCli.dumpScreen | undefined\n paneExists?: typeof zellijCli.paneExists | undefined\n closePane?: typeof zellijCli.closePane | undefined\n lifecycleHooks?: SubscriberLifecycleHooks | undefined\n terminalTailLines?: number | undefined\n}\n\ntype JsonObject = Record<string, unknown>\n\nexport interface SubscriberStatus {\n hasBuffer: boolean\n active: boolean\n lastExitedAt: string | null\n terminal: boolean\n}\n\nconst maxStderrLines = 200\n\nfunction splitLines(input: string): string[] {\n const lines = input.replace(/\\r\\n/g, '\\n').split('\\n')\n if (lines.at(-1) === '')\n return lines.slice(0, -1)\n return lines\n}\n\nfunction textFromCell(cell: unknown): string {\n if (typeof cell === 'string')\n return cell\n if (!cell || typeof cell !== 'object')\n return ''\n const object = cell as JsonObject\n const value = object.text ?? object.character ?? object.ch ?? object.content\n return typeof value === 'string' ? value : ''\n}\n\nfunction linesFromRows(rows: unknown[]): string[] {\n return rows.map((row) => {\n if (typeof row === 'string')\n return row\n if (Array.isArray(row))\n return row.map(textFromCell).join('')\n return textFromCell(row)\n })\n}\n\nfunction eventPaneId(event: JsonObject): string | undefined {\n const paneId = event.pane_id ?? event.paneId\n return typeof paneId === 'string' ? paneId : undefined\n}\n\nfunction eventType(event: JsonObject): string | undefined {\n const type = event.event ?? event.type\n return typeof type === 'string' ? type : undefined\n}\n\nfunction extractRenderedLines(event: JsonObject): string[] {\n for (const key of ['viewport', 'scrollback', 'lines'] as const) {\n const value = event[key]\n if (Array.isArray(value))\n return linesFromRows(value)\n }\n\n for (const key of ['text', 'output', 'content'] as const) {\n const value = event[key]\n if (typeof value === 'string')\n return splitLines(value)\n }\n\n return []\n}\n\nexport class SubscriberManager {\n private readonly subscribers = new Map<string, SubscriberState>()\n // Per-session start promises to prevent concurrent spawn races\n private readonly startingSessions = new Map<string, Promise<void>>()\n private readonly spawnProcess: typeof spawn\n private readonly dumpScreen: typeof zellijCli.dumpScreen\n private readonly paneExists: typeof zellijCli.paneExists\n private readonly closePane: typeof zellijCli.closePane\n private lifecycleHooks: SubscriberLifecycleHooks | undefined\n private readonly terminalTailLines: number\n\n constructor(\n private readonly sessions: SessionManager,\n private readonly maxBufferLines = Number(process.env.PTY_MAX_BUFFER_LINES ?? 50_000),\n dependencies: SubscriberManagerDependencies = {},\n ) {\n this.spawnProcess = dependencies.spawn ?? spawn\n this.dumpScreen = dependencies.dumpScreen ?? (paneId => zellijCli.dumpScreen(paneId))\n this.paneExists = dependencies.paneExists ?? (paneId => zellijCli.paneExists(paneId))\n this.closePane = dependencies.closePane ?? (paneId => zellijCli.closePane(paneId))\n this.lifecycleHooks = dependencies.lifecycleHooks\n this.terminalTailLines = dependencies.terminalTailLines ?? 200\n }\n\n setLifecycleHooks(hooks: SubscriberLifecycleHooks | undefined): void {\n this.lifecycleHooks = hooks\n }\n\n async start(session: PtySession): Promise<void> {\n const currentSession = this.sessions.find(session.id) ?? session\n if (currentSession.status === 'terminal')\n return\n const existing = this.subscribers.get(session.id)\n if (existing?.child)\n return\n\n // Prevent concurrent start races for the same session\n const inProgress = this.startingSessions.get(session.id)\n if (inProgress)\n return inProgress\n\n ensureZellijTarget()\n\n const startPromise = this.doStart(session)\n this.startingSessions.set(session.id, startPromise)\n try {\n await startPromise\n }\n finally {\n this.startingSessions.delete(session.id)\n }\n }\n\n private async doStart(session: PtySession): Promise<void> {\n const existing = this.subscribers.get(session.id)\n\n const state: SubscriberState\n = existing\n ?? {\n child: null,\n buffer: new RingBuffer(this.maxBufferLines),\n stderr: [],\n stdoutRemainder: '',\n startedAt: new Date().toISOString(),\n lastExitedAt: null,\n }\n\n if (!existing) {\n this.subscribers.set(session.id, state)\n }\n\n const child = this.spawnProcess('zellij', zellijCommandArgs(['subscribe', '--pane-id', session.paneId, '--scrollback', '--format', 'json', '--ansi']), {\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n child.stdin.end()\n // Only assign child if state is still the same (no concurrent restart)\n const currentState = this.subscribers.get(session.id)\n if (currentState !== state) {\n child.kill('SIGTERM')\n return\n }\n state.child = child\n state.lastExitedAt = null\n\n child.stdout.setEncoding('utf8')\n child.stdout.on('data', (chunk: string) => this.handleStdout(session.id, child, chunk))\n child.stderr.setEncoding('utf8')\n child.stderr.on('data', (chunk: string) => this.handleStderr(session.id, child, chunk))\n child.on('exit', () => this.handleSubscriberExit(session.id, child))\n child.on('error', error => this.handleSubscriberError(session.id, child, error))\n\n if (!existing) {\n try {\n const snapshot = await this.dumpScreen(session.paneId)\n if (this.subscribers.get(session.id) !== state || state.child !== child)\n return\n state.buffer.appendSnapshot(snapshot)\n this.sessions.updateLineCount(session.id, state.buffer.lineCount)\n }\n catch (error) {\n // dump-screen may race with pane creation; subscribe will still collect future output.\n debug('dumpScreen failed', errorMessage(error))\n }\n }\n }\n\n read(sessionId: string, input: ReadLinesInput): ReadLinesResult {\n const state = this.subscribers.get(sessionId)\n if (!state)\n throw new Error(`No subscriber buffer exists for session: ${sessionId}`)\n return state.buffer.read(input)\n }\n\n has(sessionId: string): boolean {\n return this.subscribers.has(sessionId)\n }\n\n status(sessionId: string): SubscriberStatus {\n const state = this.subscribers.get(sessionId)\n return {\n hasBuffer: Boolean(state),\n active: Boolean(state?.child),\n lastExitedAt: state?.lastExitedAt ?? null,\n terminal: this.sessions.find(sessionId)?.status === 'terminal',\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, options: { throwOnFailure?: boolean } = {}): Promise<void> {\n const session = this.sessions.get(sessionId)\n this.stop(sessionId)\n try {\n await this.closePane(session.paneId)\n }\n catch (error) {\n // Pane may already be closed by the user or command exit.\n debug('closePane failed', errorMessage(error))\n if (options.throwOnFailure)\n throw error\n }\n }\n\n private handleStdout(sessionId: string, child: ChildProcessWithoutNullStreams, chunk: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state || state.child !== child)\n return\n\n const parts = `${state.stdoutRemainder}${chunk}`.split('\\n')\n state.stdoutRemainder = parts.pop() ?? ''\n for (const part of parts) {\n this.handleJsonLine(sessionId, child, part)\n }\n }\n\n private handleJsonLine(sessionId: string, child: ChildProcessWithoutNullStreams, line: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state || state.child !== child)\n return\n const trimmed = line.trim()\n if (!trimmed)\n return\n\n let event: JsonObject\n try {\n const parsed: unknown = JSON.parse(trimmed)\n if (!parsed || typeof parsed !== 'object')\n return\n event = parsed as JsonObject\n }\n catch (error) {\n state.buffer.append(trimmed)\n this.sessions.updateLineCount(sessionId, state.buffer.lineCount)\n debug('JSON parse of subscriber event failed, treating as raw text', errorMessage(error))\n return\n }\n\n let session: PtySession\n try {\n session = this.sessions.get(sessionId)\n }\n catch (error) {\n this.forget(sessionId)\n debug('session lookup by id failed', errorMessage(error))\n return\n }\n const paneId = eventPaneId(event)\n if (paneId && paneId !== session.paneId)\n return\n\n const type = eventType(event)\n if (type === 'pane_closed' || type === 'PaneClosed') {\n this.markSessionTerminal(sessionId, 'pane_closed')\n unregisterPaneFromWatchdog(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 const marker = parseExitCodeMarkerLines(lines)\n if (!marker || marker.token !== session.exitCodeToken)\n return\n\n this.markSessionTerminal(sessionId, 'exit_marker', { exitCode: marker.exitCode })\n }\n\n private handleStderr(sessionId: string, child: ChildProcessWithoutNullStreams, chunk: string): void {\n const state = this.subscribers.get(sessionId)\n if (!state || state.child !== child)\n return\n this.appendStderr(state, ...splitLines(chunk))\n }\n\n private handleSubscriberExit(sessionId: string, child: ChildProcessWithoutNullStreams): void {\n const state = this.subscribers.get(sessionId)\n if (!state)\n return\n if (state.child !== child)\n return\n state.child = null\n state.lastExitedAt = new Date().toISOString()\n if (this.sessions.find(sessionId)?.status !== 'terminal')\n this.appendStderr(state, `[zellij-pty] subscriber exited at ${state.lastExitedAt}; last buffered output is retained.`)\n void this.reconcileSubscriberTermination(sessionId, state, 'subscriber_exit')\n }\n\n private handleSubscriberError(sessionId: string, child: ChildProcessWithoutNullStreams, error: Error): void {\n const state = this.subscribers.get(sessionId)\n if (state?.child === child) {\n this.appendStderr(state, error.message)\n state.child = null\n state.lastExitedAt = new Date().toISOString()\n const session = this.sessions.find(sessionId)\n if (session?.status !== 'terminal')\n this.sessions.updateStatus(sessionId, 'unknown')\n void this.reconcileSubscriberTermination(sessionId, state, 'subscriber_error')\n }\n }\n\n private appendStderr(state: SubscriberState, ...lines: string[]): void {\n state.stderr.push(...lines)\n if (state.stderr.length > maxStderrLines)\n state.stderr = state.stderr.slice(state.stderr.length - maxStderrLines)\n }\n\n private async reconcileSubscriberTermination(\n sessionId: string,\n state: SubscriberState,\n reason: Extract<SessionTerminalReason, 'subscriber_exit' | 'subscriber_error'>,\n ): Promise<void> {\n const session = this.sessions.find(sessionId)\n if (!session || session.status === 'terminal' || this.subscribers.get(sessionId) !== state || state.child)\n return\n\n let paneExists: boolean | undefined\n try {\n paneExists = await this.paneExists(session.paneId)\n }\n catch (error) {\n const latestState = this.subscribers.get(sessionId)\n const latestSession = this.sessions.find(sessionId)\n if (!latestState || latestState !== state || latestState.child || !latestSession || latestSession.status === 'terminal')\n return\n this.appendStderr(latestState, `[zellij-pty] ${reason} reconciliation could not verify pane ${latestSession.paneId}: ${errorMessage(error)}`)\n return\n }\n\n const latestState = this.subscribers.get(sessionId)\n const latestSession = this.sessions.find(sessionId)\n if (!latestState || latestState !== state || latestState.child || !latestSession || latestSession.status === 'terminal')\n return\n\n if (paneExists === false) {\n this.markSessionTerminal(sessionId, reason)\n unregisterPaneFromWatchdog(sessionId)\n return\n }\n\n if (paneExists === undefined) {\n this.appendStderr(latestState, `[zellij-pty] ${reason} reconciliation could not confirm whether pane ${latestSession.paneId} still exists; leaving session non-terminal.`)\n }\n }\n\n private markSessionTerminal(sessionId: string, reason: SessionTerminalReason, input: { exitCode?: number | undefined } = {}): void {\n const state = this.subscribers.get(sessionId)\n if (!state)\n return\n\n const tail = state.buffer.read({ limit: this.terminalTailLines }).lines\n const result = this.sessions.markTerminal(sessionId, {\n reason,\n tail,\n exitCode: input.exitCode,\n })\n\n if (result.created) {\n try {\n const maybePromise = this.lifecycleHooks?.onSessionTerminal?.({\n sessionId,\n reason,\n session: result.session,\n })\n if (maybePromise && typeof maybePromise.then === 'function') {\n void maybePromise.catch((error) => {\n debug('onSessionTerminal hook failed', errorMessage(error))\n })\n }\n }\n catch (error) {\n debug('onSessionTerminal hook failed', errorMessage(error))\n }\n }\n\n this.stop(sessionId)\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 === 'terminal' ? 'exited' : 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 tombstone: session.tombstone\n ? {\n reason: session.tombstone.reason,\n terminalAt: session.tombstone.terminalAt,\n tailLines: session.tombstone.tail.length,\n paneClosedAt: session.tombstone.paneClosedAt,\n }\n : null,\n }\n}\n\nexport interface NextAdvice {\n retryable: boolean\n reason: string\n}\n\nexport function nextAdvice(retryable: boolean, reason: string): NextAdvice {\n return { retryable, reason }\n}\n\nexport function jsonResponse(value: unknown): string {\n return JSON.stringify(value, null, 2)\n}\n","import { sessionManager } from '../pty/manager.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\n\nexport interface OutputSnapshot {\n text: string\n lines: string[]\n lineCount: number\n returned: number\n truncated: boolean\n}\n\nexport function emptyOutputSnapshot(lineCount = 0): OutputSnapshot {\n return { text: '', lines: [], lineCount, returned: 0, truncated: false }\n}\n\nexport interface OutputOptions {\n maxLines?: number | undefined\n grep?: string | undefined\n ignoreCase?: boolean | undefined\n}\n\nexport function validateGrep(grep: string | undefined): string | null {\n if (!grep)\n return null\n try {\n new RegExp(grep).test('')\n return null\n }\n catch (error) {\n return errorMessage(error)\n }\n}\n\nexport function readOutputSnapshot(sessionId: string, options: OutputOptions = {}): OutputSnapshot {\n const grepError = validateGrep(options.grep)\n if (grepError)\n throw new Error(`Invalid grep regex: ${grepError}`)\n\n const buffered = subscriberManager.read(sessionId, {\n limit: options.maxLines,\n grep: options.grep,\n ignoreCase: options.ignoreCase,\n })\n sessionManager.updateLineCount(sessionId, buffered.lineCount)\n\n return {\n text: buffered.lines.join('\\n'),\n lines: buffered.lines,\n lineCount: buffered.lineCount,\n returned: buffered.returned,\n truncated: buffered.offset > 0,\n }\n}\n\nexport function outputMatches(sessionId: string, grep: string, ignoreCase?: boolean | undefined): boolean {\n return readOutputSnapshot(sessionId, { maxLines: 5_000, grep, ignoreCase }).returned > 0\n}\n","export type PaneExistsFn = (paneId: string) => Promise<boolean | undefined> | boolean | undefined\n\nexport interface ClosePaneOrVerifyGoneInput {\n paneId: string\n closePane: () => Promise<void>\n paneExists?: PaneExistsFn | undefined\n}\n\nexport interface ClosePaneOrVerifyGoneResult {\n cleanupReady: boolean\n alreadyGone: boolean\n closeErrorMessage?: string | undefined\n}\n\nexport async function closePaneOrVerifyGone(input: ClosePaneOrVerifyGoneInput): Promise<ClosePaneOrVerifyGoneResult> {\n try {\n await input.closePane()\n return { cleanupReady: true, alreadyGone: false }\n }\n catch (error) {\n const closeErrorMessage = error instanceof Error ? error.message : String(error)\n const paneGone = await isPaneGone(input.paneId, input.paneExists)\n if (paneGone)\n return { cleanupReady: true, alreadyGone: true, closeErrorMessage }\n return { cleanupReady: false, alreadyGone: false, closeErrorMessage }\n }\n}\n\nasync function isPaneGone(paneId: string, paneExists?: PaneExistsFn | undefined): Promise<boolean> {\n if (!paneExists)\n return false\n\n try {\n return (await paneExists(paneId)) === false\n }\n catch {\n return false\n }\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'\nimport { closePaneOrVerifyGone } from './pane-cleanup.js'\n\nconst schema = tool.schema\n\nexport interface KillToolDependencies {\n zellijCli?: Pick<typeof zellijCli, 'sendCtrlC' | 'closePane' | 'paneExists'> | undefined\n}\n\nexport interface KillToolResult {\n killed: boolean\n cleanedUp: boolean\n id?: string | undefined\n paneId?: string | undefined\n session?: ReturnType<typeof publicSession> | undefined\n output?: ReturnType<typeof readOutputSnapshot> | undefined\n next: ReturnType<typeof nextAdvice>\n warnings: string[]\n}\n\nexport async function executeZellijPtyKill(args: { id: string }, dependencies: KillToolDependencies = {}): Promise<KillToolResult> {\n const zellijCliApi = dependencies.zellijCli ?? zellijCli\n const session = sessionManager.get(args.id)\n const warnings: string[] = []\n const output = subscriberManager.has(session.id) ? readOutputSnapshot(session.id) : undefined\n\n try {\n await zellijCliApi.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 const closeResult = await closePaneOrVerifyGone({\n paneId: session.paneId,\n closePane: () => zellijCliApi.closePane(session.paneId),\n paneExists: zellijCliApi.paneExists,\n })\n\n if (!closeResult.cleanupReady) {\n warnings.push(`close-pane failed: ${closeResult.closeErrorMessage ?? 'unknown error'}`)\n const updated = sessionManager.updateStatus(session.id, 'unknown')\n return {\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 return finalizeKilledSession(session.id, session.paneId, output, warnings)\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 return jsonResponse(await executeZellijPtyKill(args))\n },\n})\n\nasync function finalizeKilledSession(\n sessionId: string,\n paneId: string,\n output: ReturnType<typeof readOutputSnapshot> | undefined,\n warnings: string[],\n): Promise<KillToolResult> {\n subscriberManager.stop(sessionId)\n subscriberManager.forget(sessionId)\n unregisterPaneFromWatchdog(sessionId)\n sessionManager.remove(sessionId)\n return {\n killed: true,\n cleanedUp: true,\n id: sessionId,\n paneId,\n output,\n next: nextAdvice(false, 'Session was closed and removed from the in-memory registry.'),\n 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 type { PaneExistsFn } from './pane-cleanup.js'\nimport { tool } from '@opencode-ai/plugin'\nimport { sessionManager } from '../pty/manager.js'\nimport { zellijCli } from '../zellij/cli.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { readOutputSnapshot, validateGrep } from './output.js'\nimport { closePaneOrVerifyGone } from './pane-cleanup.js'\n\nconst schema = tool.schema\n\nexport interface ReadToolArgs {\n id: string\n maxLines?: number | undefined\n grep?: string | undefined\n ignoreCase?: boolean | undefined\n cleanupExitedPaneOnRead?: boolean | undefined\n}\n\nexport interface ReadCleanupResult {\n requested: boolean\n performed: boolean\n alreadyClosed: boolean\n warning?: string | undefined\n}\n\nexport interface ReadToolResult {\n session: ReturnType<typeof publicSession>\n output: ReturnType<typeof readOutputSnapshot>\n next: ReturnType<typeof nextAdvice>\n subscriberActive: boolean\n subscriberLastExitedAt: string | null\n subscriberErrors: string[]\n warnings: string[]\n cleanup: ReadCleanupResult\n}\n\nexport interface ReadToolDependencies {\n sessionManager?: Pick<typeof sessionManager, 'get' | 'updateStatus' | 'markTerminalPaneClosed'> | undefined\n subscriberManager?: Pick<typeof subscriberManager, 'status' | 'start' | 'stderr' | 'closeSessionPane'> | undefined\n publicSession?: typeof publicSession | undefined\n nextAdvice?: typeof nextAdvice | undefined\n readOutputSnapshot?: typeof readOutputSnapshot | undefined\n validateGrep?: typeof validateGrep | undefined\n paneExists?: PaneExistsFn | undefined\n defaultCleanupExitedPaneOnRead?: boolean | undefined\n}\n\nexport async function executeZellijPtyRead(args: ReadToolArgs, dependencies: ReadToolDependencies = {}): Promise<ReadToolResult> {\n const sessionManagerApi = dependencies.sessionManager ?? sessionManager\n const subscriberManagerApi = dependencies.subscriberManager ?? subscriberManager\n const publicSessionApi = dependencies.publicSession ?? publicSession\n const nextAdviceApi = dependencies.nextAdvice ?? nextAdvice\n const readOutputSnapshotApi = dependencies.readOutputSnapshot ?? readOutputSnapshot\n const validateGrepApi = dependencies.validateGrep ?? validateGrep\n const paneExistsApi = dependencies.paneExists ?? (paneId => zellijCli.paneExists(paneId))\n\n const session = sessionManagerApi.get(args.id)\n const grepError = validateGrepApi(args.grep)\n if (grepError) {\n return {\n session: publicSessionApi(session),\n output: { text: '', lines: [], lineCount: session.lineCount, returned: 0, truncated: false },\n next: nextAdviceApi(false, `Invalid grep regex: ${grepError}`),\n subscriberActive: false,\n subscriberLastExitedAt: null,\n subscriberErrors: [],\n warnings: [],\n cleanup: { requested: false, performed: false, alreadyClosed: false },\n }\n }\n\n const subscriberStatus = subscriberManagerApi.status(session.id)\n if (!subscriberStatus.hasBuffer || (!subscriberStatus.active && (session.status === 'running' || session.status === 'unknown')))\n await subscriberManagerApi.start(session)\n\n const statusAfterStart = subscriberManagerApi.status(session.id)\n const warnings: string[] = []\n if (session.humanInputOnly)\n warnings.push('This pane is human-input-only: agent writes are forbidden, but rendered output is visible to the agent.')\n\n if (!statusAfterStart.active && session.status === 'running') {\n warnings.push('Subscriber is inactive; returned output may be stale.')\n sessionManagerApi.updateStatus(session.id, 'unknown')\n }\n\n const output = readOutputSnapshotApi(session.id, { maxLines: args.maxLines, grep: args.grep, ignoreCase: args.ignoreCase })\n const cleanup = await cleanupExitedPaneOnRead(session.id, session.status, args.cleanupExitedPaneOnRead ?? dependencies.defaultCleanupExitedPaneOnRead ?? true, {\n sessionManager: sessionManagerApi,\n subscriberManager: subscriberManagerApi,\n paneExists: paneExistsApi,\n })\n if (cleanup.warning)\n warnings.push(cleanup.warning)\n\n return {\n session: publicSessionApi(session),\n output,\n next: nextAdviceApi(!isCompletedSession(session.status), nextReadReason(session.status)),\n subscriberActive: statusAfterStart.active,\n subscriberLastExitedAt: statusAfterStart.lastExitedAt,\n subscriberErrors: subscriberManagerApi.stderr(session.id),\n warnings,\n cleanup,\n }\n}\n\nasync function cleanupExitedPaneOnRead(\n sessionId: string,\n status: string,\n enabled: boolean,\n dependencies: {\n sessionManager: Pick<typeof sessionManager, 'get' | 'markTerminalPaneClosed'>\n subscriberManager: Pick<typeof subscriberManager, 'closeSessionPane'>\n paneExists: PaneExistsFn\n },\n): Promise<ReadCleanupResult> {\n const requested = enabled && isCompletedSession(status)\n if (!requested)\n return { requested: false, performed: false, alreadyClosed: false }\n\n const session = dependencies.sessionManager.get(sessionId)\n if (session.tombstone?.paneClosedAt)\n return { requested: true, performed: false, alreadyClosed: true }\n\n const closeResult = await closePaneOrVerifyGone({\n paneId: session.paneId,\n closePane: () => dependencies.subscriberManager.closeSessionPane(sessionId, { throwOnFailure: true }),\n paneExists: dependencies.paneExists,\n })\n\n if (closeResult.cleanupReady) {\n dependencies.sessionManager.markTerminalPaneClosed(sessionId)\n return { requested: true, performed: true, alreadyClosed: closeResult.alreadyGone }\n }\n return {\n requested: true,\n performed: false,\n alreadyClosed: false,\n warning: `Completed pane cleanup failed: ${closeResult.closeErrorMessage ?? 'unknown error'}`,\n }\n}\n\nexport function createZellijPtyReadTool(options: { defaultCleanupExitedPaneOnRead?: boolean | undefined, dependencies?: ReadToolDependencies | undefined } = {}) {\n return 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 cleanupExitedPaneOnRead: schema.boolean().optional().describe('Close completed panes after returning the final output. Defaults to true.'),\n },\n async execute(args) {\n return jsonResponse(await executeZellijPtyRead(args, {\n ...options.dependencies,\n defaultCleanupExitedPaneOnRead: options.defaultCleanupExitedPaneOnRead,\n }))\n },\n })\n}\n\nexport const zellijPtyReadTool = createZellijPtyReadTool()\n\nfunction isCompletedSession(status: string): boolean {\n return status === 'terminal' || status === 'exited' || status === 'killed'\n}\n\nfunction nextReadReason(status: string): string {\n if (status === 'terminal')\n return 'Session has finished; the final output is retained until the completed pane is read and cleaned up.'\n if (status === 'running')\n return 'Session is still running; read again later if more output is expected.'\n if (status === 'unknown')\n return 'Session state is unknown because the subscriber is inactive; output may be stale, but retrying read may restart observation.'\n return 'Session is no longer running.'\n}\n","import { randomUUID } from 'node:crypto'\n\nconst generatedInstanceId = randomUUID().replaceAll('-', '').slice(0, 8)\nconst existingOpenCodePrefixPattern = /^oc:[a-z0-9]{4,16}:/i\n\nexport function createOpenCodePaneTitle(title: string, instanceId = generatedInstanceId): string {\n const trimmedTitle = title.trim() || 'opencode'\n if (existingOpenCodePrefixPattern.test(trimmedTitle))\n return trimmedTitle\n\n const safeInstanceId = instanceId.replace(/[^a-z0-9]/gi, '').slice(0, 8) || generatedInstanceId\n return `oc:${safeInstanceId}:${trimmedTitle}`\n}\n","import { tool } from '@opencode-ai/plugin'\nimport { assertSudoPaneAllowed } from '../permissions/sudo-pane.js'\nimport { sessionManager } from '../pty/manager.js'\nimport { createExitCodeToken } from '../utils/exit-code.js'\nimport { createOpenCodePaneTitle } from '../utils/pane-title.js'\nimport { zellijCli } from '../zellij/cli.js'\nimport { registerPaneForWatchdog } from '../zellij/pane-watchdog.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { readOutputSnapshot } from './output.js'\n\nconst schema = tool.schema\n\nexport function shellQuote(value: string): string {\n return `'${value.replaceAll('\\'', `'\"'\"'`)}'`\n}\n\nexport function buildReviewScript(summary: string, scripts: Array<{ command: string, description: string }>): string {\n const lines = [\n 'set +e',\n 'printf \\'%s\\\\n\\' \\'=== OpenCode sudo request ===\\'',\n `printf '%s\\\\n' ${shellQuote(summary)}`,\n 'printf \\'\\\\n%s\\\\n\\' \\'Commands to review:\\'',\n ]\n\n scripts.forEach((script, index) => {\n const number = index + 1\n lines.push(`printf '\\\\n[%s/%s] %s\\\\n' ${shellQuote(String(number))} ${shellQuote(String(scripts.length))} ${shellQuote(script.description)}`)\n lines.push(`printf ' $ %s\\\\n' ${shellQuote(script.command)}`)\n })\n\n lines.push(\n 'printf \\'\\\\n%s\\\\n\\' \\'This pane is human-input-only. The agent cannot type here.\\'',\n 'read -r -p \\'Type YES to run these commands, anything else to cancel: \\' answer',\n 'if [ \"$answer\" != YES ]; then printf \\'%s\\\\n\\' \\'Cancelled by user.\\'; exit 130; fi',\n 'status=0',\n )\n\n scripts.forEach((script, index) => {\n const number = index + 1\n lines.push(`printf '\\\\n[%s/%s] %s\\\\n' ${shellQuote(String(number))} ${shellQuote(String(scripts.length))} ${shellQuote(script.description)}`)\n lines.push(`printf '$ %s\\\\n' ${shellQuote(script.command)}`)\n lines.push(`bash -lc ${shellQuote(script.command)}`)\n lines.push('code=$?')\n lines.push('if [ $code -ne 0 ]; then status=$code; printf \\'Command failed with exit code %s\\\\n\\' \"$code\"; break; fi')\n })\n\n lines.push('exit $status')\n return lines.join('\\n')\n}\n\nexport const requestSudoTool = tool({\n description: 'Open a human-reviewed, human-input-only Zellij pane for sudo or other privileged commands.',\n args: {\n summary: schema.string().min(1).describe('TL;DR of why privileged or human-reviewed execution is needed.'),\n scripts: schema\n .array(\n schema.object({\n command: schema.string().min(1).describe('Command or script to run after the user explicitly approves in the pane.'),\n description: schema.string().min(1).describe('Why this command is needed and what it is expected to change.'),\n }),\n )\n .min(1)\n .describe('Commands shown to the user for review before execution.'),\n },\n async execute(args, context) {\n const cwd = context.directory\n const exitCodeToken = createExitCodeToken()\n assertSudoPaneAllowed()\n\n const command = buildReviewScript(args.summary, args.scripts)\n const title = createOpenCodePaneTitle('zellij_pty_request_sudo')\n const paneId = await zellijCli.newPane({\n command: 'bash',\n args: ['-lc', command],\n cwd,\n title,\n floating: true,\n exitCodeToken,\n })\n\n const session = sessionManager.create({\n openCodeSessionId: context.sessionID,\n paneId,\n title,\n command: 'zellij_pty_request_sudo',\n args: [],\n cwd,\n allowAgentInput: false,\n humanInputOnly: true,\n exitCodeToken,\n })\n registerPaneForWatchdog(session)\n await subscriberManager.start(session)\n\n return jsonResponse({\n session: publicSession(session),\n output: readOutputSnapshot(session.id),\n next: nextAdvice(false, 'The user must review the summary and commands in Zellij, then type YES and any required credentials directly in the pane.'),\n warnings: [],\n })\n },\n})\n","import { setTimeout as delay } from 'node:timers/promises'\n\nexport type Probe\n = | { type: 'sleep', seconds?: number | undefined }\n | { type: 'http', url: string, expectStatus?: number | undefined, timeoutSeconds?: number | undefined }\n | { type: 'output', grep: string, ignoreCase?: boolean | undefined, timeoutSeconds?: number | undefined }\n\nexport interface ProbeResult {\n type: Probe['type']\n ok: boolean\n message: string\n elapsedMs: number\n}\n\nexport type OutputProbeReader = (grep: string, ignoreCase: boolean | undefined) => boolean\n\nconst defaultSleepSeconds = 1\nconst defaultProbeTimeoutSeconds = 20\nconst pollIntervalMs = 250\n\nexport async function runProbe(probe: Probe | undefined, outputReader: OutputProbeReader): Promise<ProbeResult> {\n const startedAt = Date.now()\n const effectiveProbe = probe ?? { type: 'sleep', seconds: defaultSleepSeconds }\n\n if (effectiveProbe.type === 'sleep') {\n const seconds = effectiveProbe.seconds ?? defaultSleepSeconds\n await delay(seconds * 1_000)\n return result(effectiveProbe.type, true, `Slept for ${seconds}s.`, startedAt)\n }\n\n if (effectiveProbe.type === 'output') {\n const timeoutSeconds = effectiveProbe.timeoutSeconds ?? defaultProbeTimeoutSeconds\n const deadline = Date.now() + timeoutSeconds * 1_000\n while (Date.now() <= deadline) {\n if (outputReader(effectiveProbe.grep, effectiveProbe.ignoreCase)) {\n return result(effectiveProbe.type, true, `Observed output matching /${effectiveProbe.grep}/.`, startedAt)\n }\n await delay(pollIntervalMs)\n }\n return result(effectiveProbe.type, false, `Timed out after ${timeoutSeconds}s waiting for output matching /${effectiveProbe.grep}/.`, startedAt)\n }\n\n const timeoutSeconds = effectiveProbe.timeoutSeconds ?? defaultProbeTimeoutSeconds\n const deadline = Date.now() + timeoutSeconds * 1_000\n const expectStatus = effectiveProbe.expectStatus\n let lastError = 'no response'\n\n while (Date.now() <= deadline) {\n try {\n const remainingMs = Math.max(1, deadline - Date.now())\n const response = await fetch(effectiveProbe.url, { signal: AbortSignal.timeout(Math.min(remainingMs, 3_000)) })\n const ok = expectStatus === undefined ? response.status >= 200 && response.status < 400 : response.status === expectStatus\n if (ok) {\n const expected = expectStatus === undefined ? '2xx/3xx' : String(expectStatus)\n return result(effectiveProbe.type, true, `HTTP probe ${effectiveProbe.url} returned expected status ${expected}.`, startedAt)\n }\n lastError = `HTTP ${response.status}`\n }\n catch (error) {\n lastError = error instanceof Error ? error.message : String(error)\n }\n await delay(pollIntervalMs)\n }\n\n return result(effectiveProbe.type, false, `Timed out after ${timeoutSeconds}s probing ${effectiveProbe.url}: ${lastError}.`, startedAt)\n}\n\nfunction result(type: Probe['type'], ok: boolean, message: string, startedAt: number): ProbeResult {\n return { type, ok, message, elapsedMs: Date.now() - startedAt }\n}\n","import type { Probe } from '../pty/probe.js'\nimport { tool } from '@opencode-ai/plugin'\nimport { sessionManager } from '../pty/manager.js'\nimport { runProbe } from '../pty/probe.js'\nimport { createExitCodeToken } from '../utils/exit-code.js'\nimport { createOpenCodePaneTitle } from '../utils/pane-title.js'\nimport { zellijCli } from '../zellij/cli.js'\nimport { registerPaneForWatchdog } from '../zellij/pane-watchdog.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { outputMatches, readOutputSnapshot, validateGrep } from './output.js'\n\nconst schema = tool.schema\n\nconst probeSchema = schema.discriminatedUnion('type', [\n schema.object({\n type: schema.literal('sleep'),\n seconds: schema.number().positive().max(300).optional().describe('Seconds to wait before returning initial output. Defaults to 1.'),\n }),\n schema.object({\n type: schema.literal('http'),\n url: schema.string().url().describe('HTTP URL to poll until it returns the expected status.'),\n expectStatus: schema.number().int().min(100).max(599).optional().describe('Expected HTTP status. Defaults to any 2xx/3xx response.'),\n timeoutSeconds: schema.number().positive().max(300).optional().describe('How long to poll before returning a failed probe result. Defaults to 20.'),\n }),\n schema.object({\n type: schema.literal('output'),\n grep: schema.string().describe('Regex to search for in observed pane output.'),\n ignoreCase: schema.boolean().optional().describe('Use case-insensitive regex matching.'),\n timeoutSeconds: schema.number().positive().max(300).optional().describe('How long to wait for matching output. Defaults to 20.'),\n }),\n])\n\nexport const zellijPtySpawnTool = tool({\n description: 'Create a visible Zellij pane and run a command in it.',\n args: {\n command: schema.string().describe('Command to run. Without args, it is executed through bash -lc.'),\n args: schema.array(schema.string()).optional().describe('Optional argv. When provided, command is executed directly without shell parsing.'),\n cwd: schema.string().optional().describe('Working directory for the new pane.'),\n title: schema.string().optional().describe('Pane title/name.'),\n probe: probeSchema.optional().describe('Optional readiness probe. Defaults to a short sleep before returning output.'),\n maxLines: schema.number().int().positive().max(5_000).optional().describe('Maximum recent output lines to return. Defaults to 200.'),\n },\n async execute(args, context) {\n const cwd = args.cwd ?? context.directory\n const exitCodeToken = createExitCodeToken()\n const grepError = args.probe?.type === 'output' ? validateGrep(args.probe.grep) : null\n if (grepError)\n throw new Error(`Invalid probe.grep regex: ${grepError}`)\n const title = createOpenCodePaneTitle(args.title ?? args.command)\n\n const paneId = await zellijCli.newPane({\n command: args.command,\n args: args.args,\n cwd,\n title,\n floating: false,\n exitCodeToken,\n })\n\n const session = sessionManager.create({\n openCodeSessionId: context.sessionID,\n paneId,\n title,\n command: args.command,\n args: args.args,\n cwd,\n allowAgentInput: true,\n humanInputOnly: false,\n exitCodeToken,\n })\n registerPaneForWatchdog(session)\n await subscriberManager.start(session)\n const probe = await runProbe(args.probe as Probe | undefined, (grep, ignoreCase) => outputMatches(session.id, grep, ignoreCase))\n const output = readOutputSnapshot(session.id, { maxLines: args.maxLines })\n\n return jsonResponse({\n session: publicSession(session),\n output,\n probe,\n next: nextAdvice(probe.ok, probe.ok ? 'Probe completed; continue with this session or read later for long-running output.' : probe.message),\n warnings: ['Registry remains in-memory; restarting OpenCode loses plugin session records.'],\n })\n },\n})\n","import { Buffer } from 'node:buffer'\nimport process from 'node:process'\n\nconst defaultMaxWriteBytes = 64 * 1024\nconst defaultChunkBytes = 8 * 1024\n\nexport function maxWriteBytes(): number {\n const configured = Number(process.env.ZELLIJ_PTY_MAX_WRITE_BYTES ?? defaultMaxWriteBytes)\n return Number.isFinite(configured) && configured > 0 ? configured : defaultMaxWriteBytes\n}\n\nexport function assertWriteSizeAllowed(data: string): void {\n const bytes = Buffer.byteLength(data, 'utf8')\n const maxBytes = maxWriteBytes()\n if (bytes > maxBytes) {\n throw new Error(`Write payload is too large: ${bytes} bytes exceeds ${maxBytes} bytes. Split the input into smaller writes.`)\n }\n}\n\nexport function chunkWriteData(data: string, maxChunkBytes = defaultChunkBytes): string[] {\n const chunks: string[] = []\n let current = ''\n let currentBytes = 0\n\n for (const character of data) {\n const characterBytes = Buffer.byteLength(character, 'utf8')\n if (current && currentBytes + characterBytes > maxChunkBytes) {\n chunks.push(current)\n current = ''\n currentBytes = 0\n }\n current += character\n currentBytes += characterBytes\n }\n\n if (current)\n chunks.push(current)\n return chunks\n}\n","import { setTimeout as delay } from 'node:timers/promises'\nimport { tool } from '@opencode-ai/plugin'\nimport { sessionManager } from '../pty/manager.js'\nimport { assertWriteSizeAllowed, chunkWriteData } from '../pty/write-data.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { zellijCli } from '../zellij/cli.js'\nimport { subscriberManager } from '../zellij/subscribe.js'\nimport { jsonResponse, nextAdvice, publicSession } from './format.js'\nimport { emptyOutputSnapshot, readOutputSnapshot } from './output.js'\n\nconst schema = tool.schema\n\nexport const zellijPtyWriteTool = tool({\n description: 'Write stdin to a Zellij PTY session. Refuses human-input-only sessions.',\n args: {\n id: schema.string().describe('zellij-pty session id returned by zellij_pty_spawn or zellij_pty_request_sudo.'),\n data: schema.string().describe('Text to write. Use \\u0003 to send Ctrl-C.'),\n maxLines: schema.number().int().positive().max(5_000).optional().describe('Maximum recent output lines to return. Defaults to 200.'),\n interruptAfterSeconds: schema.number().positive().max(300).optional().describe('Blindly send Ctrl-C after this many seconds if the pane is still running; keeps the pane alive.'),\n },\n async execute(args) {\n const session = sessionManager.get(args.id)\n if (session.humanInputOnly || !session.allowAgentInput) {\n return jsonResponse({\n session: publicSession(session),\n output: subscriberManager.has(session.id) ? readOutputSnapshot(session.id, { maxLines: args.maxLines }) : emptyOutputSnapshot(session.lineCount),\n next: nextAdvice(false, 'This session is human-input-only; the user must type directly in the Zellij pane.'),\n warnings: ['Agent writes to human-input-only sessions are forbidden.'],\n })\n }\n\n if (args.data === '\\u0003' || args.data === '\\x03') {\n await zellijCli.sendCtrlC(session.paneId)\n }\n else {\n assertWriteSizeAllowed(args.data)\n for (const chunk of chunkWriteData(args.data)) {\n await zellijCli.writeChars(session.paneId, chunk)\n }\n }\n\n session.updatedAt = new Date().toISOString()\n if (args.interruptAfterSeconds) {\n await delay(args.interruptAfterSeconds * 1_000)\n if (sessionManager.find(session.id)?.status === 'running') {\n await zellijCli.sendCtrlC(session.paneId)\n await delay(500)\n }\n }\n else {\n await delay(1_000)\n }\n\n const warnings: string[] = []\n let output = emptyOutputSnapshot(session.lineCount)\n try {\n output = readOutputSnapshot(session.id, { maxLines: args.maxLines })\n }\n catch (error) {\n warnings.push(`Session output was unavailable before the write response completed: ${errorMessage(error)}`)\n }\n\n return jsonResponse({\n session: publicSession(session),\n output,\n next: nextAdvice(true, args.interruptAfterSeconds ? 'Input was sent; Ctrl-C was sent after the requested interrupt timeout if the session was still running.' : 'Input was sent and recent output was observed.'),\n warnings,\n })\n },\n})\n","import process from 'node:process'\n\n/**\n * Detect whether the plugin process is running inside an OpenCode TUI\n * session, as opposed to a headless `opencode run` invocation.\n *\n * OpenCode spawns the TUI's renderer as a worker child process and\n * explicitly sets `OPENCODE_PROCESS_ROLE=worker`\n * (see `packages/opencode/src/cli/cmd/tui/thread.ts` in opencode). The\n * headless `opencode run` command keeps the default `main` role set by\n * the CLI entry point, so this is the most reliable signal to tell TUI\n * from headless.\n *\n * Outside the TUI there is no surface for toasts, prompts, or Zellij\n * panes, and the plugin's lifecycle hooks (watchdogs, tab title actor,\n * completion notifications) misbehave. The plugin short-circuits to a\n * no-op in headless mode to avoid leaking side effects.\n */\nexport function isOpencodeTuiMode(): boolean {\n return process.env.OPENCODE_PROCESS_ROLE === 'worker'\n}\n","import { mkdirSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { dirname } from 'node:path'\nimport process from 'node:process'\nimport { LogFileRotationTransport } from '@loglayer/transport-log-file-rotation'\nimport { LogLayer } from 'loglayer'\nimport { serializeError } from 'serialize-error'\n\n// Shared debug logger for the whole plugin. Submodules should NOT construct\n// their own LogLayer; instead call `getChildLogger(name)` to get a child\n// with a `[name]` prefix that inherits this root's transport.\n//\n// Logs are written under ~/.cache/opencode-zellij/ (overridable via\n// OPENCODE_ZELLIJ_DEBUG_LOG or XDG_CACHE_HOME). They are rotated by\n// LogFileRotationTransport — see `buildRootLogger` for the size-based\n// rotation policy. Each entry is a JSON object with level, message,\n// timestamp, and any structured metadata.\n//\n// If the transport fails to initialize (e.g. cache dir unwritable), the\n// root logger is silently null and `getChildLogger` returns null too;\n// callers should tolerate a null logger.\nconst defaultDebugLogPath = `${process.env.XDG_CACHE_HOME?.trim() || `${homedir()}/.cache`}/opencode-zellij/debug.log`\n\nfunction buildRootLogger(): LogLayer | null {\n const filename = process.env.OPENCODE_ZELLIJ_DEBUG_LOG?.trim() || defaultDebugLogPath\n if (!filename)\n return null\n\n try {\n mkdirSync(dirname(filename), { recursive: true })\n }\n catch {\n return null\n }\n\n try {\n // The filename must contain `%DATE%` and the date format must be set\n // to a value file-stream-rotator accepts. Without `%DATE%` it auto-\n // appends one and logs to stderr; without an explicit `dateFormat`\n // it falls back to 'YMD' and logs a warning to stderr. Both are\n // unwanted at plugin startup.\n const transport = new LogFileRotationTransport({\n filename: filename.includes('%DATE%') ? filename : `${filename}-%DATE%`,\n dateFormat: 'YMD',\n size: '1M',\n maxLogs: '7d',\n frequency: 'daily',\n compressOnRotate: true,\n })\n return new LogLayer({\n errorSerializer: serializeError,\n transport,\n })\n }\n catch {\n return null\n }\n}\n\nconst rootLogger = buildRootLogger()\n\n/**\n * Returns a child logger that prefixes every message with `[name]`, or\n * null if the root logger failed to initialize.\n */\nexport function getChildLogger(name: string): LogLayer | null {\n return rootLogger?.withPrefix(`[${name}]`) ?? null\n}\n","import type { PtySession, SessionTerminalReason } from '../pty/session.js'\nimport process from 'node:process'\nimport { errorMessage } from '../utils/errors.js'\nimport { getChildLogger } from '../utils/logger.js'\n\nconst logger = getChildLogger('completion-notifications')\n\nasync function postPromptAsync(serverUrl: URL, sessionID: string, body: unknown): Promise<Response> {\n const url = new URL(`/session/${encodeURIComponent(sessionID)}/prompt_async`, serverUrl)\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n }\n const directory = process.env.OPENCODE_DIRECTORY?.trim()\n if (directory)\n headers['x-opencode-directory'] = encodeURIComponent(directory)\n return fetch(url, { method: 'POST', headers, body: JSON.stringify(body) })\n}\n\nexport interface CompletionNotificationClient {\n session?: {\n prompt?: ((request: any) => Promise<unknown>) | undefined\n promptAsync?: ((request: any) => Promise<unknown>) | undefined\n }\n}\n\nexport interface CompletionNotificationContext {\n client: CompletionNotificationClient\n serverUrl?: URL | undefined\n}\n\nexport interface CompletionNotificationManager {\n handleSessionTerminal: (event: SubscriberTerminalEvent) => Promise<void>\n dispose: () => void\n}\n\nexport interface SubscriberTerminalEvent {\n sessionId: string\n reason: SessionTerminalReason\n session: PtySession\n}\n\nexport interface CompletionPromptRequest {\n sessionID: string\n parts: Array<{\n type: 'text'\n text: string\n }>\n}\n\nfunction formatExitCode(exitCode: number | null): string {\n return exitCode === null ? '?' : String(exitCode)\n}\n\n// Short, system-notification style. Contains the plugin name, pane id, and\n// exit code so the agent can immediately call zellij_pty_read on the right\n// pane without digging through session metadata.\nexport function buildCompletionPromptText(event: SubscriberTerminalEvent): string {\n const { paneId, exitCode } = event.session\n return `[zellij_pty] pane ${paneId} exit=${formatExitCode(exitCode)} — call zellij_pty_read to read, then zellij_pty_kill to close.`\n}\n\nexport function buildCompletionPromptRequest(event: SubscriberTerminalEvent): CompletionPromptRequest {\n return {\n sessionID: event.session.openCodeSessionId!,\n parts: [{ type: 'text', text: buildCompletionPromptText(event) }],\n }\n}\n\nexport class SessionCompletionNotificationManager implements CompletionNotificationManager {\n private readonly seen = new Set<string>()\n\n constructor(\n private readonly context: CompletionNotificationContext,\n ) { }\n\n dispose(): void {\n this.seen.clear()\n }\n\n async handleSessionTerminal(event: SubscriberTerminalEvent): Promise<void> {\n logger?.withMetadata({\n session: event.sessionId,\n reason: event.reason,\n paneId: event.session.paneId,\n openCodeSessionId: event.session.openCodeSessionId ?? 'null',\n }).info('handleSessionTerminal')\n if (this.seen.has(event.sessionId))\n return\n this.seen.add(event.sessionId)\n\n if (!event.session.openCodeSessionId) {\n logger?.withMetadata({ session: event.sessionId }).info('skipped: no openCodeSessionId')\n return\n }\n\n // Try the SDK client first. OpenCode 1.16.x may inject a client whose\n // session is a bare object without a working `_client` field, so fall\n // back to a direct HTTP call to the server's prompt_async endpoint.\n const session = this.context.client.session\n const sdkPrompt = session?.promptAsync ?? session?.prompt\n const request = buildCompletionPromptRequest(event)\n const sessionID = request.sessionID\n\n if (sdkPrompt) {\n try {\n logger?.withMetadata({ sessionID }).info('SDK prompt attempt')\n await sdkPrompt(request)\n logger?.withMetadata({ sessionID }).info('SDK prompt ok')\n return\n }\n catch (error) {\n logger?.withMetadata({ sessionID, error: errorMessage(error) })\n .warn('SDK prompt failed, falling back to HTTP')\n // fall through to HTTP\n }\n }\n else {\n logger?.withMetadata({\n sessionID,\n sessionKeys: session ? Object.keys(session).join(',') : 'null',\n }).info('no SDK prompt on client, using HTTP fallback')\n }\n\n if (!this.context.serverUrl) {\n logger?.withMetadata({ sessionID }).error('no serverUrl for HTTP fallback')\n return\n }\n\n try {\n const response = await postPromptAsync(this.context.serverUrl, sessionID, { parts: request.parts })\n logger?.withMetadata({\n sessionID,\n status: response.status,\n ok: response.ok,\n }).info('HTTP fallback response')\n }\n catch (error) {\n logger?.withMetadata({ sessionID, error: errorMessage(error) })\n .error('HTTP fallback threw')\n }\n }\n}\n","import type { SessionManager } from '../pty/manager.js'\nimport type { SubscriberManager } from './subscribe.js'\nimport process from 'node:process'\nimport { sessionManager } from '../pty/manager.js'\nimport { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { zellijCli } from './cli.js'\nimport { subscriberManager } from './subscribe.js'\n\nlet registered = false\nlet cleanedUp = false\n\nexport function cleanupPanesOnShutdown(\n sessions: SessionManager = sessionManager,\n subscribers: SubscriberManager = subscriberManager,\n): void {\n if (cleanedUp)\n return\n cleanedUp = true\n\n for (const session of sessions.list()) {\n try {\n zellijCli.closePaneSync(session.paneId)\n }\n catch (error) {\n // Shutdown cleanup is only a fast best-effort path; the watchdog registry remains as fallback.\n debug('cleanupPanesOnShutdown closePane failed', errorMessage(error))\n }\n\n subscribers.forget(session.id)\n try {\n sessions.remove(session.id)\n }\n catch (error) {\n // Another cleanup path may have already removed it.\n debug('cleanupPanesOnShutdown sessions.remove failed', errorMessage(error))\n }\n }\n}\n\nexport function registerShutdownCleanup(): void {\n if (registered)\n return\n registered = true\n\n process.once('exit', () => cleanupPanesOnShutdown())\n process.once('SIGINT', () => exitAfterCleanup('SIGINT', 130))\n process.once('SIGTERM', () => exitAfterCleanup('SIGTERM', 143))\n process.once('SIGHUP', () => exitAfterCleanup('SIGHUP', 129))\n}\n\nfunction exitAfterCleanup(signal: NodeJS.Signals, code: number): void {\n cleanupPanesOnShutdown()\n process.removeAllListeners(signal)\n process.exit(code)\n}\n","import { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\n\nconst execFileAsync = promisify(execFile)\n\nexport interface OpenCodeEventLike {\n type: string\n properties: unknown\n}\n\nexport 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\nexport function deletedSessionID(event: OpenCodeEventLike): string | undefined {\n if (!isRecord(event.properties))\n return undefined\n return nestedStringProperty(event.properties, 'info', 'id') ?? stringProperty(event.properties, 'sessionID')\n}\n\nasync function readGitBranch(worktree: string): Promise<string> {\n const result = await execFileAsync('git', ['-C', worktree, 'branch', '--show-current'], {\n encoding: 'utf8',\n timeout: 1_000,\n maxBuffer: 1024 * 1024,\n })\n return result.stdout\n}\n\nexport async function getInitialBranch(worktree: string, readBranch: BranchReader = readGitBranch): Promise<string | undefined> {\n try {\n return (await readBranch(worktree)).trim() || undefined\n }\n catch (error) {\n debug('getInitialBranch failed', errorMessage(error))\n return undefined\n }\n}\n\nexport function shouldReadInitialBranch(zellij: string | undefined): boolean {\n return Boolean(zellij)\n}\n","import process from 'node:process'\nimport { debug } from '../utils/debug.js'\nimport { errorMessage } from '../utils/errors.js'\nimport { ZellijCli } from './cli.js'\n\nexport interface TabTitleCli {\n renameTab: (title: string) => Promise<void>\n currentTabTitle: () => Promise<string | undefined>\n}\n\nexport type TabTitleStatus = 'idle' | 'running' | 'needs-input'\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\n// Helper functions for event parsing (mirrored from tab-title-events.ts)\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 sessionStatusType(properties: Record<string, unknown>): 'idle' | 'busy' | 'retry' | undefined {\n const status = properties.status\n if (!isRecord(status))\n return undefined\n const type = status.type\n if (type === 'idle' || type === 'busy')\n return type\n if (type === 'retry')\n return 'retry'\n return undefined\n}\n\nfunction inputRequestID(properties: Record<string, unknown>): string | undefined {\n return stringProperty(properties, 'id') ?? stringProperty(properties, 'requestID') ?? stringProperty(properties, 'permissionID')\n}\n\nfunction inputState(properties: Record<string, unknown>): string | undefined {\n return (stringProperty(properties, 'status') ?? stringProperty(properties, 'state') ?? stringProperty(properties, 'type'))?.toLowerCase()\n}\n\nfunction isResolvedInputState(state: string | undefined): boolean {\n return state === 'approved' || state === 'denied' || state === 'rejected' || state === 'resolved' || state === 'replied'\n}\n\nfunction deletedSessionID(properties: Record<string, unknown>): string | undefined {\n return nestedStringProperty(properties, 'info', 'id') ?? stringProperty(properties, 'sessionID')\n}\n\ninterface SessionRecord {\n directory: string | undefined\n parentID: string | undefined\n}\n\nexport class TabTitleIdentityModel {\n ready: Promise<void>\n projectName: string\n branchName: string | undefined\n private worktree: string\n private readBranch: (worktree: string) => Promise<string>\n private refreshGeneration = 0\n\n constructor(options: {\n projectName: string\n worktree: string\n readBranch: (worktree: string) => Promise<string>\n }) {\n this.projectName = options.projectName\n this.worktree = options.worktree\n this.readBranch = options.readBranch\n this.ready = this.refreshBranch('initial')\n }\n\n async refreshBranch(_reason?: string): Promise<void> {\n const generation = ++this.refreshGeneration\n try {\n const result = await this.readBranch(this.worktree)\n if (generation !== this.refreshGeneration)\n return\n const trimmed = result.trim() || undefined\n this.branchName = trimmed\n }\n catch (error) {\n if (generation !== this.refreshGeneration)\n return\n debug('refreshBranch failed', errorMessage(error))\n // keep previous branch\n }\n }\n\n handleEvent(event: { type: string, properties?: unknown }): Promise<void> | void {\n if (event.type === 'vcs.branch.updated') {\n return this.refreshBranch('vcs.branch.updated')\n }\n }\n}\n\nexport class TabTitleActivityModel {\n status: 'idle' | 'running' | 'needs-input' = 'idle'\n private worktreeDirectory: string\n private sessions = new Map<string, SessionRecord>()\n private scopedSessions = new Set<string>()\n private runningSessions = new Set<string>()\n private pendingInputs = new Map<string, string>()\n\n constructor(options: { worktreeDirectory: string }) {\n this.worktreeDirectory = options.worktreeDirectory\n }\n\n getSession(sessionID: string): SessionRecord | undefined {\n return this.scopedSessions.has(sessionID) ? this.sessions.get(sessionID) : undefined\n }\n\n hasPendingInput(sessionID: string, requestID: string): boolean {\n return this.pendingInputs.has(`${sessionID}:${requestID}`)\n }\n\n handleEvent(event: { type: string, properties?: unknown }): void {\n if (!isRecord(event.properties))\n return\n\n const properties = event.properties\n\n switch (event.type) {\n case 'session.created':\n case 'session.updated': {\n const info = properties.info\n if (isRecord(info)) {\n const id = stringProperty(info, 'id')\n if (id)\n this.storeSession(id, info)\n }\n break\n }\n case 'session.status': {\n const sessionID = stringProperty(properties, 'sessionID')\n const statusType = sessionStatusType(properties)\n if (sessionID && statusType) {\n if (statusType === 'idle') {\n if (this.runningSessions.has(sessionID)) {\n this.runningSessions.delete(sessionID)\n this.updateStatus()\n }\n }\n else if (statusType === 'busy' || statusType === 'retry') {\n if (this.scopedSessions.has(sessionID)) {\n this.runningSessions.add(sessionID)\n this.updateStatus()\n }\n }\n }\n break\n }\n case 'session.idle':\n case 'session.error': {\n const sessionID = stringProperty(properties, 'sessionID')\n if (sessionID && this.runningSessions.has(sessionID)) {\n this.runningSessions.delete(sessionID)\n this.updateStatus()\n }\n break\n }\n case 'question.asked':\n case 'permission.asked': {\n const id = inputRequestID(properties)\n const sessionID = stringProperty(properties, 'sessionID')\n if (id && sessionID && this.scopedSessions.has(sessionID)) {\n this.pendingInputs.set(`${sessionID}:${id}`, sessionID)\n this.runningSessions.add(sessionID)\n this.updateStatus()\n }\n break\n }\n case 'permission.updated': {\n const id = inputRequestID(properties)\n const sessionID = stringProperty(properties, 'sessionID')\n const state = inputState(properties)\n if (id && isResolvedInputState(state)) {\n this.pendingInputs.delete(`${sessionID}:${id}`)\n if (sessionID && this.runningSessions.has(sessionID))\n this.runningSessions.add(sessionID)\n this.updateStatus()\n }\n else if (id && sessionID && this.scopedSessions.has(sessionID)) {\n this.pendingInputs.set(`${sessionID}:${id}`, sessionID)\n this.runningSessions.add(sessionID)\n this.updateStatus()\n }\n break\n }\n case 'question.replied':\n case 'question.rejected':\n case 'permission.replied': {\n const id = inputRequestID(properties)\n const sessionID = stringProperty(properties, 'sessionID')\n if (id)\n this.pendingInputs.delete(`${sessionID}:${id}`)\n if (sessionID && this.runningSessions.has(sessionID))\n this.runningSessions.add(sessionID)\n this.updateStatus()\n break\n }\n case 'session.deleted': {\n const sessionID = deletedSessionID(properties)\n if (sessionID) {\n this.removeSessionAndDescendants(sessionID)\n this.updateStatus()\n }\n break\n }\n }\n }\n\n private storeSession(id: string, info: Record<string, unknown>): void {\n const directory = stringProperty(info, 'directory')\n const parentID = stringProperty(info, 'parentID')\n this.sessions.set(id, { directory, parentID })\n\n const isDirectlyScoped = directory === this.worktreeDirectory\n const isDescendantScoped = parentID ? this.scopedSessions.has(parentID) : false\n const isKnown = this.scopedSessions.has(id)\n\n if (isKnown || isDirectlyScoped || isDescendantScoped)\n this.scopedSessions.add(id)\n }\n\n private removeSessionAndDescendants(rootID: string): void {\n const toRemove = new Set<string>()\n toRemove.add(rootID)\n\n let changed = true\n while (changed) {\n changed = false\n for (const [id, session] of this.sessions) {\n if (!toRemove.has(id) && session.parentID && toRemove.has(session.parentID)) {\n toRemove.add(id)\n changed = true\n }\n }\n }\n\n for (const id of toRemove) {\n this.sessions.delete(id)\n this.scopedSessions.delete(id)\n this.runningSessions.delete(id)\n }\n\n for (const [key, sessionID] of [...this.pendingInputs.entries()]) {\n if (toRemove.has(sessionID))\n this.pendingInputs.delete(key)\n }\n }\n\n private updateStatus(): void {\n if (this.pendingInputs.size > 0)\n this.status = 'needs-input'\n else if (this.runningSessions.size > 0)\n this.status = 'running'\n else\n this.status = 'idle'\n }\n}\n\nexport class TabTitleActor {\n ready: Promise<void>\n private identity: TabTitleIdentityModel\n private activity: TabTitleActivityModel\n private emojis: TabTitleEmojis\n\n constructor(options: {\n identity: TabTitleIdentityModel\n activity: TabTitleActivityModel\n emojis?: Partial<TabTitleEmojis> | undefined\n }) {\n this.identity = options.identity\n this.activity = options.activity\n this.emojis = { ...defaultTabTitleEmojis, ...options.emojis }\n this.ready = this.identity.ready\n }\n\n get context() {\n return {\n projectName: this.identity.projectName,\n branchName: this.identity.branchName,\n status: this.activity.status,\n }\n }\n\n get title(): string {\n return formatTabTitle({\n ...this.context,\n emojis: this.emojis,\n })\n }\n\n async handleEvent(event: { type: string, properties?: unknown }): Promise<void> {\n this.activity.handleEvent(event)\n\n const identityResult = this.identity.handleEvent(event)\n if (identityResult instanceof Promise)\n await identityResult\n }\n}\n\nexport interface TabTitleManagerOptions {\n cli?: TabTitleCli\n emojis?: Partial<TabTitleEmojis> | undefined\n debounceMs?: number\n retryInitialMs?: number\n retryMaxMs?: number\n actor: TabTitleActor\n}\n\nexport class TabTitleManager {\n private desiredTitle: string | undefined\n private lastSyncedTitle: string | undefined\n private syncGeneration = 0\n private debounceTimer: ReturnType<typeof setTimeout> | undefined\n private retryTimer: ReturnType<typeof setTimeout> | undefined\n private retryAttempt = 0\n private syncInFlight = false\n private syncPromise: Promise<void> | undefined\n private readonly debounceMs: number\n private readonly retryInitialMs: number\n private readonly retryMaxMs: number\n private readonly cli: TabTitleCli\n private readonly emojis: TabTitleEmojis\n private readonly enabled: boolean\n private destroyed = false\n private destroyPromise: Promise<void> | undefined\n private readonly actor: TabTitleActor\n\n constructor(options: TabTitleManagerOptions) {\n this.cli = options.cli ?? new ZellijCli()\n this.emojis = { ...defaultTabTitleEmojis, ...options.emojis }\n this.debounceMs = options.debounceMs ?? 300\n this.retryInitialMs = options.retryInitialMs ?? 250\n this.retryMaxMs = options.retryMaxMs ?? 5_000\n this.enabled = Boolean(process.env.ZELLIJ || process.env.ZELLIJ_SESSION_NAME)\n this.actor = options.actor\n }\n\n private buildTitle(): string {\n return sanitizeTitle(formatTabTitle({\n ...this.actor.context,\n emojis: this.emojis,\n }))\n }\n\n getCurrentTitle(): string {\n return this.buildTitle()\n }\n\n async renderImmediate(): Promise<void> {\n if (!this.enabled || this.destroyed)\n return\n this.desiredTitle = this.buildTitle()\n this.clearDebounceTimer()\n await this.syncDesiredTitle()\n }\n\n scheduleUpdate(): void {\n if (!this.enabled || this.destroyed)\n return\n const title = this.buildTitle()\n if (title === this.desiredTitle && title === this.lastSyncedTitle)\n return\n this.desiredTitle = title\n\n if (this.syncInFlight)\n return\n\n this.clearRetryTimer()\n this.clearDebounceTimer()\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = undefined\n this.syncDesiredTitle()\n .catch(error => debug('debounced tab title sync failed', errorMessage(error)))\n }, this.debounceMs)\n this.unrefTimer(this.debounceTimer)\n }\n\n private async syncDesiredTitle(): Promise<void> {\n if (!this.enabled || this.destroyed)\n return\n const generation = this.syncGeneration\n if (this.destroyed || generation !== this.syncGeneration)\n return\n if (this.syncInFlight)\n return this.syncPromise\n\n this.syncInFlight = true\n this.syncPromise = this.runTitleSync(generation)\n return this.syncPromise\n }\n\n private async runTitleSync(generation: number): Promise<void> {\n try {\n while (generation === this.syncGeneration && this.desiredTitle && this.desiredTitle !== this.lastSyncedTitle) {\n const title = this.desiredTitle\n try {\n await this.cli.renameTab(title)\n if (generation !== this.syncGeneration || this.destroyed)\n return\n this.lastSyncedTitle = title\n this.retryAttempt = 0\n this.clearRetryTimer()\n }\n catch (cause) {\n debug('Failed to rename Zellij tab.', cause)\n if (generation !== this.syncGeneration || this.destroyed)\n break\n this.scheduleRetry()\n break\n }\n }\n }\n finally {\n this.syncInFlight = false\n this.syncPromise = undefined\n }\n }\n\n private scheduleRetry(): void {\n if (!this.enabled || this.destroyed || this.retryTimer || this.desiredTitle === this.lastSyncedTitle)\n return\n\n const delay = Math.min(this.retryMaxMs, this.retryInitialMs * 2 ** this.retryAttempt)\n this.retryAttempt += 1\n this.retryTimer = setTimeout(() => {\n this.retryTimer = undefined\n this.syncDesiredTitle()\n .catch(error => debug('retry tab title sync failed', errorMessage(error)))\n }, delay)\n this.unrefTimer(this.retryTimer)\n }\n\n private clearRetryTimer(): void {\n if (this.retryTimer)\n clearTimeout(this.retryTimer)\n this.retryTimer = undefined\n }\n\n private unrefTimer(timer: ReturnType<typeof setTimeout>): void {\n if (typeof timer === 'object' && timer && 'unref' in timer && typeof timer.unref === 'function')\n timer.unref()\n }\n\n private clearDebounceTimer(): void {\n if (this.debounceTimer)\n clearTimeout(this.debounceTimer)\n this.debounceTimer = undefined\n }\n\n // No-op. Previously this method captured the tab title and restored it\n // on destroy, but in practice the opencode plugin lifecycle never\n // dispatches a reliable \"session ended\" event in any mode (TUI\n // worker shutdown, `opencode run` headless, or `opencode run --interactive`\n // all exit without firing `server.instance.disposed` / `global.disposed`).\n // `process.once('exit')` only supports sync callbacks so it cannot drive\n // the async Zellij rename, and SIGKILL cannot be intercepted at all.\n // The remaining work is to clear timers so a straggler sync cannot race\n // the process exit; the tab title we set is simply left in place.\n destroy(): Promise<void> {\n if (this.destroyed)\n return this.destroyPromise ?? Promise.resolve()\n this.destroyed = true\n this.syncGeneration += 1\n this.desiredTitle = undefined\n this.clearDebounceTimer()\n this.clearRetryTimer()\n return Promise.resolve()\n }\n}\n","import type { Plugin, PluginModule } from '@opencode-ai/plugin'\nimport type { CompletionNotificationContext, CompletionNotificationManager } from './zellij/completion-notifications.js'\nimport type { OpenCodeEventLike } from './zellij/tab-title-events.js'\nimport process from 'node:process'\nimport { loadConfig } from './config.js'\nimport { configureSudoPane } from './permissions/sudo-pane.js'\nimport { sessionManager } from './pty/manager.js'\nimport { zellijPtyKillTool } from './tools/kill.js'\nimport { zellijPtyListTool } from './tools/list.js'\nimport { createZellijPtyReadTool } from './tools/read.js'\nimport { requestSudoTool } from './tools/request-sudo.js'\nimport { zellijPtySpawnTool } from './tools/spawn.js'\nimport { zellijPtyWriteTool } from './tools/write.js'\nimport { debug } from './utils/debug.js'\nimport { errorMessage } from './utils/errors.js'\nimport { isOpencodeTuiMode } from './utils/runtime.js'\nimport { SessionCompletionNotificationManager } from './zellij/completion-notifications.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, shouldReadInitialBranch } from './zellij/tab-title-events.js'\nimport { TabTitleActivityModel, TabTitleActor, TabTitleIdentityModel, TabTitleManager } from './zellij/tab-title.js'\n\nconst PLUGIN_ID = 'opencode-zellij'\n\nfunction createPtyTools(defaultCleanupExitedPaneOnRead: boolean) {\n return {\n zellij_pty_spawn: zellijPtySpawnTool,\n zellij_pty_list: zellijPtyListTool,\n zellij_pty_write: zellijPtyWriteTool,\n zellij_pty_read: createZellijPtyReadTool({ defaultCleanupExitedPaneOnRead }),\n zellij_pty_kill: zellijPtyKillTool,\n }\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\nasync function cleanupStep(stepName: string, sessionId: string, step: () => void | Promise<void>): Promise<void> {\n try {\n await step()\n }\n catch (error) {\n debug(`session.deleted cleanup failed: ${stepName} for ${sessionId}`, errorMessage(error))\n }\n}\n\nasync function cleanupDeletedSession(sessionId: string): Promise<void> {\n await cleanupStep('close pane', sessionId, () => subscriberManager.closeSessionPane(sessionId))\n await cleanupStep('forget subscriber', sessionId, () => subscriberManager.forget(sessionId))\n await cleanupStep('unregister watchdog', sessionId, () => unregisterPaneFromWatchdog(sessionId))\n await cleanupStep('remove session', sessionId, () => sessionManager.remove(sessionId))\n}\n\nexport interface ZellijPtyPluginDependencies {\n createCompletionNotifications?: (context: CompletionNotificationContext) => CompletionNotificationManager | undefined\n}\n\nexport function createZellijPtyPlugin(dependencies: ZellijPtyPluginDependencies = {}): Plugin {\n return async (input) => {\n // Headless `opencode run` has no UI to render toasts, prompts, or\n // Zellij panes, and the plugin's lifecycle hooks misbehave when the\n // owning process exits without firing the expected teardown events.\n // Short-circuit to a no-op outside the TUI so we don't leak watchdogs,\n // tab-title actors, or completion notifiers into a session that can't\n // observe them.\n if (!isOpencodeTuiMode()) {\n debug('opencode-zellij disabled: not running inside an OpenCode TUI session')\n return {}\n }\n\n const { config, warnings } = await loadConfig(input)\n for (const warning of warnings) {\n debug(warning)\n }\n configureSudoPane(config.pty.sudoPane === 'allow')\n cleanupStaleWatchdogRegistries()\n registerShutdownCleanup()\n\n const workspaceRoot = getWorkspaceRoot(input)\n const projectName = getProjectName(workspaceRoot)\n const identityModel = config.tabTitle.enabled\n ? new TabTitleIdentityModel({\n projectName,\n worktree: workspaceRoot,\n readBranch: async worktree => shouldReadInitialBranch(process.env.ZELLIJ || process.env.ZELLIJ_SESSION_NAME) ? (await getInitialBranch(worktree)) ?? '' : '',\n })\n : undefined\n const activityModel = config.tabTitle.enabled\n ? new TabTitleActivityModel({\n worktreeDirectory: workspaceRoot,\n })\n : undefined\n const actor = identityModel && activityModel\n ? new TabTitleActor({\n identity: identityModel,\n activity: activityModel,\n })\n : undefined\n const tabTitleManager = config.tabTitle.enabled && actor\n ? new TabTitleManager({\n actor,\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 const completionNotifications = dependencies.createCompletionNotifications?.({\n client: { session: input.client?.session },\n serverUrl: input.serverUrl,\n }) ?? new SessionCompletionNotificationManager({\n client: { session: input.client?.session },\n serverUrl: input.serverUrl,\n })\n subscriberManager.setLifecycleHooks({\n onSessionTerminal: event => void completionNotifications.handleSessionTerminal(event)\n .catch(error => debug('completion notification lifecycle hook failed', errorMessage(error))),\n })\n\n // Best-effort initial render; no-op when not inside a real Zellij pane.\n if (actor) {\n await actor.ready\n }\n tabTitleManager?.renderImmediate()\n .catch(error => debug('initial tab title render failed', errorMessage(error)))\n\n return {\n async event(input) {\n const event: OpenCodeEventLike = input.event\n\n if (actor && tabTitleManager) {\n await actor.handleEvent(event)\n tabTitleManager.scheduleUpdate()\n }\n if (event.type === 'server.instance.disposed' || event.type === 'global.disposed') {\n completionNotifications.dispose()\n subscriberManager.setLifecycleHooks(undefined)\n }\n\n if (event.type === 'session.deleted') {\n const sessionID = deletedSessionID(event)\n if (!sessionID)\n return\n\n const sessions = sessionManager.listByOpenCodeSession(sessionID)\n await Promise.all(sessions.map(session => cleanupDeletedSession(session.id)))\n }\n },\n tool: config.pty.enabled\n ? {\n ...createPtyTools(config.pty.cleanupExitedPaneOnRead),\n ...(config.pty.sudoPane === 'hide' ? {} : { zellij_pty_request_sudo: requestSudoTool }),\n }\n : {},\n }\n }\n}\n\n// Default export follows the V1 PluginModule shape expected by opencode's\n// plugin loader (`@opencode-ai/plugin` PluginModule = { id?, server, tui?: never }).\n// The `id` is required for file plugins; opencode uses it to identify the\n// plugin in logs and `resolvePluginId`. `server` is the plugin factory\n// (a `Plugin` = `(input, options) => Promise<Hooks>`).\n//\n// `ZellijPtyPlugin` is also re-exported as a named symbol for tests and\n// internal callers that need the raw factory; it is no longer the default\n// export so that opencode's `readV1Plugin` finds the expected object shape\n// instead of falling through to the legacy `getLegacyPlugins` path, which\n// would otherwise try to invoke every other named export as a plugin.\nexport const ZellijPtyPlugin: Plugin = createZellijPtyPlugin()\n\nexport default {\n id: PLUGIN_ID,\n server: ZellijPtyPlugin,\n} satisfies Pick<PluginModule, 'id' | 'server'>\n"],"mappings":"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"}
|