@trawlme/cli 1.18.6 → 1.18.7
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/dist/commands/scraps.d.ts +41 -1
- package/dist/commands/scraps.js +54 -6
- package/package.json +1 -1
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
export declare const scraps: Command;
|
|
3
3
|
/** The top-of-history snapshot pollRunProgress needs to identify which run
|
|
4
|
-
* it's watching — see captureBeforeRunState.
|
|
4
|
+
* it's watching — see captureBeforeRunState.
|
|
5
|
+
*
|
|
6
|
+
* #97 — `captured` discriminates WHY `id` is undefined: `true` means the GET
|
|
7
|
+
* succeeded and the scrap genuinely has no history yet (an honest "never
|
|
8
|
+
* run" signal pollRunProgress can trust immediately); `false` means the GET
|
|
9
|
+
* itself threw, so `id`/`alreadyInFlight` carry NO information at all — the
|
|
10
|
+
* scrap could easily have prior (possibly terminal) history that this
|
|
11
|
+
* lookup simply never saw. Before this field existed, both cases produced
|
|
12
|
+
* the identical `{id: undefined, alreadyInFlight: false}` shape, so
|
|
13
|
+
* pollRunProgress could not tell them apart (see its own #97 comment).
|
|
14
|
+
*/
|
|
5
15
|
interface BeforeRunState {
|
|
6
16
|
id?: string;
|
|
7
17
|
alreadyInFlight: boolean;
|
|
18
|
+
captured: boolean;
|
|
8
19
|
}
|
|
9
20
|
/**
|
|
10
21
|
* #91 P1 — replaces "await the run to completion, THEN open the activities
|
|
@@ -38,6 +49,35 @@ interface BeforeRunState {
|
|
|
38
49
|
* (the dedup case) — a same-id row that was already TERMINAL at capture is
|
|
39
50
|
* neither, and must not be latched onto as "done" (it's just the previous
|
|
40
51
|
* run, still sitting there until a genuinely new run supersedes it).
|
|
52
|
+
*
|
|
53
|
+
* #97 — capture-failed fallback. The dedup-race fix above assumes `before`
|
|
54
|
+
* is trustworthy. When `captureBeforeRunState`'s own GET threw,
|
|
55
|
+
* `before.id` is `undefined` — and that is INDISTINGUISHABLE from "the
|
|
56
|
+
* scrap has genuinely never run" (also `id: undefined`), which is exactly
|
|
57
|
+
* the case `isNewRun` above is designed to match on the very first row that
|
|
58
|
+
* ever appears. So on the very first poll, ANY pre-existing history row —
|
|
59
|
+
* even the STALE PREVIOUS run, already terminal — satisfied
|
|
60
|
+
* `last._id !== undefined` and got reported as "the run we just launched"
|
|
61
|
+
* finishing, when it was really just whatever ran before.
|
|
62
|
+
*
|
|
63
|
+
* Fix: `before.captured === false` defers trusting a baseline at all.
|
|
64
|
+
* Instead of comparing against the (unknown) `beforeId` from the start, the
|
|
65
|
+
* FIRST successful poll read is treated as the deferred capture itself —
|
|
66
|
+
* exactly what `captureBeforeRunState` would have returned had its GET
|
|
67
|
+
* succeeded — and only READS from that point on are compared against it,
|
|
68
|
+
* via the exact same `isNewRun` / `isDedupOntoInFlight` logic above. A
|
|
69
|
+
* pre-existing terminal row observed on that first read becomes `beforeId`
|
|
70
|
+
* (not a match for itself), so it correctly falls into "still the stale
|
|
71
|
+
* previous run" below and the poll keeps waiting; a row still in flight
|
|
72
|
+
* becomes the `alreadyInFlight` baseline, exactly like a successful capture
|
|
73
|
+
* would have recorded. Either way this costs at most one extra poll
|
|
74
|
+
* interval, bounded by the same deadline as everything else. The one
|
|
75
|
+
* remaining edge case — capture failed AND the scrap never ran before AND
|
|
76
|
+
* the triggered run already finished by the very first poll — is genuinely
|
|
77
|
+
* undecidable from "stale pre-existing row" with no more information than
|
|
78
|
+
* this function has, so it resolves to the same honest timeout rather than
|
|
79
|
+
* risk reporting a possibly-wrong outcome (never a lie, at worst a timeout
|
|
80
|
+
* telling the caller to check `doctor`).
|
|
41
81
|
*/
|
|
42
82
|
export declare function pollRunProgress(id: string, before: BeforeRunState | undefined, opts?: {
|
|
43
83
|
intervalMs?: number;
|
package/dist/commands/scraps.js
CHANGED
|
@@ -96,17 +96,21 @@ async function watchActivities(id) {
|
|
|
96
96
|
* recognize that dedup case too, instead of waiting forever for an `_id`
|
|
97
97
|
* that will never arrive (#93 item 1).
|
|
98
98
|
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
99
|
+
* #97 — a failed lookup used to fall back to `{alreadyInFlight:false}` with
|
|
100
|
+
* no `id`, which LOOKED identical to "scrap has never run" — but is not:
|
|
101
|
+
* the scrap may well have prior (possibly terminal) history this GET simply
|
|
102
|
+
* never observed. `captured:false` flags that distinction explicitly so
|
|
103
|
+
* pollRunProgress can defer trusting a baseline instead of risking a stale
|
|
104
|
+
* pre-existing row being reported as the run just launched.
|
|
101
105
|
*/
|
|
102
106
|
async function captureBeforeRunState(id) {
|
|
103
107
|
try {
|
|
104
108
|
const scrap = await api.get(`/api/scraps/${id}`);
|
|
105
109
|
const top = scrap.history?.[0];
|
|
106
|
-
return { id: top?._id, alreadyInFlight: top?.status === null };
|
|
110
|
+
return { id: top?._id, alreadyInFlight: top?.status === null, captured: true };
|
|
107
111
|
}
|
|
108
112
|
catch {
|
|
109
|
-
return { id: undefined, alreadyInFlight: false };
|
|
113
|
+
return { id: undefined, alreadyInFlight: false, captured: false };
|
|
110
114
|
}
|
|
111
115
|
}
|
|
112
116
|
function sleep(ms) {
|
|
@@ -148,12 +152,46 @@ const POLL_TIMEOUT_MS = LONG_RUN_TIMEOUT_MS;
|
|
|
148
152
|
* (the dedup case) — a same-id row that was already TERMINAL at capture is
|
|
149
153
|
* neither, and must not be latched onto as "done" (it's just the previous
|
|
150
154
|
* run, still sitting there until a genuinely new run supersedes it).
|
|
155
|
+
*
|
|
156
|
+
* #97 — capture-failed fallback. The dedup-race fix above assumes `before`
|
|
157
|
+
* is trustworthy. When `captureBeforeRunState`'s own GET threw,
|
|
158
|
+
* `before.id` is `undefined` — and that is INDISTINGUISHABLE from "the
|
|
159
|
+
* scrap has genuinely never run" (also `id: undefined`), which is exactly
|
|
160
|
+
* the case `isNewRun` above is designed to match on the very first row that
|
|
161
|
+
* ever appears. So on the very first poll, ANY pre-existing history row —
|
|
162
|
+
* even the STALE PREVIOUS run, already terminal — satisfied
|
|
163
|
+
* `last._id !== undefined` and got reported as "the run we just launched"
|
|
164
|
+
* finishing, when it was really just whatever ran before.
|
|
165
|
+
*
|
|
166
|
+
* Fix: `before.captured === false` defers trusting a baseline at all.
|
|
167
|
+
* Instead of comparing against the (unknown) `beforeId` from the start, the
|
|
168
|
+
* FIRST successful poll read is treated as the deferred capture itself —
|
|
169
|
+
* exactly what `captureBeforeRunState` would have returned had its GET
|
|
170
|
+
* succeeded — and only READS from that point on are compared against it,
|
|
171
|
+
* via the exact same `isNewRun` / `isDedupOntoInFlight` logic above. A
|
|
172
|
+
* pre-existing terminal row observed on that first read becomes `beforeId`
|
|
173
|
+
* (not a match for itself), so it correctly falls into "still the stale
|
|
174
|
+
* previous run" below and the poll keeps waiting; a row still in flight
|
|
175
|
+
* becomes the `alreadyInFlight` baseline, exactly like a successful capture
|
|
176
|
+
* would have recorded. Either way this costs at most one extra poll
|
|
177
|
+
* interval, bounded by the same deadline as everything else. The one
|
|
178
|
+
* remaining edge case — capture failed AND the scrap never ran before AND
|
|
179
|
+
* the triggered run already finished by the very first poll — is genuinely
|
|
180
|
+
* undecidable from "stale pre-existing row" with no more information than
|
|
181
|
+
* this function has, so it resolves to the same honest timeout rather than
|
|
182
|
+
* risk reporting a possibly-wrong outcome (never a lie, at worst a timeout
|
|
183
|
+
* telling the caller to check `doctor`).
|
|
151
184
|
*/
|
|
152
185
|
export async function pollRunProgress(id, before, opts = {}) {
|
|
153
186
|
const intervalMs = opts.intervalMs ?? POLL_INTERVAL_MS;
|
|
154
187
|
const timeoutMs = opts.timeoutMs ?? POLL_TIMEOUT_MS;
|
|
155
|
-
|
|
156
|
-
|
|
188
|
+
let beforeId = before?.id;
|
|
189
|
+
let beforeAlreadyInFlight = before?.alreadyInFlight ?? false;
|
|
190
|
+
// #97 — only an EXPLICIT captured:false (capture's GET actually threw)
|
|
191
|
+
// defers the baseline. `before` itself being undefined (callers that skip
|
|
192
|
+
// capture entirely) or `captured` being true/absent both mean "trust
|
|
193
|
+
// beforeId as given", preserving every existing call site's behavior.
|
|
194
|
+
let baselineEstablished = before?.captured ?? true;
|
|
157
195
|
console.log(chalk.dim('Live activity streaming has no signal for this run (async/cross-pod) — polling for progress instead…\n'));
|
|
158
196
|
const deadline = Date.now() + timeoutMs;
|
|
159
197
|
const seen = new Set();
|
|
@@ -172,6 +210,16 @@ export async function pollRunProgress(id, before, opts = {}) {
|
|
|
172
210
|
const last = scrap.history?.[0];
|
|
173
211
|
if (!last?._id)
|
|
174
212
|
continue; // no history row recorded yet
|
|
213
|
+
if (!baselineEstablished) {
|
|
214
|
+
// #97 — deferred capture: whatever we see on this first successful
|
|
215
|
+
// read becomes the reference point, BEFORE the isNewRun check below
|
|
216
|
+
// ever runs against it. This must happen before that check, not
|
|
217
|
+
// after, so a pre-existing terminal row is recognized as stale on
|
|
218
|
+
// this very same iteration rather than one poll late.
|
|
219
|
+
beforeId = last._id;
|
|
220
|
+
beforeAlreadyInFlight = last.status === null;
|
|
221
|
+
baselineEstablished = true;
|
|
222
|
+
}
|
|
175
223
|
const isNewRun = last._id !== beforeId;
|
|
176
224
|
const isDedupOntoInFlight = last._id === beforeId && beforeAlreadyInFlight;
|
|
177
225
|
if (!isNewRun && !isDedupOntoInFlight)
|