@firstpick/pi-package-webui 0.2.4 → 0.2.6

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
@@ -154,7 +154,7 @@ Optional companions:
154
154
  - `@firstpick/pi-extension-setup-skills` — TUI `/skills` setup command alongside WebUI-native skill toggles.
155
155
  - `@firstpick/pi-extension-todo-progress` — todo-progress rendering.
156
156
  - `@firstpick/pi-extension-tools` — TUI `/tools` active-tool manager alongside WebUI-native tool toggles.
157
- - `@firstpick/pi-extension-git-footer-status` — richer git/footer status.
157
+ - `@firstpick/pi-extension-git-footer-status` — richer extension-owned git/footer status, including the structured Web UI footer payload.
158
158
  - `@firstpick/pi-extension-stats` — stats commands and status data.
159
159
  - `@firstpick/pi-themes-bundle` — Web UI and Pi theme resources.
160
160
 
package/bin/pi-webui.mjs CHANGED
@@ -1592,34 +1592,11 @@ async function getPathSuggestionData(tab, rawQuery) {
1592
1592
  }
1593
1593
 
1594
1594
  async function getWorkspaceInfo(cwd, startedAt) {
1595
- const info = {
1595
+ return {
1596
1596
  cwd,
1597
1597
  displayCwd: displayPath(cwd),
1598
1598
  uptimeMs: Math.max(0, Date.now() - Date.parse(startedAt)),
1599
- git: { isRepo: false },
1600
- };
1601
-
1602
- const inside = await runCommand("git", ["rev-parse", "--is-inside-work-tree"], { cwd, timeoutMs: 1200 });
1603
- if (inside.exitCode !== 0 || inside.stdout.trim() !== "true") return info;
1604
-
1605
- const [branch, status] = await Promise.all([
1606
- runCommand("git", ["branch", "--show-current"], { cwd, timeoutMs: 1200 }),
1607
- runCommand("git", ["status", "--porcelain=v1", "--branch"], { cwd, timeoutMs: 1800 }),
1608
- ]);
1609
- const lines = status.stdout.split(/\r?\n/).filter(Boolean);
1610
- const branchLine = lines.find((line) => line.startsWith("## "));
1611
- const fileLines = lines.filter((line) => !line.startsWith("## "));
1612
- const untracked = fileLines.filter((line) => line.startsWith("??")).length;
1613
- const changed = fileLines.length - untracked;
1614
-
1615
- info.git = {
1616
- isRepo: true,
1617
- branch: branch.stdout.trim() || branchLine?.replace(/^##\s+/, "").split("...")[0] || "detached",
1618
- changed,
1619
- untracked,
1620
- branchStatus: branchLine,
1621
1599
  };
1622
- return info;
1623
1600
  }
1624
1601
 
1625
1602
  let activeGitWorkflowProcess = null;
@@ -2206,6 +2183,39 @@ function pendingExtensionUiMap(tab) {
2206
2183
  return tab.pendingExtensionUiRequests;
2207
2184
  }
2208
2185
 
2186
+ function extensionStatusMap(tab) {
2187
+ if (!tab.extensionStatuses) tab.extensionStatuses = new Map();
2188
+ return tab.extensionStatuses;
2189
+ }
2190
+
2191
+ function rememberExtensionStatusEvent(tab, event) {
2192
+ if (event?.type !== "extension_ui_request" || event.method !== "setStatus" || !event.statusKey) return;
2193
+ const statuses = extensionStatusMap(tab);
2194
+ if (event.statusText) statuses.set(String(event.statusKey), String(event.statusText));
2195
+ else statuses.delete(String(event.statusKey));
2196
+ }
2197
+
2198
+ function clearExtensionStatuses(tab) {
2199
+ tab?.extensionStatuses?.clear();
2200
+ }
2201
+
2202
+ function replayExtensionStatuses(tab, res) {
2203
+ for (const [statusKey, statusText] of extensionStatusMap(tab)) {
2204
+ sendSse(res, {
2205
+ type: "extension_ui_request",
2206
+ id: randomUUID(),
2207
+ method: "setStatus",
2208
+ statusKey,
2209
+ statusText,
2210
+ tabId: tab.id,
2211
+ tabTitle: tab.title,
2212
+ replayed: true,
2213
+ tabActivity: tabActivitySnapshot(tab),
2214
+ pendingExtensionUiRequestCount: pendingExtensionUiRequests(tab).length,
2215
+ });
2216
+ }
2217
+ }
2218
+
2209
2219
  function bashQueueForTab(tab) {
2210
2220
  if (!tab.bashQueue) tab.bashQueue = [];
2211
2221
  return tab.bashQueue;
@@ -2499,8 +2509,13 @@ function attachRpcToTab(tab, rpc) {
2499
2509
  if (resolveWebuiHelperResponse(tab, event) || resolveWebuiHelperRpcResponse(tab, event)) return;
2500
2510
  updateTabActivityFromEvent(tab, event);
2501
2511
  let scopedEvent = { ...event, tabId: tab.id, tabTitle: tab.title, tabActivity: tabActivitySnapshot(tab) };
2502
- if (event?.type === "pi_process_exit" || event?.type === "pi_process_error") clearPendingExtensionUiRequests(tab);
2503
- else trackPendingExtensionUiRequest(tab, scopedEvent);
2512
+ if (event?.type === "pi_process_exit" || event?.type === "pi_process_error") {
2513
+ clearPendingExtensionUiRequests(tab);
2514
+ clearExtensionStatuses(tab);
2515
+ } else {
2516
+ rememberExtensionStatusEvent(tab, scopedEvent);
2517
+ trackPendingExtensionUiRequest(tab, scopedEvent);
2518
+ }
2504
2519
  scopedEvent = { ...scopedEvent, tabActivity: tabActivitySnapshot(tab), pendingExtensionUiRequestCount: pendingExtensionUiRequests(tab).length };
2505
2520
  recordEvent(scopedEvent);
2506
2521
  for (const client of tab.sseClients) sendSse(client, scopedEvent);
@@ -2534,6 +2549,7 @@ async function createTab({ id: requestedId, index, title, titleSource, conversat
2534
2549
  pendingThinkingLevel: undefined,
2535
2550
  activity: createTabActivity(createdAt),
2536
2551
  pendingExtensionUiRequests: new Map(),
2552
+ extensionStatuses: new Map(),
2537
2553
  webuiHelperRequests: new Map(),
2538
2554
  webuiHelperResponseIds: new Set(),
2539
2555
  bashQueue: [],
@@ -2732,6 +2748,7 @@ async function updateTabCwd(id, cwd) {
2732
2748
  forgetTabState(tab);
2733
2749
  resetTabActivity(tab);
2734
2750
  clearPendingExtensionUiRequests(tab);
2751
+ clearExtensionStatuses(tab);
2735
2752
  const rpc = new PiRpcProcess({ ...piCommand, cwd: tab.cwd });
2736
2753
  attachRpcToTab(tab, rpc);
2737
2754
  rpc.start();
@@ -2766,6 +2783,7 @@ async function restartTabRpc(tab, reason = "reload") {
2766
2783
 
2767
2784
  resetTabActivity(tab);
2768
2785
  clearPendingExtensionUiRequests(tab);
2786
+ clearExtensionStatuses(tab);
2769
2787
  const rpc = new PiRpcProcess({ ...piCommand, cwd: tab.cwd });
2770
2788
  attachRpcToTab(tab, rpc);
2771
2789
  rpc.start();
@@ -3945,6 +3963,7 @@ const server = createServer(async (req, res) => {
3945
3963
  tabActivity: tabActivitySnapshot(tab),
3946
3964
  pendingExtensionUiRequestCount: pendingExtensionUiRequests(tab).length,
3947
3965
  });
3966
+ replayExtensionStatuses(tab, res);
3948
3967
  replayPendingExtensionUiRequests(tab, res);
3949
3968
  const keepAlive = setInterval(() => res.write(": keepalive\n\n"), 15000);
3950
3969
  req.on("close", () => {
@@ -4288,6 +4307,7 @@ const server = createServer(async (req, res) => {
4288
4307
  forgetTabState(tab);
4289
4308
  rememberTabState(tab, response.data);
4290
4309
  clearPendingExtensionUiRequests(tab);
4310
+ clearExtensionStatuses(tab);
4291
4311
  }
4292
4312
  sendJson(res, response.success === false ? 400 : 200, responseWithTab(response, tab));
4293
4313
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firstpick/pi-package-webui",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
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
  "type": "module",