@firstpick/pi-package-webui 0.4.8 → 0.5.0

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  Local browser UI for [Pi coding agent](https://www.npmjs.com/package/@earendil-works/pi-coding-agent).
4
4
 
5
- ![Pi Web UI main window showing multi-tab chat, controls, theme picker, and local status](https://unpkg.com/@firstpick/pi-package-webui/images/WebUI_v0.3.7.png)
5
+ ![Pi Web UI workspace dashboard showing the active project, model, session state, and quick actions](https://unpkg.com/@firstpick/pi-package-webui/images/Webui_Workspace_v0.4.8.png)
6
6
 
7
7
  Pi Web UI gives you a local browser companion for Pi: multi-tab chat, streaming output, model controls, uploads, slash-command helpers, workspace navigation, and optional extension widgets.
8
8
 
@@ -138,12 +138,128 @@ Environment variables:
138
138
  - Persistent context-window meter with manual compact and auto-compaction controls near the composer.
139
139
  - Side-panel theme picker backed by optional `@firstpick/pi-themes-bundle` themes when loaded.
140
140
  - Per-tab cwd changes, a clickable footer cwd picker, saved path fast picks, server-persisted fast picks, and restart-safe restoration of open tabs.
141
- - Detected app runner dropdown for the active tab cwd, including Cargo, Bun, npm/npx/pnpm, Python/uv, Go/Golang, Zig, C/C++, Docker Compose, root/dev/scripts shell scripts, and other common project runners with live output pinned at the top of the terminal. Projects can add browseable custom runners in `.pi-webui-runners.json` with a command (default `./`) plus a relative path to the file to run.
141
+ - Detected app runner dropdown for the active tab cwd, including Cargo, Bun, npm/npx/pnpm, Python/uv, Go/Golang, Zig, C/C++, Docker Compose, root/dev/scripts shell scripts, and other common project runners with live output pinned at the top of the terminal. Running app runners expose line-oriented stdin in the widget for interactive scripts. Projects can add browseable custom runners in `.pi-webui-runners.json` with a command (default `./`) plus a relative path to the file to run.
142
142
  - Browser support for Pi extension UI prompts, widgets, status updates, `/btw` side-question output widgets with optional context transfer/live steering, browser notifications when a tab needs an extension UI response, and an optional side-panel toggle for agent-done notifications.
143
143
  - Localhost-only Pi/Web UI update checks with a top-right update notification and confirmed restart actions: **Update Pi & restart** runs `pi update` for Pi-only updates, while **Update Pi + Packages & Restart** runs `pi update --all` for Pi plus configured packages.
144
144
  - Feedback reactions (`👍`, `👎`, `?`) on final assistant output plus tool/bash action cards, which can ask Pi to create or update a LEARNING.
145
145
  - Mobile-friendly layout and PWA install support where the browser allows it.
146
146
 
147
+ ## v0.4.8 feature gallery
148
+
149
+ These screenshots show the v0.4.8 Web UI surfaces. Unless noted otherwise, actions apply to the active tab and its current working directory.
150
+
151
+ ### Workspace dashboard
152
+
153
+ ![Pi Web UI workspace dashboard showing the active project, model, session cards, and quick actions](https://unpkg.com/@firstpick/pi-package-webui/images/Webui_Workspace_v0.4.8.png)
154
+
155
+ - **What it is:** The project home base for an active Web UI tab, combining cwd, model, context, git, queue, session, and activity status.
156
+ - **What you can do:** Start or resume work, verify the tab is pointed at the right project, jump into common session/workspace actions, and spot queued or active work before prompting.
157
+
158
+ ### Control panel
159
+
160
+ ![Pi Web UI side control panel with model, session, workspace, theme, update, optional feature, and usage controls](https://unpkg.com/@firstpick/pi-package-webui/images/Webui_ControlPanel_v0.4.8.png)
161
+
162
+ - **What it is:** The side rail for Web UI state and settings, including model, thinking effort, session/workspace controls, theme, optional companions, Remote WebUI, updates, notifications, and usage widgets.
163
+ - **What you can do:** Change model or effort, compact/manage sessions, toggle notifications, check or install optional packages, run confirmed updates/restarts, and manage remote/PIN controls when the remote companion is loaded.
164
+
165
+ ### Working-directory picker
166
+
167
+ ![Pi Web UI working-directory picker with recent paths, saved directories, and create-directory action](https://unpkg.com/@firstpick/pi-package-webui/images/Webui_CWDpicker_v0.4.8.png)
168
+
169
+ - **What it is:** A browser-native cwd chooser used at first launch and for per-tab working-directory changes.
170
+ - **What you can do:** Search and browse project paths, choose recent or saved directories, create a new directory, and start or move a Pi tab into the selected workspace.
171
+
172
+ ### App runners
173
+
174
+ ![Pi Web UI app runner selector showing detected project runners and custom runner creation](https://unpkg.com/@firstpick/pi-package-webui/images/Webui_AppRunner_v0.4.8.png)
175
+
176
+ - **What it is:** A project runner detector for common stacks plus browseable custom runners from `.pi-webui-runners.json`.
177
+ - **What you can do:** Launch dev servers, tests, builds, scripts, and custom commands from the active cwd, pass arguments, watch pinned live output, and send line-oriented stdin to interactive runners.
178
+
179
+ ### Queue manager
180
+
181
+ ![Pi Web UI queue panel with prompt-list controls and queued-message status](https://unpkg.com/@firstpick/pi-package-webui/images/Webui_Queues_v0.4.8.png)
182
+
183
+ - **What it is:** The queue surface for follow-up prompts, steering messages, user bash work, and loaded prompt lists while a tab is busy or ready.
184
+ - **What you can do:** Create or load prompt lists, run batches when supported, see pending queued messages, and decide whether prompts sent during an active run should steer the current agent or wait as follow-ups.
185
+
186
+ ### Thinking effort picker
187
+
188
+ ![Pi Web UI thinking effort picker showing off, minimal, low, medium, high, and xhigh choices](https://unpkg.com/@firstpick/pi-package-webui/images/Webui_Effort_v0.4.8.png)
189
+
190
+ - **What it is:** A browser picker for Pi's model thinking/reasoning effort setting.
191
+ - **What you can do:** Switch between `off`, `minimal`, `low`, `medium`, `high`, and `xhigh`, confirm the effective effort in the footer, and tune speed/cost/quality before sending a prompt.
192
+
193
+ ### Scoped models
194
+
195
+ ![Pi Web UI scoped models picker listing provider models and the current effective model](https://unpkg.com/@firstpick/pi-package-webui/images/Webui_ScopedModels_v0.4.8.png)
196
+
197
+ - **What it is:** A Web UI editor for `/scoped-models`, project/global model scope rules, and model cycling order.
198
+ - **What you can do:** Search available models, enable or disable scoped entries, inspect the effective model source, and save model choices so future prompts and tabs use the intended provider/model.
199
+
200
+ ### Tools setup
201
+
202
+ ![Pi Web UI tools setup dialog listing available tools with enable and disable controls](https://unpkg.com/@firstpick/pi-package-webui/images/Webui_ToolsSetup_v0.4.8.png)
203
+
204
+ - **What it is:** A browser-native `/tools` setup dialog for active and available Pi tools.
205
+ - **What you can do:** Search tools, inspect descriptions and availability, enable or disable tool access for the active session, and adjust capability exposure without leaving the browser.
206
+
207
+ ### Skills setup
208
+
209
+ ![Pi Web UI skills setup dialog listing installed skills and activation controls](https://unpkg.com/@firstpick/pi-package-webui/images/Webui_SkillSetup_v0.4.8.png)
210
+
211
+ - **What it is:** A browser-native `/skills` setup dialog for installed Pi skills.
212
+ - **What you can do:** Find skills by name or description, review what each skill is for, enable or disable skills for the active session, and make skill activation more transparent before asking Pi to work.
213
+
214
+ ### Optional features
215
+
216
+ ![Pi Web UI optional features list showing companion packages and install or update states](https://unpkg.com/@firstpick/pi-package-webui/images/Webui_OptionalFeatures_v0.4.8.png)
217
+
218
+ - **What it is:** A companion-package manager for Web UI-aware extensions, prompts, themes, and optional dashboards.
219
+ - **What you can do:** See whether each companion is enabled, disabled, installed-but-not-loaded, missing, or updateable; install/update known packages from localhost; and reload affected tabs when a feature becomes available.
220
+
221
+ ### `/btw` side questions
222
+
223
+ ![Pi Web UI BTW widget showing a side-question input and live side-thread output](https://unpkg.com/@firstpick/pi-package-webui/images/Webui_BTW_v0.4.8.png)
224
+
225
+ - **What it is:** A Web UI widget for the optional `/btw` side-question extension, keeping quick questions separate from the main agent flow.
226
+ - **What you can do:** Ask short side questions without derailing the main chat, inspect live output, steer or stop the side thread, and transfer useful context back into the main prompt when needed.
227
+
228
+ ### Guided Git workflow
229
+
230
+ ![Pi Web UI guided Git workflow showing staged changes, generated commit messages, and PR controls](https://unpkg.com/@firstpick/pi-package-webui/images/Webui_GitWorkflow_v0.4.8.png)
231
+
232
+ - **What it is:** A guided browser workflow for staging changes, generating commit messages, committing, pushing, and optionally creating a pull request.
233
+ - **What you can do:** Run the stage/message/commit/push steps, choose generated short or long commit messages, type a manual message, create or confirm PR branch names, review generated PR text, and push only after confirmation.
234
+
235
+ ### Git branch picker
236
+
237
+ ![Pi Web UI git branch picker showing the current branch and create-branch action](https://unpkg.com/@firstpick/pi-package-webui/images/Webui_GitBranches_v0.4.8.png)
238
+
239
+ - **What it is:** A footer branch picker backed by the active tab's current Git repository.
240
+ - **What you can do:** View the current branch/repo, switch local branches, create and switch to a new branch, and get warnings when a branch change could affect active agent work.
241
+
242
+ ### Git diff viewer
243
+
244
+ ![Pi Web UI Git Changes dialog showing repository status, file list, and side-by-side diff rows](https://unpkg.com/@firstpick/pi-package-webui/images/Webui_GitDiff_v0.4.8.png)
245
+
246
+ - **What it is:** A browser diff dialog for current Git changes in the active workspace.
247
+ - **What you can do:** Review staged, unstaged, untracked, and incoming changes; jump between files; see additions/deletions with line numbers; and inspect text previews before asking Pi to edit, commit, or create a PR.
248
+
249
+ ### Codex usage
250
+
251
+ ![Pi Web UI Codex usage widget showing subscription usage windows and reset timers](https://unpkg.com/@firstpick/pi-package-webui/images/Webui_CodexUsage_v0.4.8.png)
252
+
253
+ - **What it is:** A side-panel usage widget for Codex-family subscription-backed models.
254
+ - **What you can do:** Refresh usage, monitor short-window and weekly limits, see reset timing, and decide whether to switch models or delay large prompts.
255
+
256
+ ### Pi stats dashboard
257
+
258
+ ![Pi Web UI stats dashboard showing token, cost, cache, model, and daily usage analytics](https://unpkg.com/@firstpick/pi-package-webui/images/Webui_Pistats_v0.4.8.png)
259
+
260
+ - **What it is:** The browser overlay from the optional stats companion, summarizing token, cost, cache, prompt/context, model, session, and command usage.
261
+ - **What you can do:** Filter by time range, refresh analytics, review daily/model/session breakdowns, inspect cost and cache behavior, and calibrate prompt estimates for more accurate local usage visibility.
262
+
147
263
  Useful browser endpoints exposed by the local server include:
148
264
 
149
265
  - `GET /api/path-suggestions?tab=<tabId>&query=<path>` for `@` file/path references with live suggestions.
package/bin/pi-webui.mjs CHANGED
@@ -177,6 +177,7 @@ const APP_RUNNER_DETECTION_TIMEOUT_MS = 1_200;
177
177
  const APP_RUNNER_COMMAND_CACHE_TTL_MS = 30_000;
178
178
  const APP_RUNNER_OUTPUT_LINE_LIMIT = 1_000;
179
179
  const APP_RUNNER_OUTPUT_MAX_CHARS = 240_000;
180
+ const APP_RUNNER_INPUT_MAX_CHARS = 16_000;
180
181
  const APP_RUNNER_STOP_GRACE_MS = 2_500;
181
182
  const APP_RUNNER_PYTHON_ENTRIES = ["Main.py", "main.py", "src/main.py", "src/Main.py", "app.py", "src/app.py"];
182
183
  const APP_RUNNER_JS_ENTRIES = ["main.js", "src/main.js", "index.js", "src/index.js", "server.js", "src/server.js", "app.js", "src/app.js"];
@@ -838,10 +839,18 @@ function safeDownloadFileName(name, fallback = "pi-export") {
838
839
  return (text || fallback).slice(0, 180);
839
840
  }
840
841
 
841
- function contentDispositionAttachment(fileName) {
842
+ function contentDispositionHeader(fileName, disposition = "attachment") {
842
843
  const safeName = safeDownloadFileName(fileName);
843
844
  const asciiName = safeName.replace(/[^\x20-\x7e]/g, "_").replace(/["\\]/g, "_");
844
- return `attachment; filename="${asciiName}"; filename*=UTF-8''${encodeURIComponent(safeName)}`;
845
+ return `${disposition}; filename="${asciiName}"; filename*=UTF-8''${encodeURIComponent(safeName)}`;
846
+ }
847
+
848
+ function contentDispositionAttachment(fileName) {
849
+ return contentDispositionHeader(fileName, "attachment");
850
+ }
851
+
852
+ function contentDispositionInline(fileName) {
853
+ return contentDispositionHeader(fileName, "inline");
845
854
  }
846
855
 
847
856
  function registerNativeDownload(filePath, { fileName, contentType, command = "native" } = {}) {
@@ -856,15 +865,17 @@ function registerNativeDownload(filePath, { fileName, contentType, command = "na
856
865
  expiresAt,
857
866
  };
858
867
  nativeDownloadTokens.set(token, record);
868
+ const url = `/api/native-download/${encodeURIComponent(token)}`;
859
869
  return {
860
- url: `/api/native-download/${encodeURIComponent(token)}`,
870
+ url,
871
+ openUrl: record.contentType === MIME_TYPES.get(".html") ? `${url}?disposition=inline` : undefined,
861
872
  fileName: record.fileName,
862
873
  contentType: record.contentType,
863
874
  expiresAt: new Date(expiresAt).toISOString(),
864
875
  };
865
876
  }
866
877
 
867
- async function sendNativeDownload(res, token) {
878
+ async function sendNativeDownload(res, token, { inline = false } = {}) {
868
879
  pruneNativeDownloadTokens();
869
880
  const item = nativeDownloadTokens.get(token);
870
881
  if (!item) throw makeHttpError(404, "Download token expired or not found");
@@ -873,10 +884,11 @@ async function sendNativeDownload(res, token) {
873
884
  nativeDownloadTokens.delete(token);
874
885
  throw makeHttpError(404, "Download file expired or not found");
875
886
  }
887
+ const canRenderInline = inline === true && item.contentType === MIME_TYPES.get(".html");
876
888
  res.writeHead(200, {
877
889
  "content-type": item.contentType,
878
890
  "content-length": String(fileStats.size),
879
- "content-disposition": contentDispositionAttachment(item.fileName),
891
+ "content-disposition": canRenderInline ? contentDispositionInline(item.fileName) : contentDispositionAttachment(item.fileName),
880
892
  "cache-control": "no-store",
881
893
  "x-content-type-options": "nosniff",
882
894
  });
@@ -2274,6 +2286,11 @@ async function detectAppRunners(tab) {
2274
2286
  .map(publicAppRunner);
2275
2287
  }
2276
2288
 
2289
+ function appRunnerPendingLine(run) {
2290
+ if (!run || run.status !== "running") return "";
2291
+ return [run.stdoutRemainder, run.stderrRemainder].map((part) => String(part || "")).filter(Boolean).join("");
2292
+ }
2293
+
2277
2294
  function publicAppRunnerState(run) {
2278
2295
  if (!run) return null;
2279
2296
  return {
@@ -2295,6 +2312,11 @@ function publicAppRunnerState(run) {
2295
2312
  truncated: run.truncated === true,
2296
2313
  lineCount: run.lineCount || run.lines?.length || 0,
2297
2314
  lines: Array.isArray(run.lines) ? [...run.lines] : [],
2315
+ pendingLine: appRunnerPendingLine(run),
2316
+ stdinClosed: run.stdinClosed === true,
2317
+ stdinError: run.stdinError || "",
2318
+ stdinWrites: run.stdinWrites || 0,
2319
+ lastStdinAt: run.lastStdinAt || "",
2298
2320
  };
2299
2321
  }
2300
2322
 
@@ -2398,6 +2420,7 @@ function finishAppRunner(tab, run, patch = {}) {
2398
2420
  run.error = patch.error;
2399
2421
  run.status = patch.error ? "error" : patch.exitCode === 0 ? "done" : "failed";
2400
2422
  run.child = null;
2423
+ run.stdinClosed = true;
2401
2424
  run.stopping = false;
2402
2425
  appendAppRunnerLine(run, `# ${appRunnerStatusLabel(run)} after ${Math.max(0, Math.round((Date.parse(run.endedAt) - Date.parse(run.startedAt)) / 1000))}s`);
2403
2426
  if (patch.error) appendAppRunnerLine(run, `# ${patch.error}`);
@@ -2407,6 +2430,45 @@ function finishAppRunner(tab, run, patch = {}) {
2407
2430
  broadcastAppRunnerState(tab);
2408
2431
  }
2409
2432
 
2433
+ function normalizeAppRunnerInputText(value) {
2434
+ const text = String(value ?? "");
2435
+ if (text.includes("\0")) throw makeHttpError(400, "App runner input cannot contain null bytes");
2436
+ if (text.length > APP_RUNNER_INPUT_MAX_CHARS) throw makeHttpError(413, `App runner input is too long; limit is ${APP_RUNNER_INPUT_MAX_CHARS} characters`);
2437
+ return text;
2438
+ }
2439
+
2440
+ function sendAppRunnerInput(tab, value, { appendNewline = true, closeStdin = false } = {}) {
2441
+ const run = tab?.appRunner;
2442
+ if (!run || run.status !== "running") throw makeHttpError(409, "No app runner is running in this tab");
2443
+ const stdin = run.child?.stdin;
2444
+ if (!stdin || stdin.destroyed || stdin.writableEnded || run.stdinClosed === true) throw makeHttpError(409, "App runner stdin is closed");
2445
+ const text = normalizeAppRunnerInputText(value);
2446
+ const chunk = `${text}${appendNewline === false ? "" : "\n"}`;
2447
+ if (!chunk && !closeStdin) throw makeHttpError(400, "App runner input is empty");
2448
+ let buffered = false;
2449
+ try {
2450
+ if (closeStdin) {
2451
+ if (chunk) stdin.end(chunk, "utf8");
2452
+ else stdin.end();
2453
+ run.stdinClosed = true;
2454
+ } else {
2455
+ buffered = stdin.write(chunk, "utf8") === false;
2456
+ }
2457
+ } catch (error) {
2458
+ run.stdinClosed = true;
2459
+ run.stdinError = sanitizeError(error);
2460
+ throw makeHttpError(409, `App runner stdin write failed: ${run.stdinError}`);
2461
+ }
2462
+ run.stdinWrites = (run.stdinWrites || 0) + 1;
2463
+ run.lastStdinAt = new Date().toISOString();
2464
+ const closeSuffix = closeStdin ? " and closed" : "";
2465
+ if (chunk) appendAppRunnerLine(run, text ? `# stdin sent (${text.length} char${text.length === 1 ? "" : "s"})${closeSuffix}` : `# stdin sent (Enter)${closeSuffix}`);
2466
+ else appendAppRunnerLine(run, "# stdin closed (EOF)");
2467
+ recordEvent({ type: "webui_app_runner_stdin", tabId: tab.id, tabTitle: tab.title, command: run.displayCommand, chars: text.length, newline: appendNewline !== false, closed: closeStdin === true });
2468
+ scheduleAppRunnerBroadcast(tab);
2469
+ return { cwd: tab.cwd, activeRun: publicAppRunnerState(run), inputBuffered: buffered };
2470
+ }
2471
+
2410
2472
  async function startAppRunner(tab, runnerId) {
2411
2473
  if (tab.appRunner?.status === "running") throw makeHttpError(409, `App runner already running: ${tab.appRunner.displayCommand}`);
2412
2474
  const runners = await detectAppRunners(tab);
@@ -2427,12 +2489,14 @@ async function startAppRunner(tab, runnerId) {
2427
2489
  lines: [],
2428
2490
  lineCount: 0,
2429
2491
  outputChars: 0,
2492
+ stdinClosed: false,
2493
+ stdinWrites: 0,
2430
2494
  };
2431
2495
  appendAppRunnerLine(run, `$ ${run.displayCommand}`);
2432
2496
  const child = spawn(run.command, run.args, {
2433
2497
  cwd: run.cwd,
2434
2498
  env: process.env,
2435
- stdio: ["ignore", "pipe", "pipe"],
2499
+ stdio: ["pipe", "pipe", "pipe"],
2436
2500
  windowsHide: true,
2437
2501
  detached: process.platform !== "win32",
2438
2502
  });
@@ -2440,6 +2504,18 @@ async function startAppRunner(tab, runnerId) {
2440
2504
  run.pid = child.pid;
2441
2505
  tab.appRunner = run;
2442
2506
 
2507
+ child.stdin?.on("error", (error) => {
2508
+ run.stdinClosed = true;
2509
+ run.stdinError = sanitizeError(error);
2510
+ if (run.status === "running") {
2511
+ appendAppRunnerLine(run, `# stdin error: ${run.stdinError}`);
2512
+ scheduleAppRunnerBroadcast(tab);
2513
+ }
2514
+ });
2515
+ child.stdin?.on("close", () => {
2516
+ run.stdinClosed = true;
2517
+ if (run.status === "running") scheduleAppRunnerBroadcast(tab);
2518
+ });
2443
2519
  child.stdout.on("data", (chunk) => appendAppRunnerChunk(tab, run, chunk, "stdout"));
2444
2520
  child.stderr.on("data", (chunk) => appendAppRunnerChunk(tab, run, chunk, "stderr"));
2445
2521
  child.on("error", (error) => finishAppRunner(tab, run, { error: sanitizeError(error) }));
@@ -6544,7 +6620,7 @@ async function handleNativeExportCommand(tab, args, req) {
6544
6620
  return respondNative("export", {
6545
6621
  status: "succeeded",
6546
6622
  level: "info",
6547
- message: `Exported current session to HTML.\nDownload: ${download.fileName}\nLink expires: ${download.expiresAt}`,
6623
+ message: `Exported current session to HTML.\nDownload: ${download.fileName}\nOpen it in your browser when prompted.\nOpen URL: ${download.openUrl || download.url}\nDownload URL: ${download.url}\nLink expires: ${download.expiresAt}`,
6548
6624
  download,
6549
6625
  result: response.data,
6550
6626
  refresh: ["state"],
@@ -7304,7 +7380,9 @@ const server = createServer(async (req, res) => {
7304
7380
  }
7305
7381
 
7306
7382
  if (url.pathname.startsWith("/api/native-download/") && req.method === "GET") {
7307
- await sendNativeDownload(res, decodeURIComponent(url.pathname.slice("/api/native-download/".length)));
7383
+ await sendNativeDownload(res, decodeURIComponent(url.pathname.slice("/api/native-download/".length)), {
7384
+ inline: url.searchParams.get("disposition") === "inline",
7385
+ });
7308
7386
  return;
7309
7387
  }
7310
7388
 
@@ -7399,6 +7477,14 @@ const server = createServer(async (req, res) => {
7399
7477
  return;
7400
7478
  }
7401
7479
 
7480
+ if (url.pathname === "/api/app-runner/input" && req.method === "POST") {
7481
+ const body = await readJsonBody(req);
7482
+ const tab = getRequestedTab(req, url, body);
7483
+ const text = Object.prototype.hasOwnProperty.call(body, "text") ? body.text : body.input;
7484
+ sendJson(res, 200, { ok: true, data: sendAppRunnerInput(tab, text, { appendNewline: body.newline !== false, closeStdin: body.closeStdin === true || body.close === true }) });
7485
+ return;
7486
+ }
7487
+
7402
7488
  if (url.pathname === "/api/app-runner/stop" && req.method === "POST") {
7403
7489
  const body = await readJsonBody(req);
7404
7490
  const tab = getRequestedTab(req, url, body);
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firstpick/pi-package-webui",
3
- "version": "0.4.8",
3
+ "version": "0.5.0",
4
4
  "description": "Pi Web UI companion package with a local browser UI CLI plus /webui-start and /webui-status commands.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/Firstp1ck/npm-packages/tree/main/pi-package-webui#readme",
@@ -53,7 +53,7 @@
53
53
  "test": "node tests/run-all.mjs"
54
54
  },
55
55
  "dependencies": {
56
- "@earendil-works/pi-coding-agent": "^0.79.7"
56
+ "@earendil-works/pi-coding-agent": "^0.79.8"
57
57
  },
58
58
  "optionalDependencies": {
59
59
  "@firstpick/pi-extension-btw": "^0.1.0",