pi-web-ui 0.2.13 → 0.2.15

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 CHANGED
@@ -140,8 +140,10 @@ pi-web-ui server uninstall # remove the service entirely
140
140
  `/etc/systemd/system/pi-web-ui.service` and runs `systemctl enable --now`,
141
141
  logs via `journalctl -u pi-web-ui -f`.
142
142
  - **Windows** → Task Scheduler (no admin): creates a user task that starts at
143
- logon (same as a launchd agent). It runs a `.cmd` wrapper generated at
144
- `%APPDATA%\pi-web-ui\pi-web-ui.cmd` (sets env, cd's to the workspace,
143
+ logon (same as a launchd agent). It runs a PowerShell launcher generated at
144
+ `%APPDATA%\pi-web-ui\pi-web-ui.ps1` via `powershell.exe -WindowStyle
145
+ Hidden` — no black console window stays open, so there's nothing to
146
+ accidentally close/kill. The launcher sets env, cd's to the workspace,
145
147
  launches node, appends logs to `%USERPROFILE%\pi-web-ui.log`). The task XML
146
148
  is saved next to it; restarts on failure.
147
149
  - Options: `--port` (default 8787 or `$PORT`), `--cwd` (default `$PI_WEB_CWD`
@@ -336,12 +338,14 @@ pi-web-ui server stop :: stop the running instance (auto-start stays)
336
338
  pi-web-ui server uninstall :: remove the task entirely
337
339
  ```
338
340
 
339
- What it does: writes `%APPDATA%\pi-web-ui\pi-web-ui.cmd` (a `.cmd` wrapper
341
+ What it does: writes `%APPDATA%\pi-web-ui\pi-web-ui.ps1` (a PowerShell launcher
340
342
  that sets `PORT`/`PI_WEB_CWD`, cd's to the workspace, launches node and
341
343
  appends output to `%USERPROFILE%\pi-web-ui.log`) plus the Task Scheduler XML,
342
344
  then registers a **logon** task (`schtasks /Create /XML` — the task runs when
343
- you log in, same as a launchd agent; no admin needed). Preview both generated
344
- files without installing: `pi-web-ui server install --print`.
345
+ you log in, same as a launchd agent; no admin needed). The task invokes
346
+ `powershell.exe -WindowStyle Hidden`, so the server runs with **no black
347
+ console window** — there is nothing to accidentally close or kill. Preview
348
+ both generated files without installing: `pi-web-ui server install --print`.
345
349
 
346
350
  Manual alternative with `deploy/pi-web-ui-task.xml`: edit the paths, save the
347
351
  file as **UTF-16 LE** (schtasks requires it), then
package/bin/pi-web-ui.mjs CHANGED
@@ -14,7 +14,8 @@
14
14
  * (--name 自定义时 com.<name>.server),无需 sudo
15
15
  * - Linux → systemd 单元 <name>.service(/etc/systemd/system/,自动 sudo)
16
16
  * - Windows → 计划任务(Task Scheduler / schtasks,登录后自启,无需管理员),
17
- * 包装脚本与任务 XML 生成在 %APPDATA%\pi-web-ui\
17
+ * 隐藏窗口启动(无黑窗);PowerShell 启动脚本与任务 XML 生成在
18
+ * %APPDATA%\pi-web-ui\
18
19
  *
19
20
  * 环境变量(前台与系统服务均适用):PORT / PI_WEB_CWD / PI_WEB_DATA_DIR /
20
21
  * PI_CODING_AGENT_DIR。
@@ -62,7 +63,7 @@ server 选项:
62
63
  --print 只打印将生成的配置文件,不实际安装
63
64
 
64
65
  平台: macOS → launchd 用户代理 · Linux → systemd · Windows → 计划任务(schtasks)
65
- (Windows 任务登录后自启、无需管理员;stop 停止,uninstall 移除)
66
+ (Windows 任务登录后自启、无需管理员、隐藏窗口运行;stop 停止,uninstall 移除)
66
67
 
67
68
  环境变量(前台与系统服务均适用):
68
69
  PORT / PI_WEB_CWD / PI_WEB_DATA_DIR / PI_CODING_AGENT_DIR
@@ -214,6 +215,10 @@ function winCmdPath(name) {
214
215
  return join(winServiceDir(), `${name}.cmd`);
215
216
  }
216
217
 
218
+ function winPs1Path(name) {
219
+ return join(winServiceDir(), `${name}.ps1`);
220
+ }
221
+
217
222
  function winTaskXmlPath(name) {
218
223
  return join(winServiceDir(), `${name}.xml`);
219
224
  }
@@ -230,17 +235,30 @@ function winTaskExists(name) {
230
235
  );
231
236
  }
232
237
 
233
- /** Build the .cmd wrapper the scheduled task runs (set env → cd → launch node → log). */
234
- function buildWinCmd(cwd, env, logPath) {
238
+ /** Single-quote a string for embedding in a generated PowerShell script. */
239
+ function psQuote(s) {
240
+ return "'" + s.replace(/'/g, "''") + "'";
241
+ }
242
+
243
+ /**
244
+ * Build the PowerShell launcher the scheduled task runs. Task Scheduler
245
+ * launches it with -WindowStyle Hidden, so the console window is created
246
+ * hidden (SW_HIDE) — no black cmd window stays open while the server runs,
247
+ * and there is nothing to accidentally close/kill. The script sets the env,
248
+ * cd's to the workspace, then runs node in the foreground with output
249
+ * appended to the log, so the task instance IS the powershell process and
250
+ * `schtasks /End` still stops the whole tree.
251
+ */
252
+ function buildWinStartPs1(env, cwd, logPath) {
235
253
  const sets = Object.entries(env)
236
- .map(([k, v]) => `set "${k}=${v}"`)
254
+ .map(([k, v]) => `$env:${k} = ${psQuote(v)}`)
237
255
  .join("\r\n");
238
256
  return [
239
- "@echo off",
240
- "rem Generated by: pi-web-ui server install (rerun to change)",
257
+ "# Generated by: pi-web-ui server install (rerun to change)",
258
+ "# Starts the server with a hidden console window (no black cmd box).",
241
259
  sets,
242
- `cd /d "${cwd}"`,
243
- `"${NODE}" "${SERVER_ENTRY}" >> "${logPath}" 2>&1`,
260
+ `Set-Location ${psQuote(cwd)}`,
261
+ `& ${psQuote(NODE)} ${psQuote(SERVER_ENTRY)} *>> ${psQuote(logPath)}`,
244
262
  "",
245
263
  ].join("\r\n");
246
264
  }
@@ -248,13 +266,16 @@ function buildWinCmd(cwd, env, logPath) {
248
266
  /**
249
267
  * Build the Task Scheduler XML for a user task: LogonTrigger (starts at logon,
250
268
  * like a launchd agent — no admin needed), InteractiveToken, auto-restart on
251
- * failure. The task runs the .cmd wrapper via cmd.exe.
269
+ * failure. The task runs the PowerShell launcher via
270
+ * powershell.exe -WindowStyle Hidden, so no console window ever appears.
252
271
  */
253
- function buildWinTaskXml(cmdPath, cwd) {
254
- const cmdExe = join(
272
+ function buildWinTaskXml(ps1Path, cwd) {
273
+ const powershell = join(
255
274
  process.env.SystemRoot ?? "C:\\Windows",
256
275
  "System32",
257
- "cmd.exe",
276
+ "WindowsPowerShell",
277
+ "v1.0",
278
+ "powershell.exe",
258
279
  );
259
280
  return `<?xml version="1.0" encoding="UTF-16"?>
260
281
  <Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
@@ -297,8 +318,8 @@ function buildWinTaskXml(cmdPath, cwd) {
297
318
  </Settings>
298
319
  <Actions Context="Author">
299
320
  <Exec>
300
- <Command>${esc(cmdExe)}</Command>
301
- <Arguments>/c ""${esc(cmdPath)}""</Arguments>
321
+ <Command>${esc(powershell)}</Command>
322
+ <Arguments>-NoProfile -NonInteractive -ExecutionPolicy Bypass -WindowStyle Hidden -File "${esc(ps1Path)}"</Arguments>
302
323
  <WorkingDirectory>${esc(cwd)}</WorkingDirectory>
303
324
  </Exec>
304
325
  </Actions>
@@ -502,17 +523,20 @@ function uninstallSystemd(opts) {
502
523
  function installWindows(opts) {
503
524
  const { name, port, cwd, dataDir } = serviceOptions(opts);
504
525
  const env = serviceEnv(port, cwd, dataDir);
505
- const cmdPath = winCmdPath(name);
526
+ const ps1Path = winPs1Path(name);
506
527
  const xmlPath = winTaskXmlPath(name);
507
- const cmd = buildWinCmd(cwd, env, winLogPath());
508
- const xml = buildWinTaskXml(cmdPath, cwd);
528
+ const ps1 = buildWinStartPs1(env, cwd, winLogPath());
529
+ const xml = buildWinTaskXml(ps1Path, cwd);
509
530
  if (opts.print) {
510
- console.log(`# ${cmdPath}\n${cmd}`);
531
+ console.log(`# ${ps1Path}\n${ps1}`);
511
532
  console.log(`# ${xmlPath}\n${xml}`);
512
533
  return;
513
534
  }
514
- mkdirSync(dirname(cmdPath), { recursive: true });
515
- writeFileSync(cmdPath, cmd);
535
+ mkdirSync(dirname(ps1Path), { recursive: true });
536
+ // UTF-8 with BOM: Windows PowerShell 5.1 misreads BOM-less UTF-8 as ANSI.
537
+ writeFileSync(ps1Path, "\uFEFF" + ps1, "utf8");
538
+ // Remove the old-style .cmd wrapper from previous installs.
539
+ if (existsSync(winCmdPath(name))) rmSync(winCmdPath(name));
516
540
  // schtasks /Create /XML requires a UTF-16 file (with BOM).
517
541
  writeFileSync(xmlPath, "\uFEFF" + xml, "utf16le");
518
542
  if (winTaskExists(name)) {
@@ -523,7 +547,7 @@ function installWindows(opts) {
523
547
  }
524
548
  run("schtasks", ["/Create", "/TN", name, "/XML", xmlPath, "/F"]);
525
549
  run("schtasks", ["/Run", "/TN", name], { ignoreError: true });
526
- console.log(`✅ 已安装并启动计划任务 ${name}`);
550
+ console.log(`✅ 已安装并启动计划任务 ${name}(隐藏窗口运行,无黑窗)`);
527
551
  console.log(` 端口 : ${port}`);
528
552
  console.log(` 目录 : ${cwd}`);
529
553
  console.log(` 访问 : http://localhost:${port}`);
@@ -539,7 +563,7 @@ function uninstallWindows(opts) {
539
563
  if (winTaskExists(name)) {
540
564
  run("schtasks", ["/Delete", "/TN", name, "/F"], { ignoreError: true });
541
565
  }
542
- for (const f of [winCmdPath(name), winTaskXmlPath(name)]) {
566
+ for (const f of [winCmdPath(name), winPs1Path(name), winTaskXmlPath(name)]) {
543
567
  if (existsSync(f)) rmSync(f);
544
568
  }
545
569
  console.log(`🗑 已卸载 ${name}(计划任务已删除,不再自启)`);
@@ -12,9 +12,11 @@
12
12
  schtasks /Run /TN "pi-web-ui"
13
13
 
14
14
  Notes:
15
- - The task points at the .cmd wrapper the CLI generates at
16
- %APPDATA%\pi-web-ui\pi-web-ui.cmd (it sets PORT/PI_WEB_CWD, cd's to the
17
- workspace, launches node, and appends output to %USERPROFILE%\pi-web-ui.log).
15
+ - The task runs the PowerShell launcher the CLI generates at
16
+ %APPDATA%\pi-web-ui\pi-web-ui.ps1 with -WindowStyle Hidden, so the
17
+ server runs with no black console window (nothing to accidentally
18
+ close/kill). The ps1 sets PORT/PI_WEB_CWD, cd's to the workspace,
19
+ launches node, and appends output to %USERPROFILE%\pi-web-ui.log.
18
20
  Preview both generated files with: pi-web-ui server install --print
19
21
  - Save this file as UTF-16 LE (schtasks requires it; the CLI does this
20
22
  automatically when it writes the task XML).
@@ -61,8 +63,8 @@
61
63
  </Settings>
62
64
  <Actions Context="Author">
63
65
  <Exec>
64
- <Command>C:\Windows\System32\cmd.exe</Command>
65
- <Arguments>/c ""%APPDATA%\pi-web-ui\pi-web-ui.cmd""</Arguments>
66
+ <Command>C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe</Command>
67
+ <Arguments>-NoProfile -NonInteractive -ExecutionPolicy Bypass -WindowStyle Hidden -File "%APPDATA%\pi-web-ui\pi-web-ui.ps1"</Arguments>
66
68
  <WorkingDirectory>%USERPROFILE%</WorkingDirectory>
67
69
  </Exec>
68
70
  </Actions>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-web-ui",
3
- "version": "0.2.13",
3
+ "version": "0.2.15",
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",