@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 +1 -1
- package/bin/pi-webui.mjs +46 -26
- package/package.json +1 -1
- package/public/app.js +521 -140
- package/public/index.html +23 -2
- package/public/service-worker.js +1 -1
- package/public/styles.css +179 -3
- package/tests/mobile-static.test.mjs +67 -14
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
|
-
|
|
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")
|
|
2503
|
-
|
|
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