@alphacoder-v0/pi-loops 0.19.2 → 0.19.3
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/CHANGELOG.md +13 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/docs/web-ui-parity.md +12 -0
- package/package.json +1 -1
- package/src/web.mjs +54 -9
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
All notable changes to pi-loops are documented here. The format follows
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow SemVer.
|
|
5
5
|
|
|
6
|
+
## [0.19.3] - 2026-09-14
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
- **Six tabs of the browser front end and nothing you typed was sent** (#14). A browser gives one
|
|
10
|
+
address six connections, and every open tab held one for its event stream — so the sixth tab, or
|
|
11
|
+
a few left behind the first, left nothing for `POST /prompt`: the fetch queued, neither
|
|
12
|
+
succeeding nor failing, the bubble drawn and the message never delivered. A tab now closes its
|
|
13
|
+
stream fifteen seconds after going into the background (`paused in background`) and opens a new
|
|
14
|
+
one when looked at again, polling at once so the seq/epoch check reloads what it missed; the pi
|
|
15
|
+
process behind the page, and its jobs, are not involved either way. And a send that has not
|
|
16
|
+
settled in six seconds says `still sending — if it never lands, close the other tabs of this
|
|
17
|
+
address` instead of looking alive.
|
|
18
|
+
|
|
6
19
|
## [0.19.2] - 2026-09-14
|
|
7
20
|
|
|
8
21
|
### Fixed
|
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ the first sign of credentials that do not work should not be an empty inbox tomo
|
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
pi install npm:@alphacoder-v0/pi-loops # from npm, following new releases
|
|
41
|
-
pi install git:github.com/alphacoder-v0/pi-loops@v0.19.
|
|
41
|
+
pi install git:github.com/alphacoder-v0/pi-loops@v0.19.3 # or from GitHub, at a pinned tag
|
|
42
42
|
pi install /path/to/pi-loops # or a local checkout — `pi install .` in this repo
|
|
43
43
|
pi -e /path/to/pi-loops # or none of them: try it for one run, installing nothing
|
|
44
44
|
```
|
package/README.zh-CN.md
CHANGED
|
@@ -45,7 +45,7 @@ pi-loops 自己没有任何运行时依赖。
|
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
47
|
pi install npm:@alphacoder-v0/pi-loops # 从 npm 装,跟着新版本走
|
|
48
|
-
pi install git:github.com/alphacoder-v0/pi-loops@v0.19.
|
|
48
|
+
pi install git:github.com/alphacoder-v0/pi-loops@v0.19.3 # 或者从 GitHub 装,钉住一个 tag
|
|
49
49
|
pi install /path/to/pi-loops # 或者本地检出;本仓库里就是 pi install .
|
|
50
50
|
```
|
|
51
51
|
|
package/docs/web-ui-parity.md
CHANGED
|
@@ -171,6 +171,18 @@ weaker, and worth converting whenever one of them breaks.
|
|
|
171
171
|
be read as prose and waved through. `test/web-page.test.ts`: *a confirmation shows what is
|
|
172
172
|
about to run*.
|
|
173
173
|
- [x] Enter does not approve: the focus starts on cancel.
|
|
174
|
+
- [x] **A tab in the background does not hold one of the browser's six connections.** Every tab
|
|
175
|
+
used to keep an event stream open for as long as it existed, so the sixth tab — or a few
|
|
176
|
+
forgotten behind the first — left nothing for the request that sends what you typed, and the
|
|
177
|
+
message sat drawn and unsent (#14). A tab closes its stream fifteen seconds after going into the
|
|
178
|
+
background and says `paused in background`; looked at again, it subscribes anew and polls, and
|
|
179
|
+
the seq/epoch check reloads what it missed. The pi behind the page runs, and its jobs run, either
|
|
180
|
+
way. `test/web-page.test.ts`: *a tab in the background gives its connection back, and takes a
|
|
181
|
+
new one when looked at again*.
|
|
182
|
+
- [x] **A send that goes nowhere says so.** Six seconds without an answer to `/prompt` and the
|
|
183
|
+
status line reads `still sending — if it never lands, close the other tabs of this address`;
|
|
184
|
+
the request is not abandoned, and the line goes when it settles. `test/web-page.test.ts`: *a
|
|
185
|
+
send that goes nowhere says so instead of looking alive*.
|
|
174
186
|
- [x] A slash command that waits in a dialog is not reported as timed out while the person reads:
|
|
175
187
|
the browser waits up to fifteen minutes for a `/…` prompt, sixty seconds for anything else.
|
|
176
188
|
- [x] Clicking away from any dialog closes it. `test/web-page.test.ts`: *clicking outside a dialog
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alphacoder-v0/pi-loops",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.3",
|
|
4
4
|
"description": "An automation layer for pi: cron + stateful loops with a triage inbox, maker/checker verification, dynamic triggers, MCP notifications and tools, lifecycle hooks, session archives. A non-invasive pi extension.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/src/web.mjs
CHANGED
|
@@ -2442,6 +2442,10 @@ const api = (p, b) =>
|
|
|
2442
2442
|
.catch((e) => ({ success: false, error: String(e) }));
|
|
2443
2443
|
const $ = (id) => document.getElementById(id);
|
|
2444
2444
|
const feed = $("feed"), statusEl = $("status");
|
|
2445
|
+
/** How long a tab stays subscribed after it goes into the background. */
|
|
2446
|
+
const STREAM_PARK_MS = 15000;
|
|
2447
|
+
/** How long a send may take before the page says that it is taking long. */
|
|
2448
|
+
const SEND_WATCHDOG_MS = 6000;
|
|
2445
2449
|
let state = {}, cwd = "", busy = false, atBottom = true, takesImages = true;
|
|
2446
2450
|
/** Installed once the stream is up; until then a poll has nothing to compare against. */
|
|
2447
2451
|
let checkStream;
|
|
@@ -3808,7 +3812,17 @@ $("composer").onsubmit = async (e) => {
|
|
|
3808
3812
|
if (drewLocally.length > 20) drewLocally.shift();
|
|
3809
3813
|
}
|
|
3810
3814
|
images = []; drawThumbs();
|
|
3811
|
-
|
|
3815
|
+
// A send that neither succeeds nor fails is a send the browser has queued behind its connection
|
|
3816
|
+
// pool — every other tab of this address holding a stream is the usual reason (#14). The fetch is
|
|
3817
|
+
// not given up on; the page says what is happening instead of looking alive.
|
|
3818
|
+
const slow = setTimeout(() => { statusEl.textContent = "still sending — if it never lands, close the other tabs of this address"; }, SEND_WATCHDOG_MS);
|
|
3819
|
+
let r;
|
|
3820
|
+
try {
|
|
3821
|
+
r = await api("/prompt", payload);
|
|
3822
|
+
} finally {
|
|
3823
|
+
clearTimeout(slow);
|
|
3824
|
+
if (statusEl.textContent.startsWith("still sending")) statusEl.textContent = busy ? "working…" : "ready";
|
|
3825
|
+
}
|
|
3812
3826
|
if (!r.success) row("err", "error", r.error || JSON.stringify(r));
|
|
3813
3827
|
};
|
|
3814
3828
|
$("stop").onclick = () => api("/abort", {});
|
|
@@ -4498,15 +4512,46 @@ function applyEvent(ev) {
|
|
|
4498
4512
|
}
|
|
4499
4513
|
};
|
|
4500
4514
|
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4515
|
+
/*
|
|
4516
|
+
* One stream per tab, and only while the tab is looked at.
|
|
4517
|
+
*
|
|
4518
|
+
* A browser gives one address six connections, and every open tab used to hold one of them for
|
|
4519
|
+
* its event stream — so the sixth tab, or a few forgotten behind the first, left nothing for the
|
|
4520
|
+
* request that sends what you typed: the fetch queued, neither succeeding nor failing, the bubble
|
|
4521
|
+
* drawn and the message never sent (#14). A tab in the background does not need to hear events as
|
|
4522
|
+
* they happen: it closes its stream after a moment, and when it is looked at again it opens a new
|
|
4523
|
+
* one and polls, and the seq/epoch check above reloads whatever it missed. The pi process behind
|
|
4524
|
+
* this page is not involved either way; it runs, and its jobs run, whether anyone is listening.
|
|
4525
|
+
*/
|
|
4526
|
+
let es;
|
|
4527
|
+
const openStream = () => {
|
|
4528
|
+
if (es) return;
|
|
4529
|
+
es = new EventSource("/events?token=" + TOKEN);
|
|
4530
|
+
es.onmessage = (e) => {
|
|
4531
|
+
const ev = JSON.parse(e.data);
|
|
4532
|
+
if (resyncing) return void waiting.push(ev); // applied once the transcript is back
|
|
4533
|
+
applyEvent(ev);
|
|
4534
|
+
};
|
|
4535
|
+
es.onerror = () => { statusEl.textContent = "reconnecting…"; };
|
|
4536
|
+
es.onopen = () => refresh();
|
|
4506
4537
|
};
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4538
|
+
openStream();
|
|
4539
|
+
let parking;
|
|
4540
|
+
document.addEventListener("visibilitychange", () => {
|
|
4541
|
+
clearTimeout(parking);
|
|
4542
|
+
if (document.visibilityState === "hidden") {
|
|
4543
|
+
// Not at once: switching tabs and back should not cost a reconnect and a reload.
|
|
4544
|
+
parking = setTimeout(() => {
|
|
4545
|
+
if (!es || document.visibilityState !== "hidden") return;
|
|
4546
|
+
es.close();
|
|
4547
|
+
es = undefined;
|
|
4548
|
+
statusEl.textContent = "paused in background";
|
|
4549
|
+
}, STREAM_PARK_MS);
|
|
4550
|
+
} else if (!es) {
|
|
4551
|
+
openStream();
|
|
4552
|
+
refresh().catch(() => {});
|
|
4553
|
+
}
|
|
4554
|
+
});
|
|
4510
4555
|
setInterval(refresh, 8000);
|
|
4511
4556
|
})();
|
|
4512
4557
|
</script>`;
|