@flowriki/agent 0.1.0-beta.2 → 0.1.0-beta.4
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/{chunk-EYRGRDNB.js → chunk-7JLRYAQ2.js} +145 -26
- package/dist/cli.js +9 -3
- package/dist/engine.js +5 -1
- package/package.json +1 -1
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/engine.ts
|
|
4
|
-
import
|
|
4
|
+
import os5 from "os";
|
|
5
|
+
import { createRequire as createRequire4 } from "module";
|
|
6
|
+
import { spawnSync } from "child_process";
|
|
5
7
|
|
|
6
8
|
// ../agent-core/dist/index.js
|
|
7
9
|
import { z as z4 } from "zod";
|
|
@@ -11,13 +13,14 @@ import crypto22 from "crypto";
|
|
|
11
13
|
import { createRequire as createRequire3 } from "module";
|
|
12
14
|
import { WebSocket, WebSocketServer } from "ws";
|
|
13
15
|
import fs23 from "fs";
|
|
16
|
+
import os2 from "os";
|
|
14
17
|
import path23 from "path";
|
|
15
18
|
|
|
16
19
|
// ../orchestrator/dist/index.js
|
|
17
20
|
import fs4 from "fs";
|
|
18
21
|
import path3 from "path";
|
|
19
22
|
|
|
20
|
-
// ../protocol/dist/chunk-
|
|
23
|
+
// ../protocol/dist/chunk-ROEX7TWK.js
|
|
21
24
|
import { z } from "zod";
|
|
22
25
|
var LocatorOverrideSchema = z.object({
|
|
23
26
|
strategy: z.enum(["css", "xpath", "id", "testId", "text", "label", "placeholder", "altText", "title"]),
|
|
@@ -249,6 +252,9 @@ var RecordedStepSchema = RecordedTargetSchema.extend({
|
|
|
249
252
|
* stays unresolved and is reported, never invented. */
|
|
250
253
|
secretRef: z.string().regex(SECRET_REF_PATTERN).optional()
|
|
251
254
|
}).strict();
|
|
255
|
+
function slugify(name) {
|
|
256
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
257
|
+
}
|
|
252
258
|
var CURRENT_SCHEMA_VERSION = 5;
|
|
253
259
|
var FlowDocumentSchema = z.object({
|
|
254
260
|
schemaVersion: z.literal(CURRENT_SCHEMA_VERSION),
|
|
@@ -572,6 +578,7 @@ var ProjectMarkerSchema = z3.object({
|
|
|
572
578
|
/** `v1:ed25519:<base64url>` */
|
|
573
579
|
signature: z3.string()
|
|
574
580
|
});
|
|
581
|
+
var PRODUCTION_SERVICE = "https://flowriki-cloud.onrender.com";
|
|
575
582
|
|
|
576
583
|
// ../core/dist/index.js
|
|
577
584
|
function proposeAssertions(before, after) {
|
|
@@ -4200,9 +4207,6 @@ function clampRepeat(value) {
|
|
|
4200
4207
|
if (!Number.isFinite(n) || n < 2) return DEFAULT_FLAKINESS_REPEAT;
|
|
4201
4208
|
return Math.min(n, MAX_FLAKINESS_REPEAT);
|
|
4202
4209
|
}
|
|
4203
|
-
function slugify(name) {
|
|
4204
|
-
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
4205
|
-
}
|
|
4206
4210
|
function uniqueRef(flowSlug, name, taken) {
|
|
4207
4211
|
const base = `${flowSlug}_${slugify(name) || "secret"}`;
|
|
4208
4212
|
if (!taken.has(base)) {
|
|
@@ -5427,6 +5431,20 @@ function ensureRootCommit(root) {
|
|
|
5427
5431
|
git2(root, ["commit", "--allow-empty", "-m", "Initialise repository"]);
|
|
5428
5432
|
return git2(root, ["rev-list", "--max-parents=0", "HEAD"]).split("\n").pop();
|
|
5429
5433
|
}
|
|
5434
|
+
function deliveredRun(delivered) {
|
|
5435
|
+
const { flow, secrets, config } = delivered;
|
|
5436
|
+
return {
|
|
5437
|
+
readConfig: () => config,
|
|
5438
|
+
// By id, and only the one that was sent. A machine serving no checkout has
|
|
5439
|
+
// no other flow to confuse it with.
|
|
5440
|
+
getFlow: (id) => id === flow.id ? flow : null,
|
|
5441
|
+
readSecrets: () => secrets,
|
|
5442
|
+
baseUrlFor: (f) => f.baseUrl ?? config.baseUrl ?? "",
|
|
5443
|
+
environmentFor: (f) => ({ ...config.environment, ...f.environment ?? {} }),
|
|
5444
|
+
// See RunSource.resolveFile: there is no project directory here.
|
|
5445
|
+
resolveFile: () => void 0
|
|
5446
|
+
};
|
|
5447
|
+
}
|
|
5430
5448
|
|
|
5431
5449
|
// ../agent-core/dist/index.js
|
|
5432
5450
|
var PROTOCOL_VERSION = 1;
|
|
@@ -5833,7 +5851,9 @@ var Agent = class {
|
|
|
5833
5851
|
`this agent speaks protocol ${PROTOCOL_VERSION}; the command is version ${command.v}`
|
|
5834
5852
|
);
|
|
5835
5853
|
}
|
|
5836
|
-
const
|
|
5854
|
+
const delivered = command.args["flow"];
|
|
5855
|
+
const produces = command.name.startsWith("record.") || command.name === "run.cancel";
|
|
5856
|
+
const project = this.opts.projects.find((p) => p.id === command.projectId) ?? (delivered || produces ? { id: command.projectId, name: String(delivered?.name ?? command.projectId), root: "" } : void 0);
|
|
5837
5857
|
if (!project) {
|
|
5838
5858
|
return this.refuse(
|
|
5839
5859
|
command.id,
|
|
@@ -6043,16 +6063,39 @@ var AgentLink = class {
|
|
|
6043
6063
|
}
|
|
6044
6064
|
}
|
|
6045
6065
|
};
|
|
6066
|
+
var HEARTBEAT_MS = 3e4;
|
|
6046
6067
|
function adapt(socket) {
|
|
6047
6068
|
let closed = false;
|
|
6048
6069
|
const closeHandlers = [];
|
|
6049
6070
|
const fire = () => {
|
|
6050
6071
|
if (closed) return;
|
|
6051
6072
|
closed = true;
|
|
6073
|
+
clearInterval(heartbeat);
|
|
6052
6074
|
for (const handler of closeHandlers) handler();
|
|
6053
6075
|
};
|
|
6054
6076
|
socket.on("close", fire);
|
|
6055
6077
|
socket.on("error", fire);
|
|
6078
|
+
let answered = true;
|
|
6079
|
+
socket.on("pong", () => {
|
|
6080
|
+
answered = true;
|
|
6081
|
+
});
|
|
6082
|
+
const heartbeat = setInterval(() => {
|
|
6083
|
+
if (!answered) {
|
|
6084
|
+
try {
|
|
6085
|
+
socket.terminate();
|
|
6086
|
+
} catch {
|
|
6087
|
+
}
|
|
6088
|
+
fire();
|
|
6089
|
+
return;
|
|
6090
|
+
}
|
|
6091
|
+
answered = false;
|
|
6092
|
+
try {
|
|
6093
|
+
socket.ping();
|
|
6094
|
+
} catch {
|
|
6095
|
+
fire();
|
|
6096
|
+
}
|
|
6097
|
+
}, HEARTBEAT_MS);
|
|
6098
|
+
heartbeat.unref?.();
|
|
6056
6099
|
return {
|
|
6057
6100
|
send: (data) => {
|
|
6058
6101
|
if (socket.readyState !== WebSocket.OPEN) return;
|
|
@@ -6104,6 +6147,15 @@ function dialWebSocket(opts) {
|
|
|
6104
6147
|
socket.once("error", failed);
|
|
6105
6148
|
});
|
|
6106
6149
|
}
|
|
6150
|
+
var scratchRoots = /* @__PURE__ */ new Map();
|
|
6151
|
+
function scratchRoot(projectId) {
|
|
6152
|
+
let root = scratchRoots.get(projectId);
|
|
6153
|
+
if (!root) {
|
|
6154
|
+
root = fs23.mkdtempSync(path23.join(os2.tmpdir(), `flowriki-record-${projectId.replace(/[^\w-]/g, "")}-`));
|
|
6155
|
+
scratchRoots.set(projectId, root);
|
|
6156
|
+
}
|
|
6157
|
+
return root;
|
|
6158
|
+
}
|
|
6107
6159
|
function buildHandlers(deps) {
|
|
6108
6160
|
const { storeFor, storage = null, onActivity, lease, recorder } = deps;
|
|
6109
6161
|
const debugging = deps.debugger;
|
|
@@ -6389,14 +6441,22 @@ function buildHandlers(deps) {
|
|
|
6389
6441
|
if (command.flowRevision === void 0) {
|
|
6390
6442
|
return { ok: false, reason: "stale_revision", detail: "reload the flow and supply its revision before running" };
|
|
6391
6443
|
}
|
|
6392
|
-
const store = storeFor(project.root);
|
|
6393
6444
|
const flowId = String(command.args["flowId"] ?? "");
|
|
6394
|
-
const
|
|
6445
|
+
const carried = command.args["flow"];
|
|
6446
|
+
const source = carried ? deliveredRun({
|
|
6447
|
+
flow: carried,
|
|
6448
|
+
secrets: command.args["secrets"] ?? {},
|
|
6449
|
+
config: command.args["config"] ?? {}
|
|
6450
|
+
}) : storeFor(project.root);
|
|
6451
|
+
if (!carried && !project.root) {
|
|
6452
|
+
return { ok: false, reason: "failed", detail: "this machine has no checkout of that project" };
|
|
6453
|
+
}
|
|
6454
|
+
const flow = source.getFlow(flowId);
|
|
6395
6455
|
if (!flow) return { ok: false, reason: "failed", detail: `no flow ${flowId} in this project` };
|
|
6396
6456
|
if (flow.revision !== command.flowRevision) {
|
|
6397
6457
|
return { ok: false, reason: "stale_revision", detail: "the flow changed \u2014 reload it before running" };
|
|
6398
6458
|
}
|
|
6399
|
-
const missing =
|
|
6459
|
+
const missing = carried ? [] : storeFor(project.root).unresolvedSecrets(flow);
|
|
6400
6460
|
if (missing.length) {
|
|
6401
6461
|
return {
|
|
6402
6462
|
ok: false,
|
|
@@ -6418,7 +6478,7 @@ function buildHandlers(deps) {
|
|
|
6418
6478
|
signal: aborter.signal,
|
|
6419
6479
|
...typeof command.args["headless"] === "boolean" ? { headless: command.args["headless"] } : {},
|
|
6420
6480
|
...command.args["repeat"] ? { repeat: Number(command.args["repeat"]) } : {},
|
|
6421
|
-
store,
|
|
6481
|
+
store: source,
|
|
6422
6482
|
storage,
|
|
6423
6483
|
flowId,
|
|
6424
6484
|
expectedRevision: command.flowRevision,
|
|
@@ -6473,14 +6533,28 @@ function buildHandlers(deps) {
|
|
|
6473
6533
|
const url = optional("url");
|
|
6474
6534
|
const route = optional("path");
|
|
6475
6535
|
const recordedBy = optional("recordedBy");
|
|
6536
|
+
const headless = typeof command.args["headless"] === "boolean" ? command.args["headless"] : void 0;
|
|
6537
|
+
const root = project.root || scratchRoot(project.id);
|
|
6538
|
+
if (!project.root) {
|
|
6539
|
+
if (!/^f_[a-z0-9]+(?:-[a-z0-9]+)*$/.test(featureId)) throw new Error("Invalid feature ID");
|
|
6540
|
+
const workspace = new Store(root);
|
|
6541
|
+
if (!workspace.listFeatures().some((feature) => feature.id === featureId)) workspace.createFeature(featureId.slice(2));
|
|
6542
|
+
}
|
|
6476
6543
|
const started = await recorder.start({
|
|
6477
|
-
|
|
6544
|
+
// A SCRATCH DIRECTORY when this machine has no checkout of the
|
|
6545
|
+
// project. The recorder writes as it goes — that is what makes a
|
|
6546
|
+
// half-finished recording survivable — and the flow it produces is
|
|
6547
|
+
// returned on stop for the service to commit to the repository. A
|
|
6548
|
+
// machine that has the project checked out still records into it.
|
|
6549
|
+
root,
|
|
6550
|
+
projectId: project.id,
|
|
6478
6551
|
featureId,
|
|
6479
6552
|
name,
|
|
6480
6553
|
...url ? { url } : {},
|
|
6481
6554
|
...route ? { path: route } : {},
|
|
6482
6555
|
...recordedBy ? { recordedBy } : {},
|
|
6483
|
-
...command.args["environment"] ? { environment: command.args["environment"] } : {}
|
|
6556
|
+
...command.args["environment"] ? { environment: command.args["environment"] } : {},
|
|
6557
|
+
...headless === void 0 ? {} : { headless }
|
|
6484
6558
|
});
|
|
6485
6559
|
lease?.activate("run");
|
|
6486
6560
|
onActivity?.({ kind: "recording", projectId: project.id, detail: name });
|
|
@@ -6495,7 +6569,7 @@ function buildHandlers(deps) {
|
|
|
6495
6569
|
"record.stop": async (_command, project) => {
|
|
6496
6570
|
if (!recorder) return { ok: false, reason: "failed", detail: "this agent cannot record \u2014 no browser is configured" };
|
|
6497
6571
|
try {
|
|
6498
|
-
const saved = await recorder.stop();
|
|
6572
|
+
const saved = await recorder.stop(project.id);
|
|
6499
6573
|
if (!saved.ok) return { ok: false, reason: "failed", detail: saved.error };
|
|
6500
6574
|
return { ok: true, result: { flow: saved.flow, projectId: project.id } };
|
|
6501
6575
|
} finally {
|
|
@@ -6572,12 +6646,15 @@ function createAgentRuntime(options) {
|
|
|
6572
6646
|
let journal = null;
|
|
6573
6647
|
const coordinators = /* @__PURE__ */ new Map();
|
|
6574
6648
|
let recordingIn = null;
|
|
6649
|
+
let recordingProject = null;
|
|
6650
|
+
let lastRecording = null;
|
|
6575
6651
|
const coordinatorFor = (projectRoot) => {
|
|
6576
6652
|
let existing = coordinators.get(projectRoot);
|
|
6577
6653
|
if (!existing) {
|
|
6578
6654
|
existing = new RecordingCoordinator({
|
|
6579
6655
|
store: new Store(projectRoot),
|
|
6580
6656
|
emit: (event) => {
|
|
6657
|
+
if (event.type === "recording.stopped") lastRecording = { ok: true, flow: event.flow };
|
|
6581
6658
|
journal?.append({ name: `recording.${event.type.replace(/^recording\./, "")}`, data: event });
|
|
6582
6659
|
}
|
|
6583
6660
|
});
|
|
@@ -6636,13 +6713,17 @@ function createAgentRuntime(options) {
|
|
|
6636
6713
|
const coordinator = coordinatorFor(opts.root);
|
|
6637
6714
|
const { root: _root, ...rest } = opts;
|
|
6638
6715
|
const started = await coordinator.start(rest);
|
|
6716
|
+
recordingProject = opts["projectId"];
|
|
6717
|
+
lastRecording = null;
|
|
6639
6718
|
recordingIn = coordinator;
|
|
6640
6719
|
return started;
|
|
6641
6720
|
},
|
|
6642
|
-
stop: async () => {
|
|
6643
|
-
if (
|
|
6721
|
+
stop: async (projectId) => {
|
|
6722
|
+
if (projectId && recordingProject && projectId !== recordingProject) return { ok: false, error: "This recording belongs to another project" };
|
|
6723
|
+
if (lastRecording?.ok) return lastRecording;
|
|
6724
|
+
if (!recordingIn) return lastRecording ?? { ok: false, error: "no recording is in progress on this machine" };
|
|
6644
6725
|
const result = await recordingIn.stop();
|
|
6645
|
-
|
|
6726
|
+
lastRecording = result;
|
|
6646
6727
|
return result;
|
|
6647
6728
|
},
|
|
6648
6729
|
discard: async () => {
|
|
@@ -6708,20 +6789,20 @@ import fs7 from "fs";
|
|
|
6708
6789
|
|
|
6709
6790
|
// src/paths.ts
|
|
6710
6791
|
import fs6 from "fs";
|
|
6711
|
-
import
|
|
6792
|
+
import os3 from "os";
|
|
6712
6793
|
import path5 from "path";
|
|
6713
6794
|
function dataDir(env = process.env) {
|
|
6714
6795
|
const override = env["FLOWRIKI_HOME"]?.trim();
|
|
6715
6796
|
if (override) return path5.resolve(override);
|
|
6716
6797
|
if (process.platform === "win32") {
|
|
6717
6798
|
const appData = env["APPDATA"]?.trim();
|
|
6718
|
-
return appData ? path5.join(appData, "Flowriki") : path5.join(
|
|
6799
|
+
return appData ? path5.join(appData, "Flowriki") : path5.join(os3.homedir(), "AppData", "Roaming", "Flowriki");
|
|
6719
6800
|
}
|
|
6720
6801
|
if (process.platform === "darwin") {
|
|
6721
|
-
return path5.join(
|
|
6802
|
+
return path5.join(os3.homedir(), "Library", "Application Support", "Flowriki");
|
|
6722
6803
|
}
|
|
6723
6804
|
const state = env["XDG_STATE_HOME"]?.trim();
|
|
6724
|
-
return state ? path5.join(state, "flowriki") : path5.join(
|
|
6805
|
+
return state ? path5.join(state, "flowriki") : path5.join(os3.homedir(), ".local", "state", "flowriki");
|
|
6725
6806
|
}
|
|
6726
6807
|
function ensureDataDir(env = process.env) {
|
|
6727
6808
|
const dir = dataDir(env);
|
|
@@ -6788,7 +6869,6 @@ function forgetConnection(service, env = process.env) {
|
|
|
6788
6869
|
var fingerprint = (secret) => crypto3.createHash("sha256").update(secret).digest("hex").slice(0, 12);
|
|
6789
6870
|
|
|
6790
6871
|
// src/service.ts
|
|
6791
|
-
var PRODUCTION_SERVICE = "https://flowriki-cloud.onrender.com";
|
|
6792
6872
|
var BadServiceUrl = class extends Error {
|
|
6793
6873
|
};
|
|
6794
6874
|
function resolveService(explicit, env = process.env) {
|
|
@@ -6811,11 +6891,11 @@ function resolveService(explicit, env = process.env) {
|
|
|
6811
6891
|
|
|
6812
6892
|
// src/lock.ts
|
|
6813
6893
|
import fs8 from "fs";
|
|
6814
|
-
import
|
|
6894
|
+
import os4 from "os";
|
|
6815
6895
|
function takeLock(env = process.env) {
|
|
6816
6896
|
ensureDataDir(env);
|
|
6817
6897
|
const file = lockPath(env);
|
|
6818
|
-
const mine = { pid: process.pid, since: (/* @__PURE__ */ new Date()).toISOString(), host:
|
|
6898
|
+
const mine = { pid: process.pid, since: (/* @__PURE__ */ new Date()).toISOString(), host: os4.hostname() };
|
|
6819
6899
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
6820
6900
|
try {
|
|
6821
6901
|
fs8.writeFileSync(file, JSON.stringify(mine), { flag: "wx", mode: 384 });
|
|
@@ -6891,7 +6971,7 @@ function openBrowser(url, env = process.env) {
|
|
|
6891
6971
|
}
|
|
6892
6972
|
|
|
6893
6973
|
// src/engine.ts
|
|
6894
|
-
var AGENT_VERSION = "0.1.0-beta.
|
|
6974
|
+
var AGENT_VERSION = "0.1.0-beta.4";
|
|
6895
6975
|
async function connect(options = {}) {
|
|
6896
6976
|
let service;
|
|
6897
6977
|
try {
|
|
@@ -6908,7 +6988,7 @@ async function connect(options = {}) {
|
|
|
6908
6988
|
message: "the stored connection is no longer accepted \u2014 asking for a new one"
|
|
6909
6989
|
});
|
|
6910
6990
|
}
|
|
6911
|
-
const machineName = options.machineName?.trim() || `${
|
|
6991
|
+
const machineName = options.machineName?.trim() || `${os5.userInfo().username}@${os5.hostname()}`;
|
|
6912
6992
|
let asked;
|
|
6913
6993
|
try {
|
|
6914
6994
|
const res = await fetch(`${service}/api/pairing-requests`, {
|
|
@@ -7015,6 +7095,13 @@ async function start(options = {}) {
|
|
|
7015
7095
|
message: `this installation is not connected to ${service} yet`
|
|
7016
7096
|
};
|
|
7017
7097
|
}
|
|
7098
|
+
if (!browsersReady()) {
|
|
7099
|
+
options.onStatus?.("preparing", "downloading the browser Flowriki records with \u2014 this happens once");
|
|
7100
|
+
const prepared = await prepareBrowsers();
|
|
7101
|
+
if (!prepared.ok) {
|
|
7102
|
+
return { ok: false, reason: "refused", message: `this machine cannot record yet \u2014 ${prepared.message}` };
|
|
7103
|
+
}
|
|
7104
|
+
}
|
|
7018
7105
|
const lock = takeLock();
|
|
7019
7106
|
if (!lock.ok) {
|
|
7020
7107
|
return {
|
|
@@ -7061,6 +7148,36 @@ async function start(options = {}) {
|
|
|
7061
7148
|
}
|
|
7062
7149
|
};
|
|
7063
7150
|
}
|
|
7151
|
+
async function prepareBrowsers() {
|
|
7152
|
+
if (browsersReady()) {
|
|
7153
|
+
return { ok: true, already: true, message: "chromium is already installed" };
|
|
7154
|
+
}
|
|
7155
|
+
let cli;
|
|
7156
|
+
try {
|
|
7157
|
+
cli = createRequire4(import.meta.url).resolve("playwright/cli.js");
|
|
7158
|
+
} catch {
|
|
7159
|
+
return {
|
|
7160
|
+
ok: false,
|
|
7161
|
+
already: false,
|
|
7162
|
+
message: "playwright is not installed beside this agent \u2014 reinstall it"
|
|
7163
|
+
};
|
|
7164
|
+
}
|
|
7165
|
+
const run = spawnSync(process.execPath, [cli, "install", "chromium"], { stdio: "inherit" });
|
|
7166
|
+
if (run.status !== 0) {
|
|
7167
|
+
return {
|
|
7168
|
+
ok: false,
|
|
7169
|
+
already: false,
|
|
7170
|
+
message: `could not install chromium (exit ${run.status ?? "unknown"}) \u2014 try \`npx playwright@${playwrightVersion() ?? "latest"} install chromium\` yourself`
|
|
7171
|
+
};
|
|
7172
|
+
}
|
|
7173
|
+
return { ok: browsersReady(), already: false, message: "chromium installed" };
|
|
7174
|
+
}
|
|
7175
|
+
function browsersReady() {
|
|
7176
|
+
return inspectPlaywright().chromiumInstalled === true;
|
|
7177
|
+
}
|
|
7178
|
+
function playwrightVersion() {
|
|
7179
|
+
return inspectPlaywright().version;
|
|
7180
|
+
}
|
|
7064
7181
|
function status(serviceArg) {
|
|
7065
7182
|
const service = resolveService(serviceArg);
|
|
7066
7183
|
const connection = connectionFor(service);
|
|
@@ -7122,7 +7239,7 @@ async function doctor(serviceArg) {
|
|
|
7122
7239
|
}
|
|
7123
7240
|
function inspectPlaywright() {
|
|
7124
7241
|
try {
|
|
7125
|
-
const browsersPath = process.env["PLAYWRIGHT_BROWSERS_PATH"] ?? (process.platform === "win32" ? path6.join(
|
|
7242
|
+
const browsersPath = process.env["PLAYWRIGHT_BROWSERS_PATH"] ?? (process.platform === "win32" ? path6.join(os5.homedir(), "AppData", "Local", "ms-playwright") : process.platform === "darwin" ? path6.join(os5.homedir(), "Library", "Caches", "ms-playwright") : path6.join(os5.homedir(), ".cache", "ms-playwright"));
|
|
7126
7243
|
const chromiumInstalled = fs9.existsSync(browsersPath) ? fs9.readdirSync(browsersPath).some((d) => d.startsWith("chromium")) : false;
|
|
7127
7244
|
return { version: null, browsersPath, chromiumInstalled };
|
|
7128
7245
|
} catch {
|
|
@@ -7140,6 +7257,8 @@ export {
|
|
|
7140
7257
|
connect,
|
|
7141
7258
|
resolveCheckouts,
|
|
7142
7259
|
start,
|
|
7260
|
+
prepareBrowsers,
|
|
7261
|
+
browsersReady,
|
|
7143
7262
|
status,
|
|
7144
7263
|
doctor,
|
|
7145
7264
|
disconnect
|
package/dist/cli.js
CHANGED
|
@@ -4,10 +4,11 @@ import {
|
|
|
4
4
|
connect,
|
|
5
5
|
disconnect,
|
|
6
6
|
doctor,
|
|
7
|
+
prepareBrowsers,
|
|
7
8
|
resolveCheckouts,
|
|
8
9
|
start,
|
|
9
10
|
status
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-7JLRYAQ2.js";
|
|
11
12
|
|
|
12
13
|
// src/cli.ts
|
|
13
14
|
import { parseArgs } from "util";
|
|
@@ -27,6 +28,7 @@ ${bold("USAGE")}
|
|
|
27
28
|
flowriki-agent start run the agent (stays in the foreground)
|
|
28
29
|
flowriki-agent status is it connected, and what is prepared
|
|
29
30
|
flowriki-agent doctor diagnose setup problems
|
|
31
|
+
flowriki-agent prepare download the browser recording needs
|
|
30
32
|
flowriki-agent disconnect forget this computer's credential
|
|
31
33
|
|
|
32
34
|
${bold("OPTIONS")}
|
|
@@ -129,8 +131,7 @@ Run \`flowriki-agent --help\`.`);
|
|
|
129
131
|
console.log(`${bold("Flowriki agent")} ${dim(AGENT_VERSION)}`);
|
|
130
132
|
console.log(dim(` connected as ${started.connection.machineName}`));
|
|
131
133
|
if (started.projects.length === 0) {
|
|
132
|
-
console.log(
|
|
133
|
-
console.log(dim(" Add one: flowriki-agent start --project /path/to/a/checkout"));
|
|
134
|
+
console.log(dim(" ready \u2014 this machine records and runs whatever the dashboard asks for"));
|
|
134
135
|
}
|
|
135
136
|
for (const project of started.projects) {
|
|
136
137
|
console.log(dim(` project ${project.name} (${project.root})`));
|
|
@@ -150,6 +151,11 @@ Run \`flowriki-agent --help\`.`);
|
|
|
150
151
|
return await new Promise(() => {
|
|
151
152
|
});
|
|
152
153
|
}
|
|
154
|
+
case "prepare": {
|
|
155
|
+
const result = await prepareBrowsers();
|
|
156
|
+
console.log(result.ok ? green(result.message) : red(result.message));
|
|
157
|
+
return result.ok ? 0 : 1;
|
|
158
|
+
}
|
|
153
159
|
case "status": {
|
|
154
160
|
const state = status(service);
|
|
155
161
|
if (values.json) {
|
package/dist/engine.js
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
AGENT_VERSION,
|
|
4
|
+
browsersReady,
|
|
4
5
|
connect,
|
|
5
6
|
disconnect,
|
|
6
7
|
doctor,
|
|
8
|
+
prepareBrowsers,
|
|
7
9
|
resolveCheckouts,
|
|
8
10
|
start,
|
|
9
11
|
status
|
|
10
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-7JLRYAQ2.js";
|
|
11
13
|
export {
|
|
12
14
|
AGENT_VERSION,
|
|
15
|
+
browsersReady,
|
|
13
16
|
connect,
|
|
14
17
|
disconnect,
|
|
15
18
|
doctor,
|
|
19
|
+
prepareBrowsers,
|
|
16
20
|
resolveCheckouts,
|
|
17
21
|
start,
|
|
18
22
|
status
|
package/package.json
CHANGED