transitions-refine 0.3.14 → 0.3.15
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/package.json +1 -1
- package/server/relay.mjs +41 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "transitions-refine",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.15",
|
|
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
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
import { createServer } from "node:http";
|
|
26
26
|
import { randomUUID } from "node:crypto";
|
|
27
27
|
import { spawn } from "node:child_process";
|
|
28
|
-
import { existsSync } from "node:fs";
|
|
28
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
29
29
|
import { homedir } from "node:os";
|
|
30
30
|
import { delimiter, join } from "node:path";
|
|
31
31
|
import { refineTimings, DURATION_TOKENS, SCALE_TOKENS, BLUR_TOKENS, SMOOTH_OUT } from "./motion-tokens.mjs";
|
|
@@ -33,6 +33,12 @@ import { buildInjectModule } from "./inject.mjs";
|
|
|
33
33
|
|
|
34
34
|
const PORT = Number(process.env.REFINE_RELAY_PORT) || 7331;
|
|
35
35
|
const AUTO = process.env.REFINE_AUTO !== "0";
|
|
36
|
+
// Own package version, surfaced on /health so you can verify which relay build is
|
|
37
|
+
// actually running (npx caches — a stale relay is the usual "fix didn't work").
|
|
38
|
+
let PKG_VERSION = "0.0.0";
|
|
39
|
+
try {
|
|
40
|
+
PKG_VERSION = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version || PKG_VERSION;
|
|
41
|
+
} catch {}
|
|
36
42
|
|
|
37
43
|
// A bare `cursor-agent` goes interactive: it prints "⚠ Workspace Trust Required"
|
|
38
44
|
// and exits 1, so every headless refine/scan/apply job fails. Force the headless
|
|
@@ -91,6 +97,13 @@ const PENDING_TIMEOUT_MS = Number(process.env.REFINE_PENDING_TIMEOUT_MS) || 1200
|
|
|
91
97
|
// to stop (it returns {stop:true} from /jobs/next). 0 disables. Only the chat
|
|
92
98
|
// loop is affected — a wired REFINE_AGENT_CMD never polls /jobs/next.
|
|
93
99
|
const POLLER_IDLE_STOP_MS = Number(process.env.REFINE_POLLER_IDLE_STOP_MS) || 600000;
|
|
100
|
+
// While the Stop latch is held, a genuinely new `/refine live` session can resume
|
|
101
|
+
// itself implicitly: only after polling has been *quiet* this long (the old loop
|
|
102
|
+
// actually died) do we treat the next poll as a fresh session and auto-resume.
|
|
103
|
+
// Must exceed a looping agent's poll gap, so an agent that ignores Stop and keeps
|
|
104
|
+
// polling can never clear the latch — it just keeps getting {stop:true}. (An
|
|
105
|
+
// updated agent also resumes explicitly via POST /poller/start, no wait needed.)
|
|
106
|
+
const STOP_QUIET_MS = Number(process.env.REFINE_STOP_QUIET_MS) || 15000;
|
|
94
107
|
|
|
95
108
|
/** @type {Map<string, Job>} */
|
|
96
109
|
const jobs = new Map();
|
|
@@ -106,6 +119,9 @@ let lastPollAt = 0;
|
|
|
106
119
|
// re-polls — can never silently revive the session. This is what makes the
|
|
107
120
|
// panel's Stop button stick instead of flipping "Live" back on seconds later.
|
|
108
121
|
let pollerStopped = false;
|
|
122
|
+
// When did a poll last arrive *while latched*? Used to detect that the old loop
|
|
123
|
+
// went quiet so a genuinely new session (or re-run) can auto-resume.
|
|
124
|
+
let lastStoppedPollAt = 0;
|
|
109
125
|
const pollerActive = () => !pollerStopped && now() - lastPollAt < POLLER_TTL_MS;
|
|
110
126
|
const llmAvailable = () => Boolean(AGENT_CMD) || pollerActive();
|
|
111
127
|
|
|
@@ -596,9 +612,11 @@ const server = createServer(async (req, res) => {
|
|
|
596
612
|
if (method === "GET" && path === "/health") {
|
|
597
613
|
return send(res, 200, {
|
|
598
614
|
ok: true,
|
|
615
|
+
version: PKG_VERSION,
|
|
599
616
|
auto: AUTO,
|
|
600
617
|
llmAvailable: llmAvailable(),
|
|
601
618
|
pollerActive: pollerActive(),
|
|
619
|
+
pollerStopped,
|
|
602
620
|
agentCmd: Boolean(AGENT_CMD),
|
|
603
621
|
cliInstalled: cursorCliInstalled(),
|
|
604
622
|
jobs: jobs.size,
|
|
@@ -661,10 +679,20 @@ const server = createServer(async (req, res) => {
|
|
|
661
679
|
// GET /jobs/next — long-poll claimed by a `/refine live` agent (LLM jobs).
|
|
662
680
|
if (method === "GET" && path === "/jobs/next") {
|
|
663
681
|
// Stopped latch: a Stop was issued and not yet resumed. Keep telling every
|
|
664
|
-
// poller to exit and report inactive
|
|
665
|
-
//
|
|
682
|
+
// poller to exit and report inactive until either an explicit POST
|
|
683
|
+
// /poller/start, or polling goes quiet for STOP_QUIET_MS (the old loop died)
|
|
684
|
+
// and a new poll arrives — only then is it a genuinely fresh session.
|
|
685
|
+
// A pending job always wins so we never drop real work on the edge.
|
|
666
686
|
if (pollerStopped && !nextPendingLlm()) {
|
|
667
|
-
|
|
687
|
+
if (lastStoppedPollAt && now() - lastStoppedPollAt >= STOP_QUIET_MS) {
|
|
688
|
+
// Quiet gap → the previous loop is gone. This poll is a fresh session.
|
|
689
|
+
pollerStopped = false;
|
|
690
|
+
lastStoppedPollAt = 0;
|
|
691
|
+
// fall through to normal handling below (counts as live again)
|
|
692
|
+
} else {
|
|
693
|
+
lastStoppedPollAt = now(); // a poller is still hammering us → hold the latch
|
|
694
|
+
return send(res, 200, { stop: true });
|
|
695
|
+
}
|
|
668
696
|
}
|
|
669
697
|
lastPollAt = now();
|
|
670
698
|
if (!lastJobAt) lastJobAt = now(); // seed idle window on the loop's first poll
|
|
@@ -672,7 +700,8 @@ const server = createServer(async (req, res) => {
|
|
|
672
700
|
// loop to exit. A pending job always wins so we never drop real work.
|
|
673
701
|
if ((stopRequested || (POLLER_IDLE_STOP_MS && now() - lastJobAt >= POLLER_IDLE_STOP_MS)) && !nextPendingLlm()) {
|
|
674
702
|
stopRequested = false;
|
|
675
|
-
pollerStopped = true; // latch until
|
|
703
|
+
pollerStopped = true; // latch until /poller/start or a quiet gap
|
|
704
|
+
lastStoppedPollAt = 0;
|
|
676
705
|
lastJobAt = 0;
|
|
677
706
|
lastPollAt = 0; // loop is exiting → report it inactive immediately on /health
|
|
678
707
|
return send(res, 200, { stop: true });
|
|
@@ -682,7 +711,8 @@ const server = createServer(async (req, res) => {
|
|
|
682
711
|
if (res.writableEnded) return;
|
|
683
712
|
if (stopRequested && !nextPendingLlm()) {
|
|
684
713
|
stopRequested = false;
|
|
685
|
-
pollerStopped = true; // latch until
|
|
714
|
+
pollerStopped = true; // latch until /poller/start or a quiet gap
|
|
715
|
+
lastStoppedPollAt = 0;
|
|
686
716
|
lastJobAt = 0;
|
|
687
717
|
lastPollAt = 0; // loop is exiting → report it inactive immediately on /health
|
|
688
718
|
return send(res, 200, { stop: true });
|
|
@@ -705,17 +735,19 @@ const server = createServer(async (req, res) => {
|
|
|
705
735
|
if (method === "POST" && path === "/poller/stop") {
|
|
706
736
|
const wasActive = now() - lastPollAt < POLLER_TTL_MS;
|
|
707
737
|
stopRequested = true;
|
|
708
|
-
pollerStopped = true; // latch: stays stopped until
|
|
738
|
+
pollerStopped = true; // latch: stays stopped until /poller/start or a quiet gap
|
|
739
|
+
lastStoppedPollAt = 0;
|
|
709
740
|
lastPollAt = 0; // report inactive immediately; a straggler poll won't revive it
|
|
710
741
|
return send(res, 200, { ok: true, stopping: wasActive });
|
|
711
742
|
}
|
|
712
743
|
|
|
713
744
|
// POST /poller/start — a fresh `/refine live` agent (or loop) announces itself
|
|
714
745
|
// and clears the Stop latch so its polls count as live again. Without this an
|
|
715
|
-
// explicit re-run
|
|
716
|
-
//
|
|
746
|
+
// explicit re-run would have to wait out the quiet window. Call it once at loop
|
|
747
|
+
// startup, before the first GET /jobs/next.
|
|
717
748
|
if (method === "POST" && path === "/poller/start") {
|
|
718
749
|
pollerStopped = false;
|
|
750
|
+
lastStoppedPollAt = 0;
|
|
719
751
|
stopRequested = false;
|
|
720
752
|
lastJobAt = now();
|
|
721
753
|
lastPollAt = now();
|