@brettinternet/pi-loop 0.1.4 → 0.1.5
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 +2 -0
- package/index.ts +33 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,6 +26,8 @@ pi install npm:@brettinternet/pi-loop
|
|
|
26
26
|
|
|
27
27
|
Durations use `ms`, `s`, `m`, `h`, or `d`. Delays range from 1 second to 24 hours. Timed loops run for at most 30 days. During a loop, `/loop time <duration>` switches to a deadline from now or resets the current deadline; timed mode requires a non-zero delay. `/loop <count>` switches back to a count of future iterations.
|
|
28
28
|
|
|
29
|
+
A pending `/wait` or `until` watch keeps the current iteration's session alive until its wake-up turn settles (or it is cancelled). A paused wait or recurring watch holds the iteration until resumed or completed. Use `/loop delay` for a simple fixed gap between iterations; use `/wait` for a same-session follow-up and `until` for a condition that might become true earlier than a fixed deadline.
|
|
30
|
+
|
|
29
31
|
Errors retry after 30 seconds, 1 minute, and 2 minutes, then pause. Aborting pauses the loop. `/loop pause` pauses after the active iteration settles; if the loop is between iterations, it pauses immediately. Resuming then starts the next iteration. An agent `loop_pause` request pauses mid-iteration for human blockers, and resuming continues that iteration. Recovery preserves the loop so you can resume or advance it.
|
|
30
32
|
|
|
31
33
|
Chain commands in the prompt:
|
package/index.ts
CHANGED
|
@@ -639,6 +639,24 @@ export default function loopExtension(pi: ExtensionAPI): void {
|
|
|
639
639
|
let pendingFailure: PendingFailure | undefined;
|
|
640
640
|
let currentSessionManagerRef: unknown;
|
|
641
641
|
let herdrBlocked = false;
|
|
642
|
+
const pendingWakes = new Map<string, boolean>();
|
|
643
|
+
let waitingForWake = false;
|
|
644
|
+
let wakeContext: ExtensionContext | undefined;
|
|
645
|
+
|
|
646
|
+
for (const channel of ["pi-until:busy", "pi-wait:busy"]) {
|
|
647
|
+
pi.events.on(channel, (value) => {
|
|
648
|
+
if (typeof value !== "boolean") return;
|
|
649
|
+
pendingWakes.set(channel, value);
|
|
650
|
+
if (!waitingForWake || [...pendingWakes.values()].some(Boolean)) return;
|
|
651
|
+
const ctx = wakeContext;
|
|
652
|
+
if (!ctx || !ctx.isIdle()) return;
|
|
653
|
+
const state = currentState(ctx);
|
|
654
|
+
if (!state || !statusIsActive(state) || transitionInFlight) return;
|
|
655
|
+
waitingForWake = false;
|
|
656
|
+
handledSettlementKey = stateKey(ctx, state);
|
|
657
|
+
scheduleContinuation(ctx, state);
|
|
658
|
+
});
|
|
659
|
+
}
|
|
642
660
|
|
|
643
661
|
function reportHerdrBlocked(state: LoopState | undefined): void {
|
|
644
662
|
const blocked = state?.status === "paused";
|
|
@@ -1523,6 +1541,9 @@ export default function loopExtension(pi: ExtensionAPI): void {
|
|
|
1523
1541
|
clearCommandInterruption();
|
|
1524
1542
|
pendingFailure = undefined;
|
|
1525
1543
|
currentSessionManagerRef = ctx.sessionManager;
|
|
1544
|
+
pendingWakes.clear();
|
|
1545
|
+
waitingForWake = false;
|
|
1546
|
+
wakeContext = ctx;
|
|
1526
1547
|
transitionInFlight = false;
|
|
1527
1548
|
handledSettlementKey = undefined;
|
|
1528
1549
|
const loaded = latestStateFromContext(ctx);
|
|
@@ -1593,6 +1614,12 @@ export default function loopExtension(pi: ExtensionAPI): void {
|
|
|
1593
1614
|
return;
|
|
1594
1615
|
}
|
|
1595
1616
|
if (handledSettlementKey === key) return;
|
|
1617
|
+
if ([...pendingWakes.values()].some(Boolean)) {
|
|
1618
|
+
waitingForWake = true;
|
|
1619
|
+
wakeContext = ctx;
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
waitingForWake = false;
|
|
1596
1623
|
handledSettlementKey = key;
|
|
1597
1624
|
scheduleContinuation(ctx, loaded);
|
|
1598
1625
|
});
|
|
@@ -1604,6 +1631,9 @@ export default function loopExtension(pi: ExtensionAPI): void {
|
|
|
1604
1631
|
clearCommandInterruption();
|
|
1605
1632
|
pendingFailure = undefined;
|
|
1606
1633
|
currentSessionManagerRef = ctx.sessionManager;
|
|
1634
|
+
pendingWakes.clear();
|
|
1635
|
+
waitingForWake = false;
|
|
1636
|
+
wakeContext = ctx;
|
|
1607
1637
|
handledSettlementKey = undefined;
|
|
1608
1638
|
const loaded = latestStateFromContext(ctx);
|
|
1609
1639
|
const owned = loaded && stateBelongsToContext(loaded, ctx) ? loaded : undefined;
|
|
@@ -1633,6 +1663,9 @@ export default function loopExtension(pi: ExtensionAPI): void {
|
|
|
1633
1663
|
reportHerdrBlocked(undefined);
|
|
1634
1664
|
clearWidget(ctx);
|
|
1635
1665
|
currentSessionManagerRef = undefined;
|
|
1666
|
+
waitingForWake = false;
|
|
1667
|
+
wakeContext = undefined;
|
|
1668
|
+
pendingWakes.clear();
|
|
1636
1669
|
});
|
|
1637
1670
|
|
|
1638
1671
|
pi.registerCommand("loop", {
|