pi-web-ui 0.2.10 → 0.2.12
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/bin/pi-web-ui.mjs +6 -0
- package/dist/server/terminals.js +84 -4
- package/package.json +1 -1
package/bin/pi-web-ui.mjs
CHANGED
|
@@ -420,6 +420,12 @@ function serviceEnv(port, cwd, dataDir) {
|
|
|
420
420
|
// Interactive Windows tasks inherit the user's PATH; only systemd/launchd
|
|
421
421
|
// run with a minimal environment that needs an explicit PATH.
|
|
422
422
|
if (!isWin) env.PATH = process.env.PATH ?? "/usr/local/bin:/usr/bin:/bin";
|
|
423
|
+
// Same for the locale: launchd/systemd drop LANG/LC_ALL, and a C-locale
|
|
424
|
+
// shell garbles multibyte input in the terminal (UTF-8 continuation
|
|
425
|
+
// bytes 0x80–0x9F rendered as C1 control chars). Bake the installing
|
|
426
|
+
// shell's locale into the service env so spawned terminals are UTF-8.
|
|
427
|
+
if (!isWin && process.env.LANG) env.LANG = process.env.LANG;
|
|
428
|
+
if (!isWin && process.env.LC_ALL) env.LC_ALL = process.env.LC_ALL;
|
|
423
429
|
if (dataDir) env.PI_WEB_DATA_DIR = dataDir;
|
|
424
430
|
return env;
|
|
425
431
|
}
|
package/dist/server/terminals.js
CHANGED
|
@@ -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,82 @@ 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
|
+
* Environment for spawned shells. System services (launchd/systemd) run with
|
|
118
|
+
* no locale variables, which puts the shell in the C locale: its line editor
|
|
119
|
+
* then renders UTF-8 continuation bytes 0x80–0x9F as C1 control characters
|
|
120
|
+
* (e.g. `�<0091><0098>` for 员), garbling Chinese input in the terminal.
|
|
121
|
+
* Default a UTF-8 locale so multibyte text round-trips.
|
|
122
|
+
*/
|
|
123
|
+
function shellEnv() {
|
|
124
|
+
const env = { ...process.env, TERM: "xterm-256color" };
|
|
125
|
+
if (!env.LANG && !env.LC_ALL)
|
|
126
|
+
env.LANG = "en_US.UTF-8";
|
|
127
|
+
return env;
|
|
128
|
+
}
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// spawn-helper permission repair (node-pty macOS prebuilds)
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
// node-pty 1.1.0 publishes its macOS prebuilds with `spawn-helper` lacking the
|
|
133
|
+
// execute bit (mode 0644 in the npm tarball), so posix_spawn fails with EACCES
|
|
134
|
+
// and node-pty throws the generic "posix_spawnp failed". Locally-built
|
|
135
|
+
// copies (build/Release) are fine; every `npm install` that picks the prebuild
|
|
136
|
+
// — e.g. `npm i -g pi-web-ui`, which is what system-service installs run — is
|
|
137
|
+
// broken until the bit is restored. Self-heal at startup, best-effort.
|
|
138
|
+
const require = createRequire(import.meta.url);
|
|
139
|
+
/** Absolute paths of every node-pty spawn-helper this install can exec. */
|
|
140
|
+
function spawnHelperPaths() {
|
|
141
|
+
try {
|
|
142
|
+
// require.resolve("node-pty") → <pkg>/lib/index.js → package root is two up.
|
|
143
|
+
const pkgDir = dirname(dirname(require.resolve("node-pty")));
|
|
144
|
+
const out = [];
|
|
145
|
+
const built = join(pkgDir, "build", "Release", "spawn-helper");
|
|
146
|
+
if (existsSync(built))
|
|
147
|
+
out.push(built);
|
|
148
|
+
const prebuildsDir = join(pkgDir, "prebuilds");
|
|
149
|
+
if (existsSync(prebuildsDir)) {
|
|
150
|
+
for (const entry of readdirSync(prebuildsDir)) {
|
|
151
|
+
const p = join(prebuildsDir, entry, "spawn-helper");
|
|
152
|
+
if (existsSync(p))
|
|
153
|
+
out.push(p);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return out;
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return [];
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/** Restore the +x bit on node-pty's spawn-helper binaries (idempotent). */
|
|
163
|
+
function repairSpawnHelperPermissions() {
|
|
164
|
+
if (isWindows)
|
|
165
|
+
return;
|
|
166
|
+
for (const p of spawnHelperPaths()) {
|
|
167
|
+
try {
|
|
168
|
+
if ((statSync(p).mode & 0o111) === 0)
|
|
169
|
+
chmodSync(p, 0o755);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// best-effort; a read-only node_modules just keeps the old failure
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
repairSpawnHelperPermissions();
|
|
177
|
+
/** Path of a still-broken helper, for the error hint ("" when none). */
|
|
178
|
+
function brokenSpawnHelper() {
|
|
179
|
+
if (isWindows)
|
|
180
|
+
return "";
|
|
181
|
+
for (const p of spawnHelperPaths()) {
|
|
182
|
+
try {
|
|
183
|
+
if ((statSync(p).mode & 0o111) === 0)
|
|
184
|
+
return p;
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
// ignore
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return "";
|
|
191
|
+
}
|
|
115
192
|
/**
|
|
116
193
|
* Owns one or more PTYs for a client. All output is forwarded as
|
|
117
194
|
* `terminal_output` messages through the provided emit (broadcast to every
|
|
@@ -188,11 +265,14 @@ export class TerminalManager {
|
|
|
188
265
|
cols: Math.max(2, Math.floor(cols) || 80),
|
|
189
266
|
rows: Math.max(2, Math.floor(rows) || 24),
|
|
190
267
|
cwd: abs,
|
|
191
|
-
env:
|
|
268
|
+
env: shellEnv(),
|
|
192
269
|
});
|
|
193
270
|
}
|
|
194
271
|
catch (err) {
|
|
195
|
-
|
|
272
|
+
const helper = brokenSpawnHelper();
|
|
273
|
+
this.fail(id, helper
|
|
274
|
+
? `启动终端失败:${err.message}(node-pty 的 spawn-helper 缺少执行权限,请运行:chmod +x "${helper}")`
|
|
275
|
+
: `启动终端失败:${err.message}`);
|
|
196
276
|
return false;
|
|
197
277
|
}
|
|
198
278
|
const entry = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-web-ui",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.12",
|
|
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",
|