@glubean/runner 0.7.0 → 0.8.1
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/engine-bridge.d.ts +4 -0
- package/dist/engine-bridge.d.ts.map +1 -1
- package/dist/engine-bridge.js +10 -1
- package/dist/engine-bridge.js.map +1 -1
- package/dist/executor.d.ts +2 -2
- package/dist/executor.d.ts.map +1 -1
- package/dist/executor.js +9 -226
- package/dist/executor.js.map +1 -1
- package/dist/harness.js +3 -79
- package/dist/harness.js.map +1 -1
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -1
- package/dist/load/continuation-pool.d.ts +82 -0
- package/dist/load/continuation-pool.d.ts.map +1 -0
- package/dist/load/continuation-pool.js +154 -0
- package/dist/load/continuation-pool.js.map +1 -0
- package/dist/load/execute-iteration.d.ts +126 -0
- package/dist/load/execute-iteration.d.ts.map +1 -0
- package/dist/load/execute-iteration.js +367 -0
- package/dist/load/execute-iteration.js.map +1 -0
- package/dist/load/histogram.d.ts +63 -0
- package/dist/load/histogram.d.ts.map +1 -0
- package/dist/load/histogram.js +149 -0
- package/dist/load/histogram.js.map +1 -0
- package/dist/load/orchestrator.d.ts +55 -0
- package/dist/load/orchestrator.d.ts.map +1 -0
- package/dist/load/orchestrator.js +571 -0
- package/dist/load/orchestrator.js.map +1 -0
- package/dist/load/reducer.d.ts +109 -0
- package/dist/load/reducer.d.ts.map +1 -0
- package/dist/load/reducer.js +718 -0
- package/dist/load/reducer.js.map +1 -0
- package/dist/load/route-key.d.ts +38 -0
- package/dist/load/route-key.d.ts.map +1 -0
- package/dist/load/route-key.js +107 -0
- package/dist/load/route-key.js.map +1 -0
- package/dist/load/samples.d.ts +83 -0
- package/dist/load/samples.d.ts.map +1 -0
- package/dist/load/samples.js +269 -0
- package/dist/load/samples.js.map +1 -0
- package/dist/load/sink.d.ts +127 -0
- package/dist/load/sink.d.ts.map +1 -0
- package/dist/load/sink.js +351 -0
- package/dist/load/sink.js.map +1 -0
- package/dist/load/subprocess.d.ts +83 -0
- package/dist/load/subprocess.d.ts.map +1 -0
- package/dist/load/subprocess.js +229 -0
- package/dist/load/subprocess.js.map +1 -0
- package/dist/load/threshold.d.ts +44 -0
- package/dist/load/threshold.d.ts.map +1 -0
- package/dist/load/threshold.js +197 -0
- package/dist/load/threshold.js.map +1 -0
- package/dist/load/timeline.d.ts +36 -0
- package/dist/load/timeline.d.ts.map +1 -0
- package/dist/load/timeline.js +158 -0
- package/dist/load/timeline.js.map +1 -0
- package/dist/load-harness.d.ts +2 -0
- package/dist/load-harness.d.ts.map +1 -0
- package/dist/load-harness.js +105 -0
- package/dist/load-harness.js.map +1 -0
- package/dist/runner-resolve.d.ts +53 -0
- package/dist/runner-resolve.d.ts.map +1 -0
- package/dist/runner-resolve.js +264 -0
- package/dist/runner-resolve.js.map +1 -0
- package/dist/workflow/event-timeline.d.ts +3 -0
- package/dist/workflow/event-timeline.d.ts.map +1 -0
- package/dist/workflow/event-timeline.js +72 -0
- package/dist/workflow/event-timeline.js.map +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streaming over-time series for the load reducer.
|
|
3
|
+
*
|
|
4
|
+
* Buckets the run into fixed-width windows (from run start) so a consumer can draw the
|
|
5
|
+
* classic load curves: RPS, error-rate, latency percentiles, and concurrency vs time.
|
|
6
|
+
* Memory is bounded: windows start at `baseWindowMs` and, once they would exceed
|
|
7
|
+
* `maxWindows`, the width is DOUBLED and adjacent windows merged pairwise — so an
|
|
8
|
+
* arbitrarily long run keeps at most `maxWindows` windows. Each window keeps a bounded
|
|
9
|
+
* `LoadHistogram` for its latency percentiles (mergeable, so coarsening folds cleanly).
|
|
10
|
+
*/
|
|
11
|
+
import { LoadHistogram } from "./histogram.js";
|
|
12
|
+
const ZERO_PCT = { p50: 0, p90: 0, p95: 0, p99: 0, max: 0 };
|
|
13
|
+
function newWindow() {
|
|
14
|
+
return { requests: 0, errors: 0, latency: new LoadHistogram(), starts: 0, iterations: 0, peakSample: 0 };
|
|
15
|
+
}
|
|
16
|
+
export class LoadTimeline {
|
|
17
|
+
baseWindowMs;
|
|
18
|
+
maxWindows;
|
|
19
|
+
windowMs;
|
|
20
|
+
// Sparse: only windows with activity exist; finalize() fills the gaps with zeros so the
|
|
21
|
+
// emitted series is dense (a contiguous x-axis).
|
|
22
|
+
windows = new Map();
|
|
23
|
+
/** @param baseWindowMs initial window width (ms). @param maxWindows coarsening cap. */
|
|
24
|
+
constructor(baseWindowMs = 250, maxWindows = 600) {
|
|
25
|
+
this.baseWindowMs = baseWindowMs;
|
|
26
|
+
this.maxWindows = maxWindows;
|
|
27
|
+
this.windowMs = baseWindowMs;
|
|
28
|
+
}
|
|
29
|
+
/** The window index covering `offsetMs` (ms from run start), coarsening first if the
|
|
30
|
+
* index would exceed the cap (so the series stays ≤ maxWindows). */
|
|
31
|
+
indexFor(offsetMs) {
|
|
32
|
+
let idx = Math.floor(Math.max(0, offsetMs) / this.windowMs);
|
|
33
|
+
while (idx >= this.maxWindows) {
|
|
34
|
+
this.coarsen();
|
|
35
|
+
idx = Math.floor(Math.max(0, offsetMs) / this.windowMs);
|
|
36
|
+
}
|
|
37
|
+
return idx;
|
|
38
|
+
}
|
|
39
|
+
/** The LAST window covered by a run of length `runEndMs` (the run spans [0, runEndMs)), or
|
|
40
|
+
* -1 for a non-positive length. A run ending exactly on a boundary (runEndMs = k·windowMs)
|
|
41
|
+
* covers windows 0..k-1, NOT a window that starts at the run end (codex). Coarsens so the
|
|
42
|
+
* index fits the cap. */
|
|
43
|
+
runEndIndex(runEndMs) {
|
|
44
|
+
if (runEndMs <= 0)
|
|
45
|
+
return -1;
|
|
46
|
+
while (Math.ceil(runEndMs / this.windowMs) - 1 >= this.maxWindows)
|
|
47
|
+
this.coarsen();
|
|
48
|
+
return Math.ceil(runEndMs / this.windowMs) - 1;
|
|
49
|
+
}
|
|
50
|
+
/** The window covering `offsetMs`, creating it if absent. */
|
|
51
|
+
windowFor(offsetMs) {
|
|
52
|
+
const idx = this.indexFor(offsetMs);
|
|
53
|
+
let w = this.windows.get(idx);
|
|
54
|
+
if (w === undefined) {
|
|
55
|
+
w = newWindow();
|
|
56
|
+
this.windows.set(idx, w);
|
|
57
|
+
}
|
|
58
|
+
return w;
|
|
59
|
+
}
|
|
60
|
+
/** Double the window width and merge each adjacent pair (2k, 2k+1 → k). All folds are
|
|
61
|
+
* commutative (sum / max / histogram merge), so Map iteration order is irrelevant. */
|
|
62
|
+
coarsen() {
|
|
63
|
+
const next = new Map();
|
|
64
|
+
for (const [i, w] of this.windows) {
|
|
65
|
+
const ni = Math.floor(i / 2);
|
|
66
|
+
const existing = next.get(ni);
|
|
67
|
+
if (existing === undefined) {
|
|
68
|
+
next.set(ni, w);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
existing.requests += w.requests;
|
|
72
|
+
existing.errors += w.errors;
|
|
73
|
+
existing.starts += w.starts;
|
|
74
|
+
existing.iterations += w.iterations;
|
|
75
|
+
if (w.peakSample > existing.peakSample)
|
|
76
|
+
existing.peakSample = w.peakSample;
|
|
77
|
+
existing.latency.merge(w.latency);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
this.windows = next;
|
|
81
|
+
this.windowMs *= 2;
|
|
82
|
+
}
|
|
83
|
+
/** Record one request observation at `offsetMs`. `inFlight` is the live iteration count
|
|
84
|
+
* at that moment — sampled so a window busy with requests (e.g. a poll) shows concurrency. */
|
|
85
|
+
recordRequest(offsetMs, durationMs, ok, inFlight) {
|
|
86
|
+
const w = this.windowFor(offsetMs);
|
|
87
|
+
w.requests += 1;
|
|
88
|
+
if (!ok)
|
|
89
|
+
w.errors += 1;
|
|
90
|
+
w.latency.record(durationMs);
|
|
91
|
+
if (inFlight > w.peakSample)
|
|
92
|
+
w.peakSample = inFlight;
|
|
93
|
+
}
|
|
94
|
+
/** Record one started iteration at `offsetMs`. `inFlight` is the live count just after the
|
|
95
|
+
* start (its local peak), sampled so even a same-window start+end shows its concurrency. */
|
|
96
|
+
recordIterationStart(offsetMs, inFlight) {
|
|
97
|
+
const w = this.windowFor(offsetMs);
|
|
98
|
+
w.starts += 1;
|
|
99
|
+
if (inFlight > w.peakSample)
|
|
100
|
+
w.peakSample = inFlight;
|
|
101
|
+
}
|
|
102
|
+
/** Record one completed iteration (iteration:end) at `offsetMs`. */
|
|
103
|
+
recordIterationEnd(offsetMs) {
|
|
104
|
+
this.windowFor(offsetMs).iterations += 1;
|
|
105
|
+
}
|
|
106
|
+
/** Emit the dense series: every window from 0..last, idle windows zero-filled. `runEndMs`
|
|
107
|
+
* (the run's `load:end` offset) extends the series to the actual run end, so a trailing
|
|
108
|
+
* idle / sustained-in-flight period after the last recorded event (an abort, drain timeout,
|
|
109
|
+
* or hung iteration) is still present instead of being truncated (codex). */
|
|
110
|
+
finalize(runEndMs = 0) {
|
|
111
|
+
if (this.windows.size === 0)
|
|
112
|
+
return { windowMs: this.windowMs, windows: [] };
|
|
113
|
+
// Extend to the last window the run actually covered (may coarsen existing windows).
|
|
114
|
+
let maxIdx = this.runEndIndex(runEndMs);
|
|
115
|
+
for (const i of this.windows.keys())
|
|
116
|
+
if (i > maxIdx)
|
|
117
|
+
maxIdx = i;
|
|
118
|
+
const windowSec = this.windowMs / 1000;
|
|
119
|
+
const windows = [];
|
|
120
|
+
// `carriedIn` = in-flight iterations ENTERING each window = Σ(starts − ends) through the
|
|
121
|
+
// PREVIOUS windows. The window's reported concurrency is max(its sampled peak, carriedIn):
|
|
122
|
+
// - the sampled peak catches intra-window concurrency the net would cancel (a short
|
|
123
|
+
// iteration that starts and ends in one window — even after coarsening);
|
|
124
|
+
// - carriedIn catches a long iteration spanning quiet/idle windows (sustained, not zero).
|
|
125
|
+
let carriedIn = 0;
|
|
126
|
+
for (let i = 0; i <= maxIdx; i++) {
|
|
127
|
+
const w = this.windows.get(i);
|
|
128
|
+
const peakInFlight = Math.max(0, w?.peakSample ?? 0, carriedIn);
|
|
129
|
+
if (w === undefined) {
|
|
130
|
+
windows.push({
|
|
131
|
+
offsetMs: i * this.windowMs,
|
|
132
|
+
requests: 0,
|
|
133
|
+
errors: 0,
|
|
134
|
+
errorRate: 0,
|
|
135
|
+
throughputPerSec: 0,
|
|
136
|
+
latency: ZERO_PCT,
|
|
137
|
+
iterations: 0,
|
|
138
|
+
peakInFlight,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
windows.push({
|
|
143
|
+
offsetMs: i * this.windowMs,
|
|
144
|
+
requests: w.requests,
|
|
145
|
+
errors: w.errors,
|
|
146
|
+
errorRate: w.requests > 0 ? w.errors / w.requests : 0,
|
|
147
|
+
throughputPerSec: windowSec > 0 ? w.requests / windowSec : 0,
|
|
148
|
+
latency: w.latency.count > 0 ? w.latency.percentiles() : ZERO_PCT,
|
|
149
|
+
iterations: w.iterations,
|
|
150
|
+
peakInFlight,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
carriedIn += (w?.starts ?? 0) - (w?.iterations ?? 0);
|
|
154
|
+
}
|
|
155
|
+
return { windowMs: this.windowMs, windows };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=timeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline.js","sourceRoot":"","sources":["../../src/load/timeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-harness.d.ts","sourceRoot":"","sources":["../src/load-harness.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load harness — runs INSIDE the Node.js subprocess (spawned via tsx by
|
|
3
|
+
* `runLoadFileInSubprocess`). The load-execution counterpart to `harness.ts`.
|
|
4
|
+
*
|
|
5
|
+
* Because this harness and the user `.load.ts` file are loaded in the SAME
|
|
6
|
+
* process — and resolved through the SAME project-local runner — both halves
|
|
7
|
+
* co-resolve one `@glubean/sdk`, so `runLoad`'s engine carrier and the scenario's
|
|
8
|
+
* runtime carrier are identical (no split-brain).
|
|
9
|
+
*
|
|
10
|
+
* Protocol:
|
|
11
|
+
* stdin ← JSON `{ vars, secrets }` (raw; env fallback applied here)
|
|
12
|
+
* argv ← `--file=<absolute path to the .load.ts>`
|
|
13
|
+
* stdout → `WIRE_PREFIX`-tagged NDJSON `LoadHarnessMessage` lines: one
|
|
14
|
+
* `artifact` per completed plan, one `error` per import / plan-run
|
|
15
|
+
* failure, a terminal `done`. The prefix lets the parent tell protocol
|
|
16
|
+
* from ordinary user `console.log` (forwarded as-is); writes go through
|
|
17
|
+
* `writeSync(1, …)` so they flush before exit. A crash (no `done`) is
|
|
18
|
+
* surfaced by the parent from stderr.
|
|
19
|
+
*/
|
|
20
|
+
import { parseArgs } from "node:util";
|
|
21
|
+
import { writeSync } from "node:fs";
|
|
22
|
+
import { pathToFileURL } from "node:url";
|
|
23
|
+
import { bootstrap } from "./bootstrap.js";
|
|
24
|
+
import { runLoad } from "./load/orchestrator.js";
|
|
25
|
+
import { collectLoadPlans, withProcessEnvFallback, WIRE_PREFIX, } from "./load/subprocess.js";
|
|
26
|
+
/** Write one protocol message synchronously to stdout (fd 1, flush-safe). The
|
|
27
|
+
* LEADING newline guarantees the prefix begins a fresh line even when user /
|
|
28
|
+
* plugin code wrote to stdout WITHOUT a trailing newline (otherwise the message
|
|
29
|
+
* would be appended to that line and no longer start with the prefix). */
|
|
30
|
+
function emit(msg) {
|
|
31
|
+
writeSync(1, "\n" + WIRE_PREFIX + JSON.stringify(msg) + "\n");
|
|
32
|
+
}
|
|
33
|
+
/** Mark the harness done (terminal sentinel) and exit cleanly. */
|
|
34
|
+
function finishClean() {
|
|
35
|
+
emit({ type: "done" });
|
|
36
|
+
process.exit(0);
|
|
37
|
+
}
|
|
38
|
+
// A crash (uncaught error) is reported to stderr and exits nonzero WITHOUT a
|
|
39
|
+
// `done` sentinel — the parent detects the missing sentinel and surfaces the
|
|
40
|
+
// stderr text as a "did not complete" error, so nothing is silently lost.
|
|
41
|
+
function crash(message) {
|
|
42
|
+
process.stderr.write(message + "\n");
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
process.on("uncaughtException", (error) => {
|
|
46
|
+
crash(`load harness crashed: ${error?.stack ?? error?.message ?? String(error)}`);
|
|
47
|
+
});
|
|
48
|
+
process.on("unhandledRejection", (reason) => {
|
|
49
|
+
crash(`load harness crashed: ${reason instanceof Error ? (reason.stack ?? reason.message) : String(reason)}`);
|
|
50
|
+
});
|
|
51
|
+
const { values: args } = parseArgs({
|
|
52
|
+
args: process.argv.slice(2),
|
|
53
|
+
options: { file: { type: "string" } },
|
|
54
|
+
strict: false,
|
|
55
|
+
});
|
|
56
|
+
const file = args.file;
|
|
57
|
+
if (!file)
|
|
58
|
+
crash("load harness: missing required --file argument");
|
|
59
|
+
/** Read the full stdin payload (the `{ vars, secrets }` JSON). */
|
|
60
|
+
async function readStdin() {
|
|
61
|
+
const chunks = [];
|
|
62
|
+
for await (const chunk of process.stdin)
|
|
63
|
+
chunks.push(chunk);
|
|
64
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
65
|
+
}
|
|
66
|
+
const stdinRaw = await readStdin();
|
|
67
|
+
const { vars = {}, secrets = {} } = stdinRaw
|
|
68
|
+
? JSON.parse(stdinRaw)
|
|
69
|
+
: {};
|
|
70
|
+
// Register project plugins (matchers / protocol adapters) before importing the
|
|
71
|
+
// load file, which may use them — same as the test/contract paths.
|
|
72
|
+
await bootstrap(process.cwd());
|
|
73
|
+
let ns;
|
|
74
|
+
try {
|
|
75
|
+
// tsx (the spawning runtime) transforms full TypeScript; Node resolves the
|
|
76
|
+
// file's bare imports (`@glubean/sdk/load`) relative to the file's location.
|
|
77
|
+
ns = (await import(pathToFileURL(file).href));
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
// A handled per-file failure (not a crash): emit the error + the done sentinel.
|
|
81
|
+
emit({
|
|
82
|
+
type: "error",
|
|
83
|
+
message: `failed to import load file ${file}: ${e instanceof Error ? e.message : String(e)} (ensure @glubean/sdk is resolvable from the file)`,
|
|
84
|
+
});
|
|
85
|
+
finishClean();
|
|
86
|
+
}
|
|
87
|
+
const envVars = withProcessEnvFallback(vars);
|
|
88
|
+
const envSecrets = withProcessEnvFallback(secrets);
|
|
89
|
+
for (const plan of collectLoadPlans(ns)) {
|
|
90
|
+
try {
|
|
91
|
+
// runLoad can throw for an invalid plan (traffic-mix, no termination bound,
|
|
92
|
+
// bad bounds) — report it per-plan and keep going so other plans' completed
|
|
93
|
+
// artifacts still emit.
|
|
94
|
+
const artifact = await runLoad(plan, { vars: envVars, secrets: envSecrets });
|
|
95
|
+
emit({ type: "artifact", runnerId: plan.id, artifact });
|
|
96
|
+
}
|
|
97
|
+
catch (e) {
|
|
98
|
+
emit({
|
|
99
|
+
type: "error",
|
|
100
|
+
message: `load plan "${plan.id}" (${file}) failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
finishClean();
|
|
105
|
+
//# sourceMappingURL=load-harness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-harness.js","sourceRoot":"","sources":["../src/load-harness.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Diagnostic warning emitted by the executor's runner resolver. */
|
|
2
|
+
export interface RunnerWarning {
|
|
3
|
+
/** Human-readable message. */
|
|
4
|
+
message: string;
|
|
5
|
+
/** Stable code for filtering / consumer dedupe. */
|
|
6
|
+
code: "runner_fallback_no_project" | "runner_fallback_no_dist" | "runner_protocol_old" | "runner_pkg_root_not_found";
|
|
7
|
+
}
|
|
8
|
+
export interface ResolvedRunner {
|
|
9
|
+
distDir: string;
|
|
10
|
+
pkgRoot: string;
|
|
11
|
+
source: "project" | "bundled";
|
|
12
|
+
resolvedFrom?: string;
|
|
13
|
+
version?: string;
|
|
14
|
+
pendingWarnings: RunnerWarning[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resolve the runner dist/ directory + package root.
|
|
18
|
+
*
|
|
19
|
+
* Preference: project-local `@glubean/runner` (found from `projectCwd`'s
|
|
20
|
+
* `node_modules` chain). Fallback: bundled (the consumer's own runner copy).
|
|
21
|
+
*
|
|
22
|
+
* Returns warnings to be yielded as `{ type: "warning", ... }` events at
|
|
23
|
+
* the start of every `run()` call. Always emits a warning when falling
|
|
24
|
+
* back to bundled (so users see why "configure() values..." errors may
|
|
25
|
+
* appear in a misconfigured project).
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveRunnerRoot(projectCwd: string, bundledDistDir: string, bundledPkgRoot: string): ResolvedRunner;
|
|
28
|
+
/** Resolve the tsx CLI entry used to transform the user's TypeScript in the
|
|
29
|
+
* spawned harness subprocess. Cached after the first lookup. */
|
|
30
|
+
export declare function resolveTsxPath(): string;
|
|
31
|
+
/** A computed zero-project plan: extra tsx `--import` args, env redirects, and a
|
|
32
|
+
* cleanup that undoes any temp package.json. */
|
|
33
|
+
export interface ZeroProjectSetup {
|
|
34
|
+
/** tsx args to prepend (`--import <zero-project-register.mjs>`), or `[]`. */
|
|
35
|
+
tsxArgs: string[];
|
|
36
|
+
/** Env additions (`GLUBEAN_VENDORED_ROOT`), or `{}`. */
|
|
37
|
+
env: Record<string, string>;
|
|
38
|
+
/** Restore the working dir's package.json to its original state. Idempotent. */
|
|
39
|
+
cleanup(): void;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Set up zero-project (scratch) mode for a spawn rooted at `cwd`: when the cwd
|
|
43
|
+
* has no `@glubean/sdk` in node_modules, redirect the user file's `@glubean/*`
|
|
44
|
+
* imports to the resolved runner's vendored copy (via the register hook +
|
|
45
|
+
* `GLUBEAN_VENDORED_ROOT`) and ensure a `"type":"module"` package.json so the
|
|
46
|
+
* `.ts` file loads as ESM. When the cwd already has `@glubean/sdk`, this is a
|
|
47
|
+
* no-op (empty args/env, no-op cleanup).
|
|
48
|
+
*
|
|
49
|
+
* Pure w.r.t. instance state — both `TestExecutor` and the load spawn call it
|
|
50
|
+
* and own the returned `tsxArgs`/`env`/`cleanup`.
|
|
51
|
+
*/
|
|
52
|
+
export declare function prepareZeroProject(cwd: string, runnerDistDir: string, runnerPkgRoot: string): ZeroProjectSetup;
|
|
53
|
+
//# sourceMappingURL=runner-resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner-resolve.d.ts","sourceRoot":"","sources":["../src/runner-resolve.ts"],"names":[],"mappings":"AAqEA,oEAAoE;AACpE,MAAM,WAAW,aAAa;IAC5B,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,IAAI,EAAE,4BAA4B,GAAG,yBAAyB,GAAG,qBAAqB,GAAG,2BAA2B,CAAC;CACtH;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,SAAS,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,aAAa,EAAE,CAAC;CAClC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,GACrB,cAAc,CAuGhB;AAQD;iEACiE;AACjE,wBAAgB,cAAc,IAAI,MAAM,CAKvC;AAID;iDACiD;AACjD,MAAM,WAAW,gBAAgB;IAC/B,6EAA6E;IAC7E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,wDAAwD;IACxD,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,gFAAgF;IAChF,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,MAAM,GACpB,gBAAgB,CA2DlB"}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared runner-resolution internals — the delicate "where does the runner
|
|
3
|
+
* harness live + how do we spawn it" code, factored out of `executor.ts` so the
|
|
4
|
+
* test harness (`TestExecutor`) AND the load harness (`runLoadFileInSubprocess`)
|
|
5
|
+
* resolve the SAME project-local runner the SAME way.
|
|
6
|
+
*
|
|
7
|
+
* Three reused seams:
|
|
8
|
+
* - `resolveRunnerRoot` — the **dual-package hazard fix**: prefer the project's
|
|
9
|
+
* own `@glubean/runner` dist (so the spawned harness + the user file co-resolve
|
|
10
|
+
* the project's `@glubean/sdk`), fall back to the bundled copy with a warning.
|
|
11
|
+
* **Most delicate code in the package — change with care.**
|
|
12
|
+
* - `resolveTsxPath` — locate the tsx CLI to transform the user's TypeScript.
|
|
13
|
+
* - `prepareZeroProject` — scratch-mode (no node_modules) `--import` register +
|
|
14
|
+
* `GLUBEAN_VENDORED_ROOT` redirect + temp package.json, with a cleanup closure.
|
|
15
|
+
*
|
|
16
|
+
* Internal to `@glubean/runner` — not part of the public `index.ts` surface.
|
|
17
|
+
*/
|
|
18
|
+
import { existsSync, unlinkSync, readFileSync, writeFileSync, realpathSync } from "node:fs";
|
|
19
|
+
import { dirname, resolve, join } from "node:path";
|
|
20
|
+
import { createRequire } from "node:module";
|
|
21
|
+
// ── Project-local runner resolution (Plan 1) ────────────────────────────────
|
|
22
|
+
/**
|
|
23
|
+
* Walk up from a starting file path looking for the first package.json
|
|
24
|
+
* whose `name` field matches `expectedName`. Layout-independent — works
|
|
25
|
+
* regardless of dist/ depth.
|
|
26
|
+
*
|
|
27
|
+
* Returns the realpath of the package root, or undefined if not found.
|
|
28
|
+
*/
|
|
29
|
+
function findPackageRoot(startFile, expectedName) {
|
|
30
|
+
let dir = dirname(startFile);
|
|
31
|
+
for (let i = 0; i < 16; i++) {
|
|
32
|
+
const candidate = resolve(dir, "package.json");
|
|
33
|
+
if (existsSync(candidate)) {
|
|
34
|
+
try {
|
|
35
|
+
const pkg = JSON.parse(readFileSync(candidate, "utf-8"));
|
|
36
|
+
if (pkg?.name === expectedName) {
|
|
37
|
+
try {
|
|
38
|
+
return realpathSync(dir);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return dir;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// corrupt / non-json; keep walking
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const parent = dirname(dir);
|
|
50
|
+
if (parent === dir)
|
|
51
|
+
return undefined;
|
|
52
|
+
dir = parent;
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Compare two version strings (numeric major.minor.patch). Returns true
|
|
58
|
+
* if `a < b`. Tolerant of missing fields and non-numeric tails.
|
|
59
|
+
*/
|
|
60
|
+
function semverLt(a, b) {
|
|
61
|
+
const parse = (s) => s.split(/[.\-+]/).slice(0, 3).map((p) => parseInt(p, 10) || 0);
|
|
62
|
+
const [aMajor, aMinor, aPatch] = parse(a);
|
|
63
|
+
const [bMajor, bMinor, bPatch] = parse(b);
|
|
64
|
+
if (aMajor !== bMajor)
|
|
65
|
+
return aMajor < bMajor;
|
|
66
|
+
if (aMinor !== bMinor)
|
|
67
|
+
return aMinor < bMinor;
|
|
68
|
+
return aPatch < bPatch;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Resolve the runner dist/ directory + package root.
|
|
72
|
+
*
|
|
73
|
+
* Preference: project-local `@glubean/runner` (found from `projectCwd`'s
|
|
74
|
+
* `node_modules` chain). Fallback: bundled (the consumer's own runner copy).
|
|
75
|
+
*
|
|
76
|
+
* Returns warnings to be yielded as `{ type: "warning", ... }` events at
|
|
77
|
+
* the start of every `run()` call. Always emits a warning when falling
|
|
78
|
+
* back to bundled (so users see why "configure() values..." errors may
|
|
79
|
+
* appear in a misconfigured project).
|
|
80
|
+
*/
|
|
81
|
+
export function resolveRunnerRoot(projectCwd, bundledDistDir, bundledPkgRoot) {
|
|
82
|
+
const warnings = [];
|
|
83
|
+
try {
|
|
84
|
+
// Root `createRequire` at a stub path INSIDE the project cwd — not
|
|
85
|
+
// at `import.meta.url` (the workspace executor file). If we use the
|
|
86
|
+
// workspace URL, Node's resolver returns the workspace's own
|
|
87
|
+
// `@glubean/runner` via package self-reference (the `exports` field
|
|
88
|
+
// points back at itself), regardless of `paths: [projectCwd]`. With
|
|
89
|
+
// a cwd-rooted stub there's no self-reference and Node walks the
|
|
90
|
+
// project's node_modules chain correctly.
|
|
91
|
+
const req = createRequire(resolve(projectCwd, "__glubean_resolve_stub__.js"));
|
|
92
|
+
const mainEntry = req.resolve("@glubean/runner");
|
|
93
|
+
const pkgRoot = findPackageRoot(mainEntry, "@glubean/runner");
|
|
94
|
+
if (!pkgRoot) {
|
|
95
|
+
warnings.push({
|
|
96
|
+
code: "runner_pkg_root_not_found",
|
|
97
|
+
message: `Could not locate @glubean/runner's package.json above ${mainEntry}; using bundled runner.`,
|
|
98
|
+
});
|
|
99
|
+
return {
|
|
100
|
+
distDir: bundledDistDir,
|
|
101
|
+
pkgRoot: bundledPkgRoot,
|
|
102
|
+
source: "bundled",
|
|
103
|
+
pendingWarnings: warnings,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
const projectDistDir = dirname(mainEntry);
|
|
107
|
+
if (!existsSync(resolve(projectDistDir, "harness.js"))) {
|
|
108
|
+
warnings.push({
|
|
109
|
+
code: "runner_fallback_no_dist",
|
|
110
|
+
message: `Project @glubean/runner at ${pkgRoot} has no built harness.js (looked in ${projectDistDir}); using bundled runner.`,
|
|
111
|
+
});
|
|
112
|
+
return {
|
|
113
|
+
distDir: bundledDistDir,
|
|
114
|
+
pkgRoot: bundledPkgRoot,
|
|
115
|
+
source: "bundled",
|
|
116
|
+
pendingWarnings: warnings,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
let version;
|
|
120
|
+
let projectProtocol;
|
|
121
|
+
try {
|
|
122
|
+
const pkg = JSON.parse(readFileSync(resolve(pkgRoot, "package.json"), "utf-8"));
|
|
123
|
+
version = pkg.version;
|
|
124
|
+
projectProtocol = pkg.glubeanRunnerProtocol;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// best effort
|
|
128
|
+
}
|
|
129
|
+
// Min-protocol check: emit a warning if project's protocol is older
|
|
130
|
+
// than what this consumer needs, but DON'T fall back. Using project-
|
|
131
|
+
// local runner with an old protocol just means some new env channels
|
|
132
|
+
// may be silently ignored. Falling back to bundled when the project
|
|
133
|
+
// has its own SDK would re-introduce the dual-package hazard the
|
|
134
|
+
// whole fix exists to prevent. Project-local wins; missing features
|
|
135
|
+
// are surfaced via warning so the user knows to upgrade.
|
|
136
|
+
try {
|
|
137
|
+
const bundledPkg = JSON.parse(readFileSync(resolve(bundledPkgRoot, "package.json"), "utf-8"));
|
|
138
|
+
const bundledMin = bundledPkg.glubeanRunnerProtocolMinimum;
|
|
139
|
+
if (bundledMin && (!projectProtocol || semverLt(projectProtocol, bundledMin))) {
|
|
140
|
+
warnings.push({
|
|
141
|
+
code: "runner_protocol_old",
|
|
142
|
+
message: `Project @glubean/runner ${version ?? "<unknown>"} declares glubeanRunnerProtocol=${projectProtocol ?? "<unset>"}, ` +
|
|
143
|
+
`but this consumer was built for >= ${bundledMin}. ` +
|
|
144
|
+
`Using project-local runner anyway; some newer features may be silently unavailable. ` +
|
|
145
|
+
`Run \`npm i -D @glubean/runner@latest\` to silence.`,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// bundled pkg.json unreadable — skip the check; happens in test fixtures
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
distDir: projectDistDir,
|
|
154
|
+
pkgRoot,
|
|
155
|
+
source: "project",
|
|
156
|
+
resolvedFrom: mainEntry,
|
|
157
|
+
version,
|
|
158
|
+
pendingWarnings: warnings,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// No project-local runner installed. Plan 1 AC4: emit a warning whenever
|
|
163
|
+
// bundled is used so users see why version-skew "configure() values..."
|
|
164
|
+
// errors may appear.
|
|
165
|
+
warnings.push({
|
|
166
|
+
code: "runner_fallback_no_project",
|
|
167
|
+
message: `No project-local @glubean/runner found at ${projectCwd}; using consumer's bundled runner. ` +
|
|
168
|
+
`If your tests import @glubean/sdk from this project, install runner to keep module identity ` +
|
|
169
|
+
`consistent: \`npm i -D @glubean/runner\`.`,
|
|
170
|
+
});
|
|
171
|
+
return {
|
|
172
|
+
distDir: bundledDistDir,
|
|
173
|
+
pkgRoot: bundledPkgRoot,
|
|
174
|
+
source: "bundled",
|
|
175
|
+
pendingWarnings: warnings,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// ── End of project-local resolution ─────────────────────────────────────────
|
|
180
|
+
// ── tsx path resolution ─────────────────────────────────────────────────────
|
|
181
|
+
let _tsxPath;
|
|
182
|
+
/** Resolve the tsx CLI entry used to transform the user's TypeScript in the
|
|
183
|
+
* spawned harness subprocess. Cached after the first lookup. */
|
|
184
|
+
export function resolveTsxPath() {
|
|
185
|
+
if (_tsxPath)
|
|
186
|
+
return _tsxPath;
|
|
187
|
+
const req = createRequire(import.meta.url);
|
|
188
|
+
_tsxPath = resolve(dirname(req.resolve("tsx/package.json")), "dist/cli.mjs");
|
|
189
|
+
return _tsxPath;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Set up zero-project (scratch) mode for a spawn rooted at `cwd`: when the cwd
|
|
193
|
+
* has no `@glubean/sdk` in node_modules, redirect the user file's `@glubean/*`
|
|
194
|
+
* imports to the resolved runner's vendored copy (via the register hook +
|
|
195
|
+
* `GLUBEAN_VENDORED_ROOT`) and ensure a `"type":"module"` package.json so the
|
|
196
|
+
* `.ts` file loads as ESM. When the cwd already has `@glubean/sdk`, this is a
|
|
197
|
+
* no-op (empty args/env, no-op cleanup).
|
|
198
|
+
*
|
|
199
|
+
* Pure w.r.t. instance state — both `TestExecutor` and the load spawn call it
|
|
200
|
+
* and own the returned `tsxArgs`/`env`/`cleanup`.
|
|
201
|
+
*/
|
|
202
|
+
export function prepareZeroProject(cwd, runnerDistDir, runnerPkgRoot) {
|
|
203
|
+
if (existsSync(join(cwd, "node_modules", "@glubean", "sdk"))) {
|
|
204
|
+
return { tsxArgs: [], env: {}, cleanup: () => { } };
|
|
205
|
+
}
|
|
206
|
+
// Plan 1: relocate zero-project subpaths with the harness — if harness moved
|
|
207
|
+
// to project-local runner, register + vendored root must move too, otherwise
|
|
208
|
+
// scratch mode mixes project harness with bundled @glubean/* resolution.
|
|
209
|
+
const registerPath = resolve(runnerDistDir, "zero-project-register.mjs");
|
|
210
|
+
const tsxArgs = ["--import", registerPath];
|
|
211
|
+
// Use the runner package root as the synthetic parent. From there, Node's
|
|
212
|
+
// normal package resolution finds sibling @glubean/* packages in both
|
|
213
|
+
// workspace installs (packages/runner/node_modules) and published installs
|
|
214
|
+
// (ancestor node_modules).
|
|
215
|
+
const env = { GLUBEAN_VENDORED_ROOT: runnerPkgRoot };
|
|
216
|
+
const pkgPath = join(cwd, "package.json");
|
|
217
|
+
let tempPackageJson = false;
|
|
218
|
+
let originalPackageJson;
|
|
219
|
+
if (!existsSync(pkgPath)) {
|
|
220
|
+
try {
|
|
221
|
+
writeFileSync(pkgPath, '{"type":"module"}\n');
|
|
222
|
+
tempPackageJson = "created";
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
// Non-critical
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
try {
|
|
230
|
+
const original = readFileSync(pkgPath, "utf-8");
|
|
231
|
+
const pkg = JSON.parse(original);
|
|
232
|
+
if (pkg.type !== "module") {
|
|
233
|
+
originalPackageJson = original;
|
|
234
|
+
pkg.type = "module";
|
|
235
|
+
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
236
|
+
tempPackageJson = "patched";
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
// Non-critical
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return {
|
|
244
|
+
tsxArgs,
|
|
245
|
+
env,
|
|
246
|
+
cleanup() {
|
|
247
|
+
if (!tempPackageJson)
|
|
248
|
+
return;
|
|
249
|
+
try {
|
|
250
|
+
if (tempPackageJson === "created") {
|
|
251
|
+
unlinkSync(pkgPath);
|
|
252
|
+
}
|
|
253
|
+
else if (tempPackageJson === "patched" && originalPackageJson) {
|
|
254
|
+
writeFileSync(pkgPath, originalPackageJson);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
// Non-critical
|
|
259
|
+
}
|
|
260
|
+
tempPackageJson = false;
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=runner-resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner-resolve.js","sourceRoot":"","sources":["../src/runner-resolve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-timeline.d.ts","sourceRoot":"","sources":["../../src/workflow/event-timeline.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAYjD,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAqExF"}
|