diff --git a/catalog.json b/catalog.json index dfed967..0bf2775 100644 --- a/catalog.json +++ b/catalog.json @@ -2,7 +2,7 @@ "schemaVersion": 1, "providerId": "official", "name": "PI-Desktop Official Plugins", - "updatedAt": "2026-09-14T04:38:39Z", + "updatedAt": "2026-09-16T04:56:31Z", "homepage": "https://github.com/vastsa/pi-desktop-plugins", "plugins": [ { @@ -929,17 +929,17 @@ "downloads": 0, "homepage": "https://github.com/vastsa/pi-desktop-plugins/tree/main/plugins/pi.terminal", "repository": "https://github.com/vastsa/pi-desktop-plugins", - "readmeMarkdown": "# Terminal \u00b7 \u7ec8\u7aef\n\nOtty-inspired interactive terminal for PI-Desktop. It docks in the right work panel next to the conversation \u2014 there is no separate window.\n\n\u53d7 Otty \u542f\u53d1\u7684\u4ea4\u4e92\u5f0f\u7ec8\u7aef\uff0c\u53ea\u505c\u9760\u5728\u53f3\u4fa7\u5de5\u4f5c\u9762\u677f\uff08\u65e0\u72ec\u7acb\u7a97\u53e3\uff09\u3002\n\n## What it does\n\n- **Work panel view** \u2014 `Terminal` / `\u7ec8\u7aef` in the plugin views menu (icon `terminal`). Open the work panel with **Mod+J**.\n- **Tabs** \u2014 new / close / switch. Closing the view does **not** kill the shell; reopening replays a bounded in-memory scrollback. Tabs belong to the **currently open project**; switching projects shows that project's terminals only (other shells stay alive in the background until the plugin is disabled).\n- **Cross-platform shells**\n - macOS: `$SHELL` \u2192 `/bin/zsh` as a real login shell (`argv0` `-zsh`)\n - Linux: `$SHELL` \u2192 `/bin/bash` as a real login shell\n - Windows: PowerShell \u2192 `cmd.exe`; Git Bash is offered when installed\n- **Login PATH** \u2014 GUI apps often see a thin PATH. On load the plugin dumps your interactive login environment and injects it into every PTY, then prepends common tool dirs (pnpm, nvm, bun, cargo, Homebrew) if they exist. `node` / `pnpm` / `brew` should resolve the same way they do in Terminal.app.\n- Follows the app language (`en` / `zh-CN`) and color mode, including live light/dark switches while the view stays open (chrome and xterm canvas). Copy/paste: macOS `Cmd+C/V`, Windows/Linux `Ctrl+Shift+C/V`. Find: `Cmd/Ctrl+F`. Font size: `Cmd/Ctrl +` / `-`.\n\nNot in v0.1: pane splits, Recipes, SSH sessions (use **SSH Manager**), or an agent tool that types into the PTY.\n\n## Permissions\n\n| Permission | Why |\n| --- | --- |\n| `ui.view` | Work-panel Terminal view |\n| `background.service` | Keep the plugin process (and live PTYs) resident when the UI is closed |\n| `clipboard.read` / `clipboard.write` | Paste / copy |\n| `agent.prompt.inject` | Skill that tells the AI this PTY is for humans; host Bash stays the command path |\n\nNo `fs.*` permission. The plugin process reads the current workspace path and passes it to the helper as the session cwd.\n\n## How it works\n\nA bundled helper binary (`vendor/pi-pty--`) owns the real PTY (forkpty / ConPTY). The plugin process speaks a JSON-line protocol with the helper. The sandboxed view has no Node and no push channel, so output is pulled with `pty.drain` long-polls.\n\nOn Windows the helper is a GUI-subsystem binary and attaches PowerShell (or cmd / Git Bash) to ConPTY with `CREATE_NO_WINDOW`, so the shell runs inside the work-panel xterm instead of popping a separate console.\n\nThe zip packer does not preserve unix `+x`. On first spawn the plugin `chmod`s the helper.\n\n## Settings\n\n- `fontSize` \u2014 10\u201324, default 13\n- `scrollback` \u2014 in-memory reconnect buffer in lines, default 5000\n- `maxSessions` \u2014 live tab cap, default 8\n- `profiles` \u2014 JSON array of `{ id, name, shell, args, cwd, env }`. `cwd` must stay inside the workspace or home directory.\n\n## Development\n\n```bash\n# rebuild helpers (Go 1.22+). Windows binaries use -H windowsgui.\nsh plugins/pi.terminal/helper/build.sh\n\npython3 scripts/pack_plugin.py plugins/pi.terminal\npython3 scripts/rebuild_catalog.py\nnode --test tests/terminal.test.mjs tests/panel-chrome.test.mjs\n```\n\nLoad `plugins/pi.terminal` as a development plugin, then open **Terminal** from the work panel (Mod+J).\n\n## Requirements\n\n- PI-Desktop `>= 0.8.0` (`ui.view` / work-panel plugin views)\n- A helper binary for the current `process.platform` + `process.arch`\n", + "readmeMarkdown": "# Terminal \u00b7 \u7ec8\u7aef\n\nOtty-inspired interactive terminal for PI-Desktop. It docks in the right work panel next to the conversation \u2014 there is no separate window.\n\n\u53d7 Otty \u542f\u53d1\u7684\u4ea4\u4e92\u5f0f\u7ec8\u7aef\uff0c\u53ea\u505c\u9760\u5728\u53f3\u4fa7\u5de5\u4f5c\u9762\u677f\uff08\u65e0\u72ec\u7acb\u7a97\u53e3\uff09\u3002\n\n## What it does\n\n- **Work panel view** \u2014 `Terminal` / `\u7ec8\u7aef` in the plugin views menu (icon `terminal`). Open the work panel with **Mod+J**.\n- **Tabs** \u2014 new / close / switch. Closing the view does **not** kill the shell; reopening replays a bounded in-memory scrollback. Tabs belong to the **currently open project**; switching projects shows that project's terminals only (other shells stay alive in the background until the plugin is disabled).\n- **Cross-platform shells**\n - macOS: `$SHELL` \u2192 `/bin/zsh` as a real login shell (`argv0` `-zsh`)\n - Linux: `$SHELL` \u2192 `/bin/bash` as a real login shell\n - Windows: PowerShell \u2192 `cmd.exe`; Git Bash is offered when installed\n- **Login PATH** \u2014 GUI apps often see a thin PATH. On load the plugin dumps your interactive login environment and injects it into every PTY, then prepends common tool dirs (pnpm, nvm, bun, cargo, Homebrew) if they exist. `node` / `pnpm` / `brew` should resolve the same way they do in Terminal.app.\n- Follows the app language (`en` / `zh-CN`) and color mode, including live light/dark switches while the view stays open (chrome and xterm canvas). Copy/paste: macOS `Cmd+C/V`, Windows/Linux `Ctrl+Shift+C/V`. Find: `Cmd/Ctrl+F`. Font size: `Cmd/Ctrl +` / `-`.\n\nNot in v0.1: pane splits, Recipes, SSH sessions (use **SSH Manager**), or an agent tool that types into the PTY.\n\n## Permissions\n\n| Permission | Why |\n| --- | --- |\n| `ui.view` | Work-panel Terminal view |\n| `background.service` | Keep the plugin process (and live PTYs) resident when the UI is closed |\n| `clipboard.read` / `clipboard.write` | Paste / copy |\n| `agent.prompt.inject` | Skill that tells the AI this PTY is for humans; host Bash stays the command path |\n\nNo `fs.*` permission. The plugin process reads the current workspace path and passes it to the helper as the session cwd.\n\n## How it works\n\nA bundled helper binary (`vendor/pi-pty--`) owns the real PTY (forkpty / ConPTY). The plugin process speaks a JSON-line protocol with the helper. The sandboxed view has no Node and no push channel, so output is pulled with `pty.drain` long-polls.\n\nOn Windows the helper is a GUI-subsystem binary and attaches PowerShell (or cmd / Git Bash) to ConPTY by passing the HPCON through `PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE`, so the shell runs inside the work-panel xterm instead of popping a separate console. Do not add `CREATE_NO_WINDOW` to the `CreateProcess` flags: it detaches the child from the pseudoconsole, which then silently keeps its own hidden console and leaves the xterm blank.\n\nThe zip packer does not preserve unix `+x`. On first spawn the plugin `chmod`s the helper.\n\n## Settings\n\n- `fontSize` \u2014 10\u201324, default 13\n- `scrollback` \u2014 in-memory reconnect buffer in lines, default 5000\n- `maxSessions` \u2014 live tab cap, default 8\n- `profiles` \u2014 JSON array of `{ id, name, shell, args, cwd, env }`. `cwd` must stay inside the workspace or home directory.\n\n## Development\n\n```bash\n# rebuild helpers (Go 1.22+). Windows binaries use -H windowsgui.\nsh plugins/pi.terminal/helper/build.sh\n\npython3 scripts/pack_plugin.py plugins/pi.terminal\npython3 scripts/rebuild_catalog.py\nnode --test tests/terminal.test.mjs tests/panel-chrome.test.mjs\n```\n\nLoad `plugins/pi.terminal` as a development plugin, then open **Terminal** from the work panel (Mod+J).\n\n## Requirements\n\n- PI-Desktop `>= 0.8.0` (`ui.view` / work-panel plugin views)\n- A helper binary for the current `process.platform` + `process.arch`\n", "safetyNotes": "This plugin launches a real login shell as your user through a bundled PTY helper (forkpty on macOS/Linux, ConPTY on Windows). Anything you can run in a system terminal can run here, including destructive commands. It does not persist transcripts, passwords, or shell history beyond an in-memory scrollback that dies with the plugin process. Uninstalling or disabling the plugin kills every session. The AI is not given a tool that writes to the PTY; agent command execution continues to use the host Bash tool.", "versions": [ { - "version": "0.1.6", - "publishedAt": "2026-09-12T17:13:25Z", - "changelog": "Release 0.1.6: on Windows, attach PowerShell to ConPTY inside the work panel instead of opening a separate console window. Release 0.1.5: follow the app color mode only \u2014 never snap to the OS palette, which flashed when the two disagreed. Release 0.1.4: follows the app light/dark mode live in the work-panel view, including the xterm canvas. Release 0.1.3: isolates PTY tabs per open project so switching workspaces cannot mix sessions. Release 0.1.2: docks only in the right work panel; the detached window is removed. Release 0.1.1: login-shell environment so GUI-launched sessions inherit PATH (pnpm, nvm, Homebrew, cargo, bun); denser Otty-like chrome with bottom tabs, find, and font-size controls. Release 0.1.0: first release. Multi-tab PTY sessions, cross-platform default shells (zsh / bash / PowerShell / optional Git Bash), theme and language following, and copy/paste.", + "version": "0.1.7", + "publishedAt": "2026-09-16T04:56:31Z", + "changelog": "Release 0.1.7: stop passing CREATE_NO_WINDOW to the Windows helper CreateProcess call. That flag detached the child from the pseudoconsole, so the shell silently kept its own hidden console and the work-panel xterm stayed blank with no prompt or echo (issue #13). Release 0.1.6: on Windows, attach PowerShell to ConPTY inside the work panel instead of opening a separate console window. Release 0.1.5: follow the app color mode only \u2014 never snap to the OS palette, which flashed when the two disagreed. Release 0.1.4: follows the app light/dark mode live in the work-panel view, including the xterm canvas. Release 0.1.3: isolates PTY tabs per open project so switching workspaces cannot mix sessions. Release 0.1.2: docks only in the right work panel; the detached window is removed. Release 0.1.1: login-shell environment so GUI-launched sessions inherit PATH (pnpm, nvm, Homebrew, cargo, bun); denser Otty-like chrome with bottom tabs, find, and font-size controls. Release 0.1.0: first release. Multi-tab PTY sessions, cross-platform default shells (zsh / bash / PowerShell / optional Git Bash), theme and language following, and copy/paste.", "minPiDesktop": ">=0.8.0", - "shasum": "e915e96f6895a3f3881314e29099ae3c59236e8e93e6f805f4ba6d3f14919c22", - "url": "packages/pi.terminal-0.1.6.piplug", - "sizeBytes": 13952827, + "shasum": "433db0e69e3ae4b6889165131fdd622369d050af7eb32fde05456fd004d0d6f1", + "url": "packages/pi.terminal-0.1.7.piplug", + "sizeBytes": 13787119, "permissions": [ "ui.view", "background.service", diff --git a/packages/pi.terminal-0.1.7.piplug b/packages/pi.terminal-0.1.7.piplug new file mode 100644 index 0000000..4b2ddd9 Binary files /dev/null and b/packages/pi.terminal-0.1.7.piplug differ diff --git a/plugins/pi.terminal/README.md b/plugins/pi.terminal/README.md index cf6ca35..118eff2 100644 --- a/plugins/pi.terminal/README.md +++ b/plugins/pi.terminal/README.md @@ -32,7 +32,7 @@ No `fs.*` permission. The plugin process reads the current workspace path and pa A bundled helper binary (`vendor/pi-pty--`) owns the real PTY (forkpty / ConPTY). The plugin process speaks a JSON-line protocol with the helper. The sandboxed view has no Node and no push channel, so output is pulled with `pty.drain` long-polls. -On Windows the helper is a GUI-subsystem binary and attaches PowerShell (or cmd / Git Bash) to ConPTY with `CREATE_NO_WINDOW`, so the shell runs inside the work-panel xterm instead of popping a separate console. +On Windows the helper is a GUI-subsystem binary and attaches PowerShell (or cmd / Git Bash) to ConPTY by passing the HPCON through `PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE`, so the shell runs inside the work-panel xterm instead of popping a separate console. Do not add `CREATE_NO_WINDOW` to the `CreateProcess` flags: it detaches the child from the pseudoconsole, which then silently keeps its own hidden console and leaves the xterm blank. The zip packer does not preserve unix `+x`. On first spawn the plugin `chmod`s the helper. diff --git a/plugins/pi.terminal/helper/pty_windows.go b/plugins/pi.terminal/helper/pty_windows.go index 792bbb7..c526fff 100644 --- a/plugins/pi.terminal/helper/pty_windows.go +++ b/plugins/pi.terminal/helper/pty_windows.go @@ -152,7 +152,10 @@ func startPty(req request) (*ptySession, error) { nil, nil, false, - windows.CREATE_UNICODE_ENVIRONMENT|windows.EXTENDED_STARTUPINFO_PRESENT|windows.CREATE_NO_WINDOW, + // CREATE_NO_WINDOW would detach the child from the pseudoconsole: Windows + // then gives it its own hidden console (120x9001 by default) and the ConPTY + // pipes stay silent, so the work-panel xterm never sees a prompt. + windows.CREATE_UNICODE_ENVIRONMENT | windows.EXTENDED_STARTUPINFO_PRESENT, &envUTF16[0], cwdPtr, &si.StartupInfo, diff --git a/plugins/pi.terminal/manifest.json b/plugins/pi.terminal/manifest.json index 789c743..0782e4a 100644 --- a/plugins/pi.terminal/manifest.json +++ b/plugins/pi.terminal/manifest.json @@ -2,7 +2,7 @@ "schemaVersion": 1, "id": "pi.terminal", "name": "Terminal", - "version": "0.1.6", + "version": "0.1.7", "description": "Otty-inspired interactive terminal for PI-Desktop. Docks in the right work panel (no separate window), with tabs, cross-platform shell profiles, and copy/paste.", "i18n": { "en": { @@ -18,7 +18,7 @@ }, "author": "PI-Desktop", "categories": ["developer-tools", "official"], - "changelog": "Release 0.1.6: on Windows, attach PowerShell to ConPTY inside the work panel instead of opening a separate console window. Release 0.1.5: follow the app color mode only — never snap to the OS palette, which flashed when the two disagreed. Release 0.1.4: follows the app light/dark mode live in the work-panel view, including the xterm canvas. Release 0.1.3: isolates PTY tabs per open project so switching workspaces cannot mix sessions. Release 0.1.2: docks only in the right work panel; the detached window is removed. Release 0.1.1: login-shell environment so GUI-launched sessions inherit PATH (pnpm, nvm, Homebrew, cargo, bun); denser Otty-like chrome with bottom tabs, find, and font-size controls. Release 0.1.0: first release. Multi-tab PTY sessions, cross-platform default shells (zsh / bash / PowerShell / optional Git Bash), theme and language following, and copy/paste.", + "changelog": "Release 0.1.7: stop passing CREATE_NO_WINDOW to the Windows helper CreateProcess call. That flag detached the child from the pseudoconsole, so the shell silently kept its own hidden console and the work-panel xterm stayed blank with no prompt or echo (issue #13). Release 0.1.6: on Windows, attach PowerShell to ConPTY inside the work panel instead of opening a separate console window. Release 0.1.5: follow the app color mode only — never snap to the OS palette, which flashed when the two disagreed. Release 0.1.4: follows the app light/dark mode live in the work-panel view, including the xterm canvas. Release 0.1.3: isolates PTY tabs per open project so switching workspaces cannot mix sessions. Release 0.1.2: docks only in the right work panel; the detached window is removed. Release 0.1.1: login-shell environment so GUI-launched sessions inherit PATH (pnpm, nvm, Homebrew, cargo, bun); denser Otty-like chrome with bottom tabs, find, and font-size controls. Release 0.1.0: first release. Multi-tab PTY sessions, cross-platform default shells (zsh / bash / PowerShell / optional Git Bash), theme and language following, and copy/paste.", "safetyNotes": "This plugin launches a real login shell as your user through a bundled PTY helper (forkpty on macOS/Linux, ConPTY on Windows). Anything you can run in a system terminal can run here, including destructive commands. It does not persist transcripts, passwords, or shell history beyond an in-memory scrollback that dies with the plugin process. Uninstalling or disabling the plugin kills every session. The AI is not given a tool that writes to the PTY; agent command execution continues to use the host Bash tool.", "main": "main.js", "contributes": { diff --git a/plugins/pi.terminal/vendor/pi-pty-win32-arm64.exe b/plugins/pi.terminal/vendor/pi-pty-win32-arm64.exe index 6d4f8bb..1aec9c6 100755 Binary files a/plugins/pi.terminal/vendor/pi-pty-win32-arm64.exe and b/plugins/pi.terminal/vendor/pi-pty-win32-arm64.exe differ diff --git a/plugins/pi.terminal/vendor/pi-pty-win32-x64.exe b/plugins/pi.terminal/vendor/pi-pty-win32-x64.exe index 1a6e923..62830b7 100755 Binary files a/plugins/pi.terminal/vendor/pi-pty-win32-x64.exe and b/plugins/pi.terminal/vendor/pi-pty-win32-x64.exe differ diff --git a/tests/terminal.test.mjs b/tests/terminal.test.mjs index f007073..ed047b2 100644 --- a/tests/terminal.test.mjs +++ b/tests/terminal.test.mjs @@ -76,7 +76,7 @@ function waitFor(fn, timeoutMs = 1500) { test("manifest declares terminal identity, views, permissions and no agent tools", () => { assert.equal(manifest.schemaVersion, 1); assert.equal(manifest.id, "pi.terminal"); - assert.equal(manifest.version, "0.1.6"); + assert.equal(manifest.version, "0.1.7"); assert.equal(manifest.ui, undefined); assert.deepEqual(manifest.permissions, [ "ui.view", @@ -160,7 +160,16 @@ test("Windows ConPTY helper attaches the shell instead of opening a console wind const ptyJs = readFileSync(join(pluginRoot, "pty.js"), "utf8"); assert.match(winPty, /windows\.CreatePseudoConsole/); assert.match(winPty, /PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE/); - assert.match(winPty, /CREATE_NO_WINDOW/); + // Comments may name the flag to explain why it must stay out; only code matters. + const winPtyCode = winPty + .split("\n") + .filter((line) => !line.trim().startsWith("//")) + .join("\n"); + assert.doesNotMatch( + winPtyCode, + /CREATE_NO_WINDOW/, + "CREATE_NO_WINDOW detaches the child from the pseudoconsole and leaves the work-panel xterm blank", + ); assert.match(winPty, /STARTF_USESTDHANDLES/); assert.match(winPty, /STARTF_USESHOWWINDOW/); assert.match(winPty, /SW_HIDE/);