@firstpick/pi-package-webui 0.3.8 → 0.3.9
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-webui.mjs +26 -2
- package/package.json +1 -1
- package/public/app.js +7 -1
- package/tests/mobile-static.test.mjs +1 -0
package/bin/pi-webui.mjs
CHANGED
|
@@ -2776,10 +2776,23 @@ function gitBranchFromStatus(statusText) {
|
|
|
2776
2776
|
return branchLine.slice(3).trim().replace(/\.\.\..*$/, "") || "detached";
|
|
2777
2777
|
}
|
|
2778
2778
|
|
|
2779
|
+
function gitDivergenceFromBranchStatus(line) {
|
|
2780
|
+
const details = String(line || "").match(/\[(.+)\]\s*$/)?.[1] || "";
|
|
2781
|
+
const ahead = Number.parseInt(details.match(/ahead\s+(\d+)/i)?.[1] || "0", 10) || 0;
|
|
2782
|
+
const behind = Number.parseInt(details.match(/behind\s+(\d+)/i)?.[1] || "0", 10) || 0;
|
|
2783
|
+
return { ahead, behind };
|
|
2784
|
+
}
|
|
2785
|
+
|
|
2779
2786
|
function summarizeGitShortStatus(statusText) {
|
|
2780
|
-
const summary = { staged: 0, unstaged: 0, untracked: 0, conflicted: 0 };
|
|
2787
|
+
const summary = { staged: 0, unstaged: 0, untracked: 0, conflicted: 0, ahead: 0, behind: 0 };
|
|
2781
2788
|
for (const line of String(statusText || "").split(/\r?\n/)) {
|
|
2782
|
-
if (!line
|
|
2789
|
+
if (!line) continue;
|
|
2790
|
+
if (line.startsWith("## ")) {
|
|
2791
|
+
const divergence = gitDivergenceFromBranchStatus(line);
|
|
2792
|
+
summary.ahead = divergence.ahead;
|
|
2793
|
+
summary.behind = divergence.behind;
|
|
2794
|
+
continue;
|
|
2795
|
+
}
|
|
2783
2796
|
const x = line[0] || " ";
|
|
2784
2797
|
const y = line[1] || " ";
|
|
2785
2798
|
if (x === "?" && y === "?") {
|
|
@@ -3559,8 +3572,19 @@ function buildPiArgsForTab(tabIndex, title) {
|
|
|
3559
3572
|
return args;
|
|
3560
3573
|
}
|
|
3561
3574
|
|
|
3575
|
+
function isNodeScriptCommand(command) {
|
|
3576
|
+
return [".cjs", ".js", ".mjs"].includes(path.extname(String(command || "")).toLowerCase());
|
|
3577
|
+
}
|
|
3578
|
+
|
|
3562
3579
|
async function resolvePiCommand(piArgs) {
|
|
3563
3580
|
if (options.piBinExplicit) {
|
|
3581
|
+
if (isNodeScriptCommand(options.piBin)) {
|
|
3582
|
+
return {
|
|
3583
|
+
command: process.execPath,
|
|
3584
|
+
args: [options.piBin, ...piArgs],
|
|
3585
|
+
displayCommand: `${process.execPath} ${options.piBin} ${piArgs.join(" ")}`,
|
|
3586
|
+
};
|
|
3587
|
+
}
|
|
3564
3588
|
return { command: options.piBin, args: piArgs, displayCommand: `${options.piBin} ${piArgs.join(" ")}` };
|
|
3565
3589
|
}
|
|
3566
3590
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firstpick/pi-package-webui",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
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",
|
package/public/app.js
CHANGED
|
@@ -4955,7 +4955,7 @@ const GIT_FOOTER_TOOLTIP_COPY = {
|
|
|
4955
4955
|
git: "Current Git branch. detached means HEAD is not on a branch; no repo means the cwd is outside a Git work tree.",
|
|
4956
4956
|
"git-state": "Active Git operation or detached state. Finish or abort rebase/merge/cherry-pick/revert/bisect before normal commits.",
|
|
4957
4957
|
sync: "Remote tracking divergence. ↑ means local commits ahead; ↓ means remote commits to pull.",
|
|
4958
|
-
changes: "Working tree summary. 🟢 staged, ✏️ modified unstaged, ➕ untracked, ⚠️ conflicted; ✅ means no changes.",
|
|
4958
|
+
changes: "Working tree and fetched remote summary. 🟢 staged, ✏️ modified unstaged, ➕ untracked, ⚠️ conflicted; ⬇️ means fetched remote commits to pull; 🔄/✓/⚠️ fetch shows the tab git fetch state; ✅ means no changes.",
|
|
4959
4959
|
"git-extra": "Extra Git signals. 📦 stash, 🧩 dirty submodules, 🌳 worktrees, 🏷️ tag at HEAD, 🕒 last commit age, 🔓 signing mismatch.",
|
|
4960
4960
|
model: "Scoped model for this tab.",
|
|
4961
4961
|
thinking: "Reasoning/thinking effort for this tab.",
|
|
@@ -5414,10 +5414,14 @@ function gitChangesChip(label, value, className = "") {
|
|
|
5414
5414
|
function renderGitChangesOverview(data) {
|
|
5415
5415
|
const summary = data?.summary || {};
|
|
5416
5416
|
const untrackedCount = Array.isArray(data?.untracked) ? data.untracked.length : Number(summary.untracked || 0);
|
|
5417
|
+
const ahead = Number(summary.ahead || 0) || 0;
|
|
5418
|
+
const behind = Number(summary.behind || 0) || 0;
|
|
5417
5419
|
const overview = make("div", "git-changes-overview");
|
|
5418
5420
|
overview.append(
|
|
5419
5421
|
gitChangesChip("repo", data?.root || "—", "wide"),
|
|
5420
5422
|
gitChangesChip("branch", data?.branch || "detached"),
|
|
5423
|
+
gitChangesChip("ahead", ahead > 0 ? `↑${ahead}` : 0, ahead > 0 ? "warning" : "muted"),
|
|
5424
|
+
gitChangesChip("remote", behind > 0 ? `↓${behind}` : 0, behind > 0 ? "danger" : "muted"),
|
|
5421
5425
|
gitChangesChip("staged", summary.staged || 0, "success"),
|
|
5422
5426
|
gitChangesChip("modified", summary.unstaged || 0, "warning"),
|
|
5423
5427
|
gitChangesChip("untracked", untrackedCount, "muted"),
|
|
@@ -6558,6 +6562,8 @@ function scheduleRefreshFooter(delay = 300, tabContext = activeTabContext()) {
|
|
|
6558
6562
|
function formatCodexPlanType(value) {
|
|
6559
6563
|
const text = String(value || "").trim();
|
|
6560
6564
|
if (!text) return "unknown plan";
|
|
6565
|
+
const normalized = text.replace(/[\s_-]+/g, "").toLowerCase();
|
|
6566
|
+
if (normalized === "prolite") return "Usage";
|
|
6561
6567
|
return text.replace(/[_-]+/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
|
|
6562
6568
|
}
|
|
6563
6569
|
|
|
@@ -490,6 +490,7 @@ assert.match(
|
|
|
490
490
|
"side-panel section toggles should expand at most one section at a time",
|
|
491
491
|
);
|
|
492
492
|
assert.match(app, /function renderCodexUsage\(\)/, "frontend should render Codex usage buckets in the side panel");
|
|
493
|
+
assert.match(app, /if \(normalized === "prolite"\) return "Usage";/, "Codex Prolite plan labels should display as Usage in the side panel");
|
|
493
494
|
assert.match(app, /api\(`\/api\/codex-usage\$\{suffix\}`, \{ scoped: false \}\)/, "Codex usage should load through a server endpoint without browser credentials");
|
|
494
495
|
assert.match(app, /restoreSidePanelSectionState\(\);\nbindSidePanelSectionToggles\(\);/, "side panel section state should restore before toggles are bound");
|
|
495
496
|
assert.match(app, /OPTIONAL_FEATURES_STORAGE_KEY/, "optional feature disable toggles should persist in browser storage");
|