pi-web-ui 0.2.9 → 0.2.11

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.
@@ -13,10 +13,11 @@
13
13
  * `${pwd}` inside cwd/command resolves to the agent session's current working
14
14
  * directory (the same directory the agent operates in — see set_cwd).
15
15
  */
16
- import { existsSync } from "node:fs";
16
+ import { chmodSync, existsSync, readdirSync, statSync } from "node:fs";
17
17
  import { mkdir, readFile, writeFile } from "node:fs/promises";
18
+ import { createRequire } from "node:module";
18
19
  import { homedir } from "node:os";
19
- import { isAbsolute, join, resolve } from "node:path";
20
+ import { dirname, isAbsolute, join, resolve } from "node:path";
20
21
  import { spawn } from "node-pty";
21
22
  /** Location of the command list for a project: <workspaceRoot>/.pi/commands.json */
22
23
  export function commandsFilePath(workspaceRoot) {
@@ -112,6 +113,69 @@ const SHELL = isWindows
112
113
  : process.env.SHELL || "bash";
113
114
  /** `-i` is POSIX-only; cmd.exe / powershell.exe start interactively on their own. */
114
115
  const SHELL_ARGS = isWindows ? [] : ["-i"];
116
+ // ---------------------------------------------------------------------------
117
+ // spawn-helper permission repair (node-pty macOS prebuilds)
118
+ // ---------------------------------------------------------------------------
119
+ // node-pty 1.1.0 publishes its macOS prebuilds with `spawn-helper` lacking the
120
+ // execute bit (mode 0644 in the npm tarball), so posix_spawn fails with EACCES
121
+ // and node-pty throws the generic "posix_spawnp failed". Locally-built
122
+ // copies (build/Release) are fine; every `npm install` that picks the prebuild
123
+ // — e.g. `npm i -g pi-web-ui`, which is what system-service installs run — is
124
+ // broken until the bit is restored. Self-heal at startup, best-effort.
125
+ const require = createRequire(import.meta.url);
126
+ /** Absolute paths of every node-pty spawn-helper this install can exec. */
127
+ function spawnHelperPaths() {
128
+ try {
129
+ // require.resolve("node-pty") → <pkg>/lib/index.js → package root is two up.
130
+ const pkgDir = dirname(dirname(require.resolve("node-pty")));
131
+ const out = [];
132
+ const built = join(pkgDir, "build", "Release", "spawn-helper");
133
+ if (existsSync(built))
134
+ out.push(built);
135
+ const prebuildsDir = join(pkgDir, "prebuilds");
136
+ if (existsSync(prebuildsDir)) {
137
+ for (const entry of readdirSync(prebuildsDir)) {
138
+ const p = join(prebuildsDir, entry, "spawn-helper");
139
+ if (existsSync(p))
140
+ out.push(p);
141
+ }
142
+ }
143
+ return out;
144
+ }
145
+ catch {
146
+ return [];
147
+ }
148
+ }
149
+ /** Restore the +x bit on node-pty's spawn-helper binaries (idempotent). */
150
+ function repairSpawnHelperPermissions() {
151
+ if (isWindows)
152
+ return;
153
+ for (const p of spawnHelperPaths()) {
154
+ try {
155
+ if ((statSync(p).mode & 0o111) === 0)
156
+ chmodSync(p, 0o755);
157
+ }
158
+ catch {
159
+ // best-effort; a read-only node_modules just keeps the old failure
160
+ }
161
+ }
162
+ }
163
+ repairSpawnHelperPermissions();
164
+ /** Path of a still-broken helper, for the error hint ("" when none). */
165
+ function brokenSpawnHelper() {
166
+ if (isWindows)
167
+ return "";
168
+ for (const p of spawnHelperPaths()) {
169
+ try {
170
+ if ((statSync(p).mode & 0o111) === 0)
171
+ return p;
172
+ }
173
+ catch {
174
+ // ignore
175
+ }
176
+ }
177
+ return "";
178
+ }
115
179
  /**
116
180
  * Owns one or more PTYs for a client. All output is forwarded as
117
181
  * `terminal_output` messages through the provided emit (broadcast to every
@@ -192,7 +256,10 @@ export class TerminalManager {
192
256
  });
193
257
  }
194
258
  catch (err) {
195
- this.fail(id, `启动终端失败:${err.message}`);
259
+ const helper = brokenSpawnHelper();
260
+ this.fail(id, helper
261
+ ? `启动终端失败:${err.message}(node-pty 的 spawn-helper 缺少执行权限,请运行:chmod +x "${helper}")`
262
+ : `启动终端失败:${err.message}`);
196
263
  return false;
197
264
  }
198
265
  const entry = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-web-ui",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "description": "Web chat interface for the pi coding agent, powered by the pi SDK (@earendil-works/pi-coding-agent) — one-command run, Docker/systemd/launchd deployable",
5
5
  "license": "MIT",
6
6
  "type": "module",