transitions-refine 0.3.20 → 0.3.21

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/server/relay.mjs +13 -33
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "transitions-refine",
3
- "version": "0.3.20",
3
+ "version": "0.3.21",
4
4
  "description": "Live, agent-driven Refine panel for CSS/Motion transitions — injects a timeline + Refine UI and runs transitions.dev suggestions via your coding agent.",
5
5
  "type": "module",
6
6
  "bin": {
package/server/relay.mjs CHANGED
@@ -138,13 +138,6 @@ const PENDING_TIMEOUT_MS = Number(process.env.REFINE_PENDING_TIMEOUT_MS) || 1200
138
138
  // to stop (it returns {stop:true} from /jobs/next). 0 disables. Only the chat
139
139
  // loop is affected — a wired REFINE_AGENT_CMD never polls /jobs/next.
140
140
  const POLLER_IDLE_STOP_MS = Number(process.env.REFINE_POLLER_IDLE_STOP_MS) || 600000;
141
- // While the Stop latch is held, a genuinely new `/refine live` session can resume
142
- // itself implicitly: only after polling has been *quiet* this long (the old loop
143
- // actually died) do we treat the next poll as a fresh session and auto-resume.
144
- // Must exceed a looping agent's poll gap, so an agent that ignores Stop and keeps
145
- // polling can never clear the latch — it just keeps getting {stop:true}. (An
146
- // updated agent also resumes explicitly via POST /poller/start, no wait needed.)
147
- const STOP_QUIET_MS = Number(process.env.REFINE_STOP_QUIET_MS) || 15000;
148
141
 
149
142
  /** @type {Map<string, Job>} */
150
143
  const jobs = new Map();
@@ -160,9 +153,6 @@ let lastPollAt = 0;
160
153
  // re-polls — can never silently revive the session. This is what makes the
161
154
  // panel's Stop button stick instead of flipping "Live" back on seconds later.
162
155
  let pollerStopped = false;
163
- // When did a poll last arrive *while latched*? Used to detect that the old loop
164
- // went quiet so a genuinely new session (or re-run) can auto-resume.
165
- let lastStoppedPollAt = 0;
166
156
  const pollerActive = () => !pollerStopped && now() - lastPollAt < POLLER_TTL_MS;
167
157
  const llmAvailable = () => Boolean(agentCmd()) || pollerActive();
168
158
 
@@ -740,21 +730,15 @@ const server = createServer(async (req, res) => {
740
730
 
741
731
  // GET /jobs/next — long-poll claimed by a `/refine live` agent (LLM jobs).
742
732
  if (method === "GET" && path === "/jobs/next") {
743
- // Stopped latch: a Stop was issued and not yet resumed. Keep telling every
744
- // poller to exit and report inactive until either an explicit POST
745
- // /poller/start, or polling goes quiet for STOP_QUIET_MS (the old loop died)
746
- // and a new poll arrives only then is it a genuinely fresh session.
747
- // A pending job always wins so we never drop real work on the edge.
733
+ // Stopped latch: a Stop was issued and not yet resumed. STICKY every poll
734
+ // gets {stop:true} and the poller reports inactive until an explicit
735
+ // POST /poller/start (a fresh `/refine live` / loop announcing itself) or a
736
+ // relay restart. We deliberately do NOT auto-resume on a quiet gap: a stubborn
737
+ // agent's straggler poll arriving seconds later would be misread as a new
738
+ // session and flip the panel back to "Live" — which is exactly the bug where
739
+ // Stop "didn't stick". A pending job still wins so we never drop real work.
748
740
  if (pollerStopped && !nextPendingLlm()) {
749
- if (lastStoppedPollAt && now() - lastStoppedPollAt >= STOP_QUIET_MS) {
750
- // Quiet gap → the previous loop is gone. This poll is a fresh session.
751
- pollerStopped = false;
752
- lastStoppedPollAt = 0;
753
- // fall through to normal handling below (counts as live again)
754
- } else {
755
- lastStoppedPollAt = now(); // a poller is still hammering us → hold the latch
756
- return send(res, 200, { stop: true });
757
- }
741
+ return send(res, 200, { stop: true });
758
742
  }
759
743
  lastPollAt = now();
760
744
  if (!lastJobAt) lastJobAt = now(); // seed idle window on the loop's first poll
@@ -762,8 +746,7 @@ const server = createServer(async (req, res) => {
762
746
  // loop to exit. A pending job always wins so we never drop real work.
763
747
  if ((stopRequested || (POLLER_IDLE_STOP_MS && now() - lastJobAt >= POLLER_IDLE_STOP_MS)) && !nextPendingLlm()) {
764
748
  stopRequested = false;
765
- pollerStopped = true; // latch until /poller/start or a quiet gap
766
- lastStoppedPollAt = 0;
749
+ pollerStopped = true; // latch until an explicit /poller/start
767
750
  lastJobAt = 0;
768
751
  lastPollAt = 0; // loop is exiting → report it inactive immediately on /health
769
752
  return send(res, 200, { stop: true });
@@ -773,8 +756,7 @@ const server = createServer(async (req, res) => {
773
756
  if (res.writableEnded) return;
774
757
  if (stopRequested && !nextPendingLlm()) {
775
758
  stopRequested = false;
776
- pollerStopped = true; // latch until /poller/start or a quiet gap
777
- lastStoppedPollAt = 0;
759
+ pollerStopped = true; // latch until an explicit /poller/start
778
760
  lastJobAt = 0;
779
761
  lastPollAt = 0; // loop is exiting → report it inactive immediately on /health
780
762
  return send(res, 200, { stop: true });
@@ -797,8 +779,7 @@ const server = createServer(async (req, res) => {
797
779
  if (method === "POST" && path === "/poller/stop") {
798
780
  const wasActive = now() - lastPollAt < POLLER_TTL_MS;
799
781
  stopRequested = true;
800
- pollerStopped = true; // latch: stays stopped until /poller/start or a quiet gap
801
- lastStoppedPollAt = 0;
782
+ pollerStopped = true; // latch: stays stopped until an explicit /poller/start
802
783
  lastPollAt = 0; // report inactive immediately; a straggler poll won't revive it
803
784
  return send(res, 200, { ok: true, stopping: wasActive });
804
785
  }
@@ -822,11 +803,10 @@ const server = createServer(async (req, res) => {
822
803
 
823
804
  // POST /poller/start — a fresh `/refine live` agent (or loop) announces itself
824
805
  // and clears the Stop latch so its polls count as live again. Without this an
825
- // explicit re-run would have to wait out the quiet window. Call it once at loop
826
- // startup, before the first GET /jobs/next.
806
+ // explicit re-run couldn't resume at all (the sticky latch tells every poll to
807
+ // stop). Call it once at loop startup, before the first GET /jobs/next.
827
808
  if (method === "POST" && path === "/poller/start") {
828
809
  pollerStopped = false;
829
- lastStoppedPollAt = 0;
830
810
  stopRequested = false;
831
811
  lastJobAt = now();
832
812
  lastPollAt = now();