@hasna/browser 0.2.6 → 0.3.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/dist/cli/index.js +814 -618
- package/dist/db/scripts.d.ts +84 -0
- package/dist/db/scripts.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/lib/ai-inference.d.ts +21 -0
- package/dist/lib/ai-inference.d.ts.map +1 -0
- package/dist/lib/script-engine.d.ts +28 -0
- package/dist/lib/script-engine.d.ts.map +1 -0
- package/dist/mcp/index.js +644 -458
- package/dist/server/index.js +44 -0
- package/package.json +1 -1
package/dist/mcp/index.js
CHANGED
|
@@ -4,6 +4,7 @@ var __create = Object.create;
|
|
|
4
4
|
var __getProtoOf = Object.getPrototypeOf;
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
9
|
var __toESM = (mod, isNodeMode, target) => {
|
|
9
10
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
@@ -16,6 +17,20 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
16
17
|
});
|
|
17
18
|
return to;
|
|
18
19
|
};
|
|
20
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
21
|
+
var __toCommonJS = (from) => {
|
|
22
|
+
var entry = __moduleCache.get(from), desc;
|
|
23
|
+
if (entry)
|
|
24
|
+
return entry;
|
|
25
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
26
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
27
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
28
|
+
get: () => from[key],
|
|
29
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
30
|
+
}));
|
|
31
|
+
__moduleCache.set(from, entry);
|
|
32
|
+
return entry;
|
|
33
|
+
};
|
|
19
34
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
20
35
|
var __export = (target, all) => {
|
|
21
36
|
for (var name in all)
|
|
@@ -372,6 +387,50 @@ function runMigrations(db) {
|
|
|
372
387
|
);
|
|
373
388
|
CREATE INDEX IF NOT EXISTS idx_api_endpoints_session ON api_endpoints(session_id);
|
|
374
389
|
`
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
version: 9,
|
|
393
|
+
sql: `
|
|
394
|
+
CREATE TABLE IF NOT EXISTS scripts (
|
|
395
|
+
id TEXT PRIMARY KEY,
|
|
396
|
+
name TEXT NOT NULL UNIQUE,
|
|
397
|
+
domain TEXT NOT NULL DEFAULT '',
|
|
398
|
+
description TEXT DEFAULT '',
|
|
399
|
+
variables TEXT NOT NULL DEFAULT '{}',
|
|
400
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
401
|
+
updated_at TEXT DEFAULT (datetime('now')),
|
|
402
|
+
last_run TEXT,
|
|
403
|
+
run_count INTEGER DEFAULT 0
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
CREATE TABLE IF NOT EXISTS script_steps (
|
|
407
|
+
id TEXT PRIMARY KEY,
|
|
408
|
+
script_id TEXT NOT NULL REFERENCES scripts(id) ON DELETE CASCADE,
|
|
409
|
+
step_order INTEGER NOT NULL,
|
|
410
|
+
type TEXT NOT NULL,
|
|
411
|
+
config TEXT NOT NULL DEFAULT '{}',
|
|
412
|
+
description TEXT DEFAULT '',
|
|
413
|
+
ai_enabled INTEGER DEFAULT 0,
|
|
414
|
+
ai_config TEXT DEFAULT '{}'
|
|
415
|
+
);
|
|
416
|
+
CREATE INDEX IF NOT EXISTS idx_script_steps_order ON script_steps(script_id, step_order);
|
|
417
|
+
|
|
418
|
+
CREATE TABLE IF NOT EXISTS script_runs (
|
|
419
|
+
id TEXT PRIMARY KEY,
|
|
420
|
+
script_id TEXT NOT NULL REFERENCES scripts(id) ON DELETE CASCADE,
|
|
421
|
+
status TEXT NOT NULL DEFAULT 'running',
|
|
422
|
+
current_step INTEGER DEFAULT 0,
|
|
423
|
+
total_steps INTEGER DEFAULT 0,
|
|
424
|
+
current_description TEXT DEFAULT '',
|
|
425
|
+
variables TEXT DEFAULT '{}',
|
|
426
|
+
steps_log TEXT DEFAULT '[]',
|
|
427
|
+
errors TEXT DEFAULT '[]',
|
|
428
|
+
started_at TEXT DEFAULT (datetime('now')),
|
|
429
|
+
completed_at TEXT,
|
|
430
|
+
duration_ms INTEGER
|
|
431
|
+
);
|
|
432
|
+
CREATE INDEX IF NOT EXISTS idx_script_runs_script ON script_runs(script_id, status);
|
|
433
|
+
`
|
|
375
434
|
}
|
|
376
435
|
];
|
|
377
436
|
for (const m of migrations) {
|
|
@@ -2271,6 +2330,10 @@ var init_snapshot = __esm(() => {
|
|
|
2271
2330
|
});
|
|
2272
2331
|
|
|
2273
2332
|
// src/lib/self-heal.ts
|
|
2333
|
+
var exports_self_heal = {};
|
|
2334
|
+
__export(exports_self_heal, {
|
|
2335
|
+
healSelector: () => healSelector
|
|
2336
|
+
});
|
|
2274
2337
|
async function healSelector(page, selector, sessionId) {
|
|
2275
2338
|
const attempts = [];
|
|
2276
2339
|
attempts.push(`selector: ${selector}`);
|
|
@@ -6583,7 +6646,7 @@ var require_operation = __commonJS((exports, module) => {
|
|
|
6583
6646
|
// node_modules/@img/colour/color.cjs
|
|
6584
6647
|
var require_color = __commonJS((exports, module) => {
|
|
6585
6648
|
var __defProp2 = Object.defineProperty;
|
|
6586
|
-
var
|
|
6649
|
+
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
|
|
6587
6650
|
var __getOwnPropNames2 = Object.getOwnPropertyNames;
|
|
6588
6651
|
var __hasOwnProp2 = Object.prototype.hasOwnProperty;
|
|
6589
6652
|
var __export2 = (target, all) => {
|
|
@@ -6594,16 +6657,16 @@ var require_color = __commonJS((exports, module) => {
|
|
|
6594
6657
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
6595
6658
|
for (let key of __getOwnPropNames2(from))
|
|
6596
6659
|
if (!__hasOwnProp2.call(to, key) && key !== except)
|
|
6597
|
-
__defProp2(to, key, { get: () => from[key], enumerable: !(desc =
|
|
6660
|
+
__defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
|
|
6598
6661
|
}
|
|
6599
6662
|
return to;
|
|
6600
6663
|
};
|
|
6601
|
-
var
|
|
6664
|
+
var __toCommonJS2 = (mod) => __copyProps(__defProp2({}, "__esModule", { value: true }), mod);
|
|
6602
6665
|
var index_exports = {};
|
|
6603
6666
|
__export2(index_exports, {
|
|
6604
6667
|
default: () => index_default
|
|
6605
6668
|
});
|
|
6606
|
-
module.exports =
|
|
6669
|
+
module.exports = __toCommonJS2(index_exports);
|
|
6607
6670
|
var colors = {
|
|
6608
6671
|
aliceblue: [240, 248, 255],
|
|
6609
6672
|
antiquewhite: [250, 235, 215],
|
|
@@ -10602,395 +10665,498 @@ async function clickByVision(page, description, opts) {
|
|
|
10602
10665
|
}
|
|
10603
10666
|
var DEFAULT_MODEL = "claude-sonnet-4-5-20250929";
|
|
10604
10667
|
|
|
10605
|
-
// src/
|
|
10606
|
-
var
|
|
10607
|
-
__export(
|
|
10608
|
-
|
|
10609
|
-
|
|
10610
|
-
|
|
10611
|
-
|
|
10668
|
+
// src/db/scripts.ts
|
|
10669
|
+
var exports_scripts = {};
|
|
10670
|
+
__export(exports_scripts, {
|
|
10671
|
+
upsertScript: () => upsertScript,
|
|
10672
|
+
updateRunProgress: () => updateRunProgress,
|
|
10673
|
+
startRun: () => startRun,
|
|
10674
|
+
migrateJsonScripts: () => migrateJsonScripts,
|
|
10612
10675
|
listScripts: () => listScripts,
|
|
10613
|
-
|
|
10614
|
-
|
|
10676
|
+
listRuns: () => listRuns,
|
|
10677
|
+
getSteps: () => getSteps,
|
|
10678
|
+
getScriptByName: () => getScriptByName,
|
|
10679
|
+
getScript: () => getScript,
|
|
10680
|
+
getRun: () => getRun,
|
|
10681
|
+
deleteScriptByName: () => deleteScriptByName,
|
|
10615
10682
|
deleteScript: () => deleteScript,
|
|
10616
|
-
|
|
10617
|
-
|
|
10683
|
+
createScript: () => createScript,
|
|
10684
|
+
completeRun: () => completeRun
|
|
10618
10685
|
});
|
|
10619
10686
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
10620
|
-
|
|
10621
|
-
|
|
10622
|
-
|
|
10623
|
-
|
|
10624
|
-
|
|
10625
|
-
|
|
10626
|
-
|
|
10687
|
+
function createScript(data) {
|
|
10688
|
+
const db = getDatabase();
|
|
10689
|
+
const id = randomUUID12();
|
|
10690
|
+
db.prepare("INSERT INTO scripts (id, name, domain, description, variables) VALUES (?, ?, ?, ?, ?)").run(id, data.name, data.domain ?? "", data.description ?? "", JSON.stringify(data.variables ?? {}));
|
|
10691
|
+
for (let i = 0;i < data.steps.length; i++) {
|
|
10692
|
+
const step = data.steps[i];
|
|
10693
|
+
db.prepare("INSERT INTO script_steps (id, script_id, step_order, type, config, description, ai_enabled, ai_config) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(randomUUID12(), id, i, step.type, JSON.stringify(step.config), step.description ?? "", step.ai_enabled ? 1 : 0, JSON.stringify(step.ai_config ?? {}));
|
|
10694
|
+
}
|
|
10695
|
+
return getScript(id);
|
|
10627
10696
|
}
|
|
10628
|
-
function
|
|
10629
|
-
const
|
|
10630
|
-
|
|
10631
|
-
|
|
10697
|
+
function upsertScript(data) {
|
|
10698
|
+
const existing = getScriptByName(data.name);
|
|
10699
|
+
if (existing) {
|
|
10700
|
+
deleteScript(existing.id);
|
|
10701
|
+
}
|
|
10702
|
+
return createScript(data);
|
|
10632
10703
|
}
|
|
10633
|
-
function
|
|
10634
|
-
const
|
|
10635
|
-
const
|
|
10636
|
-
|
|
10637
|
-
|
|
10638
|
-
|
|
10639
|
-
writeFileSync3(path, JSON.stringify(script, null, 2));
|
|
10640
|
-
return path;
|
|
10704
|
+
function getScript(id) {
|
|
10705
|
+
const db = getDatabase();
|
|
10706
|
+
const row = db.query("SELECT * FROM scripts WHERE id = ?").get(id);
|
|
10707
|
+
if (!row)
|
|
10708
|
+
return null;
|
|
10709
|
+
return { ...row, variables: JSON.parse(row.variables), run_count: row.run_count ?? 0 };
|
|
10641
10710
|
}
|
|
10642
|
-
function
|
|
10643
|
-
const
|
|
10644
|
-
|
|
10711
|
+
function getScriptByName(name) {
|
|
10712
|
+
const db = getDatabase();
|
|
10713
|
+
const row = db.query("SELECT * FROM scripts WHERE name = ?").get(name);
|
|
10714
|
+
if (!row)
|
|
10645
10715
|
return null;
|
|
10646
|
-
return JSON.parse(
|
|
10716
|
+
return { ...row, variables: JSON.parse(row.variables), run_count: row.run_count ?? 0 };
|
|
10647
10717
|
}
|
|
10648
10718
|
function listScripts() {
|
|
10649
|
-
const
|
|
10719
|
+
const db = getDatabase();
|
|
10720
|
+
return db.query("SELECT * FROM scripts ORDER BY updated_at DESC").all().map((row) => ({ ...row, variables: JSON.parse(row.variables), run_count: row.run_count ?? 0 }));
|
|
10721
|
+
}
|
|
10722
|
+
function deleteScript(id) {
|
|
10723
|
+
const db = getDatabase();
|
|
10724
|
+
return db.prepare("DELETE FROM scripts WHERE id = ?").run(id).changes > 0;
|
|
10725
|
+
}
|
|
10726
|
+
function deleteScriptByName(name) {
|
|
10727
|
+
const db = getDatabase();
|
|
10728
|
+
return db.prepare("DELETE FROM scripts WHERE name = ?").run(name).changes > 0;
|
|
10729
|
+
}
|
|
10730
|
+
function getSteps(scriptId) {
|
|
10731
|
+
const db = getDatabase();
|
|
10732
|
+
return db.query("SELECT * FROM script_steps WHERE script_id = ? ORDER BY step_order").all(scriptId).map((row) => ({
|
|
10733
|
+
...row,
|
|
10734
|
+
config: JSON.parse(row.config),
|
|
10735
|
+
ai_enabled: !!row.ai_enabled,
|
|
10736
|
+
ai_config: JSON.parse(row.ai_config)
|
|
10737
|
+
}));
|
|
10738
|
+
}
|
|
10739
|
+
function startRun(scriptId, totalSteps) {
|
|
10740
|
+
const db = getDatabase();
|
|
10741
|
+
const id = randomUUID12();
|
|
10742
|
+
db.prepare("INSERT INTO script_runs (id, script_id, status, total_steps) VALUES (?, ?, 'running', ?)").run(id, scriptId, totalSteps);
|
|
10743
|
+
return getRun(id);
|
|
10744
|
+
}
|
|
10745
|
+
function updateRunProgress(runId, step, description, stepsLog, variables) {
|
|
10746
|
+
const db = getDatabase();
|
|
10747
|
+
db.prepare("UPDATE script_runs SET current_step = ?, current_description = ?, steps_log = ?, variables = ? WHERE id = ?").run(step, description, JSON.stringify(stepsLog), JSON.stringify(variables), runId);
|
|
10748
|
+
}
|
|
10749
|
+
function completeRun(runId, status, errors2, durationMs) {
|
|
10750
|
+
const db = getDatabase();
|
|
10751
|
+
db.prepare("UPDATE script_runs SET status = ?, errors = ?, duration_ms = ?, completed_at = datetime('now') WHERE id = ?").run(status, JSON.stringify(errors2), durationMs, runId);
|
|
10752
|
+
const run = getRun(runId);
|
|
10753
|
+
if (run) {
|
|
10754
|
+
db.prepare("UPDATE scripts SET last_run = datetime('now'), run_count = run_count + 1, updated_at = datetime('now') WHERE id = ?").run(run.script_id);
|
|
10755
|
+
}
|
|
10756
|
+
}
|
|
10757
|
+
function getRun(runId) {
|
|
10758
|
+
const db = getDatabase();
|
|
10759
|
+
const row = db.query("SELECT * FROM script_runs WHERE id = ?").get(runId);
|
|
10760
|
+
if (!row)
|
|
10761
|
+
return null;
|
|
10762
|
+
return {
|
|
10763
|
+
...row,
|
|
10764
|
+
variables: JSON.parse(row.variables),
|
|
10765
|
+
steps_log: JSON.parse(row.steps_log),
|
|
10766
|
+
errors: JSON.parse(row.errors)
|
|
10767
|
+
};
|
|
10768
|
+
}
|
|
10769
|
+
function listRuns(scriptId) {
|
|
10770
|
+
const db = getDatabase();
|
|
10771
|
+
const query = scriptId ? db.query("SELECT * FROM script_runs WHERE script_id = ? ORDER BY started_at DESC LIMIT 20").all(scriptId) : db.query("SELECT * FROM script_runs ORDER BY started_at DESC LIMIT 20").all();
|
|
10772
|
+
return query.map((row) => ({
|
|
10773
|
+
...row,
|
|
10774
|
+
variables: JSON.parse(row.variables),
|
|
10775
|
+
steps_log: JSON.parse(row.steps_log),
|
|
10776
|
+
errors: JSON.parse(row.errors)
|
|
10777
|
+
}));
|
|
10778
|
+
}
|
|
10779
|
+
function migrateJsonScripts() {
|
|
10780
|
+
const { existsSync: existsSync5, readdirSync: readdirSync4, readFileSync: readFileSync3 } = __require("fs");
|
|
10781
|
+
const { join: join9 } = __require("path");
|
|
10782
|
+
const { getDataDir: getDataDir4 } = (init_schema(), __toCommonJS(exports_schema));
|
|
10783
|
+
const dir = join9(getDataDir4(), "scripts");
|
|
10650
10784
|
if (!existsSync5(dir))
|
|
10651
|
-
return
|
|
10652
|
-
|
|
10785
|
+
return 0;
|
|
10786
|
+
const files = readdirSync4(dir).filter((f) => f.endsWith(".json"));
|
|
10787
|
+
let migrated = 0;
|
|
10788
|
+
for (const file of files) {
|
|
10653
10789
|
try {
|
|
10654
|
-
const
|
|
10655
|
-
|
|
10656
|
-
|
|
10657
|
-
|
|
10658
|
-
|
|
10659
|
-
|
|
10790
|
+
const raw = JSON.parse(readFileSync3(join9(dir, file), "utf8"));
|
|
10791
|
+
if (!raw.name || !raw.steps)
|
|
10792
|
+
continue;
|
|
10793
|
+
if (getScriptByName(raw.name))
|
|
10794
|
+
continue;
|
|
10795
|
+
const steps = raw.steps.map((s) => {
|
|
10796
|
+
const isAI = s.type === "ai";
|
|
10797
|
+
return {
|
|
10798
|
+
type: isAI ? "extract" : s.type,
|
|
10799
|
+
config: {
|
|
10800
|
+
action: s.action,
|
|
10801
|
+
selector: s.selector,
|
|
10802
|
+
url: s.url,
|
|
10803
|
+
value: s.value,
|
|
10804
|
+
text: s.text,
|
|
10805
|
+
timeout: s.timeout,
|
|
10806
|
+
connector: s.connector,
|
|
10807
|
+
args: s.args,
|
|
10808
|
+
format: s.format,
|
|
10809
|
+
pattern: s.pattern,
|
|
10810
|
+
json_path: s.json_path,
|
|
10811
|
+
check: s.check,
|
|
10812
|
+
source: s.check,
|
|
10813
|
+
seconds: s.seconds,
|
|
10814
|
+
equals: s.equals,
|
|
10815
|
+
contains: s.contains,
|
|
10816
|
+
skip_to: s.skip_to,
|
|
10817
|
+
name: s.name,
|
|
10818
|
+
save_as: s.save_as,
|
|
10819
|
+
...isAI ? { prompt: s.prompt, source: s.check ?? "last_output" } : {}
|
|
10820
|
+
},
|
|
10821
|
+
description: s.description ?? "",
|
|
10822
|
+
ai_enabled: isAI || !!s.ai?.enabled,
|
|
10823
|
+
ai_config: isAI ? { provider: s.model === "haiku" || s.model === "sonnet" || s.model === "opus" ? "anthropic" : "cerebras", model: s.model ?? "fast" } : s.ai ?? {}
|
|
10824
|
+
};
|
|
10825
|
+
});
|
|
10826
|
+
createScript({
|
|
10827
|
+
name: raw.name,
|
|
10828
|
+
domain: raw.domain ?? "",
|
|
10829
|
+
description: raw.description ?? "",
|
|
10830
|
+
variables: raw.variables ?? {},
|
|
10831
|
+
steps
|
|
10832
|
+
});
|
|
10833
|
+
migrated++;
|
|
10834
|
+
} catch {}
|
|
10835
|
+
}
|
|
10836
|
+
return migrated;
|
|
10660
10837
|
}
|
|
10661
|
-
|
|
10662
|
-
|
|
10663
|
-
|
|
10664
|
-
|
|
10665
|
-
|
|
10666
|
-
|
|
10667
|
-
|
|
10838
|
+
var init_scripts = __esm(() => {
|
|
10839
|
+
init_schema();
|
|
10840
|
+
});
|
|
10841
|
+
|
|
10842
|
+
// src/lib/ai-inference.ts
|
|
10843
|
+
function resolve(opts) {
|
|
10844
|
+
if (opts?.model && ALIASES[opts.model])
|
|
10845
|
+
return ALIASES[opts.model];
|
|
10846
|
+
if (opts?.provider && opts?.model)
|
|
10847
|
+
return { provider: opts.provider, model: opts.model };
|
|
10848
|
+
if (opts?.provider === "anthropic")
|
|
10849
|
+
return ALIASES.haiku;
|
|
10850
|
+
return ALIASES.fast;
|
|
10851
|
+
}
|
|
10852
|
+
async function infer(prompt, opts) {
|
|
10853
|
+
const { provider, model } = resolve(opts);
|
|
10854
|
+
const maxTokens = opts?.maxTokens ?? 1024;
|
|
10855
|
+
if (provider === "anthropic") {
|
|
10856
|
+
const apiKey2 = process.env["ANTHROPIC_API_KEY"];
|
|
10857
|
+
if (!apiKey2)
|
|
10858
|
+
throw new Error("ANTHROPIC_API_KEY not set");
|
|
10859
|
+
const res2 = await fetch("https://api.anthropic.com/v1/messages", {
|
|
10860
|
+
method: "POST",
|
|
10861
|
+
headers: { "content-type": "application/json", "x-api-key": apiKey2, "anthropic-version": "2023-06-01" },
|
|
10862
|
+
body: JSON.stringify({ model, max_tokens: maxTokens, messages: [{ role: "user", content: prompt }] })
|
|
10863
|
+
});
|
|
10864
|
+
if (!res2.ok)
|
|
10865
|
+
throw new Error(`Anthropic API ${res2.status}: ${(await res2.text()).slice(0, 200)}`);
|
|
10866
|
+
const data2 = await res2.json();
|
|
10867
|
+
return data2.content?.[0]?.text ?? "";
|
|
10868
|
+
}
|
|
10869
|
+
const apiKey = process.env["CEREBRAS_API_KEY"];
|
|
10870
|
+
if (!apiKey)
|
|
10871
|
+
throw new Error("CEREBRAS_API_KEY not set");
|
|
10872
|
+
const res = await fetch("https://api.cerebras.ai/v1/chat/completions", {
|
|
10873
|
+
method: "POST",
|
|
10874
|
+
headers: { "content-type": "application/json", Authorization: `Bearer ${apiKey}` },
|
|
10875
|
+
body: JSON.stringify({ model, max_tokens: maxTokens, temperature: opts?.temperature ?? 0, messages: [{ role: "user", content: prompt }] })
|
|
10876
|
+
});
|
|
10877
|
+
if (!res.ok)
|
|
10878
|
+
throw new Error(`Cerebras API ${res.status}: ${(await res.text()).slice(0, 200)}`);
|
|
10879
|
+
const data = await res.json();
|
|
10880
|
+
return data.choices?.[0]?.message?.content ?? "";
|
|
10668
10881
|
}
|
|
10882
|
+
var ALIASES;
|
|
10883
|
+
var init_ai_inference = __esm(() => {
|
|
10884
|
+
ALIASES = {
|
|
10885
|
+
fast: { provider: "cerebras", model: "llama-4-scout-17b-16e-instruct" },
|
|
10886
|
+
scout: { provider: "cerebras", model: "llama-4-scout-17b-16e-instruct" },
|
|
10887
|
+
maverick: { provider: "cerebras", model: "llama-4-maverick-17b-128e-instruct" },
|
|
10888
|
+
haiku: { provider: "anthropic", model: "claude-haiku-4-5-20251001" },
|
|
10889
|
+
sonnet: { provider: "anthropic", model: "claude-sonnet-4-5-20250929" },
|
|
10890
|
+
opus: { provider: "anthropic", model: "claude-opus-4-6" }
|
|
10891
|
+
};
|
|
10892
|
+
});
|
|
10893
|
+
|
|
10894
|
+
// src/lib/script-engine.ts
|
|
10895
|
+
var exports_script_engine = {};
|
|
10896
|
+
__export(exports_script_engine, {
|
|
10897
|
+
executeScriptSync: () => executeScriptSync,
|
|
10898
|
+
executeScript: () => executeScript
|
|
10899
|
+
});
|
|
10669
10900
|
function interpolate(template, vars) {
|
|
10670
|
-
return template.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g, (
|
|
10671
|
-
|
|
10901
|
+
return template.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g, (_, key) => vars[key] ?? `{{${key}}}`);
|
|
10902
|
+
}
|
|
10903
|
+
function interpolateConfig(config, vars) {
|
|
10904
|
+
const result = {};
|
|
10905
|
+
for (const [k, v] of Object.entries(config)) {
|
|
10906
|
+
if (typeof v === "string")
|
|
10907
|
+
result[k] = interpolate(v, vars);
|
|
10908
|
+
else if (Array.isArray(v))
|
|
10909
|
+
result[k] = v.map((item) => typeof item === "string" ? interpolate(item, vars) : item);
|
|
10910
|
+
else
|
|
10911
|
+
result[k] = v;
|
|
10912
|
+
}
|
|
10913
|
+
return result;
|
|
10914
|
+
}
|
|
10915
|
+
function executeScript(scriptId, page, overrides = {}) {
|
|
10916
|
+
const steps = getSteps(scriptId);
|
|
10917
|
+
const run = startRun(scriptId, steps.length);
|
|
10918
|
+
_runSteps(run.id, scriptId, steps, page, overrides).catch((err) => {
|
|
10919
|
+
completeRun(run.id, "failed", [err instanceof Error ? err.message : String(err)], 0);
|
|
10672
10920
|
});
|
|
10921
|
+
return run.id;
|
|
10673
10922
|
}
|
|
10674
|
-
function
|
|
10675
|
-
|
|
10923
|
+
async function executeScriptSync(scriptId, page, overrides = {}) {
|
|
10924
|
+
const steps = getSteps(scriptId);
|
|
10925
|
+
const run = startRun(scriptId, steps.length);
|
|
10926
|
+
return _runSteps(run.id, scriptId, steps, page, overrides);
|
|
10676
10927
|
}
|
|
10677
|
-
async function
|
|
10928
|
+
async function _runSteps(runId, scriptId, steps, page, overrides) {
|
|
10678
10929
|
const t0 = Date.now();
|
|
10679
|
-
const
|
|
10930
|
+
const { getScript: getScript2 } = await Promise.resolve().then(() => (init_scripts(), exports_scripts));
|
|
10931
|
+
const script = getScript2(scriptId);
|
|
10932
|
+
const vars = { ...script?.variables ?? {}, ...overrides };
|
|
10680
10933
|
const errors2 = [];
|
|
10934
|
+
const stepsLog = [];
|
|
10681
10935
|
let executed = 0;
|
|
10682
10936
|
let failed = 0;
|
|
10683
|
-
|
|
10684
|
-
|
|
10685
|
-
|
|
10686
|
-
|
|
10687
|
-
current_step: 0,
|
|
10688
|
-
total_steps: script.steps.length,
|
|
10689
|
-
current_step_description: "Starting...",
|
|
10690
|
-
steps_log: [],
|
|
10691
|
-
started_at: new Date().toISOString()
|
|
10692
|
-
};
|
|
10693
|
-
activeJobs.set(job.id, job);
|
|
10694
|
-
for (let i = 0;i < script.steps.length; i++) {
|
|
10695
|
-
const step = script.steps[i];
|
|
10696
|
-
const desc = stepDescription(step);
|
|
10937
|
+
for (let i = 0;i < steps.length; i++) {
|
|
10938
|
+
const step = steps[i];
|
|
10939
|
+
const cfg = interpolateConfig(step.config, vars);
|
|
10940
|
+
const desc = step.description || `${step.type}`;
|
|
10697
10941
|
executed++;
|
|
10698
|
-
|
|
10699
|
-
|
|
10700
|
-
job.steps_log.push({ step: i + 1, type: step.type, description: desc, status: "running" });
|
|
10942
|
+
stepsLog.push({ step: i + 1, type: step.type, description: desc, status: "running" });
|
|
10943
|
+
updateRunProgress(runId, i + 1, desc, stepsLog, vars);
|
|
10701
10944
|
const stepStart = Date.now();
|
|
10702
10945
|
try {
|
|
10703
10946
|
switch (step.type) {
|
|
10704
10947
|
case "browser":
|
|
10705
|
-
await
|
|
10948
|
+
await execBrowser(cfg, step, page, vars);
|
|
10706
10949
|
break;
|
|
10707
10950
|
case "connector":
|
|
10708
|
-
await
|
|
10951
|
+
await execConnector(cfg, step, vars);
|
|
10709
10952
|
break;
|
|
10710
10953
|
case "extract":
|
|
10711
|
-
|
|
10712
|
-
break;
|
|
10713
|
-
case "ai":
|
|
10714
|
-
await runAIStep(step, vars);
|
|
10954
|
+
await execExtract(cfg, step, vars);
|
|
10715
10955
|
break;
|
|
10716
10956
|
case "wait":
|
|
10717
|
-
await new Promise((r) => setTimeout(r, (
|
|
10957
|
+
await new Promise((r) => setTimeout(r, (cfg.seconds ?? 3) * 1000));
|
|
10718
10958
|
break;
|
|
10719
|
-
case "condition":
|
|
10720
|
-
|
|
10721
|
-
let conditionMet = true;
|
|
10722
|
-
if (step.equals !== undefined)
|
|
10723
|
-
conditionMet = checkVal === interpolate(step.equals, vars);
|
|
10724
|
-
if (step.contains !== undefined)
|
|
10725
|
-
conditionMet = checkVal?.includes(interpolate(step.contains, vars)) ?? false;
|
|
10726
|
-
if (!conditionMet && step.skip_to !== undefined) {
|
|
10727
|
-
i = step.skip_to - 1;
|
|
10728
|
-
}
|
|
10959
|
+
case "condition":
|
|
10960
|
+
i = execCondition(cfg, vars, i);
|
|
10729
10961
|
break;
|
|
10730
|
-
|
|
10731
|
-
|
|
10732
|
-
const stateName = interpolate(step.name ?? script.name, vars);
|
|
10733
|
-
try {
|
|
10734
|
-
const { saveStateFromPage: saveStateFromPage2 } = await Promise.resolve().then(() => (init_storage_state(), exports_storage_state));
|
|
10735
|
-
const path = await saveStateFromPage2(page, stateName);
|
|
10736
|
-
vars["saved_state_path"] = path;
|
|
10737
|
-
} catch {}
|
|
10962
|
+
case "save_state":
|
|
10963
|
+
await execSaveState(cfg, page, vars);
|
|
10738
10964
|
break;
|
|
10739
|
-
}
|
|
10740
10965
|
}
|
|
10741
|
-
|
|
10742
|
-
|
|
10743
|
-
logEntry.duration_ms = Date.now() - stepStart;
|
|
10966
|
+
stepsLog[stepsLog.length - 1].status = "ok";
|
|
10967
|
+
stepsLog[stepsLog.length - 1].duration_ms = Date.now() - stepStart;
|
|
10744
10968
|
} catch (err) {
|
|
10745
10969
|
failed++;
|
|
10746
|
-
const msg = `Step ${i + 1} (${step.type}
|
|
10970
|
+
const msg = `Step ${i + 1} (${step.type}): ${err instanceof Error ? err.message : String(err)}`;
|
|
10747
10971
|
errors2.push(msg);
|
|
10748
|
-
|
|
10749
|
-
|
|
10750
|
-
|
|
10751
|
-
|
|
10752
|
-
if (step.type === "browser" && step.action === "navigate")
|
|
10972
|
+
stepsLog[stepsLog.length - 1].status = "failed";
|
|
10973
|
+
stepsLog[stepsLog.length - 1].error = err instanceof Error ? err.message : String(err);
|
|
10974
|
+
stepsLog[stepsLog.length - 1].duration_ms = Date.now() - stepStart;
|
|
10975
|
+
if (step.type === "browser" && cfg.action === "navigate")
|
|
10753
10976
|
break;
|
|
10754
10977
|
}
|
|
10978
|
+
updateRunProgress(runId, i + 1, desc, stepsLog, vars);
|
|
10755
10979
|
}
|
|
10756
|
-
const
|
|
10757
|
-
|
|
10758
|
-
|
|
10759
|
-
|
|
10760
|
-
variables: vars,
|
|
10761
|
-
errors: errors2,
|
|
10762
|
-
duration_ms: Date.now() - t0
|
|
10763
|
-
};
|
|
10764
|
-
job.status = failed === 0 ? "completed" : "failed";
|
|
10765
|
-
job.result = result;
|
|
10766
|
-
return result;
|
|
10980
|
+
const durationMs = Date.now() - t0;
|
|
10981
|
+
const status = failed === 0 ? "completed" : "failed";
|
|
10982
|
+
completeRun(runId, status, errors2, durationMs);
|
|
10983
|
+
return { run_id: runId, success: failed === 0, steps_executed: executed, steps_failed: failed, errors: errors2, duration_ms: durationMs, variables: vars };
|
|
10767
10984
|
}
|
|
10768
|
-
function
|
|
10769
|
-
const
|
|
10770
|
-
const job = {
|
|
10771
|
-
id: jobId,
|
|
10772
|
-
script_name: script.name,
|
|
10773
|
-
status: "running",
|
|
10774
|
-
current_step: 0,
|
|
10775
|
-
total_steps: script.steps.length,
|
|
10776
|
-
current_step_description: "Starting...",
|
|
10777
|
-
steps_log: [],
|
|
10778
|
-
started_at: new Date().toISOString()
|
|
10779
|
-
};
|
|
10780
|
-
activeJobs.set(jobId, job);
|
|
10781
|
-
runScript(script, page, overrides, jobId).catch((err) => {
|
|
10782
|
-
job.status = "failed";
|
|
10783
|
-
job.current_step_description = `Fatal error: ${err instanceof Error ? err.message : String(err)}`;
|
|
10784
|
-
});
|
|
10785
|
-
return jobId;
|
|
10786
|
-
}
|
|
10787
|
-
async function runBrowserStep(step, page, vars) {
|
|
10788
|
-
const action = step.action;
|
|
10789
|
-
if (!action)
|
|
10790
|
-
throw new Error("Browser step missing action");
|
|
10985
|
+
async function execBrowser(cfg, step, page, vars) {
|
|
10986
|
+
const action = cfg.action;
|
|
10791
10987
|
switch (action) {
|
|
10792
|
-
case "navigate":
|
|
10793
|
-
|
|
10794
|
-
await page.goto(url, { waitUntil: "domcontentloaded", timeout: step.timeout ?? 30000 });
|
|
10988
|
+
case "navigate":
|
|
10989
|
+
await page.goto(cfg.url, { waitUntil: "domcontentloaded", timeout: cfg.timeout ?? 30000 });
|
|
10795
10990
|
await new Promise((r) => setTimeout(r, 1000));
|
|
10796
10991
|
vars["current_url"] = page.url();
|
|
10797
10992
|
vars["current_title"] = await page.title();
|
|
10798
10993
|
break;
|
|
10799
|
-
}
|
|
10800
10994
|
case "type": {
|
|
10801
|
-
const selector =
|
|
10802
|
-
const value =
|
|
10803
|
-
|
|
10995
|
+
const selector = cfg.selector ?? "input";
|
|
10996
|
+
const value = cfg.value ?? cfg.text ?? "";
|
|
10997
|
+
try {
|
|
10998
|
+
await page.fill(selector, value);
|
|
10999
|
+
} catch (origErr) {
|
|
11000
|
+
if (step.ai_enabled) {
|
|
11001
|
+
const healed = await aiSelfHeal(page, `input field for typing "${value}"`, step);
|
|
11002
|
+
if (healed) {
|
|
11003
|
+
await page.mouse.click(healed.x, healed.y);
|
|
11004
|
+
await page.keyboard.type(value);
|
|
11005
|
+
} else
|
|
11006
|
+
throw origErr;
|
|
11007
|
+
} else {
|
|
11008
|
+
const { healSelector: healSelector2 } = await Promise.resolve().then(() => exports_self_heal);
|
|
11009
|
+
const result = await healSelector2(page, selector);
|
|
11010
|
+
if (result.found && result.locator)
|
|
11011
|
+
await result.locator.fill(value);
|
|
11012
|
+
else
|
|
11013
|
+
throw origErr;
|
|
11014
|
+
}
|
|
11015
|
+
}
|
|
10804
11016
|
break;
|
|
10805
11017
|
}
|
|
10806
11018
|
case "click": {
|
|
10807
|
-
const selector =
|
|
10808
|
-
|
|
11019
|
+
const selector = cfg.selector;
|
|
11020
|
+
try {
|
|
11021
|
+
await page.click(selector, { timeout: cfg.timeout ?? 1e4 });
|
|
11022
|
+
} catch (origErr) {
|
|
11023
|
+
if (step.ai_enabled) {
|
|
11024
|
+
const healed = await aiSelfHeal(page, `clickable element matching "${selector}"`, step);
|
|
11025
|
+
if (healed)
|
|
11026
|
+
await page.mouse.click(healed.x, healed.y);
|
|
11027
|
+
else
|
|
11028
|
+
throw origErr;
|
|
11029
|
+
} else {
|
|
11030
|
+
const { healSelector: healSelector2 } = await Promise.resolve().then(() => exports_self_heal);
|
|
11031
|
+
const result = await healSelector2(page, selector);
|
|
11032
|
+
if (result.found && result.locator)
|
|
11033
|
+
await result.locator.click();
|
|
11034
|
+
else
|
|
11035
|
+
throw origErr;
|
|
11036
|
+
}
|
|
11037
|
+
}
|
|
10809
11038
|
await new Promise((r) => setTimeout(r, 500));
|
|
10810
11039
|
break;
|
|
10811
11040
|
}
|
|
10812
11041
|
case "click_text": {
|
|
10813
|
-
const text =
|
|
10814
|
-
|
|
11042
|
+
const text = cfg.text;
|
|
11043
|
+
try {
|
|
11044
|
+
await page.getByText(text, { exact: false }).first().click({ timeout: cfg.timeout ?? 1e4 });
|
|
11045
|
+
} catch (origErr) {
|
|
11046
|
+
if (step.ai_enabled) {
|
|
11047
|
+
const healed = await aiSelfHeal(page, `button or link with text "${text}"`, step);
|
|
11048
|
+
if (healed)
|
|
11049
|
+
await page.mouse.click(healed.x, healed.y);
|
|
11050
|
+
else
|
|
11051
|
+
throw origErr;
|
|
11052
|
+
} else
|
|
11053
|
+
throw origErr;
|
|
11054
|
+
}
|
|
10815
11055
|
await new Promise((r) => setTimeout(r, 500));
|
|
10816
11056
|
break;
|
|
10817
11057
|
}
|
|
10818
|
-
case "wait_for_navigation":
|
|
11058
|
+
case "wait_for_navigation":
|
|
10819
11059
|
try {
|
|
10820
|
-
await page.waitForNavigation({ timeout:
|
|
11060
|
+
await page.waitForNavigation({ timeout: cfg.timeout ?? 15000 });
|
|
10821
11061
|
} catch {}
|
|
10822
11062
|
await new Promise((r) => setTimeout(r, 1000));
|
|
10823
11063
|
vars["current_url"] = page.url();
|
|
10824
11064
|
break;
|
|
10825
|
-
}
|
|
10826
11065
|
case "wait_for_text": {
|
|
10827
|
-
const text =
|
|
10828
|
-
await page.waitForSelector(`text=${text}`, { timeout:
|
|
11066
|
+
const text = cfg.text;
|
|
11067
|
+
await page.waitForSelector(`text=${text}`, { timeout: cfg.timeout ?? 1e4 });
|
|
10829
11068
|
break;
|
|
10830
11069
|
}
|
|
10831
|
-
case "snapshot":
|
|
11070
|
+
case "snapshot":
|
|
10832
11071
|
vars["page_text"] = await page.evaluate(() => document.body?.textContent?.trim() ?? "");
|
|
10833
11072
|
break;
|
|
10834
|
-
}
|
|
10835
|
-
}
|
|
10836
|
-
}
|
|
10837
|
-
async function runConnectorStep(step, vars) {
|
|
10838
|
-
const connectorName = step.connector;
|
|
10839
|
-
if (!connectorName)
|
|
10840
|
-
throw new Error("Connector step missing connector name");
|
|
10841
|
-
const args = (step.args ?? []).map((a) => interpolate(a, vars));
|
|
10842
|
-
let stdout = "";
|
|
10843
|
-
try {
|
|
10844
|
-
const bin = `connect-${connectorName}`;
|
|
10845
|
-
const proc = Bun.spawn([bin, ...args], {
|
|
10846
|
-
stdout: "pipe",
|
|
10847
|
-
stderr: "pipe",
|
|
10848
|
-
env: { ...process.env, HOME: process.env.HOME ?? "" }
|
|
10849
|
-
});
|
|
10850
|
-
stdout = await new Response(proc.stdout).text();
|
|
10851
|
-
const stderr = await new Response(proc.stderr).text();
|
|
10852
|
-
const exitCode = await proc.exited;
|
|
10853
|
-
vars["last_success"] = String(exitCode === 0);
|
|
10854
|
-
vars["last_exit_code"] = String(exitCode);
|
|
10855
|
-
if (exitCode !== 0 && stderr)
|
|
10856
|
-
stdout = stderr;
|
|
10857
|
-
} catch (e) {
|
|
10858
|
-
vars["last_success"] = "false";
|
|
10859
|
-
throw new Error(`Connector ${connectorName} failed: ${e.message ?? String(e)}`);
|
|
10860
|
-
}
|
|
10861
|
-
vars["last_output"] = stdout;
|
|
10862
|
-
try {
|
|
10863
|
-
const parsed = JSON.parse(stdout);
|
|
10864
|
-
if (typeof parsed === "object" && parsed !== null) {
|
|
10865
|
-
for (const [k, v] of Object.entries(parsed)) {
|
|
10866
|
-
if (typeof v === "string" || typeof v === "number") {
|
|
10867
|
-
vars[`last.${k}`] = String(v);
|
|
10868
|
-
}
|
|
10869
|
-
}
|
|
10870
|
-
}
|
|
10871
|
-
} catch {}
|
|
10872
|
-
if (step.save_as) {
|
|
10873
|
-
vars[step.save_as] = stdout;
|
|
10874
11073
|
}
|
|
10875
11074
|
}
|
|
10876
|
-
function
|
|
10877
|
-
|
|
10878
|
-
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
|
|
10883
|
-
|
|
10884
|
-
|
|
10885
|
-
extract: (data) => data.content?.[0]?.text ?? ""
|
|
10886
|
-
};
|
|
10887
|
-
}
|
|
10888
|
-
const apiKey = process.env["CEREBRAS_API_KEY"];
|
|
10889
|
-
if (!apiKey)
|
|
10890
|
-
throw new Error("CEREBRAS_API_KEY not set \u2014 required for AI steps (set CEREBRAS_API_KEY or use provider: 'anthropic')");
|
|
10891
|
-
return {
|
|
10892
|
-
url: "https://api.cerebras.ai/v1/chat/completions",
|
|
10893
|
-
headers: { "content-type": "application/json", Authorization: `Bearer ${apiKey}` },
|
|
10894
|
-
body: (model, prompt) => ({ model, max_tokens: 1024, messages: [{ role: "user", content: prompt }] }),
|
|
10895
|
-
extract: (data) => data.choices?.[0]?.message?.content ?? ""
|
|
10896
|
-
};
|
|
10897
|
-
}
|
|
10898
|
-
async function runAIStep(step, vars) {
|
|
10899
|
-
const prompt = interpolate(step.prompt ?? "", vars);
|
|
10900
|
-
if (!prompt)
|
|
10901
|
-
throw new Error("AI step missing prompt");
|
|
10902
|
-
const modelAlias = step.model ?? "fast";
|
|
10903
|
-
const resolved = MODEL_MAP[modelAlias] ?? { provider: "cerebras", model: modelAlias };
|
|
10904
|
-
const saveTo = step.save_as ?? "ai_response";
|
|
10905
|
-
const provider = getAIProvider(resolved.provider);
|
|
10906
|
-
const response = await fetch(provider.url, {
|
|
10907
|
-
method: "POST",
|
|
10908
|
-
headers: provider.headers,
|
|
10909
|
-
body: JSON.stringify(provider.body(resolved.model, prompt))
|
|
11075
|
+
async function execConnector(cfg, step, vars) {
|
|
11076
|
+
const connector = cfg.connector;
|
|
11077
|
+
if (!connector)
|
|
11078
|
+
throw new Error("Connector step missing 'connector' in config");
|
|
11079
|
+
const args = cfg.args ?? [];
|
|
11080
|
+
const proc = Bun.spawn([`connect-${connector}`, ...args], {
|
|
11081
|
+
stdout: "pipe",
|
|
11082
|
+
stderr: "pipe",
|
|
11083
|
+
env: { ...process.env, HOME: process.env.HOME ?? "" }
|
|
10910
11084
|
});
|
|
10911
|
-
|
|
10912
|
-
|
|
10913
|
-
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
const
|
|
10917
|
-
vars[
|
|
10918
|
-
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10922
|
-
|
|
10923
|
-
|
|
10924
|
-
|
|
10925
|
-
|
|
10926
|
-
|
|
10927
|
-
|
|
10928
|
-
|
|
10929
|
-
|
|
10930
|
-
|
|
11085
|
+
const stdout = await new Response(proc.stdout).text();
|
|
11086
|
+
const stderr = await new Response(proc.stderr).text();
|
|
11087
|
+
const exitCode = await proc.exited;
|
|
11088
|
+
if (exitCode !== 0 && !stdout)
|
|
11089
|
+
throw new Error(`Connector ${connector} failed: ${stderr.slice(0, 200)}`);
|
|
11090
|
+
const raw = stdout || stderr;
|
|
11091
|
+
vars["last_output"] = raw;
|
|
11092
|
+
if (step.ai_enabled && step.ai_config?.prompt) {
|
|
11093
|
+
const aiPrompt = interpolate(step.ai_config.prompt, { ...vars, last_output: raw });
|
|
11094
|
+
const provider = step.ai_config.provider ?? "cerebras";
|
|
11095
|
+
const model = step.ai_config.model ?? "fast";
|
|
11096
|
+
const parsed = await infer(aiPrompt, { provider, model });
|
|
11097
|
+
const saveTo = cfg.save_as ?? "last_output";
|
|
11098
|
+
vars[saveTo] = parsed.trim();
|
|
11099
|
+
} else if (cfg.save_as) {
|
|
11100
|
+
vars[cfg.save_as] = raw;
|
|
11101
|
+
}
|
|
11102
|
+
}
|
|
11103
|
+
async function execExtract(cfg, step, vars) {
|
|
11104
|
+
const saveTo = cfg.save_as ?? "extracted";
|
|
11105
|
+
if (step.ai_enabled || cfg.prompt) {
|
|
11106
|
+
const source = cfg.source ? vars[cfg.source] ?? "" : vars["last_output"] ?? "";
|
|
11107
|
+
const prompt = interpolate(cfg.prompt ?? `Extract the key information from this text:
|
|
11108
|
+
|
|
11109
|
+
${source}`, { ...vars, source });
|
|
11110
|
+
const provider = step.ai_config?.provider ?? "cerebras";
|
|
11111
|
+
const model = step.ai_config?.model ?? "fast";
|
|
11112
|
+
const result = await infer(prompt, { provider, model });
|
|
11113
|
+
vars[saveTo] = result.trim();
|
|
11114
|
+
vars["last_output"] = result.trim();
|
|
11115
|
+
return;
|
|
10931
11116
|
}
|
|
10932
|
-
|
|
10933
|
-
|
|
10934
|
-
|
|
10935
|
-
}
|
|
10936
|
-
function runExtractStep(step, vars) {
|
|
10937
|
-
const saveTo = step.save_as ?? "extracted";
|
|
10938
|
-
if (step.pattern) {
|
|
10939
|
-
const source = step.check ? vars[step.check] ?? "" : vars["last_output"] ?? "";
|
|
10940
|
-
const regex = new RegExp(step.pattern);
|
|
10941
|
-
const match = regex.exec(source);
|
|
11117
|
+
if (cfg.pattern) {
|
|
11118
|
+
const source = cfg.source ? vars[cfg.source] ?? "" : vars["last_output"] ?? "";
|
|
11119
|
+
const match = new RegExp(cfg.pattern).exec(source);
|
|
10942
11120
|
if (match) {
|
|
10943
11121
|
vars[saveTo] = decodeHtmlEntities(match[1] ?? match[0]);
|
|
10944
11122
|
}
|
|
10945
11123
|
}
|
|
10946
|
-
if (step.json_path) {
|
|
10947
|
-
const source = vars["last_output"] ?? "{}";
|
|
10948
|
-
try {
|
|
10949
|
-
let obj = JSON.parse(source);
|
|
10950
|
-
for (const key of step.json_path.split(".")) {
|
|
10951
|
-
obj = obj?.[key];
|
|
10952
|
-
}
|
|
10953
|
-
if (obj !== undefined)
|
|
10954
|
-
vars[saveTo] = String(obj);
|
|
10955
|
-
} catch {}
|
|
10956
|
-
}
|
|
10957
11124
|
}
|
|
10958
|
-
function
|
|
10959
|
-
const
|
|
10960
|
-
|
|
10961
|
-
|
|
10962
|
-
|
|
10963
|
-
|
|
10964
|
-
|
|
10965
|
-
|
|
10966
|
-
|
|
10967
|
-
return
|
|
10968
|
-
name: parsed.name,
|
|
10969
|
-
domain: parsed.domain,
|
|
10970
|
-
description: parsed.description ?? "",
|
|
10971
|
-
variables: parsed.variables ?? {},
|
|
10972
|
-
steps: parsed.steps,
|
|
10973
|
-
created_at: new Date().toISOString(),
|
|
10974
|
-
updated_at: new Date().toISOString()
|
|
10975
|
-
};
|
|
11125
|
+
function execCondition(cfg, vars, i) {
|
|
11126
|
+
const checkVal = vars[cfg.check ?? ""];
|
|
11127
|
+
let met = true;
|
|
11128
|
+
if (cfg.equals !== undefined)
|
|
11129
|
+
met = checkVal === interpolate(cfg.equals, vars);
|
|
11130
|
+
if (cfg.contains !== undefined)
|
|
11131
|
+
met = checkVal?.includes(interpolate(cfg.contains, vars)) ?? false;
|
|
11132
|
+
if (!met && cfg.skip_to !== undefined)
|
|
11133
|
+
return cfg.skip_to - 1;
|
|
11134
|
+
return i;
|
|
10976
11135
|
}
|
|
10977
|
-
function
|
|
10978
|
-
|
|
10979
|
-
|
|
10980
|
-
|
|
11136
|
+
async function execSaveState(cfg, page, vars) {
|
|
11137
|
+
const name = interpolate(cfg.name ?? "default", vars);
|
|
11138
|
+
try {
|
|
11139
|
+
const { saveStateFromPage: saveStateFromPage2 } = await Promise.resolve().then(() => (init_storage_state(), exports_storage_state));
|
|
11140
|
+
vars["saved_state_path"] = await saveStateFromPage2(page, name);
|
|
11141
|
+
} catch {}
|
|
10981
11142
|
}
|
|
10982
|
-
|
|
10983
|
-
|
|
10984
|
-
|
|
10985
|
-
|
|
10986
|
-
|
|
10987
|
-
|
|
10988
|
-
|
|
10989
|
-
|
|
10990
|
-
|
|
10991
|
-
|
|
10992
|
-
|
|
10993
|
-
|
|
11143
|
+
async function aiSelfHeal(page, description, step) {
|
|
11144
|
+
try {
|
|
11145
|
+
const { findElementByVision: findElementByVision2 } = await Promise.resolve().then(() => exports_vision_fallback);
|
|
11146
|
+
const provider = step.ai_config?.provider ?? undefined;
|
|
11147
|
+
const model = step.ai_config?.model ?? undefined;
|
|
11148
|
+
const result = await findElementByVision2(page, description, { model: model ?? provider });
|
|
11149
|
+
if (result.found)
|
|
11150
|
+
return { x: result.x, y: result.y };
|
|
11151
|
+
} catch {}
|
|
11152
|
+
return null;
|
|
11153
|
+
}
|
|
11154
|
+
function decodeHtmlEntities(str) {
|
|
11155
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/'/g, "'");
|
|
11156
|
+
}
|
|
11157
|
+
var init_script_engine = __esm(() => {
|
|
11158
|
+
init_scripts();
|
|
11159
|
+
init_ai_inference();
|
|
10994
11160
|
});
|
|
10995
11161
|
|
|
10996
11162
|
// src/lib/api-detector.ts
|
|
@@ -11141,8 +11307,8 @@ __export(exports_datasets, {
|
|
|
11141
11307
|
deleteDataset: () => deleteDataset
|
|
11142
11308
|
});
|
|
11143
11309
|
import { randomUUID as randomUUID14 } from "crypto";
|
|
11144
|
-
import { writeFileSync as
|
|
11145
|
-
import { join as
|
|
11310
|
+
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync9 } from "fs";
|
|
11311
|
+
import { join as join9 } from "path";
|
|
11146
11312
|
import { homedir as homedir9 } from "os";
|
|
11147
11313
|
function saveDataset(data) {
|
|
11148
11314
|
const db = getDatabase();
|
|
@@ -11181,14 +11347,14 @@ function exportDataset(name, format) {
|
|
|
11181
11347
|
const dataset = getDatasetByName(name);
|
|
11182
11348
|
if (!dataset)
|
|
11183
11349
|
throw new Error(`Dataset '${name}' not found`);
|
|
11184
|
-
const dir =
|
|
11185
|
-
|
|
11350
|
+
const dir = join9(process.env["BROWSER_DATA_DIR"] ?? join9(homedir9(), ".browser"), "exports");
|
|
11351
|
+
mkdirSync9(dir, { recursive: true });
|
|
11186
11352
|
const filename = `${name}.${format}`;
|
|
11187
|
-
const path =
|
|
11353
|
+
const path = join9(dir, filename);
|
|
11188
11354
|
if (format === "csv") {
|
|
11189
11355
|
const rows = dataset.data;
|
|
11190
11356
|
if (rows.length === 0) {
|
|
11191
|
-
|
|
11357
|
+
writeFileSync3(path, "");
|
|
11192
11358
|
return { path, size: 0 };
|
|
11193
11359
|
}
|
|
11194
11360
|
const headers = Object.keys(rows[0]);
|
|
@@ -11201,11 +11367,11 @@ function exportDataset(name, format) {
|
|
|
11201
11367
|
}
|
|
11202
11368
|
const content = csvLines.join(`
|
|
11203
11369
|
`);
|
|
11204
|
-
|
|
11370
|
+
writeFileSync3(path, content);
|
|
11205
11371
|
return { path, size: content.length };
|
|
11206
11372
|
} else {
|
|
11207
11373
|
const content = JSON.stringify(dataset.data, null, 2);
|
|
11208
|
-
|
|
11374
|
+
writeFileSync3(path, content);
|
|
11209
11375
|
return { path, size: content.length };
|
|
11210
11376
|
}
|
|
11211
11377
|
}
|
|
@@ -11219,8 +11385,8 @@ __export(exports_auth, {
|
|
|
11219
11385
|
loginWithCredentials: () => loginWithCredentials,
|
|
11220
11386
|
getCredentials: () => getCredentials
|
|
11221
11387
|
});
|
|
11222
|
-
import { existsSync as
|
|
11223
|
-
import { join as
|
|
11388
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
11389
|
+
import { join as join10 } from "path";
|
|
11224
11390
|
import { homedir as homedir10 } from "os";
|
|
11225
11391
|
async function getCredentials(service) {
|
|
11226
11392
|
try {
|
|
@@ -11231,9 +11397,9 @@ async function getCredentials(service) {
|
|
|
11231
11397
|
return { email: email.value, password: password.value };
|
|
11232
11398
|
}
|
|
11233
11399
|
} catch {}
|
|
11234
|
-
const secretsPath =
|
|
11235
|
-
if (
|
|
11236
|
-
const content =
|
|
11400
|
+
const secretsPath = join10(homedir10(), ".secrets");
|
|
11401
|
+
if (existsSync5(secretsPath)) {
|
|
11402
|
+
const content = readFileSync3(secretsPath, "utf8");
|
|
11237
11403
|
const lines = content.split(`
|
|
11238
11404
|
`);
|
|
11239
11405
|
const prefix = service.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
@@ -11413,11 +11579,11 @@ __export(exports_dist, {
|
|
|
11413
11579
|
DEFAULT_CONFIG: () => DEFAULT_CONFIG
|
|
11414
11580
|
});
|
|
11415
11581
|
import { Database as Database2 } from "bun:sqlite";
|
|
11416
|
-
import { existsSync as
|
|
11417
|
-
import { dirname, join as
|
|
11418
|
-
import { existsSync as existsSync22, mkdirSync as mkdirSync22, readFileSync as
|
|
11582
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync10 } from "fs";
|
|
11583
|
+
import { dirname, join as join11, resolve as resolve2 } from "path";
|
|
11584
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync22, readFileSync as readFileSync4, readdirSync as readdirSync4, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3 } from "fs";
|
|
11419
11585
|
import { homedir as homedir11 } from "os";
|
|
11420
|
-
import { basename as basename2, dirname as dirname2, join as join22, resolve as
|
|
11586
|
+
import { basename as basename2, dirname as dirname2, join as join22, resolve as resolve22 } from "path";
|
|
11421
11587
|
import { existsSync as existsSync32, mkdirSync as mkdirSync32, readFileSync as readFileSync22, writeFileSync as writeFileSync22 } from "fs";
|
|
11422
11588
|
import { homedir as homedir22 } from "os";
|
|
11423
11589
|
import { join as join32 } from "path";
|
|
@@ -11428,10 +11594,10 @@ function isInMemoryDb(path) {
|
|
|
11428
11594
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
11429
11595
|
}
|
|
11430
11596
|
function findNearestMementosDb(startDir) {
|
|
11431
|
-
let dir =
|
|
11597
|
+
let dir = resolve2(startDir);
|
|
11432
11598
|
while (true) {
|
|
11433
|
-
const candidate =
|
|
11434
|
-
if (
|
|
11599
|
+
const candidate = join11(dir, ".mementos", "mementos.db");
|
|
11600
|
+
if (existsSync6(candidate))
|
|
11435
11601
|
return candidate;
|
|
11436
11602
|
const parent = dirname(dir);
|
|
11437
11603
|
if (parent === dir)
|
|
@@ -11441,9 +11607,9 @@ function findNearestMementosDb(startDir) {
|
|
|
11441
11607
|
return null;
|
|
11442
11608
|
}
|
|
11443
11609
|
function findGitRoot(startDir) {
|
|
11444
|
-
let dir =
|
|
11610
|
+
let dir = resolve2(startDir);
|
|
11445
11611
|
while (true) {
|
|
11446
|
-
if (
|
|
11612
|
+
if (existsSync6(join11(dir, ".git")))
|
|
11447
11613
|
return dir;
|
|
11448
11614
|
const parent = dirname(dir);
|
|
11449
11615
|
if (parent === dir)
|
|
@@ -11463,18 +11629,18 @@ function getDbPath() {
|
|
|
11463
11629
|
if (process.env["MEMENTOS_DB_SCOPE"] === "project") {
|
|
11464
11630
|
const gitRoot = findGitRoot(cwd);
|
|
11465
11631
|
if (gitRoot) {
|
|
11466
|
-
return
|
|
11632
|
+
return join11(gitRoot, ".mementos", "mementos.db");
|
|
11467
11633
|
}
|
|
11468
11634
|
}
|
|
11469
11635
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
11470
|
-
return
|
|
11636
|
+
return join11(home, ".mementos", "mementos.db");
|
|
11471
11637
|
}
|
|
11472
11638
|
function ensureDir2(filePath) {
|
|
11473
11639
|
if (isInMemoryDb(filePath))
|
|
11474
11640
|
return;
|
|
11475
|
-
const dir = dirname(
|
|
11476
|
-
if (!
|
|
11477
|
-
|
|
11641
|
+
const dir = dirname(resolve2(filePath));
|
|
11642
|
+
if (!existsSync6(dir)) {
|
|
11643
|
+
mkdirSync10(dir, { recursive: true });
|
|
11478
11644
|
}
|
|
11479
11645
|
}
|
|
11480
11646
|
function getDatabase2(dbPath) {
|
|
@@ -13328,7 +13494,7 @@ function loadConfig() {
|
|
|
13328
13494
|
let fileConfig = {};
|
|
13329
13495
|
if (existsSync22(configPath)) {
|
|
13330
13496
|
try {
|
|
13331
|
-
const raw =
|
|
13497
|
+
const raw = readFileSync4(configPath, "utf-8");
|
|
13332
13498
|
fileConfig = JSON.parse(raw);
|
|
13333
13499
|
} catch {}
|
|
13334
13500
|
}
|
|
@@ -13361,7 +13527,7 @@ function readGlobalConfig() {
|
|
|
13361
13527
|
if (!existsSync22(p))
|
|
13362
13528
|
return {};
|
|
13363
13529
|
try {
|
|
13364
|
-
return JSON.parse(
|
|
13530
|
+
return JSON.parse(readFileSync4(p, "utf-8"));
|
|
13365
13531
|
} catch {
|
|
13366
13532
|
return {};
|
|
13367
13533
|
}
|
|
@@ -13369,7 +13535,7 @@ function readGlobalConfig() {
|
|
|
13369
13535
|
function writeGlobalConfig(data) {
|
|
13370
13536
|
const p = globalConfigPath();
|
|
13371
13537
|
ensureDir22(dirname2(p));
|
|
13372
|
-
|
|
13538
|
+
writeFileSync4(p, JSON.stringify(data, null, 2), "utf-8");
|
|
13373
13539
|
}
|
|
13374
13540
|
function getActiveProfile() {
|
|
13375
13541
|
const envProfile = process.env["MEMENTOS_PROFILE"];
|
|
@@ -13391,7 +13557,7 @@ function listProfiles2() {
|
|
|
13391
13557
|
const dir = profilesDir();
|
|
13392
13558
|
if (!existsSync22(dir))
|
|
13393
13559
|
return [];
|
|
13394
|
-
return
|
|
13560
|
+
return readdirSync4(dir).filter((f) => f.endsWith(".db")).map((f) => basename2(f, ".db")).sort();
|
|
13395
13561
|
}
|
|
13396
13562
|
function deleteProfile2(name) {
|
|
13397
13563
|
const dbPath = join22(profilesDir(), `${name}.db`);
|
|
@@ -16034,30 +16200,30 @@ __export(exports_dist2, {
|
|
|
16034
16200
|
acquireLock: () => acquireLock2
|
|
16035
16201
|
});
|
|
16036
16202
|
import { Database as Database3 } from "bun:sqlite";
|
|
16037
|
-
import { mkdirSync as
|
|
16038
|
-
import { join as
|
|
16203
|
+
import { mkdirSync as mkdirSync11 } from "fs";
|
|
16204
|
+
import { join as join12, dirname as dirname3 } from "path";
|
|
16039
16205
|
import { homedir as homedir12 } from "os";
|
|
16040
16206
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
16041
16207
|
import { mkdirSync as mkdirSync23, copyFileSync as copyFileSync3, statSync as statSync2 } from "fs";
|
|
16042
16208
|
import { join as join33 } from "path";
|
|
16043
16209
|
import { homedir as homedir33 } from "os";
|
|
16044
|
-
import { readFileSync as
|
|
16210
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
16045
16211
|
import { join as join23 } from "path";
|
|
16046
16212
|
import { homedir as homedir23 } from "os";
|
|
16047
16213
|
import { randomUUID as randomUUID22 } from "crypto";
|
|
16048
|
-
import { readFileSync as readFileSync23, writeFileSync as
|
|
16214
|
+
import { readFileSync as readFileSync23, writeFileSync as writeFileSync5, mkdirSync as mkdirSync33 } from "fs";
|
|
16049
16215
|
import { join as join43, dirname as dirname22 } from "path";
|
|
16050
16216
|
import { homedir as homedir42 } from "os";
|
|
16051
16217
|
function getDbPath2() {
|
|
16052
16218
|
if (process.env.CONVERSATIONS_DB_PATH)
|
|
16053
16219
|
return process.env.CONVERSATIONS_DB_PATH;
|
|
16054
|
-
return
|
|
16220
|
+
return join12(homedir12(), ".conversations", "messages.db");
|
|
16055
16221
|
}
|
|
16056
16222
|
function getDb() {
|
|
16057
16223
|
if (db)
|
|
16058
16224
|
return db;
|
|
16059
16225
|
const dbPath = getDbPath2();
|
|
16060
|
-
|
|
16226
|
+
mkdirSync11(dirname3(dbPath), { recursive: true });
|
|
16061
16227
|
db = new Database3(dbPath, { create: true });
|
|
16062
16228
|
db.exec("PRAGMA journal_mode = WAL");
|
|
16063
16229
|
db.exec("PRAGMA busy_timeout = 5000");
|
|
@@ -16299,7 +16465,7 @@ function loadConfig2() {
|
|
|
16299
16465
|
if (cachedConfig && now2 - configLoadedAt < CONFIG_CACHE_MS)
|
|
16300
16466
|
return cachedConfig;
|
|
16301
16467
|
try {
|
|
16302
|
-
const raw =
|
|
16468
|
+
const raw = readFileSync5(getConfigPath(), "utf-8");
|
|
16303
16469
|
cachedConfig = JSON.parse(raw);
|
|
16304
16470
|
configLoadedAt = now2;
|
|
16305
16471
|
return cachedConfig;
|
|
@@ -17216,7 +17382,7 @@ function useSpaceMessages(spaceName) {
|
|
|
17216
17382
|
}
|
|
17217
17383
|
function isNameTaken(name) {
|
|
17218
17384
|
try {
|
|
17219
|
-
const { getDb: getDb2 } = (init_db(),
|
|
17385
|
+
const { getDb: getDb2 } = (init_db(), __toCommonJS2(exports_db));
|
|
17220
17386
|
const db2 = getDb2();
|
|
17221
17387
|
const row = db2.prepare("SELECT agent FROM agent_presence WHERE agent = ?").get(name);
|
|
17222
17388
|
return !!row;
|
|
@@ -17245,7 +17411,7 @@ function getAutoName() {
|
|
|
17245
17411
|
cachedAutoName = name;
|
|
17246
17412
|
try {
|
|
17247
17413
|
mkdirSync33(dirname22(AGENT_ID_FILE), { recursive: true });
|
|
17248
|
-
|
|
17414
|
+
writeFileSync5(AGENT_ID_FILE, name + `
|
|
17249
17415
|
`, "utf-8");
|
|
17250
17416
|
} catch {}
|
|
17251
17417
|
return name;
|
|
@@ -17851,7 +18017,7 @@ function getGraphStats() {
|
|
|
17851
18017
|
map[r.relation] = r.c;
|
|
17852
18018
|
return { total_edges: total, by_relation: map };
|
|
17853
18019
|
}
|
|
17854
|
-
var __create2, __getProtoOf2, __defProp3, __getOwnPropNames2,
|
|
18020
|
+
var __create2, __getProtoOf2, __defProp3, __getOwnPropNames2, __getOwnPropDesc2, __hasOwnProp2, __toESM2 = (mod, isNodeMode, target) => {
|
|
17855
18021
|
target = mod != null ? __create2(__getProtoOf2(mod)) : {};
|
|
17856
18022
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp3(target, "default", { value: mod, enumerable: true }) : target;
|
|
17857
18023
|
for (let key of __getOwnPropNames2(mod))
|
|
@@ -17861,17 +18027,17 @@ var __create2, __getProtoOf2, __defProp3, __getOwnPropNames2, __getOwnPropDesc,
|
|
|
17861
18027
|
enumerable: true
|
|
17862
18028
|
});
|
|
17863
18029
|
return to;
|
|
17864
|
-
},
|
|
17865
|
-
var entry =
|
|
18030
|
+
}, __moduleCache2, __toCommonJS2 = (from) => {
|
|
18031
|
+
var entry = __moduleCache2.get(from), desc;
|
|
17866
18032
|
if (entry)
|
|
17867
18033
|
return entry;
|
|
17868
18034
|
entry = __defProp3({}, "__esModule", { value: true });
|
|
17869
18035
|
if (from && typeof from === "object" || typeof from === "function")
|
|
17870
18036
|
__getOwnPropNames2(from).map((key) => !__hasOwnProp2.call(entry, key) && __defProp3(entry, key, {
|
|
17871
18037
|
get: () => from[key],
|
|
17872
|
-
enumerable: !(desc =
|
|
18038
|
+
enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable
|
|
17873
18039
|
}));
|
|
17874
|
-
|
|
18040
|
+
__moduleCache2.set(from, entry);
|
|
17875
18041
|
return entry;
|
|
17876
18042
|
}, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports), __export3 = (target, all) => {
|
|
17877
18043
|
for (var name in all)
|
|
@@ -17887,9 +18053,9 @@ var init_dist2 = __esm(() => {
|
|
|
17887
18053
|
__getProtoOf2 = Object.getPrototypeOf;
|
|
17888
18054
|
__defProp3 = Object.defineProperty;
|
|
17889
18055
|
__getOwnPropNames2 = Object.getOwnPropertyNames;
|
|
17890
|
-
|
|
18056
|
+
__getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
|
|
17891
18057
|
__hasOwnProp2 = Object.prototype.hasOwnProperty;
|
|
17892
|
-
|
|
18058
|
+
__moduleCache2 = /* @__PURE__ */ new WeakMap;
|
|
17893
18059
|
exports_db = {};
|
|
17894
18060
|
__export3(exports_db, {
|
|
17895
18061
|
getDbPath: () => getDbPath2,
|
|
@@ -20459,18 +20625,18 @@ __export(exports_dist3, {
|
|
|
20459
20625
|
AgentNotFoundError: () => AgentNotFoundError2
|
|
20460
20626
|
});
|
|
20461
20627
|
import { Database as Database4 } from "bun:sqlite";
|
|
20462
|
-
import { existsSync as
|
|
20463
|
-
import { dirname as dirname5, join as
|
|
20628
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync12 } from "fs";
|
|
20629
|
+
import { dirname as dirname5, join as join13, resolve as resolve3 } from "path";
|
|
20464
20630
|
import { existsSync as existsSync33 } from "fs";
|
|
20465
20631
|
import { join as join34 } from "path";
|
|
20466
|
-
import { existsSync as existsSync23, mkdirSync as mkdirSync24, readFileSync as
|
|
20632
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync24, readFileSync as readFileSync6, readdirSync as readdirSync5, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
20467
20633
|
import { join as join24 } from "path";
|
|
20468
20634
|
import { existsSync as existsSync43, readFileSync as readFileSync24, readdirSync as readdirSync22, writeFileSync as writeFileSync23 } from "fs";
|
|
20469
20635
|
import { join as join44 } from "path";
|
|
20470
20636
|
import { existsSync as existsSync52 } from "fs";
|
|
20471
20637
|
import { join as join52 } from "path";
|
|
20472
20638
|
import { readFileSync as readFileSync33, statSync as statSync22 } from "fs";
|
|
20473
|
-
import { relative, resolve as
|
|
20639
|
+
import { relative, resolve as resolve23, join as join62 } from "path";
|
|
20474
20640
|
import { execSync as execSync2 } from "child_process";
|
|
20475
20641
|
|
|
20476
20642
|
class TodosClient {
|
|
@@ -20693,8 +20859,8 @@ function isInMemoryDb2(path) {
|
|
|
20693
20859
|
function findNearestTodosDb(startDir) {
|
|
20694
20860
|
let dir = resolve3(startDir);
|
|
20695
20861
|
while (true) {
|
|
20696
|
-
const candidate =
|
|
20697
|
-
if (
|
|
20862
|
+
const candidate = join13(dir, ".todos", "todos.db");
|
|
20863
|
+
if (existsSync7(candidate))
|
|
20698
20864
|
return candidate;
|
|
20699
20865
|
const parent = dirname5(dir);
|
|
20700
20866
|
if (parent === dir)
|
|
@@ -20706,7 +20872,7 @@ function findNearestTodosDb(startDir) {
|
|
|
20706
20872
|
function findGitRoot2(startDir) {
|
|
20707
20873
|
let dir = resolve3(startDir);
|
|
20708
20874
|
while (true) {
|
|
20709
|
-
if (
|
|
20875
|
+
if (existsSync7(join13(dir, ".git")))
|
|
20710
20876
|
return dir;
|
|
20711
20877
|
const parent = dirname5(dir);
|
|
20712
20878
|
if (parent === dir)
|
|
@@ -20726,18 +20892,18 @@ function getDbPath3() {
|
|
|
20726
20892
|
if (process.env["TODOS_DB_SCOPE"] === "project") {
|
|
20727
20893
|
const gitRoot = findGitRoot2(cwd);
|
|
20728
20894
|
if (gitRoot) {
|
|
20729
|
-
return
|
|
20895
|
+
return join13(gitRoot, ".todos", "todos.db");
|
|
20730
20896
|
}
|
|
20731
20897
|
}
|
|
20732
20898
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
20733
|
-
return
|
|
20899
|
+
return join13(home, ".todos", "todos.db");
|
|
20734
20900
|
}
|
|
20735
20901
|
function ensureDir3(filePath) {
|
|
20736
20902
|
if (isInMemoryDb2(filePath))
|
|
20737
20903
|
return;
|
|
20738
20904
|
const dir = dirname5(resolve3(filePath));
|
|
20739
|
-
if (!
|
|
20740
|
-
|
|
20905
|
+
if (!existsSync7(dir)) {
|
|
20906
|
+
mkdirSync12(dir, { recursive: true });
|
|
20741
20907
|
}
|
|
20742
20908
|
}
|
|
20743
20909
|
function getDatabase3(dbPath) {
|
|
@@ -21203,28 +21369,28 @@ function ensureDir23(dir) {
|
|
|
21203
21369
|
function listJsonFiles(dir) {
|
|
21204
21370
|
if (!existsSync23(dir))
|
|
21205
21371
|
return [];
|
|
21206
|
-
return
|
|
21372
|
+
return readdirSync5(dir).filter((f) => f.endsWith(".json"));
|
|
21207
21373
|
}
|
|
21208
21374
|
function readJsonFile(path) {
|
|
21209
21375
|
try {
|
|
21210
|
-
return JSON.parse(
|
|
21376
|
+
return JSON.parse(readFileSync6(path, "utf-8"));
|
|
21211
21377
|
} catch {
|
|
21212
21378
|
return null;
|
|
21213
21379
|
}
|
|
21214
21380
|
}
|
|
21215
21381
|
function writeJsonFile(path, data) {
|
|
21216
|
-
|
|
21382
|
+
writeFileSync6(path, JSON.stringify(data, null, 2) + `
|
|
21217
21383
|
`);
|
|
21218
21384
|
}
|
|
21219
21385
|
function readHighWaterMark(dir) {
|
|
21220
21386
|
const path = join24(dir, ".highwatermark");
|
|
21221
21387
|
if (!existsSync23(path))
|
|
21222
21388
|
return 1;
|
|
21223
|
-
const val = parseInt(
|
|
21389
|
+
const val = parseInt(readFileSync6(path, "utf-8").trim(), 10);
|
|
21224
21390
|
return isNaN(val) ? 1 : val;
|
|
21225
21391
|
}
|
|
21226
21392
|
function writeHighWaterMark(dir, value) {
|
|
21227
|
-
|
|
21393
|
+
writeFileSync6(join24(dir, ".highwatermark"), String(value));
|
|
21228
21394
|
}
|
|
21229
21395
|
function getFileMtimeMs(path) {
|
|
21230
21396
|
try {
|
|
@@ -24586,7 +24752,7 @@ function collectFiles(basePath, extensions) {
|
|
|
24586
24752
|
return files.sort();
|
|
24587
24753
|
}
|
|
24588
24754
|
function extractTodos(options, db2) {
|
|
24589
|
-
const basePath =
|
|
24755
|
+
const basePath = resolve23(options.path);
|
|
24590
24756
|
const tags = options.patterns || [...EXTRACT_TAGS];
|
|
24591
24757
|
const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
|
|
24592
24758
|
const files = collectFiles(basePath, extensions);
|
|
@@ -24595,7 +24761,7 @@ function extractTodos(options, db2) {
|
|
|
24595
24761
|
const fullPath = statSync22(basePath).isFile() ? basePath : join62(basePath, file);
|
|
24596
24762
|
try {
|
|
24597
24763
|
const source = readFileSync33(fullPath, "utf-8");
|
|
24598
|
-
const relPath = statSync22(basePath).isFile() ? relative(
|
|
24764
|
+
const relPath = statSync22(basePath).isFile() ? relative(resolve23(basePath, ".."), fullPath) : file;
|
|
24599
24765
|
const comments = extractFromSource(source, relPath, tags);
|
|
24600
24766
|
allComments.push(...comments);
|
|
24601
24767
|
} catch {}
|
|
@@ -25814,8 +25980,8 @@ __export(exports_dist4, {
|
|
|
25814
25980
|
CATEGORIES: () => CATEGORIES,
|
|
25815
25981
|
AGENT_TARGETS: () => AGENT_TARGETS
|
|
25816
25982
|
});
|
|
25817
|
-
import { existsSync as
|
|
25818
|
-
import { join as
|
|
25983
|
+
import { existsSync as existsSync8, cpSync, mkdirSync as mkdirSync13, writeFileSync as writeFileSync7, rmSync as rmSync2, readdirSync as readdirSync6, statSync as statSync4, readFileSync as readFileSync7, accessSync, constants } from "fs";
|
|
25984
|
+
import { join as join14, dirname as dirname6 } from "path";
|
|
25819
25985
|
import { homedir as homedir13 } from "os";
|
|
25820
25986
|
import { fileURLToPath } from "url";
|
|
25821
25987
|
import { existsSync as existsSync24, readFileSync as readFileSync25, readdirSync as readdirSync23 } from "fs";
|
|
@@ -25927,35 +26093,35 @@ function normalizeSkillName(name) {
|
|
|
25927
26093
|
function findSkillsDir() {
|
|
25928
26094
|
let dir = __dirname2;
|
|
25929
26095
|
for (let i = 0;i < 5; i++) {
|
|
25930
|
-
const candidate =
|
|
25931
|
-
if (
|
|
26096
|
+
const candidate = join14(dir, "skills");
|
|
26097
|
+
if (existsSync8(candidate)) {
|
|
25932
26098
|
return candidate;
|
|
25933
26099
|
}
|
|
25934
26100
|
dir = dirname6(dir);
|
|
25935
26101
|
}
|
|
25936
|
-
return
|
|
26102
|
+
return join14(__dirname2, "..", "skills");
|
|
25937
26103
|
}
|
|
25938
26104
|
function getSkillPath(name) {
|
|
25939
26105
|
const skillName = normalizeSkillName(name);
|
|
25940
|
-
return
|
|
26106
|
+
return join14(SKILLS_DIR, skillName);
|
|
25941
26107
|
}
|
|
25942
26108
|
function skillExists(name) {
|
|
25943
|
-
return
|
|
26109
|
+
return existsSync8(getSkillPath(name));
|
|
25944
26110
|
}
|
|
25945
26111
|
function installSkill(name, options = {}) {
|
|
25946
26112
|
const { targetDir = process.cwd(), overwrite = false } = options;
|
|
25947
26113
|
const skillName = normalizeSkillName(name);
|
|
25948
26114
|
const sourcePath = getSkillPath(name);
|
|
25949
|
-
const destDir =
|
|
25950
|
-
const destPath =
|
|
25951
|
-
if (!
|
|
26115
|
+
const destDir = join14(targetDir, ".skills");
|
|
26116
|
+
const destPath = join14(destDir, skillName);
|
|
26117
|
+
if (!existsSync8(sourcePath)) {
|
|
25952
26118
|
return {
|
|
25953
26119
|
skill: name,
|
|
25954
26120
|
success: false,
|
|
25955
26121
|
error: `Skill '${name}' not found`
|
|
25956
26122
|
};
|
|
25957
26123
|
}
|
|
25958
|
-
if (
|
|
26124
|
+
if (existsSync8(destPath) && !overwrite) {
|
|
25959
26125
|
return {
|
|
25960
26126
|
skill: name,
|
|
25961
26127
|
success: false,
|
|
@@ -25964,10 +26130,10 @@ function installSkill(name, options = {}) {
|
|
|
25964
26130
|
};
|
|
25965
26131
|
}
|
|
25966
26132
|
try {
|
|
25967
|
-
if (!
|
|
25968
|
-
|
|
26133
|
+
if (!existsSync8(destDir)) {
|
|
26134
|
+
mkdirSync13(destDir, { recursive: true });
|
|
25969
26135
|
}
|
|
25970
|
-
if (
|
|
26136
|
+
if (existsSync8(destPath) && overwrite) {
|
|
25971
26137
|
rmSync2(destPath, { recursive: true, force: true });
|
|
25972
26138
|
}
|
|
25973
26139
|
cpSync(sourcePath, destPath, {
|
|
@@ -26006,10 +26172,10 @@ function installSkills(names, options = {}) {
|
|
|
26006
26172
|
return names.map((name) => installSkill(name, options));
|
|
26007
26173
|
}
|
|
26008
26174
|
function updateSkillsIndex(skillsDir) {
|
|
26009
|
-
const indexPath =
|
|
26175
|
+
const indexPath = join14(skillsDir, "index.ts");
|
|
26010
26176
|
const meta = loadMeta(skillsDir);
|
|
26011
26177
|
const disabledSet = new Set(meta.disabled || []);
|
|
26012
|
-
const skills =
|
|
26178
|
+
const skills = readdirSync6(skillsDir).filter((f) => f.startsWith("skill-") && !f.includes(".") && !disabledSet.has(f.replace("skill-", "")));
|
|
26013
26179
|
const exports = skills.map((s) => {
|
|
26014
26180
|
const name = s.replace("skill-", "").replace(/-/g, "_");
|
|
26015
26181
|
return `export * as ${name} from './${s}/src/index.js';`;
|
|
@@ -26022,31 +26188,31 @@ function updateSkillsIndex(skillsDir) {
|
|
|
26022
26188
|
|
|
26023
26189
|
${exports}
|
|
26024
26190
|
`;
|
|
26025
|
-
|
|
26191
|
+
writeFileSync7(indexPath, content);
|
|
26026
26192
|
}
|
|
26027
26193
|
function getMetaPath(skillsDir) {
|
|
26028
|
-
return
|
|
26194
|
+
return join14(skillsDir, ".meta.json");
|
|
26029
26195
|
}
|
|
26030
26196
|
function loadMeta(skillsDir) {
|
|
26031
26197
|
const metaPath2 = getMetaPath(skillsDir);
|
|
26032
|
-
if (
|
|
26198
|
+
if (existsSync8(metaPath2)) {
|
|
26033
26199
|
try {
|
|
26034
|
-
return JSON.parse(
|
|
26200
|
+
return JSON.parse(readFileSync7(metaPath2, "utf-8"));
|
|
26035
26201
|
} catch {}
|
|
26036
26202
|
}
|
|
26037
26203
|
return { skills: {} };
|
|
26038
26204
|
}
|
|
26039
26205
|
function saveMeta(skillsDir, meta) {
|
|
26040
|
-
|
|
26206
|
+
writeFileSync7(getMetaPath(skillsDir), JSON.stringify(meta, null, 2));
|
|
26041
26207
|
}
|
|
26042
26208
|
function recordInstall(skillsDir, name) {
|
|
26043
26209
|
const meta = loadMeta(skillsDir);
|
|
26044
26210
|
const skillName = normalizeSkillName(name);
|
|
26045
26211
|
let version = "unknown";
|
|
26046
26212
|
try {
|
|
26047
|
-
const pkgPath =
|
|
26048
|
-
if (
|
|
26049
|
-
const pkg = JSON.parse(
|
|
26213
|
+
const pkgPath = join14(skillsDir, skillName, "package.json");
|
|
26214
|
+
if (existsSync8(pkgPath)) {
|
|
26215
|
+
const pkg = JSON.parse(readFileSync7(pkgPath, "utf-8"));
|
|
26050
26216
|
version = pkg.version || "unknown";
|
|
26051
26217
|
}
|
|
26052
26218
|
} catch {}
|
|
@@ -26059,12 +26225,12 @@ function recordRemove(skillsDir, name) {
|
|
|
26059
26225
|
saveMeta(skillsDir, meta);
|
|
26060
26226
|
}
|
|
26061
26227
|
function getInstallMeta(targetDir = process.cwd()) {
|
|
26062
|
-
return loadMeta(
|
|
26228
|
+
return loadMeta(join14(targetDir, ".skills"));
|
|
26063
26229
|
}
|
|
26064
26230
|
function disableSkill(name, targetDir = process.cwd()) {
|
|
26065
|
-
const skillsDir =
|
|
26231
|
+
const skillsDir = join14(targetDir, ".skills");
|
|
26066
26232
|
const skillName = normalizeSkillName(name);
|
|
26067
|
-
if (!
|
|
26233
|
+
if (!existsSync8(join14(skillsDir, skillName)))
|
|
26068
26234
|
return false;
|
|
26069
26235
|
const meta = loadMeta(skillsDir);
|
|
26070
26236
|
const disabled = new Set(meta.disabled || []);
|
|
@@ -26077,7 +26243,7 @@ function disableSkill(name, targetDir = process.cwd()) {
|
|
|
26077
26243
|
return true;
|
|
26078
26244
|
}
|
|
26079
26245
|
function enableSkill(name, targetDir = process.cwd()) {
|
|
26080
|
-
const skillsDir =
|
|
26246
|
+
const skillsDir = join14(targetDir, ".skills");
|
|
26081
26247
|
const meta = loadMeta(skillsDir);
|
|
26082
26248
|
const disabled = new Set(meta.disabled || []);
|
|
26083
26249
|
if (!disabled.has(name))
|
|
@@ -26089,24 +26255,24 @@ function enableSkill(name, targetDir = process.cwd()) {
|
|
|
26089
26255
|
return true;
|
|
26090
26256
|
}
|
|
26091
26257
|
function getDisabledSkills(targetDir = process.cwd()) {
|
|
26092
|
-
const meta = loadMeta(
|
|
26258
|
+
const meta = loadMeta(join14(targetDir, ".skills"));
|
|
26093
26259
|
return meta.disabled || [];
|
|
26094
26260
|
}
|
|
26095
26261
|
function getInstalledSkills(targetDir = process.cwd()) {
|
|
26096
|
-
const skillsDir =
|
|
26097
|
-
if (!
|
|
26262
|
+
const skillsDir = join14(targetDir, ".skills");
|
|
26263
|
+
if (!existsSync8(skillsDir)) {
|
|
26098
26264
|
return [];
|
|
26099
26265
|
}
|
|
26100
|
-
return
|
|
26101
|
-
const fullPath =
|
|
26266
|
+
return readdirSync6(skillsDir).filter((f) => {
|
|
26267
|
+
const fullPath = join14(skillsDir, f);
|
|
26102
26268
|
return f.startsWith("skill-") && statSync4(fullPath).isDirectory();
|
|
26103
26269
|
}).map((f) => f.replace("skill-", ""));
|
|
26104
26270
|
}
|
|
26105
26271
|
function removeSkill(name, targetDir = process.cwd()) {
|
|
26106
26272
|
const skillName = normalizeSkillName(name);
|
|
26107
|
-
const skillsDir =
|
|
26108
|
-
const skillPath =
|
|
26109
|
-
if (!
|
|
26273
|
+
const skillsDir = join14(targetDir, ".skills");
|
|
26274
|
+
const skillPath = join14(skillsDir, skillName);
|
|
26275
|
+
if (!existsSync8(skillPath)) {
|
|
26110
26276
|
return false;
|
|
26111
26277
|
}
|
|
26112
26278
|
rmSync2(skillPath, { recursive: true, force: true });
|
|
@@ -26117,25 +26283,25 @@ function removeSkill(name, targetDir = process.cwd()) {
|
|
|
26117
26283
|
function getAgentSkillsDir(agent, scope = "global", projectDir) {
|
|
26118
26284
|
const agentDir = `.${agent}`;
|
|
26119
26285
|
if (scope === "project") {
|
|
26120
|
-
return
|
|
26286
|
+
return join14(projectDir || process.cwd(), agentDir, "skills");
|
|
26121
26287
|
}
|
|
26122
|
-
return
|
|
26288
|
+
return join14(homedir13(), agentDir, "skills");
|
|
26123
26289
|
}
|
|
26124
26290
|
function getAgentSkillPath(name, agent, scope = "global", projectDir) {
|
|
26125
26291
|
const skillName = normalizeSkillName(name);
|
|
26126
|
-
return
|
|
26292
|
+
return join14(getAgentSkillsDir(agent, scope, projectDir), skillName);
|
|
26127
26293
|
}
|
|
26128
26294
|
function installSkillForAgent(name, options, generateSkillMd) {
|
|
26129
26295
|
const { agent, scope = "global", projectDir } = options;
|
|
26130
26296
|
const skillName = normalizeSkillName(name);
|
|
26131
26297
|
const sourcePath = getSkillPath(name);
|
|
26132
|
-
if (!
|
|
26298
|
+
if (!existsSync8(sourcePath)) {
|
|
26133
26299
|
return { skill: name, success: false, error: `Skill '${name}' not found` };
|
|
26134
26300
|
}
|
|
26135
26301
|
let skillMdContent = null;
|
|
26136
|
-
const skillMdPath =
|
|
26137
|
-
if (
|
|
26138
|
-
skillMdContent =
|
|
26302
|
+
const skillMdPath = join14(sourcePath, "SKILL.md");
|
|
26303
|
+
if (existsSync8(skillMdPath)) {
|
|
26304
|
+
skillMdContent = readFileSync7(skillMdPath, "utf-8");
|
|
26139
26305
|
} else if (generateSkillMd) {
|
|
26140
26306
|
skillMdContent = generateSkillMd(name);
|
|
26141
26307
|
}
|
|
@@ -26144,8 +26310,8 @@ function installSkillForAgent(name, options, generateSkillMd) {
|
|
|
26144
26310
|
}
|
|
26145
26311
|
const destDir = getAgentSkillPath(name, agent, scope, projectDir);
|
|
26146
26312
|
if (scope === "global") {
|
|
26147
|
-
const agentBaseDir2 =
|
|
26148
|
-
if (!
|
|
26313
|
+
const agentBaseDir2 = join14(homedir13(), `.${agent}`);
|
|
26314
|
+
if (!existsSync8(agentBaseDir2)) {
|
|
26149
26315
|
const agentLabels = {
|
|
26150
26316
|
claude: "Claude Code",
|
|
26151
26317
|
codex: "Codex CLI",
|
|
@@ -26168,8 +26334,8 @@ function installSkillForAgent(name, options, generateSkillMd) {
|
|
|
26168
26334
|
}
|
|
26169
26335
|
}
|
|
26170
26336
|
try {
|
|
26171
|
-
|
|
26172
|
-
|
|
26337
|
+
mkdirSync13(destDir, { recursive: true });
|
|
26338
|
+
writeFileSync7(join14(destDir, "SKILL.md"), skillMdContent);
|
|
26173
26339
|
return { skill: name, success: true, path: destDir };
|
|
26174
26340
|
} catch (error) {
|
|
26175
26341
|
return {
|
|
@@ -26182,7 +26348,7 @@ function installSkillForAgent(name, options, generateSkillMd) {
|
|
|
26182
26348
|
function removeSkillForAgent(name, options) {
|
|
26183
26349
|
const { agent, scope = "global", projectDir } = options;
|
|
26184
26350
|
const destDir = getAgentSkillPath(name, agent, scope, projectDir);
|
|
26185
|
-
if (!
|
|
26351
|
+
if (!existsSync8(destDir)) {
|
|
26186
26352
|
return false;
|
|
26187
26353
|
}
|
|
26188
26354
|
rmSync2(destDir, { recursive: true, force: true });
|
|
@@ -32503,8 +32669,8 @@ var NEVER = INVALID;
|
|
|
32503
32669
|
// src/mcp/index.ts
|
|
32504
32670
|
init_session();
|
|
32505
32671
|
init_actions();
|
|
32506
|
-
import { readFileSync as
|
|
32507
|
-
import { join as
|
|
32672
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
32673
|
+
import { join as join15 } from "path";
|
|
32508
32674
|
|
|
32509
32675
|
// src/lib/screenshot.ts
|
|
32510
32676
|
init_types();
|
|
@@ -33274,7 +33440,7 @@ async function closeTab(page, index) {
|
|
|
33274
33440
|
init_dialogs();
|
|
33275
33441
|
init_profiles();
|
|
33276
33442
|
init_types();
|
|
33277
|
-
var _pkg = JSON.parse(
|
|
33443
|
+
var _pkg = JSON.parse(readFileSync8(join15(import.meta.dir, "../../package.json"), "utf8"));
|
|
33278
33444
|
var networkLogCleanup = new Map;
|
|
33279
33445
|
var consoleCaptureCleanup = new Map;
|
|
33280
33446
|
var harCaptures = new Map;
|
|
@@ -34979,14 +35145,17 @@ server.tool("browser_profile_delete", "Delete a saved browser profile", { name:
|
|
|
34979
35145
|
return err(e);
|
|
34980
35146
|
}
|
|
34981
35147
|
});
|
|
34982
|
-
server.tool("browser_script_run", "Run a saved
|
|
34983
|
-
name: exports_external.string().describe("Script name
|
|
35148
|
+
server.tool("browser_script_run", "Run a saved script asynchronously. Returns run_id immediately \u2014 poll with browser_script_status for step-by-step progress. Scripts combine browser actions + connector calls + AI reasoning. Works with any engine (Bun.WebView, Playwright, CDP).", {
|
|
35149
|
+
name: exports_external.string().describe("Script name"),
|
|
34984
35150
|
session_id: exports_external.string().optional(),
|
|
34985
|
-
|
|
34986
|
-
|
|
35151
|
+
engine: exports_external.enum(["playwright", "cdp", "lightpanda", "bun", "auto"]).optional().default("auto"),
|
|
35152
|
+
variables: exports_external.record(exports_external.string()).optional().describe("Override script variables")
|
|
35153
|
+
}, async ({ name, session_id, engine, variables }) => {
|
|
34987
35154
|
try {
|
|
34988
|
-
const {
|
|
34989
|
-
const
|
|
35155
|
+
const { getScriptByName: getScriptByName2, migrateJsonScripts: migrateJsonScripts2, getSteps: getSteps2 } = await Promise.resolve().then(() => (init_scripts(), exports_scripts));
|
|
35156
|
+
const { executeScript: executeScript2 } = await Promise.resolve().then(() => (init_script_engine(), exports_script_engine));
|
|
35157
|
+
migrateJsonScripts2();
|
|
35158
|
+
const script = getScriptByName2(name);
|
|
34990
35159
|
if (!script)
|
|
34991
35160
|
return err(new Error(`Script '${name}' not found. Use browser_script_list to see available scripts.`));
|
|
34992
35161
|
let sid;
|
|
@@ -34995,55 +35164,72 @@ server.tool("browser_script_run", "Run a saved login script asynchronously. Retu
|
|
|
34995
35164
|
sid = resolveSessionId(session_id);
|
|
34996
35165
|
page = getSessionPage(sid);
|
|
34997
35166
|
} else {
|
|
34998
|
-
const result = await createSession2({ headless: true });
|
|
35167
|
+
const result = await createSession2({ engine: engine ?? "auto", headless: true });
|
|
34999
35168
|
sid = result.session.id;
|
|
35000
35169
|
page = result.page;
|
|
35001
35170
|
}
|
|
35002
|
-
const
|
|
35003
|
-
|
|
35171
|
+
const steps = getSteps2(script.id);
|
|
35172
|
+
const runId = executeScript2(script.id, page, variables ?? {});
|
|
35173
|
+
return json({ run_id: runId, session_id: sid, script: name, total_steps: steps.length, message: "Script running. Poll with browser_script_status." });
|
|
35004
35174
|
} catch (e) {
|
|
35005
35175
|
return err(e);
|
|
35006
35176
|
}
|
|
35007
35177
|
});
|
|
35008
|
-
server.tool("browser_script_status", "Check
|
|
35178
|
+
server.tool("browser_script_status", "Check progress of a running script. Shows current step, step-by-step log with durations, and final result when complete.", { run_id: exports_external.string() }, async ({ run_id }) => {
|
|
35009
35179
|
try {
|
|
35010
|
-
const {
|
|
35011
|
-
const
|
|
35012
|
-
if (!
|
|
35013
|
-
return err(new Error(`
|
|
35180
|
+
const { getRun: getRun3 } = await Promise.resolve().then(() => (init_scripts(), exports_scripts));
|
|
35181
|
+
const run = getRun3(run_id);
|
|
35182
|
+
if (!run)
|
|
35183
|
+
return err(new Error(`Run '${run_id}' not found`));
|
|
35014
35184
|
return json({
|
|
35015
|
-
status:
|
|
35016
|
-
progress: `${
|
|
35017
|
-
current_step:
|
|
35018
|
-
steps_log:
|
|
35019
|
-
|
|
35185
|
+
status: run.status,
|
|
35186
|
+
progress: `${run.current_step}/${run.total_steps}`,
|
|
35187
|
+
current_step: run.current_description,
|
|
35188
|
+
steps_log: run.steps_log,
|
|
35189
|
+
errors: run.errors.length > 0 ? run.errors : undefined,
|
|
35190
|
+
duration_ms: run.duration_ms,
|
|
35191
|
+
completed: run.completed_at
|
|
35020
35192
|
});
|
|
35021
35193
|
} catch (e) {
|
|
35022
35194
|
return err(e);
|
|
35023
35195
|
}
|
|
35024
35196
|
});
|
|
35025
|
-
server.tool("browser_script_list", "List all saved
|
|
35197
|
+
server.tool("browser_script_list", "List all saved scripts", {}, async () => {
|
|
35026
35198
|
try {
|
|
35027
|
-
const { listScripts: listScripts2 } = await Promise.resolve().then(() => (
|
|
35028
|
-
|
|
35199
|
+
const { listScripts: listScripts2, migrateJsonScripts: migrateJsonScripts2 } = await Promise.resolve().then(() => (init_scripts(), exports_scripts));
|
|
35200
|
+
migrateJsonScripts2();
|
|
35201
|
+
const scripts = listScripts2();
|
|
35202
|
+
return json({ scripts: scripts.map((s) => ({ name: s.name, domain: s.domain, description: s.description, run_count: s.run_count, last_run: s.last_run })), count: scripts.length });
|
|
35029
35203
|
} catch (e) {
|
|
35030
35204
|
return err(e);
|
|
35031
35205
|
}
|
|
35032
35206
|
});
|
|
35033
|
-
server.tool("browser_script_save", "Save a
|
|
35207
|
+
server.tool("browser_script_save", "Save a script. Steps are stored in SQLite. Each step has a type (browser/connector/extract/wait/condition/save_state), config, and optional AI config for intelligent fallbacks.", {
|
|
35208
|
+
name: exports_external.string(),
|
|
35209
|
+
domain: exports_external.string().optional().default(""),
|
|
35210
|
+
description: exports_external.string().optional().default(""),
|
|
35211
|
+
variables: exports_external.record(exports_external.string()).optional().default({}),
|
|
35212
|
+
steps: exports_external.array(exports_external.object({
|
|
35213
|
+
type: exports_external.enum(["browser", "connector", "extract", "wait", "condition", "save_state"]),
|
|
35214
|
+
config: exports_external.record(exports_external.unknown()).default({}),
|
|
35215
|
+
description: exports_external.string().optional().default(""),
|
|
35216
|
+
ai_enabled: exports_external.boolean().optional().default(false),
|
|
35217
|
+
ai_config: exports_external.record(exports_external.unknown()).optional().default({})
|
|
35218
|
+
}))
|
|
35219
|
+
}, async ({ name, domain, description, variables, steps }) => {
|
|
35034
35220
|
try {
|
|
35035
|
-
const {
|
|
35036
|
-
const script =
|
|
35037
|
-
const
|
|
35038
|
-
return json({
|
|
35221
|
+
const { upsertScript: upsertScript2, getSteps: getSteps2 } = await Promise.resolve().then(() => (init_scripts(), exports_scripts));
|
|
35222
|
+
const script = upsertScript2({ name, domain, description, variables, steps });
|
|
35223
|
+
const savedSteps = getSteps2(script.id);
|
|
35224
|
+
return json({ id: script.id, name: script.name, steps: savedSteps.length });
|
|
35039
35225
|
} catch (e) {
|
|
35040
35226
|
return err(e);
|
|
35041
35227
|
}
|
|
35042
35228
|
});
|
|
35043
|
-
server.tool("browser_script_delete", "Delete a saved
|
|
35229
|
+
server.tool("browser_script_delete", "Delete a saved script", { name: exports_external.string() }, async ({ name }) => {
|
|
35044
35230
|
try {
|
|
35045
|
-
const {
|
|
35046
|
-
return json({ deleted:
|
|
35231
|
+
const { deleteScriptByName: deleteScriptByName2 } = await Promise.resolve().then(() => (init_scripts(), exports_scripts));
|
|
35232
|
+
return json({ deleted: deleteScriptByName2(name) });
|
|
35047
35233
|
} catch (e) {
|
|
35048
35234
|
return err(e);
|
|
35049
35235
|
}
|