@flowriki/agent 0.1.0-beta.53 → 0.1.0-beta.55
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.
|
@@ -14,7 +14,9 @@ import { spawn as spawn2 } from "child_process";
|
|
|
14
14
|
import fs3 from "fs";
|
|
15
15
|
import os3 from "os";
|
|
16
16
|
import path3 from "path";
|
|
17
|
+
import { execFile as execFile2 } from "child_process";
|
|
17
18
|
import fs4 from "fs";
|
|
19
|
+
import os4 from "os";
|
|
18
20
|
import path4 from "path";
|
|
19
21
|
|
|
20
22
|
// ../test-model/dist/chunk-I5COYCQ5.js
|
|
@@ -2647,7 +2649,7 @@ async function cloudDevices(account, key) {
|
|
|
2647
2649
|
if (!res.ok) throw new Error(`${account.provider} answered ${res.status}.`);
|
|
2648
2650
|
return res.json();
|
|
2649
2651
|
};
|
|
2650
|
-
const platformOf = (
|
|
2652
|
+
const platformOf = (os5) => /android/i.test(os5) ? "android" : /ios/i.test(os5) ? "ios" : null;
|
|
2651
2653
|
const out = [];
|
|
2652
2654
|
if (account.provider === "browserstack") {
|
|
2653
2655
|
for (const d of await get("https://api-cloud.browserstack.com/app-automate/devices.json")) {
|
|
@@ -2661,11 +2663,11 @@ async function cloudDevices(account, key) {
|
|
|
2661
2663
|
if (p) out.push({ name: d.name, platform: p, osVersion: d.osVersion });
|
|
2662
2664
|
}
|
|
2663
2665
|
} else {
|
|
2664
|
-
for (const
|
|
2665
|
-
const listed = await get(`https://mobile-api.lambdatest.com/mobile-automation/api/v1/list?region=us&os=${
|
|
2666
|
+
for (const os5 of ["android", "ios"]) {
|
|
2667
|
+
const listed = await get(`https://mobile-api.lambdatest.com/mobile-automation/api/v1/list?region=us&os=${os5}`);
|
|
2666
2668
|
for (const [, devices] of Object.entries(listed)) {
|
|
2667
2669
|
if (!Array.isArray(devices)) continue;
|
|
2668
|
-
for (const d of devices) out.push({ name: d.deviceName, platform:
|
|
2670
|
+
for (const d of devices) out.push({ name: d.deviceName, platform: os5, osVersion: d.platformVersion });
|
|
2669
2671
|
}
|
|
2670
2672
|
}
|
|
2671
2673
|
}
|
|
@@ -3313,6 +3315,16 @@ var MobileSession = class _MobileSession {
|
|
|
3313
3315
|
}
|
|
3314
3316
|
return png;
|
|
3315
3317
|
}
|
|
3318
|
+
/** The screen as a picture to LOOK at — the recorder's mirror, the run
|
|
3319
|
+
* page's live phone — at most `maxPx` on its longer side. A phone's own
|
|
3320
|
+
* resolution is three to four times what a mirror draws, and every byte
|
|
3321
|
+
* of it crosses the control channel each time; on macOS `sips` shrinks it
|
|
3322
|
+
* in a few milliseconds, elsewhere the full picture is sent. Evidence
|
|
3323
|
+
* files keep the full size. */
|
|
3324
|
+
async preview(maxPx = 900) {
|
|
3325
|
+
const png = await this.screenshot();
|
|
3326
|
+
return shrink(png, maxPx);
|
|
3327
|
+
}
|
|
3316
3328
|
/** Android: the activity on screen. iOS has none worth reading. */
|
|
3317
3329
|
async currentScreenName() {
|
|
3318
3330
|
if (this.platform !== "android") return "";
|
|
@@ -3510,6 +3522,22 @@ var MobileSession = class _MobileSession {
|
|
|
3510
3522
|
await this.driver.close();
|
|
3511
3523
|
}
|
|
3512
3524
|
};
|
|
3525
|
+
async function shrink(png, maxPx) {
|
|
3526
|
+
if (process.platform !== "darwin") return png;
|
|
3527
|
+
const dir = fs4.mkdtempSync(path4.join(os4.tmpdir(), "flowriki-shot-"));
|
|
3528
|
+
const file = path4.join(dir, "s.png");
|
|
3529
|
+
try {
|
|
3530
|
+
fs4.writeFileSync(file, png);
|
|
3531
|
+
await new Promise((resolve, reject) => {
|
|
3532
|
+
execFile2("/usr/bin/sips", ["-Z", String(maxPx), file], { timeout: 5e3 }, (error) => error ? reject(error) : resolve());
|
|
3533
|
+
});
|
|
3534
|
+
return fs4.readFileSync(file);
|
|
3535
|
+
} catch {
|
|
3536
|
+
return png;
|
|
3537
|
+
} finally {
|
|
3538
|
+
fs4.rmSync(dir, { recursive: true, force: true });
|
|
3539
|
+
}
|
|
3540
|
+
}
|
|
3513
3541
|
var ANDROID_KEYS = {
|
|
3514
3542
|
enter: 66,
|
|
3515
3543
|
return: 66,
|
|
@@ -4166,6 +4194,7 @@ export {
|
|
|
4166
4194
|
checkMobileAssertion,
|
|
4167
4195
|
openSessionOn,
|
|
4168
4196
|
MobileSession,
|
|
4197
|
+
shrink,
|
|
4169
4198
|
MOBILE_TIMEOUTS,
|
|
4170
4199
|
performMobileStep,
|
|
4171
4200
|
runMobileSteps,
|
|
@@ -68,7 +68,7 @@ import {
|
|
|
68
68
|
textIndependent,
|
|
69
69
|
validateActors,
|
|
70
70
|
webCloudOf
|
|
71
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-3XKTIMRP.js";
|
|
72
72
|
|
|
73
73
|
// src/engine/machine.ts
|
|
74
74
|
import fs from "fs";
|
|
@@ -76,7 +76,7 @@ import os from "os";
|
|
|
76
76
|
import path from "path";
|
|
77
77
|
import { createRequire } from "module";
|
|
78
78
|
import { spawnSync } from "child_process";
|
|
79
|
-
var AGENT_VERSION = "0.1.0-beta.
|
|
79
|
+
var AGENT_VERSION = "0.1.0-beta.55";
|
|
80
80
|
async function prepareBrowsers() {
|
|
81
81
|
if (browsersReady()) {
|
|
82
82
|
return { ok: true, already: true, message: "chromium is already installed" };
|
|
@@ -136,7 +136,7 @@ async function checkMachine() {
|
|
|
136
136
|
}
|
|
137
137
|
} catch {
|
|
138
138
|
}
|
|
139
|
-
const { mobileDoctor: mobileDoctor2 } = await import("./dist-
|
|
139
|
+
const { mobileDoctor: mobileDoctor2 } = await import("./dist-RTDFWPOC.js");
|
|
140
140
|
return {
|
|
141
141
|
agentVersion: AGENT_VERSION,
|
|
142
142
|
node: process.versions.node,
|
|
@@ -9846,8 +9846,11 @@ var ownerOf = (l) => l.draft ? "recording" : "debug";
|
|
|
9846
9846
|
var SECRET_WORDS = /password|passwd|pass[-_\s]?code|pwd|secret|otp|\bpin\b|cvv|cvc/i;
|
|
9847
9847
|
async function screenOf(l, withImage = false) {
|
|
9848
9848
|
l.session.changed();
|
|
9849
|
-
const screen = await
|
|
9850
|
-
|
|
9849
|
+
const [screen, png, where] = await Promise.all([
|
|
9850
|
+
l.session.screen(),
|
|
9851
|
+
withImage ? l.session.preview() : Promise.resolve(null),
|
|
9852
|
+
l.session.currentScreenName()
|
|
9853
|
+
]);
|
|
9851
9854
|
return {
|
|
9852
9855
|
...png ? { image: png.toString("base64") } : {},
|
|
9853
9856
|
width: screen.size.width,
|
|
@@ -9862,7 +9865,7 @@ async function screenOf(l, withImage = false) {
|
|
|
9862
9865
|
...n2.value ? { value: n2.password ? "\u2022\u2022\u2022" : n2.value } : {},
|
|
9863
9866
|
...n2.id ? { id: n2.id } : {}
|
|
9864
9867
|
})),
|
|
9865
|
-
where
|
|
9868
|
+
where,
|
|
9866
9869
|
device: l.session.deviceName
|
|
9867
9870
|
};
|
|
9868
9871
|
}
|
|
@@ -9890,7 +9893,7 @@ function mobileHandlers(ctx) {
|
|
|
9890
9893
|
const session = live.get(platform)?.session ?? openSessionOn(platform);
|
|
9891
9894
|
if (!session) return { ok: true, result: { image: null } };
|
|
9892
9895
|
try {
|
|
9893
|
-
const png = await session.
|
|
9896
|
+
const png = await session.preview(720);
|
|
9894
9897
|
return { ok: true, result: { image: png.toString("base64"), device: session.deviceName } };
|
|
9895
9898
|
} catch {
|
|
9896
9899
|
return { ok: true, result: { image: null } };
|
|
@@ -10003,18 +10006,18 @@ function mobileHandlers(ctx) {
|
|
|
10003
10006
|
if (op === "run" || step.type === "signIn" || step.type === "assert") {
|
|
10004
10007
|
const done = await runMobileSteps(l.session, [step], { values: l.values, resolveSecret: l.resolveSecret, resolveAuth: l.resolveAuth, ...l.runHelper ? { runHelper: l.runHelper } : {} });
|
|
10005
10008
|
const result = done.results[0];
|
|
10006
|
-
if (op === "run") return { ok: true, result: { result: result ?? null
|
|
10009
|
+
if (op === "run") return { ok: true, result: { result: result ?? null } };
|
|
10007
10010
|
if (done.status !== "passed") throw new Error(result?.detail ?? done.error ?? "it did not work");
|
|
10008
10011
|
} else {
|
|
10009
10012
|
await performMobileStep(l.session, step, { values: l.values, resolveSecret: l.resolveSecret, resolveAuth: l.resolveAuth, ...l.runHelper ? { runHelper: l.runHelper } : {} });
|
|
10010
10013
|
}
|
|
10011
10014
|
} catch (error) {
|
|
10012
10015
|
if (secret2) l.typed.delete(ref);
|
|
10013
|
-
return { ok: true, result: { kept: false, error: error.message.split("\n")[0]
|
|
10016
|
+
return { ok: true, result: { kept: false, error: error.message.split("\n")[0] } };
|
|
10014
10017
|
}
|
|
10015
|
-
await new Promise((r) => setTimeout(r,
|
|
10018
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
10016
10019
|
l.draft?.steps.push(step);
|
|
10017
|
-
return { ok: true, result: { kept: true, step, durationMs: Date.now() - t0, steps: l.draft?.steps ?? []
|
|
10020
|
+
return { ok: true, result: { kept: true, step, durationMs: Date.now() - t0, steps: l.draft?.steps ?? [] } };
|
|
10018
10021
|
}
|
|
10019
10022
|
if (op === "check") {
|
|
10020
10023
|
const assertion = RecordedStepSchema.shape.proposals.element.parse({ enabled: true, ...command.args["assertion"] });
|
|
@@ -10336,75 +10339,15 @@ function createClaudeCli(options) {
|
|
|
10336
10339
|
ask(ask) {
|
|
10337
10340
|
if (current) return { started: false, detail: "The assistant is already answering a question on this machine." };
|
|
10338
10341
|
fs43.mkdirSync(scratchRoot2, { recursive: true, mode: 448 });
|
|
10339
|
-
const dir =
|
|
10342
|
+
const dir = path42.join(scratchRoot2, `project-${ask.projectId.replace(/[^A-Za-z0-9_-]/g, "_")}`);
|
|
10343
|
+
fs43.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
10340
10344
|
const mcpConfigPath = path42.join(dir, "mcp.json");
|
|
10341
10345
|
fs43.writeFileSync(
|
|
10342
10346
|
mcpConfigPath,
|
|
10343
10347
|
JSON.stringify({ mcpServers: { [MCP_SERVER_NAME]: { command: options.mcp.command, args: options.mcp.args } } }),
|
|
10344
10348
|
{ mode: 384 }
|
|
10345
10349
|
);
|
|
10346
|
-
|
|
10347
|
-
try {
|
|
10348
|
-
child = spawn2(
|
|
10349
|
-
binary,
|
|
10350
|
-
buildAskArgs({
|
|
10351
|
-
prompt: ask.prompt,
|
|
10352
|
-
mcpConfigPath,
|
|
10353
|
-
projectId: ask.projectId,
|
|
10354
|
-
projectName: ask.projectName,
|
|
10355
|
-
...ask.sessionId ? { sessionId: ask.sessionId } : {},
|
|
10356
|
-
...ask.folders?.length ? { folders: ask.folders } : {},
|
|
10357
|
-
...ask.mode ? { mode: ask.mode } : {}
|
|
10358
|
-
}),
|
|
10359
|
-
// THE SCRATCH FOLDER, not the project: nothing here to read or write.
|
|
10360
|
-
{ cwd: dir, stdio: ["ignore", "pipe", "pipe"] }
|
|
10361
|
-
);
|
|
10362
|
-
} catch {
|
|
10363
|
-
fs43.rmSync(dir, { recursive: true, force: true });
|
|
10364
|
-
return { started: false, detail: "The assistant\u2019s command-line tool could not be started." };
|
|
10365
|
-
}
|
|
10366
|
-
current = { askId: ask.askId, child };
|
|
10367
|
-
let buffer = "", stderr = "", sawDone = false, ended = false;
|
|
10368
|
-
const handleLine = (line) => {
|
|
10369
|
-
for (const event of eventsFromLine(ask.askId, line)) {
|
|
10370
|
-
if (event.name === "assistant.done") sawDone = true;
|
|
10371
|
-
ask.emit(event.name, event.data);
|
|
10372
|
-
}
|
|
10373
|
-
};
|
|
10374
|
-
const end = (ok, detail) => {
|
|
10375
|
-
if (ended) return;
|
|
10376
|
-
ended = true;
|
|
10377
|
-
clearTimeout(timer);
|
|
10378
|
-
if (buffer.trim()) handleLine(buffer);
|
|
10379
|
-
if (!sawDone) ask.emit("assistant.done", { askId: ask.askId, ok, result: detail });
|
|
10380
|
-
current = null;
|
|
10381
|
-
fs43.rmSync(dir, { recursive: true, force: true });
|
|
10382
|
-
};
|
|
10383
|
-
const timer = setTimeout(() => {
|
|
10384
|
-
child.kill("SIGTERM");
|
|
10385
|
-
end(false, `Stopped after ${Math.max(1, Math.round(maxAskMs / 6e4))} minutes. Whatever it saved so far is on the Branches page \u2014 send \u201Ccontinue\u201D to carry on.`);
|
|
10386
|
-
}, maxAskMs);
|
|
10387
|
-
timer.unref?.();
|
|
10388
|
-
child.stdout?.on("data", (chunk) => {
|
|
10389
|
-
buffer += chunk.toString();
|
|
10390
|
-
let at;
|
|
10391
|
-
while ((at = buffer.indexOf("\n")) >= 0) {
|
|
10392
|
-
handleLine(buffer.slice(0, at));
|
|
10393
|
-
buffer = buffer.slice(at + 1);
|
|
10394
|
-
}
|
|
10395
|
-
});
|
|
10396
|
-
child.stderr?.on("data", (chunk) => {
|
|
10397
|
-
stderr = (stderr + chunk.toString()).slice(-2e3);
|
|
10398
|
-
});
|
|
10399
|
-
child.on("error", () => end(false, "The assistant\u2019s command-line tool could not be started."));
|
|
10400
|
-
child.on(
|
|
10401
|
-
"close",
|
|
10402
|
-
(code) => end(
|
|
10403
|
-
code === 0,
|
|
10404
|
-
cancelled === ask.askId ? "Stopped." : code === 0 ? "" : stderr.trim().split("\n").slice(-3).join(" ") || `The assistant stopped (exit ${code ?? "?"}).`
|
|
10405
|
-
)
|
|
10406
|
-
);
|
|
10407
|
-
return { started: true };
|
|
10350
|
+
return launch(ask, dir, mcpConfigPath, ask.sessionId);
|
|
10408
10351
|
},
|
|
10409
10352
|
cancel(askId) {
|
|
10410
10353
|
if (!current || current.askId !== askId) return false;
|
|
@@ -10414,8 +10357,85 @@ function createClaudeCli(options) {
|
|
|
10414
10357
|
setTimeout(() => child.kill("SIGKILL"), 3e3).unref?.();
|
|
10415
10358
|
return true;
|
|
10416
10359
|
},
|
|
10417
|
-
busy
|
|
10360
|
+
busy() {
|
|
10361
|
+
return current !== null;
|
|
10362
|
+
}
|
|
10418
10363
|
};
|
|
10364
|
+
function launch(ask, dir, mcpConfigPath, sessionId) {
|
|
10365
|
+
let child;
|
|
10366
|
+
try {
|
|
10367
|
+
child = spawn2(
|
|
10368
|
+
binary,
|
|
10369
|
+
buildAskArgs({
|
|
10370
|
+
prompt: ask.prompt,
|
|
10371
|
+
mcpConfigPath,
|
|
10372
|
+
projectId: ask.projectId,
|
|
10373
|
+
projectName: ask.projectName,
|
|
10374
|
+
...sessionId ? { sessionId } : {},
|
|
10375
|
+
...ask.folders?.length ? { folders: ask.folders } : {},
|
|
10376
|
+
...ask.mode ? { mode: ask.mode } : {},
|
|
10377
|
+
...ask.brief ? { brief: ask.brief } : {}
|
|
10378
|
+
}),
|
|
10379
|
+
// THE SCRATCH FOLDER, not the project: nothing here to read or write.
|
|
10380
|
+
{ cwd: dir, stdio: ["ignore", "pipe", "pipe"] }
|
|
10381
|
+
);
|
|
10382
|
+
} catch {
|
|
10383
|
+
return { started: false, detail: "The assistant\u2019s command-line tool could not be started." };
|
|
10384
|
+
}
|
|
10385
|
+
current = { askId: ask.askId, child };
|
|
10386
|
+
let buffer = "", stderr = "", sawDone = false, ended = false;
|
|
10387
|
+
let silentFailure = false;
|
|
10388
|
+
const handleLine = (line) => {
|
|
10389
|
+
for (const event of eventsFromLine(ask.askId, line)) {
|
|
10390
|
+
if (event.name === "assistant.done" && event.data["ok"] === false && !String(event.data["result"] ?? "").trim()) {
|
|
10391
|
+
silentFailure = true;
|
|
10392
|
+
continue;
|
|
10393
|
+
}
|
|
10394
|
+
if (event.name === "assistant.done") sawDone = true;
|
|
10395
|
+
ask.emit(event.name, event.data);
|
|
10396
|
+
}
|
|
10397
|
+
};
|
|
10398
|
+
const end = (ok, detail) => {
|
|
10399
|
+
if (ended) return;
|
|
10400
|
+
ended = true;
|
|
10401
|
+
clearTimeout(timer);
|
|
10402
|
+
if (buffer.trim()) handleLine(buffer);
|
|
10403
|
+
current = null;
|
|
10404
|
+
if (silentFailure && sessionId && /no conversation found/i.test(stderr) && cancelled !== ask.askId) {
|
|
10405
|
+
const again = launch(ask, dir, mcpConfigPath, void 0);
|
|
10406
|
+
if (again.started) return;
|
|
10407
|
+
}
|
|
10408
|
+
if (!sawDone) {
|
|
10409
|
+
const why = detail || stderr.trim().split("\n").filter((l) => l && !/^Warning:/.test(l)).slice(-3).join(" ") || "The assistant stopped without saying why.";
|
|
10410
|
+
ask.emit("assistant.done", { askId: ask.askId, ok: ok && !silentFailure, result: ok && !silentFailure ? "" : why });
|
|
10411
|
+
}
|
|
10412
|
+
};
|
|
10413
|
+
const timer = setTimeout(() => {
|
|
10414
|
+
child.kill("SIGTERM");
|
|
10415
|
+
end(false, `Stopped after ${Math.max(1, Math.round(maxAskMs / 6e4))} minutes. Whatever it saved so far is on the Branches page \u2014 send \u201Ccontinue\u201D to carry on.`);
|
|
10416
|
+
}, maxAskMs);
|
|
10417
|
+
timer.unref?.();
|
|
10418
|
+
child.stdout?.on("data", (chunk) => {
|
|
10419
|
+
buffer += chunk.toString();
|
|
10420
|
+
let at;
|
|
10421
|
+
while ((at = buffer.indexOf("\n")) >= 0) {
|
|
10422
|
+
handleLine(buffer.slice(0, at));
|
|
10423
|
+
buffer = buffer.slice(at + 1);
|
|
10424
|
+
}
|
|
10425
|
+
});
|
|
10426
|
+
child.stderr?.on("data", (chunk) => {
|
|
10427
|
+
stderr = (stderr + chunk.toString()).slice(-2e3);
|
|
10428
|
+
});
|
|
10429
|
+
child.on("error", () => end(false, "The assistant\u2019s command-line tool could not be started."));
|
|
10430
|
+
child.on(
|
|
10431
|
+
"close",
|
|
10432
|
+
(code) => end(
|
|
10433
|
+
code === 0,
|
|
10434
|
+
cancelled === ask.askId ? "Stopped." : code === 0 ? "" : stderr.trim().split("\n").filter((l) => l && !/^Warning:/.test(l)).slice(-3).join(" ") || `The assistant stopped (exit ${code ?? "?"}).`
|
|
10435
|
+
)
|
|
10436
|
+
);
|
|
10437
|
+
return { started: true };
|
|
10438
|
+
}
|
|
10419
10439
|
}
|
|
10420
10440
|
function createAgentRuntime(options) {
|
|
10421
10441
|
const lease = new BrowserLease();
|
package/dist/cli.js
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
runtimeValue,
|
|
24
24
|
start,
|
|
25
25
|
status
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-NWJWMDVO.js";
|
|
27
27
|
import {
|
|
28
28
|
CLOUD_PROVIDERS,
|
|
29
29
|
CLOUD_PROVIDER_NAME,
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
screenLines,
|
|
50
50
|
stepRefusedOn,
|
|
51
51
|
targetFor
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-3XKTIMRP.js";
|
|
53
53
|
|
|
54
54
|
// src/cli.ts
|
|
55
55
|
import { parseArgs } from "util";
|
|
@@ -40,12 +40,13 @@ import {
|
|
|
40
40
|
run,
|
|
41
41
|
runMobileSteps,
|
|
42
42
|
screenLines,
|
|
43
|
+
shrink,
|
|
43
44
|
stopAppium,
|
|
44
45
|
targetFor,
|
|
45
46
|
textOf,
|
|
46
47
|
toolEnv,
|
|
47
48
|
typesSecrets
|
|
48
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-3XKTIMRP.js";
|
|
49
50
|
export {
|
|
50
51
|
AGENT_HOME,
|
|
51
52
|
APPIUM_DIR,
|
|
@@ -87,6 +88,7 @@ export {
|
|
|
87
88
|
runMobileSteps,
|
|
88
89
|
run as runTool,
|
|
89
90
|
screenLines,
|
|
91
|
+
shrink,
|
|
90
92
|
stopAppium,
|
|
91
93
|
targetFor,
|
|
92
94
|
textOf,
|
package/dist/engine.js
CHANGED
package/package.json
CHANGED