feat: add hidden integrated terminal#2094
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
3 issues found across 12 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/desktop/electron/main.mjs">
<violation number="1" location="apps/desktop/electron/main.mjs:3075">
P2: `destroyed` listener is registered once per terminal creation and never cleaned up. Repeated create/kill cycles can trigger MaxListeners warnings and unnecessary listener/memory growth.</violation>
</file>
<file name="apps/app/src/react-app/domains/session/chat/session-page.tsx">
<violation number="1" location="apps/app/src/react-app/domains/session/chat/session-page.tsx:1122">
P2: Hiding the panel unmounts and kills the PTY, so reopening loses the shell session instead of just hiding it.</violation>
<violation number="2" location="apps/app/src/react-app/domains/session/chat/session-page.tsx:1128">
P2: Terminal remote gating uses workspace display type instead of runtime remote state. This can incorrectly enable a local PTY on remote sessions or block terminal on local sessions when metadata differs.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| }); | ||
|
|
||
| terminalProcesses.set(terminalId, { process: child, webContentsId: event.sender.id }); | ||
| event.sender.once("destroyed", () => killTerminalsForWebContents(event.sender.id)); |
There was a problem hiding this comment.
P2: destroyed listener is registered once per terminal creation and never cleaned up. Repeated create/kill cycles can trigger MaxListeners warnings and unnecessary listener/memory growth.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/electron/main.mjs, line 3075:
<comment>`destroyed` listener is registered once per terminal creation and never cleaned up. Repeated create/kill cycles can trigger MaxListeners warnings and unnecessary listener/memory growth.</comment>
<file context>
@@ -3015,6 +3051,56 @@ ipcMain.handle("openwork:system:askMicrophoneAccess", async () => {
+ });
+
+ terminalProcesses.set(terminalId, { process: child, webContentsId: event.sender.id });
+ event.sender.once("destroyed", () => killTerminalsForWebContents(event.sender.id));
+ child.onData((data) => {
+ if (event.sender.isDestroyed()) return;
</file context>
| event.sender.once("destroyed", () => killTerminalsForWebContents(event.sender.id)); | |
| if (!event.sender.__openworkTerminalCleanupRegistered) { | |
| event.sender.__openworkTerminalCleanupRegistered = true; | |
| event.sender.once("destroyed", () => killTerminalsForWebContents(event.sender.id)); | |
| } |
| <ResizablePanel defaultSize="280px" minSize="160px" maxSize="55%" className="min-h-0"> | ||
| <TerminalDock | ||
| workspaceRoot={props.selectedWorkspaceRoot} | ||
| isRemoteWorkspace={props.selectedWorkspaceDisplay.workspaceType === "remote"} |
There was a problem hiding this comment.
P2: Terminal remote gating uses workspace display type instead of runtime remote state. This can incorrectly enable a local PTY on remote sessions or block terminal on local sessions when metadata differs.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/app/src/react-app/domains/session/chat/session-page.tsx, line 1128:
<comment>Terminal remote gating uses workspace display type instead of runtime remote state. This can incorrectly enable a local PTY on remote sessions or block terminal on local sessions when metadata differs.</comment>
<file context>
@@ -1114,7 +1118,20 @@ export function SessionPage(props: SessionPageProps) {
+ <ResizablePanel defaultSize="280px" minSize="160px" maxSize="55%" className="min-h-0">
+ <TerminalDock
+ workspaceRoot={props.selectedWorkspaceRoot}
+ isRemoteWorkspace={props.selectedWorkspaceDisplay.workspaceType === "remote"}
+ onClose={() => props.onTerminalOpenChange?.(false)}
+ />
</file context>
| isRemoteWorkspace={props.selectedWorkspaceDisplay.workspaceType === "remote"} | |
| isRemoteWorkspace={props.surface?.isRemoteWorkspace ?? false} |
| </div> | ||
| </div> | ||
| </ResizablePanel> | ||
| {props.terminalOpen ? ( |
There was a problem hiding this comment.
P2: Hiding the panel unmounts and kills the PTY, so reopening loses the shell session instead of just hiding it.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/app/src/react-app/domains/session/chat/session-page.tsx, line 1122:
<comment>Hiding the panel unmounts and kills the PTY, so reopening loses the shell session instead of just hiding it.</comment>
<file context>
@@ -1114,7 +1118,20 @@ export function SessionPage(props: SessionPageProps) {
</div>
- </div>
+ </ResizablePanel>
+ {props.terminalOpen ? (
+ <>
+ <ResizableHandle withHandle />
</file context>
Summary
Cmd/Ctrl+J.@lydell/node-ptyalias becausenode-pty@1.1.0loaded but failed to fork locally withposix_spawnp failed.Validation
pnpm --filter @openwork/app typecheckpassed.pnpm --filter @openwork/desktop typecheck:electronpassed.pnpm --filter @openwork/app buildpassed.node -e "import('node-pty').then(...)"printedPASS openwork-terminal-proof.Daytona Proof
Sandbox:
openwork-test-20260604-152359Recording:
Frame-by-frame screenshots:
Show terminal: https://8090-mlzktgfcqzp4bmaf.daytonaproxy01.net/screenshots/daytona-screenshot-20260604-222740.png/workspace/terminal-proof: https://8090-mlzktgfcqzp4bmaf.daytonaproxy01.net/screenshots/daytona-screenshot-20260604-222807.pngCtrl+J: https://8090-mlzktgfcqzp4bmaf.daytonaproxy01.net/screenshots/daytona-screenshot-20260604-222924.pngCDP assertions:
navigator.userAgent.includes("Electron/") === true.Boolean(window.__OPENWORK_ELECTRON__?.terminal) === true.Ctrl+J:!document.body.innerText.includes("Terminal ·") === true.assert-terminal-ok:/workspace/terminal-proof.Recording duration after finalization:
221.666667seconds.