@relayflows/sdk 2.0.31 → 2.0.32
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/authored-preflight.d.ts +4 -0
- package/dist/authored-preflight.d.ts.map +1 -0
- package/dist/authored-preflight.js +50 -0
- package/dist/authored-preflight.js.map +1 -0
- package/dist/authored-worker-step.d.ts.map +1 -1
- package/dist/authored-worker-step.js +3 -2
- package/dist/authored-worker-step.js.map +1 -1
- package/dist/cli/check.d.ts +10 -2
- package/dist/cli/check.d.ts.map +1 -1
- package/dist/cli/check.js +16 -137
- package/dist/cli/check.js.map +1 -1
- package/dist/cli/cli-probe.d.ts +20 -0
- package/dist/cli/cli-probe.d.ts.map +1 -0
- package/dist/cli/cli-probe.js +166 -0
- package/dist/cli/cli-probe.js.map +1 -0
- package/dist/cli/cloud-mirror-session.d.ts +97 -0
- package/dist/cli/cloud-mirror-session.d.ts.map +1 -0
- package/dist/cli/cloud-mirror-session.js +264 -0
- package/dist/cli/cloud-mirror-session.js.map +1 -0
- package/dist/cli-commands.d.ts +6 -0
- package/dist/cli-commands.d.ts.map +1 -1
- package/dist/cli-commands.js +1 -0
- package/dist/cli-commands.js.map +1 -1
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +84 -18
- package/dist/cli.js.map +1 -1
- package/dist/cloud-deploy.d.ts +1 -1
- package/dist/cloud-deploy.d.ts.map +1 -1
- package/dist/cloud-deploy.js +24 -8
- package/dist/cloud-deploy.js.map +1 -1
- package/dist/cloud-mirror-ledger.d.ts +40 -0
- package/dist/cloud-mirror-ledger.d.ts.map +1 -0
- package/dist/cloud-mirror-ledger.js +142 -0
- package/dist/cloud-mirror-ledger.js.map +1 -0
- package/dist/cloud-mirror-step.d.ts +168 -0
- package/dist/cloud-mirror-step.d.ts.map +1 -0
- package/dist/cloud-mirror-step.js +504 -0
- package/dist/cloud-mirror-step.js.map +1 -0
- package/dist/cloud-mirror-transport.d.ts +94 -0
- package/dist/cloud-mirror-transport.d.ts.map +1 -0
- package/dist/cloud-mirror-transport.js +163 -0
- package/dist/cloud-mirror-transport.js.map +1 -0
- package/dist/cloud-mirror.d.ts +132 -0
- package/dist/cloud-mirror.d.ts.map +1 -0
- package/dist/cloud-mirror.js +556 -0
- package/dist/cloud-mirror.js.map +1 -0
- package/dist/hosted-extension-runtime.js +1 -1
- package/dist/package-version.d.ts +10 -0
- package/dist/package-version.d.ts.map +1 -0
- package/dist/package-version.js +22 -0
- package/dist/package-version.js.map +1 -0
- package/dist/preflight.d.ts +14 -0
- package/dist/preflight.d.ts.map +1 -1
- package/dist/preflight.js +18 -3
- package/dist/preflight.js.map +1 -1
- package/dist/relay-cli.d.ts.map +1 -1
- package/dist/relay-cli.js +1 -21
- package/dist/relay-cli.js.map +1 -1
- package/package.json +2 -2
- package/src/authored-preflight.ts +46 -0
- package/src/authored-worker-step.ts +4 -3
- package/src/cli/check.ts +25 -163
- package/src/cli/cli-probe.ts +194 -0
- package/src/cli/cloud-mirror-session.ts +329 -0
- package/src/cli-commands.ts +1 -0
- package/src/cli.ts +94 -19
- package/src/cloud-deploy.ts +26 -8
- package/src/cloud-mirror-ledger.ts +161 -0
- package/src/cloud-mirror-step.ts +618 -0
- package/src/cloud-mirror-transport.ts +261 -0
- package/src/cloud-mirror.ts +633 -0
- package/src/hosted-extension-runtime.ts +1 -1
- package/src/package-version.ts +23 -0
- package/src/preflight.ts +31 -7
- package/src/relay-cli.ts +1 -24
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
// Mirroring a local run onto the Cloud dashboard, while it runs.
|
|
2
|
+
//
|
|
3
|
+
// A hosted run is watchable because something inside the sandbox reads its
|
|
4
|
+
// journal every few seconds and pushes what it finds. Nothing did that for a
|
|
5
|
+
// run started in a terminal, so a local run was invisible: the same flow, the
|
|
6
|
+
// same journal, the same evidence, and no page to look at. This is that
|
|
7
|
+
// reader, on the other side of the boundary.
|
|
8
|
+
//
|
|
9
|
+
// ## What it reads
|
|
10
|
+
//
|
|
11
|
+
// Only this run's journals. The sandbox reporter scans its whole data
|
|
12
|
+
// directory because a sandbox holds exactly one run; a developer's
|
|
13
|
+
// `~/.relayflowd` holds every run they have ever started, including other
|
|
14
|
+
// people's work in a shared checkout. So the set of journals is *derived*: the
|
|
15
|
+
// root, plus the child journals the root's own authored-step index names. A
|
|
16
|
+
// journal this run did not create is never opened, let alone uploaded.
|
|
17
|
+
//
|
|
18
|
+
// ## What it costs a run
|
|
19
|
+
//
|
|
20
|
+
// Nothing that can fail the run. Every push collapses to a boolean at the
|
|
21
|
+
// transport (`cloud-mirror-transport.ts`), each poll is bounded by its own
|
|
22
|
+
// deadline, and a poll that overruns is abandoned rather than allowed to grow
|
|
23
|
+
// with the flow. A journal that cannot be read keeps the previously cached
|
|
24
|
+
// view for that journal: a snapshot never gets emptier because a read failed.
|
|
25
|
+
//
|
|
26
|
+
// ## Ordering at the end
|
|
27
|
+
//
|
|
28
|
+
// The terminal callback is last, and that is load-bearing. Cloud revokes the
|
|
29
|
+
// run's credential when the run goes terminal, so the transcripts and the
|
|
30
|
+
// final step rows have to land before it — otherwise the mirror would report
|
|
31
|
+
// the run finished and then find itself unable to say what it did.
|
|
32
|
+
import { open, readFile, stat } from 'node:fs/promises';
|
|
33
|
+
import { isAbsolute, join, relative as relative_, resolve } from 'node:path';
|
|
34
|
+
import { walkJournal, JournalReadError } from './journal-reader.js';
|
|
35
|
+
import { fitSnapshot, mirrorJournal, withGraphHints, DEPENDS_ON_MAX_ENTRIES, SNAPSHOT_DEPENDS_ON_MAX, MAX_INT32, } from './cloud-mirror-step.js';
|
|
36
|
+
import { redact } from './redact.js';
|
|
37
|
+
/** How often the journals are re-read. The sandbox reporter's own cadence. */
|
|
38
|
+
export const MIRROR_POLL_INTERVAL_MS = 10_000;
|
|
39
|
+
/** Whole-poll budget, independent of how many journals exist. */
|
|
40
|
+
export const MIRROR_POLL_BUDGET_MS = 8_000;
|
|
41
|
+
/** Budget for the final poll and every push that follows it. */
|
|
42
|
+
export const MIRROR_FINISH_BUDGET_MS = 30_000;
|
|
43
|
+
/** Republish an unchanged view this often, so a stalled view still looks fresh. */
|
|
44
|
+
export const MIRROR_SNAPSHOT_HEARTBEAT_MS = 120_000;
|
|
45
|
+
/** Final step rows one report carries; the rest are counted, not sent. */
|
|
46
|
+
export const MIRROR_MAX_FINAL_STEPS = 256;
|
|
47
|
+
/** Step views held across polls. Bounds the mirror, not the run. */
|
|
48
|
+
export const MIRROR_STEP_CACHE_MAX = 512;
|
|
49
|
+
/** Assembled `<stepName>/agent.log` cap, as the hosted executor uses. */
|
|
50
|
+
export const MIRROR_TRANSCRIPT_MAX_BYTES = 1024 * 1024;
|
|
51
|
+
/** Steps whose transcripts are uploaded. Beyond this the rows still land. */
|
|
52
|
+
export const MIRROR_MAX_TRANSCRIPT_UPLOADS = 64;
|
|
53
|
+
/** The run's own `runner.log`, as the `/logs` route serves it. */
|
|
54
|
+
export const MIRROR_RUNNER_LOG_MAX_BYTES = 256 * 1024;
|
|
55
|
+
/**
|
|
56
|
+
* Re-reads of a journal a writer was mid-flight in, and the wait between.
|
|
57
|
+
*
|
|
58
|
+
* `walkJournal` copies the file and refuses a torn snapshot as `journal_busy`,
|
|
59
|
+
* which on a *live* run is the ordinary case, not a fault — `flows status`
|
|
60
|
+
* has always retried it for exactly that reason. Without the same policy the
|
|
61
|
+
* mirror simply skipped a busy journal: a resume could not read the spec it
|
|
62
|
+
* was about to register, so it registered nothing at all and the run stayed
|
|
63
|
+
* off the dashboard.
|
|
64
|
+
*/
|
|
65
|
+
export const MIRROR_BUSY_RETRIES = 5;
|
|
66
|
+
export const MIRROR_BUSY_DELAY_MS = 50;
|
|
67
|
+
/** Journals one mirror will follow: the root, plus the children it admitted. */
|
|
68
|
+
export const MIRROR_MAX_JOURNALS = 4096;
|
|
69
|
+
/**
|
|
70
|
+
* One consistent read of a journal, retrying only the mid-write case.
|
|
71
|
+
*
|
|
72
|
+
* Shared by the poller and by the resume path that reads a run's spec, so
|
|
73
|
+
* both treat a writer being mid-flight the way `flows status` does. Every
|
|
74
|
+
* other failure propagates unchanged: a corrupt journal is not a busy one.
|
|
75
|
+
*/
|
|
76
|
+
export async function readJournalEvents(runId, dataDir, sleep = ms => new Promise(done => { setTimeout(done, ms); })) {
|
|
77
|
+
for (let attempt = 1;; attempt += 1) {
|
|
78
|
+
try {
|
|
79
|
+
const events = [];
|
|
80
|
+
for await (const event of walkJournal(runId, dataDir))
|
|
81
|
+
events.push(event);
|
|
82
|
+
return events;
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
const busy = error instanceof JournalReadError && error.code === 'journal_busy';
|
|
86
|
+
if (!busy || attempt >= MIRROR_BUSY_RETRIES)
|
|
87
|
+
throw error;
|
|
88
|
+
await sleep(MIRROR_BUSY_DELAY_MS);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Where a transcript for `runId` is allowed to live: under this data
|
|
94
|
+
* directory's own tree for that run, and nowhere else.
|
|
95
|
+
*
|
|
96
|
+
* The path comes out of the journal, which the worker wrote — so it is not
|
|
97
|
+
* hostile input in the ordinary case. But a journal is a file on a developer's
|
|
98
|
+
* disk, this reader uploads whatever it is handed, and "reads only this run's
|
|
99
|
+
* journals" has to mean the files too. An unconfined path turns a crafted or
|
|
100
|
+
* corrupted journal into an arbitrary-file upload, which is a much worse
|
|
101
|
+
* failure than a missing transcript.
|
|
102
|
+
*/
|
|
103
|
+
export function transcriptRoot(dataDir, runId) {
|
|
104
|
+
return join(resolve(dataDir), 'runs', runId);
|
|
105
|
+
}
|
|
106
|
+
/** True when `path` resolves inside `root` — a prefix test that `..` cannot pass. */
|
|
107
|
+
export function withinRoot(root, path) {
|
|
108
|
+
const relative = relative_(root, resolve(path));
|
|
109
|
+
return relative.length > 0 && !relative.startsWith('..') && !isAbsolute(relative);
|
|
110
|
+
}
|
|
111
|
+
async function defaultReadTranscript(path) {
|
|
112
|
+
const info = await stat(path);
|
|
113
|
+
if (!info.isFile())
|
|
114
|
+
throw new Error('transcript is not a regular file');
|
|
115
|
+
// Bound the read, not just the result: materializing a huge file only to
|
|
116
|
+
// discard all but the tail can exhaust the CLI before it reports at all.
|
|
117
|
+
if (info.size <= MIRROR_TRANSCRIPT_MAX_BYTES) {
|
|
118
|
+
return { bytes: await readFile(path), size: info.size };
|
|
119
|
+
}
|
|
120
|
+
const handle = await open(path, 'r');
|
|
121
|
+
try {
|
|
122
|
+
const buffer = Buffer.alloc(MIRROR_TRANSCRIPT_MAX_BYTES);
|
|
123
|
+
const { bytesRead } = await handle.read(buffer, 0, MIRROR_TRANSCRIPT_MAX_BYTES, info.size - MIRROR_TRANSCRIPT_MAX_BYTES);
|
|
124
|
+
return { bytes: buffer.subarray(0, bytesRead), size: info.size };
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
await handle.close();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Assemble one step's attempts into the single object `/logs` serves.
|
|
132
|
+
*
|
|
133
|
+
* The frame vocabulary is Cloud's: each kept attempt is preceded by a
|
|
134
|
+
* `relayflow.attempt` marker and a dropped one leaves a
|
|
135
|
+
* `relayflow.attempt.omitted` marker in its place, so the dashboard's renderer
|
|
136
|
+
* and `flows logs --step` read a mirrored transcript exactly as they read a
|
|
137
|
+
* hosted one. A reader that sees fewer attempts than ran has been lied to.
|
|
138
|
+
*/
|
|
139
|
+
export async function assembleTranscript(attempts, read, maxBytes = MIRROR_TRANSCRIPT_MAX_BYTES) {
|
|
140
|
+
const ordered = [...attempts].sort((left, right) => left.attempt - right.attempt);
|
|
141
|
+
const marker = (value) => Buffer.from(`${JSON.stringify(value)}\n`, 'utf8');
|
|
142
|
+
const parts = [];
|
|
143
|
+
let total = 0;
|
|
144
|
+
let kept = 0;
|
|
145
|
+
let omitted = 0;
|
|
146
|
+
let truncated = false;
|
|
147
|
+
// Newest first: the last attempt is what the run's outcome rests on.
|
|
148
|
+
for (let index = ordered.length - 1; index >= 0; index -= 1) {
|
|
149
|
+
const { attempt, path } = ordered[index];
|
|
150
|
+
let read_;
|
|
151
|
+
try {
|
|
152
|
+
read_ = await read(path);
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
// A missing attempt file is still an attempt that happened.
|
|
156
|
+
parts.unshift(marker({ type: 'relayflow.attempt.omitted', attempt, bytes: 0 }));
|
|
157
|
+
total += parts[0].length;
|
|
158
|
+
omitted += 1;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const reserve = 128 * (index + 1);
|
|
162
|
+
if (kept > 0 && read_.bytes.length > maxBytes - total - reserve) {
|
|
163
|
+
parts.unshift(marker({ type: 'relayflow.attempt.omitted', attempt, bytes: read_.size }));
|
|
164
|
+
total += parts[0].length;
|
|
165
|
+
omitted += 1;
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
let content = read_.bytes;
|
|
169
|
+
let cut = read_.size > content.length;
|
|
170
|
+
const cap = maxBytes - reserve;
|
|
171
|
+
if (content.length > cap) {
|
|
172
|
+
content = content.subarray(content.length - cap);
|
|
173
|
+
cut = true;
|
|
174
|
+
}
|
|
175
|
+
if (cut) {
|
|
176
|
+
// A tail cut lands mid-frame and this object is parsed as JSONL: open on
|
|
177
|
+
// the first WHOLE frame rather than a broken one. A file with no newline
|
|
178
|
+
// is one frame, so there is nothing to snap to and it is left as it is.
|
|
179
|
+
const firstFrame = content.indexOf(0x0a);
|
|
180
|
+
if (firstFrame >= 0 && firstFrame + 1 < content.length)
|
|
181
|
+
content = content.subarray(firstFrame + 1);
|
|
182
|
+
truncated = true;
|
|
183
|
+
}
|
|
184
|
+
const head = marker({ type: 'relayflow.attempt', attempt, bytes: content.length, truncated: cut });
|
|
185
|
+
const body = content.length > 0 && content[content.length - 1] !== 0x0a
|
|
186
|
+
? Buffer.concat([content, Buffer.from('\n')])
|
|
187
|
+
: content;
|
|
188
|
+
parts.unshift(head, body);
|
|
189
|
+
total += head.length + body.length;
|
|
190
|
+
kept += 1;
|
|
191
|
+
}
|
|
192
|
+
return { bytes: Buffer.concat(parts), kept, omitted, truncated };
|
|
193
|
+
}
|
|
194
|
+
export function createRunMirror(options) {
|
|
195
|
+
const env = options.env ?? process.env;
|
|
196
|
+
const now = options.now ?? Date.now;
|
|
197
|
+
const intervalMs = options.intervalMs ?? MIRROR_POLL_INTERVAL_MS;
|
|
198
|
+
const pollBudgetMs = options.pollBudgetMs ?? MIRROR_POLL_BUDGET_MS;
|
|
199
|
+
const heartbeatMs = options.snapshotHeartbeatMs ?? MIRROR_SNAPSHOT_HEARTBEAT_MS;
|
|
200
|
+
const readJournal = options.readJournal ?? readJournalEvents;
|
|
201
|
+
const readTranscript = options.readTranscript ?? defaultReadTranscript;
|
|
202
|
+
const diagnostic = options.diagnostic ?? (() => { });
|
|
203
|
+
/** The journals this run owns: the root, and every child its index names. */
|
|
204
|
+
const journals = [];
|
|
205
|
+
const known = new Set();
|
|
206
|
+
const finished = new Set();
|
|
207
|
+
const steps = new Map();
|
|
208
|
+
/** Final rows by `<journal>/<step>`, so two journals cannot collide on a step id. */
|
|
209
|
+
const finals = new Map();
|
|
210
|
+
const transcripts = new Map();
|
|
211
|
+
const hints = new Map();
|
|
212
|
+
/** Live steps the cache cap dropped, by identity, so a capped view owns up to it. */
|
|
213
|
+
const evicted = new Set();
|
|
214
|
+
/** Finished steps past the report cap, by identity. Counted, never sent. */
|
|
215
|
+
const unreported = new Set();
|
|
216
|
+
let timer;
|
|
217
|
+
/**
|
|
218
|
+
* The poll currently running, if one is. `clearInterval` stops future polls
|
|
219
|
+
* but not one already in flight: that poll shares the step cache and the
|
|
220
|
+
* sequence counter with `finish`, and Cloud revokes the run token at the
|
|
221
|
+
* terminal callback — so a poll that outlived the finish could publish a
|
|
222
|
+
* stale view it can never repair, or none at all.
|
|
223
|
+
*/
|
|
224
|
+
let inFlight;
|
|
225
|
+
let stopped = false;
|
|
226
|
+
/** Set immediately before the terminal callback; nothing may publish after it. */
|
|
227
|
+
let terminalReported = false;
|
|
228
|
+
let sequence = 0;
|
|
229
|
+
let acknowledged;
|
|
230
|
+
let acknowledgedAt = now();
|
|
231
|
+
const admit = (runId) => {
|
|
232
|
+
// Far above any real authored run, and a bound all the same: the child
|
|
233
|
+
// list comes out of a journal, and a reader of a journal bounds what it
|
|
234
|
+
// will grow to hold.
|
|
235
|
+
if (known.has(runId) || journals.length >= MIRROR_MAX_JOURNALS)
|
|
236
|
+
return;
|
|
237
|
+
known.add(runId);
|
|
238
|
+
journals.push(runId);
|
|
239
|
+
};
|
|
240
|
+
const remember = (journalRunId, step, order) => {
|
|
241
|
+
const key = `${journalRunId}/${step.stepName}`;
|
|
242
|
+
const existing = steps.get(key);
|
|
243
|
+
const changed = existing === undefined || fingerprint(existing.step) !== fingerprint(step);
|
|
244
|
+
steps.set(key, { step, order, changedAt: changed ? now() : existing.changedAt });
|
|
245
|
+
evicted.delete(key);
|
|
246
|
+
while (steps.size > MIRROR_STEP_CACHE_MAX) {
|
|
247
|
+
// Evict the least recently changed *completed* step first: the live work
|
|
248
|
+
// is the whole point of a live view.
|
|
249
|
+
const victim = [...steps.entries()].sort(comparePriority).pop();
|
|
250
|
+
if (victim === undefined)
|
|
251
|
+
break;
|
|
252
|
+
steps.delete(victim[0]);
|
|
253
|
+
evicted.add(victim[0]);
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
const scan = async (deadline) => {
|
|
257
|
+
// Index-based, over the live array: a child journal the root's index names
|
|
258
|
+
// is appended during this very pass, and a run whose only steps are its
|
|
259
|
+
// children would otherwise publish nothing until the next poll — which for
|
|
260
|
+
// a short run is never, because `finish` scans once.
|
|
261
|
+
for (let index = 0; index < journals.length; index += 1) {
|
|
262
|
+
const runId = journals[index];
|
|
263
|
+
if (now() > deadline)
|
|
264
|
+
break;
|
|
265
|
+
if (finished.has(runId))
|
|
266
|
+
continue;
|
|
267
|
+
let events;
|
|
268
|
+
try {
|
|
269
|
+
events = await readJournal(runId, options.dataDir);
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
// Two ordinary conditions, neither worth a line on someone's terminal
|
|
273
|
+
// once a poll: `run_not_found`, because a child journal is named in
|
|
274
|
+
// the index the moment its step is admitted and that can precede the
|
|
275
|
+
// file; and `journal_busy` past its retries, because a hot journal is
|
|
276
|
+
// what a running flow looks like. Both keep the cached view.
|
|
277
|
+
const ordinary = error instanceof JournalReadError
|
|
278
|
+
&& (error.code === 'run_not_found' || error.code === 'journal_busy');
|
|
279
|
+
if (!ordinary) {
|
|
280
|
+
diagnostic(`could not read journal ${runId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
281
|
+
}
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
let folded;
|
|
285
|
+
try {
|
|
286
|
+
folded = mirrorJournal(runId, events, now(), env);
|
|
287
|
+
}
|
|
288
|
+
catch (error) {
|
|
289
|
+
diagnostic(`could not fold journal ${runId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
for (const child of folded.children)
|
|
293
|
+
admit(child);
|
|
294
|
+
for (const [key, hint] of folded.hints) {
|
|
295
|
+
// Merge, never replace: a completion record can omit a label or an
|
|
296
|
+
// edge the admission carried, and the view must not lose a step's
|
|
297
|
+
// name between them.
|
|
298
|
+
const existing = hints.get(key);
|
|
299
|
+
hints.set(key, {
|
|
300
|
+
...(hint.label ?? existing?.label ? { label: hint.label ?? existing?.label } : {}),
|
|
301
|
+
...(hint.after ?? existing?.after ? { after: hint.after ?? existing?.after } : {}),
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
folded.steps.forEach((step, order) => remember(runId, step, order));
|
|
305
|
+
for (const row of folded.finals) {
|
|
306
|
+
const key = `${runId}/${row.stepName}`;
|
|
307
|
+
// The report cap bounds what this process holds, not just what it
|
|
308
|
+
// sends: a run with ten thousand steps must not grow its own mirror.
|
|
309
|
+
// Steps past it are counted by identity, so a step read twice is one
|
|
310
|
+
// missing step and not two.
|
|
311
|
+
if (!finals.has(key) && finals.size >= MIRROR_MAX_FINAL_STEPS) {
|
|
312
|
+
unreported.add(key);
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
finals.set(key, { journalRunId: runId, row });
|
|
316
|
+
}
|
|
317
|
+
for (const ref of folded.transcripts) {
|
|
318
|
+
if (!finals.has(`${runId}/${ref.stepName}`))
|
|
319
|
+
continue;
|
|
320
|
+
// Only files under this run's own tree. A journal names its transcript
|
|
321
|
+
// paths, and this reader uploads what it is handed, so the confinement
|
|
322
|
+
// belongs here rather than in the reader's caller.
|
|
323
|
+
const root = transcriptRoot(options.dataDir, runId);
|
|
324
|
+
const attempts = ref.attempts.filter(attempt => withinRoot(root, attempt.path));
|
|
325
|
+
if (attempts.length < ref.attempts.length) {
|
|
326
|
+
diagnostic(`ignored ${ref.attempts.length - attempts.length} transcript path(s) outside ${runId}'s own tree`);
|
|
327
|
+
}
|
|
328
|
+
if (attempts.length === 0)
|
|
329
|
+
continue;
|
|
330
|
+
transcripts.set(`${runId}/${ref.stepName}`, { stepName: ref.stepName, attempts });
|
|
331
|
+
}
|
|
332
|
+
if (folded.terminal)
|
|
333
|
+
finished.add(runId);
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
/** The cached view in display order: journal order, journal by journal. */
|
|
337
|
+
const ordered = () => {
|
|
338
|
+
const names = new Set([...steps.values()].map(entry => entry.step.stepName));
|
|
339
|
+
return [...steps.entries()]
|
|
340
|
+
.sort(([leftKey, left], [rightKey, right]) => {
|
|
341
|
+
const journal = leftKey.split('/')[0].localeCompare(rightKey.split('/')[0]);
|
|
342
|
+
return journal !== 0 ? journal : left.order - right.order;
|
|
343
|
+
})
|
|
344
|
+
.map(([, entry]) => withGraphHints(entry.step, hints, entry.step.journalRunId, SNAPSHOT_DEPENDS_ON_MAX, names));
|
|
345
|
+
};
|
|
346
|
+
const publishSnapshot = async (deadline) => {
|
|
347
|
+
// The invariant is narrow and exact: nothing publishes after the terminal
|
|
348
|
+
// callback, which revokes the credential and must be last. `finish` stops
|
|
349
|
+
// *waiting* for an in-flight poll once its deadline passes, so that poll can
|
|
350
|
+
// still be running when the callback goes out — and a view arriving then is
|
|
351
|
+
// worse than a missing one, because the final rows have already replaced it.
|
|
352
|
+
//
|
|
353
|
+
// Deliberately not gated on "finish has begun": finish takes its own last
|
|
354
|
+
// reading first, and that is the snapshot showing the run's final moments.
|
|
355
|
+
if (terminalReported)
|
|
356
|
+
return;
|
|
357
|
+
const view = ordered();
|
|
358
|
+
if (view.length === 0)
|
|
359
|
+
return;
|
|
360
|
+
// `elapsedMs` moves every poll and is excluded from the comparison, or the
|
|
361
|
+
// throttle would degenerate into "push every interval".
|
|
362
|
+
const print = view.map(fingerprint).join('|');
|
|
363
|
+
if (print === acknowledged && now() - acknowledgedAt < heartbeatMs)
|
|
364
|
+
return;
|
|
365
|
+
sequence += 1;
|
|
366
|
+
const snapshot = fitSnapshot(view, {
|
|
367
|
+
sequence,
|
|
368
|
+
capturedAt: new Date(now()).toISOString(),
|
|
369
|
+
alreadyOmitted: evicted.size,
|
|
370
|
+
});
|
|
371
|
+
const budget = deadline - now();
|
|
372
|
+
if (budget <= 0)
|
|
373
|
+
return;
|
|
374
|
+
if (await options.client.publishSnapshot(snapshot, { timeoutMs: budget })) {
|
|
375
|
+
acknowledged = print;
|
|
376
|
+
acknowledgedAt = now();
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
const poll = async (budgetMs) => {
|
|
380
|
+
if (inFlight !== undefined || stopped)
|
|
381
|
+
return;
|
|
382
|
+
let settle = () => { };
|
|
383
|
+
inFlight = new Promise(done => { settle = done; });
|
|
384
|
+
try {
|
|
385
|
+
const deadline = now() + budgetMs;
|
|
386
|
+
await scan(deadline);
|
|
387
|
+
// Finish takes its own reading; a poll racing it adds nothing.
|
|
388
|
+
if (!stopped)
|
|
389
|
+
await publishSnapshot(deadline);
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
diagnostic(`poll failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
393
|
+
}
|
|
394
|
+
finally {
|
|
395
|
+
const done = inFlight;
|
|
396
|
+
inFlight = undefined;
|
|
397
|
+
settle();
|
|
398
|
+
void done;
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
/**
|
|
402
|
+
* The budget left, as a per-request timeout.
|
|
403
|
+
*
|
|
404
|
+
* `finish` had a deadline it only checked *between* phases, while every
|
|
405
|
+
* request underneath carried its own 30-second timeout — so a stalled Cloud
|
|
406
|
+
* could hold a finished local run open for minutes, and the CLI awaits this
|
|
407
|
+
* before returning the run's exit code. Handing each request the remaining
|
|
408
|
+
* budget makes the deadline mean what it says.
|
|
409
|
+
*/
|
|
410
|
+
const remaining = (deadline) => Math.max(1, deadline - now());
|
|
411
|
+
/**
|
|
412
|
+
* The object name for one step's transcript, unique across journals.
|
|
413
|
+
*
|
|
414
|
+
* The caches here are keyed `<journal>/<step>` precisely because child
|
|
415
|
+
* journals can repeat a kernel step id — and then the object key and the
|
|
416
|
+
* row's `sandboxId` used only the step id, so two steps overwrote each
|
|
417
|
+
* other's log and the run page showed one step's transcript for both.
|
|
418
|
+
*
|
|
419
|
+
* Only a genuine collision is disambiguated. The common run has one journal
|
|
420
|
+
* per step, and keeping the bare step id there means a mirrored transcript is
|
|
421
|
+
* named exactly as a hosted one is.
|
|
422
|
+
*/
|
|
423
|
+
const transcriptName = (journalRunId, stepName) => {
|
|
424
|
+
const repeated = [...finals.keys()].filter(key => key.endsWith(`/${stepName}`)).length > 1;
|
|
425
|
+
return repeated ? `${journalRunId}.${stepName}` : stepName;
|
|
426
|
+
};
|
|
427
|
+
const uploadTranscripts = async (deadline) => {
|
|
428
|
+
let uploaded = 0;
|
|
429
|
+
for (const [key, ref] of transcripts) {
|
|
430
|
+
if (uploaded >= MIRROR_MAX_TRANSCRIPT_UPLOADS || now() > deadline)
|
|
431
|
+
break;
|
|
432
|
+
const entry = finals.get(key);
|
|
433
|
+
if (entry === undefined)
|
|
434
|
+
continue;
|
|
435
|
+
const objectName = transcriptName(entry.journalRunId, ref.stepName);
|
|
436
|
+
let assembled;
|
|
437
|
+
try {
|
|
438
|
+
assembled = await assembleTranscript(ref.attempts, readTranscript);
|
|
439
|
+
}
|
|
440
|
+
catch (error) {
|
|
441
|
+
diagnostic(`could not assemble the transcript for ${ref.stepName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
if (assembled.bytes.length === 0)
|
|
445
|
+
continue;
|
|
446
|
+
// Name the row after the object only once the object is there, so no row
|
|
447
|
+
// ever points at a transcript that was never written.
|
|
448
|
+
if (await options.client.putObject(`${objectName}/agent.log`, assembled.bytes, undefined, remaining(deadline))) {
|
|
449
|
+
finals.set(key, { ...entry, row: { ...entry.row, sandboxId: objectName } });
|
|
450
|
+
uploaded += 1;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
const publishFinal = async (deadline) => {
|
|
455
|
+
const sent = [...finals.values()];
|
|
456
|
+
// A capped report says how many steps it left out. A run page that shows
|
|
457
|
+
// 256 of 400 steps without saying so is worse than one that shows none.
|
|
458
|
+
const omitted = Math.min(unreported.size, MAX_INT32);
|
|
459
|
+
const names = new Set(sent.map(entry => entry.row.stepName));
|
|
460
|
+
const withGraph = sent.map(entry => withGraphHints(entry.row, hints, entry.journalRunId, DEPENDS_ON_MAX_ENTRIES, names));
|
|
461
|
+
if (now() > deadline)
|
|
462
|
+
return;
|
|
463
|
+
if (!await options.client.publishSteps(withGraph, omitted, undefined, remaining(deadline))) {
|
|
464
|
+
diagnostic('Cloud did not accept the final step report; the run page keeps its live view');
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
return {
|
|
468
|
+
get runId() { return options.client.runId; },
|
|
469
|
+
get runUrl() { return options.client.runUrl; },
|
|
470
|
+
start(rootRunId) {
|
|
471
|
+
admit(rootRunId);
|
|
472
|
+
if (timer !== undefined || stopped)
|
|
473
|
+
return;
|
|
474
|
+
timer = setInterval(() => { void poll(pollBudgetMs); }, intervalMs);
|
|
475
|
+
// Never hold the process open for an observation.
|
|
476
|
+
timer.unref?.();
|
|
477
|
+
},
|
|
478
|
+
event(event) {
|
|
479
|
+
void options.client.publishEvent(event);
|
|
480
|
+
},
|
|
481
|
+
async finish(outcome) {
|
|
482
|
+
if (timer !== undefined) {
|
|
483
|
+
clearInterval(timer);
|
|
484
|
+
timer = undefined;
|
|
485
|
+
}
|
|
486
|
+
const deadline = now() + MIRROR_FINISH_BUDGET_MS;
|
|
487
|
+
try {
|
|
488
|
+
// Let an in-flight poll settle before touching the shared cache, and
|
|
489
|
+
// stop it publishing afterwards. Bounded by the same deadline as
|
|
490
|
+
// everything else here, so a wedged poll cannot hold the CLI open.
|
|
491
|
+
if (inFlight !== undefined) {
|
|
492
|
+
await Promise.race([
|
|
493
|
+
inFlight,
|
|
494
|
+
new Promise(done => { setTimeout(done, remaining(deadline)).unref?.(); }),
|
|
495
|
+
]);
|
|
496
|
+
}
|
|
497
|
+
stopped = true;
|
|
498
|
+
// One last reading, so the page shows the run's actual last moments
|
|
499
|
+
// rather than whatever the previous poll happened to catch.
|
|
500
|
+
await scan(deadline);
|
|
501
|
+
await publishSnapshot(deadline);
|
|
502
|
+
if (outcome.log !== undefined && outcome.log.length > 0) {
|
|
503
|
+
// The CLI's own output, redacted on the way out. It is not a
|
|
504
|
+
// transcript the worker already scrubbed: it is whatever this
|
|
505
|
+
// invocation printed on a developer's machine, including diagnostics
|
|
506
|
+
// that can quote a command line or an environment value.
|
|
507
|
+
const bytes = Buffer.from(redact(outcome.log.join('\n'), env), 'utf8');
|
|
508
|
+
await options.client.putObject('runner.log', bytes.length > MIRROR_RUNNER_LOG_MAX_BYTES
|
|
509
|
+
? bytes.subarray(bytes.length - MIRROR_RUNNER_LOG_MAX_BYTES)
|
|
510
|
+
: bytes, undefined, remaining(deadline));
|
|
511
|
+
}
|
|
512
|
+
await uploadTranscripts(deadline);
|
|
513
|
+
await publishFinal(deadline);
|
|
514
|
+
// Last, always: this transition revokes the credential every call
|
|
515
|
+
// above depends on.
|
|
516
|
+
terminalReported = true;
|
|
517
|
+
await options.client.reportTerminal(outcome.status, redactJson(outcome.result, env), outcome.error, undefined, remaining(deadline));
|
|
518
|
+
}
|
|
519
|
+
catch (error) {
|
|
520
|
+
diagnostic(`could not finish the mirror: ${error instanceof Error ? error.message : String(error)}`);
|
|
521
|
+
}
|
|
522
|
+
finally {
|
|
523
|
+
stopped = true;
|
|
524
|
+
}
|
|
525
|
+
},
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Redact every string the report carries, leaf by leaf.
|
|
530
|
+
*
|
|
531
|
+
* Not `redact(JSON.stringify(...))`: the redactor's value patterns end in
|
|
532
|
+
* `\\S+`, which across serialized JSON would swallow the closing quote and the
|
|
533
|
+
* next key, and hand Cloud a document it cannot parse. Redacting leaves keeps
|
|
534
|
+
* the shape intact and still scrubs every free-text field.
|
|
535
|
+
*/
|
|
536
|
+
function redactJson(value, env) {
|
|
537
|
+
if (typeof value === 'string')
|
|
538
|
+
return redact(value, env);
|
|
539
|
+
if (Array.isArray(value))
|
|
540
|
+
return value.map(entry => redactJson(entry, env));
|
|
541
|
+
if (value !== null && typeof value === 'object') {
|
|
542
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, redactJson(entry, env)]));
|
|
543
|
+
}
|
|
544
|
+
return value;
|
|
545
|
+
}
|
|
546
|
+
/** Everything about a step but its ever-moving elapsed time. */
|
|
547
|
+
function fingerprint(step) {
|
|
548
|
+
const { elapsedMs: _elapsedMs, ...rest } = step;
|
|
549
|
+
return JSON.stringify(rest);
|
|
550
|
+
}
|
|
551
|
+
/** Least recently changed first, and a running step is never the first victim. */
|
|
552
|
+
function comparePriority([, left], [, right]) {
|
|
553
|
+
const liveness = Number(left.step.state === 'done') - Number(right.step.state === 'done');
|
|
554
|
+
return liveness !== 0 ? liveness : right.changedAt - left.changedAt;
|
|
555
|
+
}
|
|
556
|
+
//# sourceMappingURL=cloud-mirror.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloud-mirror.js","sourceRoot":"","sources":["../src/cloud-mirror.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,7 +14,7 @@ const REALPATH = realpath;
|
|
|
14
14
|
const PATH_DIRNAME = dirname;
|
|
15
15
|
const PATH_JOIN = join;
|
|
16
16
|
const PATH_RESOLVE = resolve;
|
|
17
|
-
const SOFTWARE_FACTORY_SHA256 = '
|
|
17
|
+
const SOFTWARE_FACTORY_SHA256 = 'b97a3466c2affabb61afa655d4b2f726942d753c0466740b64ba26a78da359c6';
|
|
18
18
|
const ARRAY_IS_ARRAY = Array.isArray;
|
|
19
19
|
const OBJECT_FREEZE = Object.freeze;
|
|
20
20
|
const WEAK_MAP_GET = Function.prototype.call.bind(WeakMap.prototype.get);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read the installed SDK package version from the manifest beside this module.
|
|
3
|
+
*
|
|
4
|
+
* The same relative URL works from `src/` during development and `dist/` in a
|
|
5
|
+
* built or npm-installed package. Reading the manifest at runtime keeps the
|
|
6
|
+
* CLI output tied to the bytes that are actually installed instead of a
|
|
7
|
+
* hardcoded release value that can drift between package files.
|
|
8
|
+
*/
|
|
9
|
+
export declare function packageVersion(): string;
|
|
10
|
+
//# sourceMappingURL=package-version.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-version.d.ts","sourceRoot":"","sources":["../src/package-version.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAYvC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
/**
|
|
3
|
+
* Read the installed SDK package version from the manifest beside this module.
|
|
4
|
+
*
|
|
5
|
+
* The same relative URL works from `src/` during development and `dist/` in a
|
|
6
|
+
* built or npm-installed package. Reading the manifest at runtime keeps the
|
|
7
|
+
* CLI output tied to the bytes that are actually installed instead of a
|
|
8
|
+
* hardcoded release value that can drift between package files.
|
|
9
|
+
*/
|
|
10
|
+
export function packageVersion() {
|
|
11
|
+
try {
|
|
12
|
+
const manifest = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
13
|
+
const version = manifest.version;
|
|
14
|
+
return typeof version === 'string' && version.length > 0 ? version : '0.0.0';
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// Version display is cosmetic. Keep the CLI usable if a host strips the
|
|
18
|
+
// manifest from an otherwise runnable package artifact.
|
|
19
|
+
return '0.0.0';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=package-version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-version.js","sourceRoot":"","sources":["../src/package-version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC;QACH,MAAM,QAAQ,GAAY,IAAI,CAAC,KAAK,CAClC,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAClE,CAAC;QACF,MAAM,OAAO,GAAI,QAAkC,CAAC,OAAO,CAAC;QAC5D,OAAO,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IAC/E,CAAC;IAAC,MAAM,CAAC;QACP,wEAAwE;QACxE,wDAAwD;QACxD,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC"}
|