@farmslot/recipe-runner 0.23.0
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/CHANGELOG.md +255 -0
- package/LICENSE +21 -0
- package/README.md +274 -0
- package/bin/farmslot-visual-review.mjs +152 -0
- package/dist/adapters/app-lifecycle.d.ts +41 -0
- package/dist/adapters/app-lifecycle.d.ts.map +1 -0
- package/dist/adapters/app-lifecycle.js +224 -0
- package/dist/adapters/app-lifecycle.js.map +1 -0
- package/dist/adapters/core.d.ts +5 -0
- package/dist/adapters/core.d.ts.map +1 -0
- package/dist/adapters/core.js +433 -0
- package/dist/adapters/core.js.map +1 -0
- package/dist/adapters/gesture.d.ts +12 -0
- package/dist/adapters/gesture.d.ts.map +1 -0
- package/dist/adapters/gesture.js +76 -0
- package/dist/adapters/gesture.js.map +1 -0
- package/dist/adapters/ui.d.ts +33 -0
- package/dist/adapters/ui.d.ts.map +1 -0
- package/dist/adapters/ui.js +130 -0
- package/dist/adapters/ui.js.map +1 -0
- package/dist/cli/error-output.d.ts +6 -0
- package/dist/cli/error-output.d.ts.map +1 -0
- package/dist/cli/error-output.js +19 -0
- package/dist/cli/error-output.js.map +1 -0
- package/dist/cli/index.d.ts +12 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +29 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/run-command.d.ts +8 -0
- package/dist/cli/run-command.d.ts.map +1 -0
- package/dist/cli/run-command.js +253 -0
- package/dist/cli/run-command.js.map +1 -0
- package/dist/cli/support.d.ts +31 -0
- package/dist/cli/support.d.ts.map +1 -0
- package/dist/cli/support.js +297 -0
- package/dist/cli/support.js.map +1 -0
- package/dist/cli/validate-command.d.ts +4 -0
- package/dist/cli/validate-command.d.ts.map +1 -0
- package/dist/cli/validate-command.js +52 -0
- package/dist/cli/validate-command.js.map +1 -0
- package/dist/core/compose.d.ts +23 -0
- package/dist/core/compose.d.ts.map +1 -0
- package/dist/core/compose.js +104 -0
- package/dist/core/compose.js.map +1 -0
- package/dist/core/execution.d.ts +44 -0
- package/dist/core/execution.d.ts.map +1 -0
- package/dist/core/execution.js +304 -0
- package/dist/core/execution.js.map +1 -0
- package/dist/core/failure.d.ts +23 -0
- package/dist/core/failure.d.ts.map +1 -0
- package/dist/core/failure.js +43 -0
- package/dist/core/failure.js.map +1 -0
- package/dist/core/graph.d.ts +12 -0
- package/dist/core/graph.d.ts.map +1 -0
- package/dist/core/graph.js +65 -0
- package/dist/core/graph.js.map +1 -0
- package/dist/core/hud.d.ts +11 -0
- package/dist/core/hud.d.ts.map +1 -0
- package/dist/core/hud.js +120 -0
- package/dist/core/hud.js.map +1 -0
- package/dist/core/invocation.d.ts +13 -0
- package/dist/core/invocation.d.ts.map +1 -0
- package/dist/core/invocation.js +68 -0
- package/dist/core/invocation.js.map +1 -0
- package/dist/core/json.d.ts +9 -0
- package/dist/core/json.d.ts.map +1 -0
- package/dist/core/json.js +74 -0
- package/dist/core/json.js.map +1 -0
- package/dist/core/library-manifest.d.ts +53 -0
- package/dist/core/library-manifest.d.ts.map +1 -0
- package/dist/core/library-manifest.js +263 -0
- package/dist/core/library-manifest.js.map +1 -0
- package/dist/core/library.d.ts +80 -0
- package/dist/core/library.d.ts.map +1 -0
- package/dist/core/library.js +321 -0
- package/dist/core/library.js.map +1 -0
- package/dist/core/parameters.d.ts +5 -0
- package/dist/core/parameters.d.ts.map +1 -0
- package/dist/core/parameters.js +57 -0
- package/dist/core/parameters.js.map +1 -0
- package/dist/core/passive-observations.d.ts +25 -0
- package/dist/core/passive-observations.d.ts.map +1 -0
- package/dist/core/passive-observations.js +62 -0
- package/dist/core/passive-observations.js.map +1 -0
- package/dist/core/path.d.ts +7 -0
- package/dist/core/path.d.ts.map +1 -0
- package/dist/core/path.js +147 -0
- package/dist/core/path.js.map +1 -0
- package/dist/core/recording-cleanup.d.ts +10 -0
- package/dist/core/recording-cleanup.d.ts.map +1 -0
- package/dist/core/recording-cleanup.js +32 -0
- package/dist/core/recording-cleanup.js.map +1 -0
- package/dist/core/resolution-error.d.ts +7 -0
- package/dist/core/resolution-error.d.ts.map +1 -0
- package/dist/core/resolution-error.js +9 -0
- package/dist/core/resolution-error.js.map +1 -0
- package/dist/core/runner.d.ts +4 -0
- package/dist/core/runner.d.ts.map +1 -0
- package/dist/core/runner.js +738 -0
- package/dist/core/runner.js.map +1 -0
- package/dist/core/scroll-to.d.ts +111 -0
- package/dist/core/scroll-to.d.ts.map +1 -0
- package/dist/core/scroll-to.js +353 -0
- package/dist/core/scroll-to.js.map +1 -0
- package/dist/core/suite.d.ts +25 -0
- package/dist/core/suite.d.ts.map +1 -0
- package/dist/core/suite.js +76 -0
- package/dist/core/suite.js.map +1 -0
- package/dist/core/trace.d.ts +5 -0
- package/dist/core/trace.d.ts.map +1 -0
- package/dist/core/trace.js +25 -0
- package/dist/core/trace.js.map +1 -0
- package/dist/core/trust-error.d.ts +9 -0
- package/dist/core/trust-error.d.ts.map +1 -0
- package/dist/core/trust-error.js +18 -0
- package/dist/core/trust-error.js.map +1 -0
- package/dist/core/trust-input.d.ts +20 -0
- package/dist/core/trust-input.d.ts.map +1 -0
- package/dist/core/trust-input.js +68 -0
- package/dist/core/trust-input.js.map +1 -0
- package/dist/core/trust.d.ts +28 -0
- package/dist/core/trust.d.ts.map +1 -0
- package/dist/core/trust.js +284 -0
- package/dist/core/trust.js.map +1 -0
- package/dist/core/types.d.ts +319 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/validation.d.ts +4 -0
- package/dist/core/validation.d.ts.map +1 -0
- package/dist/core/validation.js +18 -0
- package/dist/core/validation.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/node/writers.d.ts +27 -0
- package/dist/node/writers.d.ts.map +1 -0
- package/dist/node/writers.js +99 -0
- package/dist/node/writers.js.map +1 -0
- package/dist/recording/android-mirror.d.ts +10 -0
- package/dist/recording/android-mirror.d.ts.map +1 -0
- package/dist/recording/android-mirror.js +180 -0
- package/dist/recording/android-mirror.js.map +1 -0
- package/dist/recording/capture-helper-timing.d.ts +4 -0
- package/dist/recording/capture-helper-timing.d.ts.map +1 -0
- package/dist/recording/capture-helper-timing.js +47 -0
- package/dist/recording/capture-helper-timing.js.map +1 -0
- package/dist/recording/capture-helper.d.ts +10 -0
- package/dist/recording/capture-helper.d.ts.map +1 -0
- package/dist/recording/capture-helper.js +335 -0
- package/dist/recording/capture-helper.js.map +1 -0
- package/dist/recording/cdp-video-recorder.d.ts +9 -0
- package/dist/recording/cdp-video-recorder.d.ts.map +1 -0
- package/dist/recording/cdp-video-recorder.js +319 -0
- package/dist/recording/cdp-video-recorder.js.map +1 -0
- package/dist/recording/frame-sampler.d.ts +19 -0
- package/dist/recording/frame-sampler.d.ts.map +1 -0
- package/dist/recording/frame-sampler.js +29 -0
- package/dist/recording/frame-sampler.js.map +1 -0
- package/dist/recording/timeline.d.ts +15 -0
- package/dist/recording/timeline.d.ts.map +1 -0
- package/dist/recording/timeline.js +88 -0
- package/dist/recording/timeline.js.map +1 -0
- package/dist/runtime/browser-extension.d.ts +17 -0
- package/dist/runtime/browser-extension.d.ts.map +1 -0
- package/dist/runtime/browser-extension.js +42 -0
- package/dist/runtime/browser-extension.js.map +1 -0
- package/dist/runtime/cdp.d.ts +138 -0
- package/dist/runtime/cdp.d.ts.map +1 -0
- package/dist/runtime/cdp.js +1429 -0
- package/dist/runtime/cdp.js.map +1 -0
- package/dist/runtime/decision-types.d.ts +23 -0
- package/dist/runtime/decision-types.d.ts.map +1 -0
- package/dist/runtime/decision-types.js +2 -0
- package/dist/runtime/decision-types.js.map +1 -0
- package/dist/runtime/deps-readiness.d.ts +21 -0
- package/dist/runtime/deps-readiness.d.ts.map +1 -0
- package/dist/runtime/deps-readiness.js +141 -0
- package/dist/runtime/deps-readiness.js.map +1 -0
- package/dist/runtime/log-analysis.d.ts +48 -0
- package/dist/runtime/log-analysis.d.ts.map +1 -0
- package/dist/runtime/log-analysis.js +128 -0
- package/dist/runtime/log-analysis.js.map +1 -0
- package/dist/runtime/metro-probe.d.ts +5 -0
- package/dist/runtime/metro-probe.d.ts.map +1 -0
- package/dist/runtime/metro-probe.js +24 -0
- package/dist/runtime/metro-probe.js.map +1 -0
- package/dist/runtime/operation.d.ts +32 -0
- package/dist/runtime/operation.d.ts.map +1 -0
- package/dist/runtime/operation.js +184 -0
- package/dist/runtime/operation.js.map +1 -0
- package/dist/runtime/orchestrate-up.d.ts +22 -0
- package/dist/runtime/orchestrate-up.d.ts.map +1 -0
- package/dist/runtime/orchestrate-up.js +35 -0
- package/dist/runtime/orchestrate-up.js.map +1 -0
- package/dist/runtime/react-native-bridge.d.ts +17 -0
- package/dist/runtime/react-native-bridge.d.ts.map +1 -0
- package/dist/runtime/react-native-bridge.js +57 -0
- package/dist/runtime/react-native-bridge.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +8 -0
- package/dist/version.js.map +1 -0
- package/package.json +163 -0
- package/test/fixtures/scroll-to-visible/README.md +39 -0
- package/visual-review/feedback-draft.mjs +82 -0
- package/visual-review/index.d.mts +41 -0
- package/visual-review/index.mjs +4 -0
- package/visual-review/recipe-board.mjs +142 -0
- package/visual-review/review-board.mjs +981 -0
- package/visual-review/server.mjs +69 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// Invocation records keep concurrent command observations independent of locks.
|
|
2
|
+
import { execFileSync } from 'node:child_process';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { validateOperationRecord } from '@farmslot/protocol';
|
|
7
|
+
export function processIdentity(pid) {
|
|
8
|
+
try {
|
|
9
|
+
const value = execFileSync('ps', ['-p', String(pid), '-o', 'lstart='], {
|
|
10
|
+
encoding: 'utf8',
|
|
11
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
12
|
+
}).trim();
|
|
13
|
+
return value || undefined;
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
if (error.status === 1)
|
|
17
|
+
return undefined;
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export class OperationRecord {
|
|
22
|
+
constructor(directory, command, target, options = {}) {
|
|
23
|
+
this.lastFlush = 0;
|
|
24
|
+
this.disabled = false;
|
|
25
|
+
const id = randomUUID();
|
|
26
|
+
const now = new Date().toISOString();
|
|
27
|
+
this.notification = options.mirrorDirectory
|
|
28
|
+
? path.join(path.dirname(options.mirrorDirectory), 'operations-updated.json')
|
|
29
|
+
: undefined;
|
|
30
|
+
this.file = path.join(directory, `${id}.json`);
|
|
31
|
+
this.files = [
|
|
32
|
+
this.file,
|
|
33
|
+
...(options.mirrorDirectory ? [path.join(options.mirrorDirectory, `${id}.json`)] : []),
|
|
34
|
+
];
|
|
35
|
+
const logPath = path.join(options.mirrorDirectory ?? directory, `${id}.log`);
|
|
36
|
+
ensureRuntimeDirectory(path.dirname(logPath));
|
|
37
|
+
fs.writeFileSync(logPath, '', { flag: 'wx', mode: 0o600 });
|
|
38
|
+
fs.chmodSync(logPath, 0o600);
|
|
39
|
+
const identity = processIdentity(process.pid);
|
|
40
|
+
if (!identity)
|
|
41
|
+
throw new Error('Cannot identify the operation owner process');
|
|
42
|
+
this.value = {
|
|
43
|
+
schemaVersion: 1,
|
|
44
|
+
id,
|
|
45
|
+
...(options.parentId ? { parentId: options.parentId } : {}),
|
|
46
|
+
command,
|
|
47
|
+
target,
|
|
48
|
+
pid: process.pid,
|
|
49
|
+
processStartedAt: identity,
|
|
50
|
+
startedAt: now,
|
|
51
|
+
updatedAt: now,
|
|
52
|
+
status: 'running',
|
|
53
|
+
logPath,
|
|
54
|
+
};
|
|
55
|
+
for (const file of this.files)
|
|
56
|
+
ensureRuntimeDirectory(path.dirname(file));
|
|
57
|
+
this.flush();
|
|
58
|
+
this.timer = setInterval(() => this.observe(() => this.flush()), 5000);
|
|
59
|
+
this.timer.unref();
|
|
60
|
+
}
|
|
61
|
+
stage(stage) {
|
|
62
|
+
if (stage === this.value.stage)
|
|
63
|
+
return;
|
|
64
|
+
this.value.stage = stage;
|
|
65
|
+
this.value.stageStartedAt = new Date().toISOString();
|
|
66
|
+
this.observe(() => this.flush());
|
|
67
|
+
}
|
|
68
|
+
output(chunk) {
|
|
69
|
+
if (chunk.length === 0)
|
|
70
|
+
return;
|
|
71
|
+
this.observe(() => {
|
|
72
|
+
fs.appendFileSync(this.value.logPath, chunk);
|
|
73
|
+
this.value.lastOutputAt = new Date().toISOString();
|
|
74
|
+
if (Date.now() - this.lastFlush >= 1000)
|
|
75
|
+
this.flush();
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
finish(exitCode) {
|
|
79
|
+
clearInterval(this.timer);
|
|
80
|
+
this.value.exitCode = exitCode;
|
|
81
|
+
this.value.status = exitCode === 0 ? 'pass' : 'fail';
|
|
82
|
+
this.value.finishedAt = new Date().toISOString();
|
|
83
|
+
this.observe(() => this.flush());
|
|
84
|
+
}
|
|
85
|
+
observe(write) {
|
|
86
|
+
if (this.disabled)
|
|
87
|
+
return;
|
|
88
|
+
try {
|
|
89
|
+
write();
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
// Observation is optional. Stop it explicitly without terminating the
|
|
93
|
+
// command or its children from an event callback. Old records go stale.
|
|
94
|
+
this.disabled = true;
|
|
95
|
+
clearInterval(this.timer);
|
|
96
|
+
process.stderr.write(`Operation observation disabled for ${this.value.id}: ${error.message}\n`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
flush() {
|
|
100
|
+
this.lastFlush = Date.now();
|
|
101
|
+
this.value.updatedAt = new Date(this.lastFlush).toISOString();
|
|
102
|
+
for (const file of this.files) {
|
|
103
|
+
const temporary = `${file}.${process.pid}.tmp`;
|
|
104
|
+
fs.writeFileSync(temporary, `${JSON.stringify(this.value)}\n`, { mode: 0o600 });
|
|
105
|
+
fs.chmodSync(temporary, 0o600);
|
|
106
|
+
fs.renameSync(temporary, file);
|
|
107
|
+
}
|
|
108
|
+
if (this.notification) {
|
|
109
|
+
const temporary = `${this.notification}.${this.value.id}.tmp`;
|
|
110
|
+
fs.writeFileSync(temporary, JSON.stringify({ updatedAt: this.value.updatedAt }), {
|
|
111
|
+
mode: 0o600,
|
|
112
|
+
});
|
|
113
|
+
fs.chmodSync(temporary, 0o600);
|
|
114
|
+
fs.renameSync(temporary, this.notification);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// New observation directories must remain traversable even under a restrictive umask.
|
|
119
|
+
export function ensureRuntimeDirectory(directory) {
|
|
120
|
+
if (fs.existsSync(directory))
|
|
121
|
+
return;
|
|
122
|
+
ensureRuntimeDirectory(path.dirname(directory));
|
|
123
|
+
try {
|
|
124
|
+
fs.mkdirSync(directory, { mode: 0o700 });
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
// Another invocation can create the shared directory first.
|
|
128
|
+
if (error.code === 'EEXIST')
|
|
129
|
+
return;
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
fs.chmodSync(directory, 0o700);
|
|
133
|
+
}
|
|
134
|
+
export function readOperations(directory, onInvalid) {
|
|
135
|
+
if (!fs.existsSync(directory))
|
|
136
|
+
return [];
|
|
137
|
+
return fs
|
|
138
|
+
.readdirSync(directory)
|
|
139
|
+
.filter((name) => /^[a-f0-9-]{36}\.json$/.test(name))
|
|
140
|
+
.flatMap((name) => {
|
|
141
|
+
try {
|
|
142
|
+
const value = JSON.parse(fs.readFileSync(path.join(directory, name), 'utf8'));
|
|
143
|
+
validateOperationRecord(value, name.slice(0, -5));
|
|
144
|
+
return [value];
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
// Another invocation may prune a completed record between list and read.
|
|
148
|
+
if (error.code === 'ENOENT')
|
|
149
|
+
return [];
|
|
150
|
+
if (!onInvalid)
|
|
151
|
+
throw error;
|
|
152
|
+
onInvalid(error);
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
})
|
|
156
|
+
.sort((a, b) => a.startedAt.localeCompare(b.startedAt));
|
|
157
|
+
}
|
|
158
|
+
/** Keep captured text bounded without copying the whole tail for every chunk. */
|
|
159
|
+
export class OperationOutputTail {
|
|
160
|
+
constructor(limit = 64 * 1024 * 1024) {
|
|
161
|
+
this.limit = limit;
|
|
162
|
+
this.chunks = [];
|
|
163
|
+
this.length = 0;
|
|
164
|
+
}
|
|
165
|
+
append(chunk) {
|
|
166
|
+
if (!chunk)
|
|
167
|
+
return;
|
|
168
|
+
this.chunks.push(chunk);
|
|
169
|
+
this.length += chunk.length;
|
|
170
|
+
while (this.length > this.limit) {
|
|
171
|
+
const first = this.chunks[0];
|
|
172
|
+
const remove = Math.min(first.length, this.length - this.limit);
|
|
173
|
+
if (remove === first.length)
|
|
174
|
+
this.chunks.shift();
|
|
175
|
+
else
|
|
176
|
+
this.chunks[0] = first.slice(remove);
|
|
177
|
+
this.length -= remove;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
toString() {
|
|
181
|
+
return this.chunks.join('');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=operation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operation.js","sourceRoot":"","sources":["../../src/runtime/operation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { RuntimeDecisionReport, RuntimeReadinessDecision } from './decision-types.js';
|
|
2
|
+
export interface OrchestrateRuntimeUpOptions<T extends RuntimeDecisionReport = RuntimeDecisionReport> {
|
|
3
|
+
decide: () => Promise<T>;
|
|
4
|
+
onInstall: (report: T) => Promise<void>;
|
|
5
|
+
onLaunch: (report: T) => Promise<void>;
|
|
6
|
+
onReady: (report: T) => Promise<void>;
|
|
7
|
+
onBlocked?: (report: T) => Promise<void>;
|
|
8
|
+
/** Shared flag — set true after first install attempt to prevent loops. */
|
|
9
|
+
installAttempted?: {
|
|
10
|
+
value: boolean;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export interface OrchestrateRuntimeUpResult<T extends RuntimeDecisionReport = RuntimeDecisionReport> {
|
|
14
|
+
report: T;
|
|
15
|
+
exitDecision: RuntimeReadinessDecision;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Generic install → relaunch decision loop for product runners.
|
|
19
|
+
* Hosts supply shell/platform actions via onInstall/onLaunch/onReady callbacks.
|
|
20
|
+
*/
|
|
21
|
+
export declare function orchestrateRuntimeUp<T extends RuntimeDecisionReport>(options: OrchestrateRuntimeUpOptions<T>): Promise<OrchestrateRuntimeUpResult<T>>;
|
|
22
|
+
//# sourceMappingURL=orchestrate-up.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrate-up.d.ts","sourceRoot":"","sources":["../../src/runtime/orchestrate-up.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAE3F,MAAM,WAAW,2BAA2B,CAC1C,CAAC,SAAS,qBAAqB,GAAG,qBAAqB;IAEvD,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;IACzB,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,OAAO,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;CACvC;AAED,MAAM,WAAW,0BAA0B,CACzC,CAAC,SAAS,qBAAqB,GAAG,qBAAqB;IAEvD,MAAM,EAAE,CAAC,CAAC;IACV,YAAY,EAAE,wBAAwB,CAAC;CACxC;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,SAAS,qBAAqB,EACxE,OAAO,EAAE,2BAA2B,CAAC,CAAC,CAAC,GACtC,OAAO,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,CA4BxC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic install → relaunch decision loop for product runners.
|
|
3
|
+
* Hosts supply shell/platform actions via onInstall/onLaunch/onReady callbacks.
|
|
4
|
+
*/
|
|
5
|
+
export async function orchestrateRuntimeUp(options) {
|
|
6
|
+
const installFlag = options.installAttempted ?? { value: false };
|
|
7
|
+
const report = await options.decide();
|
|
8
|
+
switch (report.decision) {
|
|
9
|
+
case 'install': {
|
|
10
|
+
if (installFlag.value) {
|
|
11
|
+
throw new Error(`install did not resolve runtime (${report.reasonCode})`);
|
|
12
|
+
}
|
|
13
|
+
installFlag.value = true;
|
|
14
|
+
await options.onInstall(report);
|
|
15
|
+
return orchestrateRuntimeUp({ ...options, installAttempted: installFlag });
|
|
16
|
+
}
|
|
17
|
+
case 'launch':
|
|
18
|
+
case 'relaunch':
|
|
19
|
+
case 'build':
|
|
20
|
+
await options.onLaunch(report);
|
|
21
|
+
return { report, exitDecision: report.decision };
|
|
22
|
+
case 'ready':
|
|
23
|
+
await options.onReady(report);
|
|
24
|
+
return { report, exitDecision: 'ready' };
|
|
25
|
+
case 'blocked':
|
|
26
|
+
if (options.onBlocked)
|
|
27
|
+
await options.onBlocked(report);
|
|
28
|
+
return { report, exitDecision: 'blocked' };
|
|
29
|
+
default:
|
|
30
|
+
if (options.onBlocked)
|
|
31
|
+
await options.onBlocked(report);
|
|
32
|
+
return { report, exitDecision: report.decision };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=orchestrate-up.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrate-up.js","sourceRoot":"","sources":["../../src/runtime/orchestrate-up.ts"],"names":[],"mappings":"AAqBA;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAAuC;IAEvC,MAAM,WAAW,GAAG,OAAO,CAAC,gBAAgB,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IACjE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC;IAEtC,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CAAC,oCAAoC,MAAM,CAAC,UAAU,GAAG,CAAC,CAAC;YAC5E,CAAC;YACD,WAAW,CAAC,KAAK,GAAG,IAAI,CAAC;YACzB,MAAM,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAChC,OAAO,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,CAAC,CAAC;QAC7E,CAAC;QACD,KAAK,QAAQ,CAAC;QACd,KAAK,UAAU,CAAC;QAChB,KAAK,OAAO;YACV,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC/B,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;QACnD,KAAK,OAAO;YACV,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC9B,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;QAC3C,KAAK,SAAS;YACZ,IAAI,OAAO,CAAC,SAAS;gBAAE,MAAM,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACvD,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;QAC7C;YACE,IAAI,OAAO,CAAC,SAAS;gBAAE,MAAM,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACvD,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;IACrD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { UiActionTransport } from '../adapters/ui.js';
|
|
2
|
+
import type { ActionExecutionContext } from '../core/types.js';
|
|
3
|
+
export type ReactNativeBridgeCommandName = 'navigate' | 'press' | 'keyPress' | 'setInput' | 'scroll' | 'waitFor' | 'screenshot' | 'status' | 'lifecycle' | 'hud' | 'trace' | 'observeUi';
|
|
4
|
+
export interface ReactNativeBridgeCommand {
|
|
5
|
+
command: ReactNativeBridgeCommandName;
|
|
6
|
+
nodeId: string;
|
|
7
|
+
payload: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
export interface ReactNativeBridge {
|
|
10
|
+
send(command: ReactNativeBridgeCommand, context: ActionExecutionContext): Promise<unknown>;
|
|
11
|
+
}
|
|
12
|
+
export interface CreateReactNativeBridgeUiTransportOptions {
|
|
13
|
+
bridge: ReactNativeBridge;
|
|
14
|
+
}
|
|
15
|
+
export declare function createReactNativeBridgeUiTransport(options: CreateReactNativeBridgeUiTransportOptions): UiActionTransport;
|
|
16
|
+
export declare const createReactNativeCdpBridgeUiTransport: typeof createReactNativeBridgeUiTransport;
|
|
17
|
+
//# sourceMappingURL=react-native-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-native-bridge.d.ts","sourceRoot":"","sources":["../../src/runtime/react-native-bridge.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAoB,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,KAAK,EAAE,sBAAsB,EAA2B,MAAM,kBAAkB,CAAC;AAExF,MAAM,MAAM,4BAA4B,GACpC,UAAU,GACV,OAAO,GACP,UAAU,GACV,UAAU,GACV,QAAQ,GACR,SAAS,GACT,YAAY,GACZ,QAAQ,GACR,WAAW,GACX,KAAK,GACL,OAAO,GACP,WAAW,CAAC;AAEhB,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,4BAA4B,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,OAAO,EAAE,wBAAwB,EAAE,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC5F;AAED,MAAM,WAAW,yCAAyC;IACxD,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAgBD,wBAAgB,kCAAkC,CAChD,OAAO,EAAE,yCAAyC,GACjD,iBAAiB,CAwBnB;AAED,eAAO,MAAM,qCAAqC,2CAAqC,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const RN_COMMANDS = {
|
|
2
|
+
'ui.navigate': 'navigate',
|
|
3
|
+
'ui.press': 'press',
|
|
4
|
+
'ui.key_press': 'keyPress',
|
|
5
|
+
'ui.set_input': 'setInput',
|
|
6
|
+
'ui.scroll': 'scroll',
|
|
7
|
+
'ui.wait_for': 'waitFor',
|
|
8
|
+
'ui.screenshot': 'screenshot',
|
|
9
|
+
'app.status': 'status',
|
|
10
|
+
'app.lifecycle': 'lifecycle',
|
|
11
|
+
'app.hud': 'hud',
|
|
12
|
+
'app.trace': 'trace',
|
|
13
|
+
};
|
|
14
|
+
export function createReactNativeBridgeUiTransport(options) {
|
|
15
|
+
return {
|
|
16
|
+
async execute(action, node, context) {
|
|
17
|
+
const { action: _action, ...payload } = node;
|
|
18
|
+
const command = RN_COMMANDS[action];
|
|
19
|
+
if (!command) {
|
|
20
|
+
throw new Error(`${action} is not supported by the React Native bridge. Next: use the native Agent Device adapter for ${action}.`);
|
|
21
|
+
}
|
|
22
|
+
return options.bridge.send({ command, nodeId: context.nodeId, payload }, context);
|
|
23
|
+
},
|
|
24
|
+
async observe(refs, node, context) {
|
|
25
|
+
const result = await options.bridge.send({
|
|
26
|
+
command: 'observeUi',
|
|
27
|
+
nodeId: context.nodeId,
|
|
28
|
+
payload: { refs, node },
|
|
29
|
+
}, context);
|
|
30
|
+
return normalizeBridgeObservationResult(result, refs);
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export const createReactNativeCdpBridgeUiTransport = createReactNativeBridgeUiTransport;
|
|
35
|
+
function normalizeBridgeObservationResult(result, refs) {
|
|
36
|
+
if (!result || typeof result !== 'object' || Array.isArray(result)) {
|
|
37
|
+
return {
|
|
38
|
+
warnings: refs.map((ref) => ({ ref, message: 'Bridge observeUi returned no object.' })),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const record = result;
|
|
42
|
+
if (record.ok === false) {
|
|
43
|
+
const message = typeof record.error === 'string' ? record.error : 'Bridge observeUi failed.';
|
|
44
|
+
return { warnings: refs.map((ref) => ({ ref, message })) };
|
|
45
|
+
}
|
|
46
|
+
const observations = record.observations;
|
|
47
|
+
const warnings = record.warnings;
|
|
48
|
+
return {
|
|
49
|
+
...(observations && typeof observations === 'object' && !Array.isArray(observations)
|
|
50
|
+
? { observations: observations }
|
|
51
|
+
: {}),
|
|
52
|
+
...(Array.isArray(warnings)
|
|
53
|
+
? { warnings: warnings }
|
|
54
|
+
: {}),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=react-native-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-native-bridge.js","sourceRoot":"","sources":["../../src/runtime/react-native-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,qBAAqB,QAAsB,CAAC"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
const require = createRequire(import.meta.url);
|
|
3
|
+
const packageJson = require('../package.json');
|
|
4
|
+
if (typeof packageJson.version !== 'string' || !packageJson.version) {
|
|
5
|
+
throw new Error('@farmslot/recipe-runner package version is missing.');
|
|
6
|
+
}
|
|
7
|
+
export const RECIPE_RUNNER_VERSION = packageJson.version;
|
|
8
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAA0B,CAAC;AAExE,IAAI,OAAO,WAAW,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;IACpE,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAG,WAAW,CAAC,OAAO,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@farmslot/recipe-runner",
|
|
3
|
+
"version": "0.23.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"farmslot-visual-review": "./bin/farmslot-visual-review.mjs"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./cli": {
|
|
17
|
+
"types": "./dist/cli/index.d.ts",
|
|
18
|
+
"import": "./dist/cli/index.js",
|
|
19
|
+
"default": "./dist/cli/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./cli/support": {
|
|
22
|
+
"types": "./dist/cli/support.d.ts",
|
|
23
|
+
"import": "./dist/cli/support.js",
|
|
24
|
+
"default": "./dist/cli/support.js"
|
|
25
|
+
},
|
|
26
|
+
"./runner": {
|
|
27
|
+
"types": "./dist/core/runner.d.ts",
|
|
28
|
+
"import": "./dist/core/runner.js",
|
|
29
|
+
"default": "./dist/core/runner.js"
|
|
30
|
+
},
|
|
31
|
+
"./types": {
|
|
32
|
+
"types": "./dist/core/types.d.ts",
|
|
33
|
+
"import": "./dist/core/types.js",
|
|
34
|
+
"default": "./dist/core/types.js"
|
|
35
|
+
},
|
|
36
|
+
"./writers": {
|
|
37
|
+
"types": "./dist/node/writers.d.ts",
|
|
38
|
+
"import": "./dist/node/writers.js",
|
|
39
|
+
"default": "./dist/node/writers.js"
|
|
40
|
+
},
|
|
41
|
+
"./adapters/core": {
|
|
42
|
+
"types": "./dist/adapters/core.d.ts",
|
|
43
|
+
"import": "./dist/adapters/core.js",
|
|
44
|
+
"default": "./dist/adapters/core.js"
|
|
45
|
+
},
|
|
46
|
+
"./adapters/app-lifecycle": {
|
|
47
|
+
"types": "./dist/adapters/app-lifecycle.d.ts",
|
|
48
|
+
"import": "./dist/adapters/app-lifecycle.js",
|
|
49
|
+
"default": "./dist/adapters/app-lifecycle.js"
|
|
50
|
+
},
|
|
51
|
+
"./adapters/ui": {
|
|
52
|
+
"types": "./dist/adapters/ui.d.ts",
|
|
53
|
+
"import": "./dist/adapters/ui.js",
|
|
54
|
+
"default": "./dist/adapters/ui.js"
|
|
55
|
+
},
|
|
56
|
+
"./runtime/browser-extension": {
|
|
57
|
+
"types": "./dist/runtime/browser-extension.d.ts",
|
|
58
|
+
"import": "./dist/runtime/browser-extension.js",
|
|
59
|
+
"default": "./dist/runtime/browser-extension.js"
|
|
60
|
+
},
|
|
61
|
+
"./runtime/cdp": {
|
|
62
|
+
"types": "./dist/runtime/cdp.d.ts",
|
|
63
|
+
"import": "./dist/runtime/cdp.js",
|
|
64
|
+
"default": "./dist/runtime/cdp.js"
|
|
65
|
+
},
|
|
66
|
+
"./runtime/react-native-bridge": {
|
|
67
|
+
"types": "./dist/runtime/react-native-bridge.d.ts",
|
|
68
|
+
"import": "./dist/runtime/react-native-bridge.js",
|
|
69
|
+
"default": "./dist/runtime/react-native-bridge.js"
|
|
70
|
+
},
|
|
71
|
+
"./runtime/deps-readiness": {
|
|
72
|
+
"types": "./dist/runtime/deps-readiness.d.ts",
|
|
73
|
+
"import": "./dist/runtime/deps-readiness.js",
|
|
74
|
+
"default": "./dist/runtime/deps-readiness.js"
|
|
75
|
+
},
|
|
76
|
+
"./runtime/log-analysis": {
|
|
77
|
+
"types": "./dist/runtime/log-analysis.d.ts",
|
|
78
|
+
"import": "./dist/runtime/log-analysis.js",
|
|
79
|
+
"default": "./dist/runtime/log-analysis.js"
|
|
80
|
+
},
|
|
81
|
+
"./runtime/metro-probe": {
|
|
82
|
+
"types": "./dist/runtime/metro-probe.d.ts",
|
|
83
|
+
"import": "./dist/runtime/metro-probe.js",
|
|
84
|
+
"default": "./dist/runtime/metro-probe.js"
|
|
85
|
+
},
|
|
86
|
+
"./runtime/decision-types": {
|
|
87
|
+
"types": "./dist/runtime/decision-types.d.ts",
|
|
88
|
+
"import": "./dist/runtime/decision-types.js",
|
|
89
|
+
"default": "./dist/runtime/decision-types.js"
|
|
90
|
+
},
|
|
91
|
+
"./runtime/orchestrate-up": {
|
|
92
|
+
"types": "./dist/runtime/orchestrate-up.d.ts",
|
|
93
|
+
"import": "./dist/runtime/orchestrate-up.js",
|
|
94
|
+
"default": "./dist/runtime/orchestrate-up.js"
|
|
95
|
+
},
|
|
96
|
+
"./visual-review": {
|
|
97
|
+
"types": "./visual-review/index.d.mts",
|
|
98
|
+
"import": "./visual-review/index.mjs",
|
|
99
|
+
"default": "./visual-review/index.mjs"
|
|
100
|
+
},
|
|
101
|
+
"./runtime/operation": {
|
|
102
|
+
"types": "./dist/runtime/operation.d.ts",
|
|
103
|
+
"import": "./dist/runtime/operation.js",
|
|
104
|
+
"default": "./dist/runtime/operation.js"
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"scripts": {
|
|
108
|
+
"typecheck": "tsc --noEmit --project tsconfig.json",
|
|
109
|
+
"test": "node ../../scripts/quality/run-tsx-tests.mjs --cwd . --tsconfig tsconfig.json test src/core/observations.test.ts && node --test test/visual-review-tool.test.mjs",
|
|
110
|
+
"format": "prettier --write --ignore-path ../../.prettierignore .",
|
|
111
|
+
"format:check": "prettier --check --ignore-path ../../.prettierignore .",
|
|
112
|
+
"lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
113
|
+
"lint:fix": "eslint \"src/**/*.ts\" \"test/**/*.ts\" --fix",
|
|
114
|
+
"quality": "prettier --check --ignore-path ../../.prettierignore . && eslint \"src/**/*.ts\" \"test/**/*.ts\" && tsc --noEmit --project tsconfig.json && yarn build && yarn test",
|
|
115
|
+
"build": "yarn workspace @farmslot/protocol build && rm -rf dist && tsc --project tsconfig.build.json",
|
|
116
|
+
"prepack": "cd ../.. && node scripts/quality/check-farmslot-package-readiness.mjs --require-changelog --packages @farmslot/recipe-runner && yarn workspace @farmslot/recipe-runner build",
|
|
117
|
+
"prepublishOnly": "node ../../scripts/quality/check-farmslot-package-readiness.mjs --publish --packages @farmslot/recipe-runner"
|
|
118
|
+
},
|
|
119
|
+
"dependencies": {
|
|
120
|
+
"@farmslot/protocol": "0.34.0",
|
|
121
|
+
"commander": "^12.0.0",
|
|
122
|
+
"semver": "^7.7.3",
|
|
123
|
+
"ws": "^8.18.0"
|
|
124
|
+
},
|
|
125
|
+
"devDependencies": {
|
|
126
|
+
"@types/node": "^22.0.0",
|
|
127
|
+
"@types/ws": "^8.5.12",
|
|
128
|
+
"eslint": "^10.3.0",
|
|
129
|
+
"prettier": "^3.8.3",
|
|
130
|
+
"tsx": "^4.19.0",
|
|
131
|
+
"typescript": "^5.6.0"
|
|
132
|
+
},
|
|
133
|
+
"repository": {
|
|
134
|
+
"type": "git",
|
|
135
|
+
"url": "git+https://github.com/deeeed/farmslot.git",
|
|
136
|
+
"directory": "packages/recipe-runner"
|
|
137
|
+
},
|
|
138
|
+
"bugs": {
|
|
139
|
+
"url": "https://github.com/deeeed/farmslot/issues"
|
|
140
|
+
},
|
|
141
|
+
"license": "MIT",
|
|
142
|
+
"homepage": "https://farmslot.io/docs/architecture/recipe-runner",
|
|
143
|
+
"keywords": [
|
|
144
|
+
"farmslot",
|
|
145
|
+
"recipe-runner",
|
|
146
|
+
"validation",
|
|
147
|
+
"agentic-engineering"
|
|
148
|
+
],
|
|
149
|
+
"files": [
|
|
150
|
+
"README.md",
|
|
151
|
+
"LICENSE",
|
|
152
|
+
"bin/**/*.mjs",
|
|
153
|
+
"visual-review/**/*.mjs",
|
|
154
|
+
"visual-review/**/*.d.mts",
|
|
155
|
+
"dist/**/*.js",
|
|
156
|
+
"dist/**/*.d.ts",
|
|
157
|
+
"dist/**/*.d.ts.map",
|
|
158
|
+
"dist/**/*.js.map"
|
|
159
|
+
],
|
|
160
|
+
"publishConfig": {
|
|
161
|
+
"access": "public"
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# scroll-to-visible conformance
|
|
2
|
+
|
|
3
|
+
Two layers exercise the `ui.scroll_to` contract.
|
|
4
|
+
|
|
5
|
+
## Provider-neutral suite
|
|
6
|
+
|
|
7
|
+
`test/scroll-to-visible.test.ts` runs recipes through `createRecipeRunner` and
|
|
8
|
+
`createStandardUiAdapters` against a fake native-style provider: one scroll surface in
|
|
9
|
+
window coordinates, one device lock, and a retained session:
|
|
10
|
+
|
|
11
|
+
| Case | Expectation |
|
|
12
|
+
| -------------------------------------------- | ------------------------------------------------------------------------- |
|
|
13
|
+
| Target already in the safe viewport | `alreadyVisible: true`, no `scrollTo` call, settlement `skipped` |
|
|
14
|
+
| Far target | one absolute `scrollTo`, `before`/`after` bounds, settled, `finalVisible` |
|
|
15
|
+
| Flattened Text target + measurable anchor | passes via `visibility_anchor_test_id`; target still asserted present |
|
|
16
|
+
| Anchor present, target missing | `SCROLL_TARGET_MISSING`; the anchor never stands in for the target |
|
|
17
|
+
| Row under the HUD | `safeViewport` excludes the HUD; the row ends above it |
|
|
18
|
+
| Layout that never stops changing | `SCROLL_SETTLEMENT_TIMEOUT` with the last geometry |
|
|
19
|
+
| Layout that shifts once, then settles | passes with the settled bounds |
|
|
20
|
+
| Three nodes on one retained session | same `sessionId`, one connection, no self-lock |
|
|
21
|
+
| Provider that keeps its lock | next node fails `SCROLL_SESSION_CONFLICT` |
|
|
22
|
+
| Surface missing / box-less target, no anchor | `SCROLL_SURFACE_MISSING` / `SCROLL_TARGET_NOT_MEASURABLE` |
|
|
23
|
+
| Content too short to reach the target | `SCROLL_TARGET_NOT_VISIBLE`; `verify_visible: false` records it instead |
|
|
24
|
+
|
|
25
|
+
Every failure is `cause_class: harness` with `error_code` and the observed geometry in
|
|
26
|
+
`error_details`. Absolute versus relative `ui.scroll` movement is covered in
|
|
27
|
+
`test/recipe-runner.test.ts`.
|
|
28
|
+
|
|
29
|
+
## Real browser page
|
|
30
|
+
|
|
31
|
+
`page.html` is the same scenario set on a real DOM: a `scroll-surface` container, a far
|
|
32
|
+
`history-proof` row, a `display: contents` `flat-text` span inside the measurable
|
|
33
|
+
`flat-anchor` row, and a `jitter-target` below a block that grows on every animation
|
|
34
|
+
frame when the URL has `?jitter=1`. Serve it from the Command Center Vite origin so the
|
|
35
|
+
CDP runner can attach to it:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
<ui_url>/@fs<repo>/packages/recipe-runner/test/fixtures/scroll-to-visible/page.html
|
|
39
|
+
```
|