@todoforai/edge 0.13.12 → 0.13.14
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/index.js +217 -132
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -47695,7 +47695,7 @@ var require_ignore = __commonJS((exports, module) => {
|
|
|
47695
47695
|
makeArray(isString(pattern) ? splitPattern(pattern) : pattern).forEach(this._add, this);
|
|
47696
47696
|
return this._added;
|
|
47697
47697
|
}
|
|
47698
|
-
test(
|
|
47698
|
+
test(path8, checkUnignored, mode) {
|
|
47699
47699
|
let ignored = false;
|
|
47700
47700
|
let unignored = false;
|
|
47701
47701
|
let matchedRule;
|
|
@@ -47704,7 +47704,7 @@ var require_ignore = __commonJS((exports, module) => {
|
|
|
47704
47704
|
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
47705
47705
|
return;
|
|
47706
47706
|
}
|
|
47707
|
-
const matched = rule[mode].test(
|
|
47707
|
+
const matched = rule[mode].test(path8);
|
|
47708
47708
|
if (!matched) {
|
|
47709
47709
|
return;
|
|
47710
47710
|
}
|
|
@@ -47725,20 +47725,20 @@ var require_ignore = __commonJS((exports, module) => {
|
|
|
47725
47725
|
var throwError = (message, Ctor) => {
|
|
47726
47726
|
throw new Ctor(message);
|
|
47727
47727
|
};
|
|
47728
|
-
var checkPath = (
|
|
47729
|
-
if (!isString(
|
|
47728
|
+
var checkPath = (path8, originalPath, doThrow) => {
|
|
47729
|
+
if (!isString(path8)) {
|
|
47730
47730
|
return doThrow(`path must be a string, but got \`${originalPath}\``, TypeError);
|
|
47731
47731
|
}
|
|
47732
|
-
if (!
|
|
47732
|
+
if (!path8) {
|
|
47733
47733
|
return doThrow(`path must not be empty`, TypeError);
|
|
47734
47734
|
}
|
|
47735
|
-
if (checkPath.isNotRelative(
|
|
47735
|
+
if (checkPath.isNotRelative(path8)) {
|
|
47736
47736
|
const r = "`path.relative()`d";
|
|
47737
47737
|
return doThrow(`path should be a ${r} string, but got "${originalPath}"`, RangeError);
|
|
47738
47738
|
}
|
|
47739
47739
|
return true;
|
|
47740
47740
|
};
|
|
47741
|
-
var isNotRelative = (
|
|
47741
|
+
var isNotRelative = (path8) => REGEX_TEST_INVALID_PATH.test(path8);
|
|
47742
47742
|
checkPath.isNotRelative = isNotRelative;
|
|
47743
47743
|
checkPath.convert = (p10) => p10;
|
|
47744
47744
|
|
|
@@ -47767,15 +47767,15 @@ var require_ignore = __commonJS((exports, module) => {
|
|
|
47767
47767
|
return this.add(pattern);
|
|
47768
47768
|
}
|
|
47769
47769
|
_test(originalPath, cache, checkUnignored, slices) {
|
|
47770
|
-
const
|
|
47771
|
-
checkPath(
|
|
47772
|
-
return this._t(
|
|
47770
|
+
const path8 = originalPath && checkPath.convert(originalPath);
|
|
47771
|
+
checkPath(path8, originalPath, this._strictPathCheck ? throwError : RETURN_FALSE);
|
|
47772
|
+
return this._t(path8, cache, checkUnignored, slices);
|
|
47773
47773
|
}
|
|
47774
|
-
checkIgnore(
|
|
47775
|
-
if (!REGEX_TEST_TRAILING_SLASH.test(
|
|
47776
|
-
return this.test(
|
|
47774
|
+
checkIgnore(path8) {
|
|
47775
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path8)) {
|
|
47776
|
+
return this.test(path8);
|
|
47777
47777
|
}
|
|
47778
|
-
const slices =
|
|
47778
|
+
const slices = path8.split(SLASH).filter(Boolean);
|
|
47779
47779
|
slices.pop();
|
|
47780
47780
|
if (slices.length) {
|
|
47781
47781
|
const parent = this._t(slices.join(SLASH) + SLASH, this._testCache, true, slices);
|
|
@@ -47783,42 +47783,42 @@ var require_ignore = __commonJS((exports, module) => {
|
|
|
47783
47783
|
return parent;
|
|
47784
47784
|
}
|
|
47785
47785
|
}
|
|
47786
|
-
return this._rules.test(
|
|
47786
|
+
return this._rules.test(path8, false, MODE_CHECK_IGNORE);
|
|
47787
47787
|
}
|
|
47788
|
-
_t(
|
|
47789
|
-
if (
|
|
47790
|
-
return cache[
|
|
47788
|
+
_t(path8, cache, checkUnignored, slices) {
|
|
47789
|
+
if (path8 in cache) {
|
|
47790
|
+
return cache[path8];
|
|
47791
47791
|
}
|
|
47792
47792
|
if (!slices) {
|
|
47793
|
-
slices =
|
|
47793
|
+
slices = path8.split(SLASH).filter(Boolean);
|
|
47794
47794
|
}
|
|
47795
47795
|
slices.pop();
|
|
47796
47796
|
if (!slices.length) {
|
|
47797
|
-
return cache[
|
|
47797
|
+
return cache[path8] = this._rules.test(path8, checkUnignored, MODE_IGNORE);
|
|
47798
47798
|
}
|
|
47799
47799
|
const parent = this._t(slices.join(SLASH) + SLASH, cache, checkUnignored, slices);
|
|
47800
|
-
return cache[
|
|
47800
|
+
return cache[path8] = parent.ignored ? parent : this._rules.test(path8, checkUnignored, MODE_IGNORE);
|
|
47801
47801
|
}
|
|
47802
|
-
ignores(
|
|
47803
|
-
return this._test(
|
|
47802
|
+
ignores(path8) {
|
|
47803
|
+
return this._test(path8, this._ignoreCache, false).ignored;
|
|
47804
47804
|
}
|
|
47805
47805
|
createFilter() {
|
|
47806
|
-
return (
|
|
47806
|
+
return (path8) => !this.ignores(path8);
|
|
47807
47807
|
}
|
|
47808
47808
|
filter(paths) {
|
|
47809
47809
|
return makeArray(paths).filter(this.createFilter());
|
|
47810
47810
|
}
|
|
47811
|
-
test(
|
|
47812
|
-
return this._test(
|
|
47811
|
+
test(path8) {
|
|
47812
|
+
return this._test(path8, this._testCache, true);
|
|
47813
47813
|
}
|
|
47814
47814
|
}
|
|
47815
47815
|
var factory = (options) => new Ignore(options);
|
|
47816
|
-
var isPathValid = (
|
|
47816
|
+
var isPathValid = (path8) => checkPath(path8 && checkPath.convert(path8), path8, RETURN_FALSE);
|
|
47817
47817
|
var setupWindows = () => {
|
|
47818
47818
|
const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
|
|
47819
47819
|
checkPath.convert = makePosix;
|
|
47820
47820
|
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
47821
|
-
checkPath.isNotRelative = (
|
|
47821
|
+
checkPath.isNotRelative = (path8) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path8) || isNotRelative(path8);
|
|
47822
47822
|
};
|
|
47823
47823
|
if (typeof process !== "undefined" && process.platform === "win32") {
|
|
47824
47824
|
setupWindows();
|
|
@@ -48477,12 +48477,14 @@ var BRIDGE_PORT = parseInt(process.env.TODOFORAI_BROWSER_BRIDGE_PORT || "43127",
|
|
|
48477
48477
|
var BRIDGE_EDGE_ID = "local-browser-bridge";
|
|
48478
48478
|
var REQUEST_TIMEOUT_MS = 30000;
|
|
48479
48479
|
var isOpen = (ws) => !!ws && ws.readyState === import_websocket.default.OPEN;
|
|
48480
|
+
var describeExt = (ext) => ext ? `${ext.build ?? "?"}@${ext.version ?? "?"} (${ext.browser ?? "?"})` : "unknown extension";
|
|
48480
48481
|
|
|
48481
48482
|
class BrowserExtensionBridge {
|
|
48482
48483
|
debug;
|
|
48483
48484
|
server;
|
|
48484
48485
|
wss;
|
|
48485
48486
|
extensionWs = null;
|
|
48487
|
+
extIdentity = null;
|
|
48486
48488
|
pending = new Map;
|
|
48487
48489
|
constructor(debug = false) {
|
|
48488
48490
|
this.debug = debug;
|
|
@@ -48563,8 +48565,18 @@ class BrowserExtensionBridge {
|
|
|
48563
48565
|
console.log("[browser-bridge:recv]", data.type);
|
|
48564
48566
|
if (data.type === "hello") {
|
|
48565
48567
|
const isTabChannel = data.role === "extension-tab" || data.role === "extension";
|
|
48566
|
-
if (data.role === "extension-control")
|
|
48568
|
+
if (data.role === "extension-control") {
|
|
48569
|
+
const ident = describeExt(data.ext);
|
|
48570
|
+
const prev = this.extensionWs;
|
|
48571
|
+
if (isOpen(prev) && prev !== ws) {
|
|
48572
|
+
console.log(`[browser-bridge] control taken over by ${ident} (was ${describeExt(this.extIdentity)})`);
|
|
48573
|
+
prev.send(JSON.stringify({ type: "control_superseded", payload: { by: ident } }));
|
|
48574
|
+
} else if (this.debug) {
|
|
48575
|
+
console.log(`[browser-bridge] control acquired by ${ident}`);
|
|
48576
|
+
}
|
|
48567
48577
|
this.extensionWs = ws;
|
|
48578
|
+
this.extIdentity = data.ext ?? null;
|
|
48579
|
+
}
|
|
48568
48580
|
if (data.role === "extension-control" || isTabChannel) {
|
|
48569
48581
|
if (isOpen(ws))
|
|
48570
48582
|
ws.send(JSON.stringify({ type: "connected_edge", payload: { edgeId: BRIDGE_EDGE_ID } }));
|
|
@@ -48617,8 +48629,12 @@ class BrowserExtensionBridge {
|
|
|
48617
48629
|
}
|
|
48618
48630
|
}
|
|
48619
48631
|
handleClose(ws) {
|
|
48620
|
-
if (this.extensionWs === ws)
|
|
48632
|
+
if (this.extensionWs === ws) {
|
|
48633
|
+
if (this.debug)
|
|
48634
|
+
console.log(`[browser-bridge] control released by ${describeExt(this.extIdentity)}`);
|
|
48621
48635
|
this.extensionWs = null;
|
|
48636
|
+
this.extIdentity = null;
|
|
48637
|
+
}
|
|
48622
48638
|
for (const [requestId, pending] of this.pending) {
|
|
48623
48639
|
if (pending.ws !== ws)
|
|
48624
48640
|
continue;
|
|
@@ -48629,9 +48645,9 @@ class BrowserExtensionBridge {
|
|
|
48629
48645
|
}
|
|
48630
48646
|
|
|
48631
48647
|
// src/handlers.ts
|
|
48632
|
-
import
|
|
48648
|
+
import fs12 from "fs";
|
|
48633
48649
|
import { mkdir, rm as rm2, writeFile } from "fs/promises";
|
|
48634
|
-
import
|
|
48650
|
+
import path9 from "path";
|
|
48635
48651
|
|
|
48636
48652
|
// src/path-utils.ts
|
|
48637
48653
|
import path2 from "path";
|
|
@@ -48849,6 +48865,15 @@ var tool_catalog_default = {
|
|
|
48849
48865
|
description: "Use to generate speech audio from text, clone voices, or list voices. Needs ELEVENLABS_API_KEY.",
|
|
48850
48866
|
versionCmd: "elevenlabs-api --version 2>/dev/null | head -1"
|
|
48851
48867
|
},
|
|
48868
|
+
"codex-imagegen-api": {
|
|
48869
|
+
category: "media",
|
|
48870
|
+
pkg: "@todoforai/codex-imagegen-api",
|
|
48871
|
+
installer: "npm",
|
|
48872
|
+
label: "Image Gen",
|
|
48873
|
+
capabilities: "AI image generation & editing via TODOFORAI backend (gpt-image)",
|
|
48874
|
+
description: 'Use to generate or edit images. Subcommands: `codex-imagegen-api generate "<prompt>" -o out.png [--size 1024x1024] [--quality low|medium|high]` and `codex-imagegen-api edit "<instruction>" -i in.png -o out.png` (repeat `-i` for multiple reference images).',
|
|
48875
|
+
versionCmd: "codex-imagegen-api --version 2>/dev/null | head -1"
|
|
48876
|
+
},
|
|
48852
48877
|
"suno-api": {
|
|
48853
48878
|
category: "media",
|
|
48854
48879
|
pkg: "@todoforai/suno-api",
|
|
@@ -49066,7 +49091,6 @@ var tool_catalog_default = {
|
|
|
49066
49091
|
label: "TODOforAI",
|
|
49067
49092
|
capabilities: "Create & manage TODOs, run workflows, API access",
|
|
49068
49093
|
description: "Use to programmatically create/list/update TODOs in TODOforAI, kick off workflows, call the platform API.",
|
|
49069
|
-
statusCmd: "todoai whoami >/dev/null 2>&1",
|
|
49070
49094
|
installCmd: "bun add -g @todoforai/cli",
|
|
49071
49095
|
versionCmd: "todoai --version 2>/dev/null | head -1",
|
|
49072
49096
|
internal: true
|
|
@@ -51864,9 +51888,9 @@ function consumeExitedOutput(pid) {
|
|
|
51864
51888
|
}
|
|
51865
51889
|
|
|
51866
51890
|
// src/functions.ts
|
|
51867
|
-
import
|
|
51868
|
-
import
|
|
51869
|
-
import
|
|
51891
|
+
import fs11 from "fs";
|
|
51892
|
+
import path8 from "path";
|
|
51893
|
+
import os9 from "os";
|
|
51870
51894
|
|
|
51871
51895
|
// src/skills.ts
|
|
51872
51896
|
import fs9 from "fs";
|
|
@@ -52043,6 +52067,62 @@ function sanitize(s) {
|
|
|
52043
52067
|
return s.split(/\s+/).filter(Boolean).join(" ");
|
|
52044
52068
|
}
|
|
52045
52069
|
|
|
52070
|
+
// src/agent-md.ts
|
|
52071
|
+
import fs10 from "fs";
|
|
52072
|
+
import path7 from "path";
|
|
52073
|
+
import os8 from "os";
|
|
52074
|
+
var MAX_BYTES = 64 * 1024;
|
|
52075
|
+
var FILENAMES = ["AGENT.md", "AGENTS.md"];
|
|
52076
|
+
async function discoverAgentMd(rootPaths, opts = {}) {
|
|
52077
|
+
const includeUserScope = opts.includeUserScope ?? true;
|
|
52078
|
+
const maxBytes = opts.maxBytes ?? MAX_BYTES;
|
|
52079
|
+
const dirs = [
|
|
52080
|
+
...rootPaths.map((p10) => ({ dir: p10, scope: "repo" }))
|
|
52081
|
+
];
|
|
52082
|
+
if (includeUserScope) {
|
|
52083
|
+
dirs.push({ dir: path7.join(os8.homedir(), ".agents"), scope: "user" });
|
|
52084
|
+
}
|
|
52085
|
+
const files = [];
|
|
52086
|
+
const errors = [];
|
|
52087
|
+
const seen = new Set;
|
|
52088
|
+
for (const { dir, scope } of dirs) {
|
|
52089
|
+
for (const name of FILENAMES) {
|
|
52090
|
+
const full = path7.join(dir, name);
|
|
52091
|
+
if (seen.has(full))
|
|
52092
|
+
continue;
|
|
52093
|
+
let stat;
|
|
52094
|
+
try {
|
|
52095
|
+
stat = fs10.statSync(full);
|
|
52096
|
+
} catch {
|
|
52097
|
+
continue;
|
|
52098
|
+
}
|
|
52099
|
+
if (!stat.isFile())
|
|
52100
|
+
continue;
|
|
52101
|
+
seen.add(full);
|
|
52102
|
+
try {
|
|
52103
|
+
const fd3 = fs10.openSync(full, "r");
|
|
52104
|
+
const buf = Buffer.alloc(maxBytes);
|
|
52105
|
+
let bytes;
|
|
52106
|
+
try {
|
|
52107
|
+
bytes = fs10.readSync(fd3, buf, 0, maxBytes, 0);
|
|
52108
|
+
} finally {
|
|
52109
|
+
fs10.closeSync(fd3);
|
|
52110
|
+
}
|
|
52111
|
+
files.push({
|
|
52112
|
+
path: full,
|
|
52113
|
+
scope,
|
|
52114
|
+
content: buf.subarray(0, bytes).toString("utf-8"),
|
|
52115
|
+
bytes: stat.size,
|
|
52116
|
+
truncated: stat.size > maxBytes
|
|
52117
|
+
});
|
|
52118
|
+
} catch (e) {
|
|
52119
|
+
errors.push({ path: full, message: `read failed: ${e?.message ?? e}` });
|
|
52120
|
+
}
|
|
52121
|
+
}
|
|
52122
|
+
}
|
|
52123
|
+
return { files, errors };
|
|
52124
|
+
}
|
|
52125
|
+
|
|
52046
52126
|
// src/functions.ts
|
|
52047
52127
|
var FUNCTION_REGISTRY = new Map;
|
|
52048
52128
|
function register(name, fn2) {
|
|
@@ -52058,12 +52138,12 @@ register("get_environment_variable", async (args) => ({
|
|
|
52058
52138
|
value: process.env[args.var_name] ?? null
|
|
52059
52139
|
}));
|
|
52060
52140
|
register("get_system_info", async () => {
|
|
52061
|
-
let system2 =
|
|
52141
|
+
let system2 = os9.platform();
|
|
52062
52142
|
if (system2 === "darwin")
|
|
52063
52143
|
system2 = "macOS";
|
|
52064
52144
|
else if (system2 === "linux") {
|
|
52065
52145
|
try {
|
|
52066
|
-
const release =
|
|
52146
|
+
const release = fs11.readFileSync("/etc/os-release", "utf-8");
|
|
52067
52147
|
const m = release.match(/PRETTY_NAME="(.+?)"/);
|
|
52068
52148
|
if (m)
|
|
52069
52149
|
system2 = m[1];
|
|
@@ -52073,10 +52153,10 @@ register("get_system_info", async () => {
|
|
|
52073
52153
|
system2 = "Linux";
|
|
52074
52154
|
}
|
|
52075
52155
|
} else if (system2 === "win32") {
|
|
52076
|
-
system2 = `Windows ${
|
|
52156
|
+
system2 = `Windows ${os9.release()}`;
|
|
52077
52157
|
}
|
|
52078
|
-
const shell = process.env.SHELL ?
|
|
52079
|
-
const mount_path =
|
|
52158
|
+
const shell = process.env.SHELL ? path8.basename(process.env.SHELL) : "unknown";
|
|
52159
|
+
const mount_path = path8.join(os9.homedir(), ".todoforai", "mnt", "todoforai");
|
|
52080
52160
|
return { system: system2, shell, mount_path };
|
|
52081
52161
|
});
|
|
52082
52162
|
register("get_available_tools", async () => {
|
|
@@ -52120,11 +52200,11 @@ register("uninstall_tool", async (args) => {
|
|
|
52120
52200
|
});
|
|
52121
52201
|
register("get_workspace_tree", async (args) => {
|
|
52122
52202
|
const { path: p10, max_depth = 2 } = args;
|
|
52123
|
-
const root =
|
|
52124
|
-
if (!
|
|
52203
|
+
const root = path8.resolve(p10.replace(/^~/, process.env.HOME || "~"));
|
|
52204
|
+
if (!fs11.existsSync(root) || !fs11.statSync(root).isDirectory()) {
|
|
52125
52205
|
return { tree: "", is_git: false };
|
|
52126
52206
|
}
|
|
52127
|
-
const isGit =
|
|
52207
|
+
const isGit = fs11.existsSync(path8.join(root, ".git"));
|
|
52128
52208
|
if (process.platform !== "win32") {
|
|
52129
52209
|
try {
|
|
52130
52210
|
const { execSync: execSync2 } = await import("child_process");
|
|
@@ -52147,12 +52227,12 @@ register("get_workspace_tree", async (args) => {
|
|
|
52147
52227
|
const ig2 = ignore();
|
|
52148
52228
|
if (isGit) {
|
|
52149
52229
|
let scanGitignores = function(dir) {
|
|
52150
|
-
const giPath =
|
|
52151
|
-
if (
|
|
52230
|
+
const giPath = path8.join(dir, ".gitignore");
|
|
52231
|
+
if (fs11.existsSync(giPath)) {
|
|
52152
52232
|
try {
|
|
52153
|
-
const relDir =
|
|
52233
|
+
const relDir = path8.relative(root, dir).replace(/\\/g, "/");
|
|
52154
52234
|
const prefix = relDir === "" || relDir === "." ? "" : relDir + "/";
|
|
52155
|
-
for (let line of
|
|
52235
|
+
for (let line of fs11.readFileSync(giPath, "utf-8").split(`
|
|
52156
52236
|
`)) {
|
|
52157
52237
|
line = line.trim();
|
|
52158
52238
|
if (!line || line.startsWith("#"))
|
|
@@ -52166,21 +52246,21 @@ register("get_workspace_tree", async (args) => {
|
|
|
52166
52246
|
} catch {}
|
|
52167
52247
|
}
|
|
52168
52248
|
try {
|
|
52169
|
-
for (const e of
|
|
52249
|
+
for (const e of fs11.readdirSync(dir, { withFileTypes: true })) {
|
|
52170
52250
|
if (e.isDirectory() && e.name !== ".git")
|
|
52171
|
-
scanGitignores(
|
|
52251
|
+
scanGitignores(path8.join(dir, e.name));
|
|
52172
52252
|
}
|
|
52173
52253
|
} catch {}
|
|
52174
52254
|
};
|
|
52175
52255
|
scanGitignores(root);
|
|
52176
52256
|
}
|
|
52177
|
-
const lines = [
|
|
52257
|
+
const lines = [path8.basename(root) + "/"];
|
|
52178
52258
|
function walk(dirPath, prefix, depth) {
|
|
52179
52259
|
if (depth > max_depth)
|
|
52180
52260
|
return;
|
|
52181
52261
|
let entries;
|
|
52182
52262
|
try {
|
|
52183
|
-
entries =
|
|
52263
|
+
entries = fs11.readdirSync(dirPath, { withFileTypes: true });
|
|
52184
52264
|
} catch {
|
|
52185
52265
|
return;
|
|
52186
52266
|
}
|
|
@@ -52188,7 +52268,7 @@ register("get_workspace_tree", async (args) => {
|
|
|
52188
52268
|
if (e.name === ".git")
|
|
52189
52269
|
return false;
|
|
52190
52270
|
if (isGit) {
|
|
52191
|
-
let rel =
|
|
52271
|
+
let rel = path8.relative(root, path8.join(dirPath, e.name)).replace(/\\/g, "/");
|
|
52192
52272
|
if (e.isDirectory())
|
|
52193
52273
|
rel += "/";
|
|
52194
52274
|
if (ig2.ignores(rel))
|
|
@@ -52210,7 +52290,7 @@ register("get_workspace_tree", async (args) => {
|
|
|
52210
52290
|
lines.push(`${prefix}${connector}${entry.name}${suffix}`);
|
|
52211
52291
|
if (entry.isDirectory()) {
|
|
52212
52292
|
const extension2 = isLast ? " " : "│ ";
|
|
52213
|
-
walk(
|
|
52293
|
+
walk(path8.join(dirPath, entry.name), prefix + extension2, depth + 1);
|
|
52214
52294
|
}
|
|
52215
52295
|
}
|
|
52216
52296
|
}
|
|
@@ -52223,25 +52303,30 @@ register("get_skills", async (args) => {
|
|
|
52223
52303
|
const includeUserScope = args?.includeUserScope ?? true;
|
|
52224
52304
|
return await discoverSkills(paths, { includeUserScope });
|
|
52225
52305
|
});
|
|
52306
|
+
register("get_agent_md", async (args) => {
|
|
52307
|
+
const paths = Array.isArray(args?.paths) ? args.paths : [];
|
|
52308
|
+
const includeUserScope = args?.includeUserScope ?? true;
|
|
52309
|
+
return await discoverAgentMd(paths, { includeUserScope });
|
|
52310
|
+
});
|
|
52226
52311
|
register("get_os_aware_default_path", async () => {
|
|
52227
52312
|
let p10 = getPlatformDefaultDirectory();
|
|
52228
|
-
if (!p10.endsWith(
|
|
52229
|
-
p10 +=
|
|
52313
|
+
if (!p10.endsWith(path8.sep))
|
|
52314
|
+
p10 += path8.sep;
|
|
52230
52315
|
return { path: p10 };
|
|
52231
52316
|
});
|
|
52232
52317
|
register("create_directory", async (args) => {
|
|
52233
52318
|
const { name } = args;
|
|
52234
52319
|
if (!name?.trim())
|
|
52235
52320
|
throw new Error("Folder name cannot be empty");
|
|
52236
|
-
const baseDir =
|
|
52237
|
-
let target =
|
|
52238
|
-
if (!
|
|
52239
|
-
target =
|
|
52240
|
-
const existed =
|
|
52241
|
-
|
|
52321
|
+
const baseDir = path8.resolve(getPathOrDefault(args.path).replace(/^~/, process.env.HOME || "~"));
|
|
52322
|
+
let target = path8.resolve(name.replace(/^~/, process.env.HOME || "~"));
|
|
52323
|
+
if (!path8.isAbsolute(name))
|
|
52324
|
+
target = path8.join(baseDir, name.trim());
|
|
52325
|
+
const existed = fs11.existsSync(target);
|
|
52326
|
+
fs11.mkdirSync(target, { recursive: true });
|
|
52242
52327
|
let full = target;
|
|
52243
|
-
if (!full.endsWith(
|
|
52244
|
-
full +=
|
|
52328
|
+
if (!full.endsWith(path8.sep))
|
|
52329
|
+
full += path8.sep;
|
|
52245
52330
|
return { path: full, created: !existed, exists: true };
|
|
52246
52331
|
});
|
|
52247
52332
|
FUNCTION_REGISTRY.set("getOSAwareDefaultPath", FUNCTION_REGISTRY.get("get_os_aware_default_path"));
|
|
@@ -52275,7 +52360,7 @@ register("execute_shell_command", async (args, client) => {
|
|
|
52275
52360
|
if (!canStream) {
|
|
52276
52361
|
const { exec } = await import("child_process");
|
|
52277
52362
|
const result = await new Promise((resolve) => {
|
|
52278
|
-
exec(cmd, { cwd: cwd ||
|
|
52363
|
+
exec(cmd, { cwd: cwd || os9.tmpdir(), encoding: "utf-8", timeout: timeout * 1000, maxBuffer: 10485760, env: { ...buildEnvWithTools(), ...getConnectionEnv(), TODOFORAI_TODO_ID: todoId, TODOFORAI_MESSAGE_ID: messageId, TODOFORAI_BLOCK_ID: blockId, TODOFORAI_AGENT_SETTINGS_ID: agentSettingsId } }, (_err, stdout, stderr) => {
|
|
52279
52364
|
resolve((stdout || "") + (stderr || ""));
|
|
52280
52365
|
});
|
|
52281
52366
|
});
|
|
@@ -52340,17 +52425,17 @@ var LIST_DIR_MAX_ENTRIES = 1e4;
|
|
|
52340
52425
|
register("list_dir", async (args) => {
|
|
52341
52426
|
const { path: p10, rootPath = "", fallbackRootPaths = [] } = args;
|
|
52342
52427
|
const fullPath = resolveFilePath(p10, rootPath, fallbackRootPaths);
|
|
52343
|
-
const st2 =
|
|
52428
|
+
const st2 = fs11.statSync(fullPath);
|
|
52344
52429
|
if (!st2.isDirectory())
|
|
52345
52430
|
throw new Error(`Not a directory: ${fullPath}`);
|
|
52346
|
-
const dirents =
|
|
52431
|
+
const dirents = fs11.readdirSync(fullPath, { withFileTypes: true });
|
|
52347
52432
|
if (dirents.length > LIST_DIR_MAX_ENTRIES) {
|
|
52348
52433
|
throw new Error(`Directory too large: ${dirents.length} entries (max ${LIST_DIR_MAX_ENTRIES})`);
|
|
52349
52434
|
}
|
|
52350
52435
|
const entries = dirents.map((d) => {
|
|
52351
52436
|
let size = 0, mtime = 0, mode = 0, is_dir = d.isDirectory();
|
|
52352
52437
|
try {
|
|
52353
|
-
const s =
|
|
52438
|
+
const s = fs11.lstatSync(path8.join(fullPath, d.name));
|
|
52354
52439
|
size = Number(s.size);
|
|
52355
52440
|
mtime = s.mtimeMs / 1000;
|
|
52356
52441
|
mode = s.mode & 511;
|
|
@@ -52363,21 +52448,21 @@ register("list_dir", async (args) => {
|
|
|
52363
52448
|
register("create_file", async (args) => {
|
|
52364
52449
|
const { path: p10, content, rootPath = "", fallbackRootPaths = [] } = args;
|
|
52365
52450
|
const fullPath = resolveFilePath(p10, rootPath, fallbackRootPaths);
|
|
52366
|
-
const dir =
|
|
52451
|
+
const dir = path8.dirname(fullPath);
|
|
52367
52452
|
if (dir)
|
|
52368
|
-
|
|
52369
|
-
|
|
52453
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
52454
|
+
fs11.writeFileSync(fullPath, content, "utf-8");
|
|
52370
52455
|
return { path: fullPath, bytes: Buffer.byteLength(content, "utf-8") };
|
|
52371
52456
|
});
|
|
52372
52457
|
register("read_file_base64", async (args) => {
|
|
52373
52458
|
const { path: p10, rootPath = "", fallbackRootPaths = [] } = args;
|
|
52374
52459
|
const fullPath = resolveFilePath(p10, rootPath, fallbackRootPaths);
|
|
52375
|
-
if (!
|
|
52460
|
+
if (!fs11.existsSync(fullPath))
|
|
52376
52461
|
throw new Error(`File not found: ${fullPath}`);
|
|
52377
|
-
const stat =
|
|
52462
|
+
const stat = fs11.statSync(fullPath);
|
|
52378
52463
|
if (stat.size > 50000000)
|
|
52379
52464
|
throw new Error(`File too large: ${stat.size.toLocaleString()} bytes (max 50MB)`);
|
|
52380
|
-
const data =
|
|
52465
|
+
const data = fs11.readFileSync(fullPath);
|
|
52381
52466
|
return { path: fullPath, base64: data.toString("base64"), bytes: data.length };
|
|
52382
52467
|
});
|
|
52383
52468
|
register("download_attachment", async (args, client) => {
|
|
@@ -52394,13 +52479,13 @@ register("download_attachment", async (args, client) => {
|
|
|
52394
52479
|
throw new Error(`Backend responded with ${res.status}`);
|
|
52395
52480
|
const base = getPathOrDefault(rootPath);
|
|
52396
52481
|
let target = p10.replace(/^~/, process.env.HOME || "~");
|
|
52397
|
-
if (!
|
|
52398
|
-
target =
|
|
52399
|
-
target =
|
|
52400
|
-
|
|
52482
|
+
if (!path8.isAbsolute(target))
|
|
52483
|
+
target = path8.join(base, target);
|
|
52484
|
+
target = path8.resolve(target);
|
|
52485
|
+
fs11.mkdirSync(path8.dirname(target), { recursive: true });
|
|
52401
52486
|
try {
|
|
52402
52487
|
const data = Buffer.from(await res.arrayBuffer());
|
|
52403
|
-
|
|
52488
|
+
fs11.writeFileSync(target, data);
|
|
52404
52489
|
return { path: target, bytes: data.length };
|
|
52405
52490
|
} catch (e) {
|
|
52406
52491
|
throw new Error(`Download failed: ${e.message}`);
|
|
@@ -52428,13 +52513,13 @@ register("register_attachment", async (args, client) => {
|
|
|
52428
52513
|
const { filePath, userId = "test-user", isPublic = false, agentSettingsId = "", todoId = "", rootPath = "" } = args;
|
|
52429
52514
|
const base = getPathOrDefault(rootPath);
|
|
52430
52515
|
let target = filePath.replace(/^~/, process.env.HOME || "~");
|
|
52431
|
-
if (!
|
|
52432
|
-
target =
|
|
52433
|
-
target =
|
|
52434
|
-
if (!
|
|
52516
|
+
if (!path8.isAbsolute(target))
|
|
52517
|
+
target = path8.join(base, target);
|
|
52518
|
+
target = path8.resolve(target);
|
|
52519
|
+
if (!fs11.existsSync(target))
|
|
52435
52520
|
throw new Error(`File not found: ${target}`);
|
|
52436
52521
|
const form = new FormData;
|
|
52437
|
-
form.append("file", new Blob([
|
|
52522
|
+
form.append("file", new Blob([fs11.readFileSync(target)]), path8.basename(target));
|
|
52438
52523
|
if (userId)
|
|
52439
52524
|
form.append("userId", userId);
|
|
52440
52525
|
if (agentSettingsId)
|
|
@@ -52478,9 +52563,9 @@ async function handleBlockSave(payload, send) {
|
|
|
52478
52563
|
const { blockId, todoId, filepath, rootPath, fallbackRootPaths = [], content, requestId } = payload;
|
|
52479
52564
|
try {
|
|
52480
52565
|
const resolved = resolveFilePath(filepath, rootPath, fallbackRootPaths);
|
|
52481
|
-
const ext =
|
|
52566
|
+
const ext = path9.extname(resolved).toLowerCase();
|
|
52482
52567
|
if (ext === ".docx" || ext === ".xlsx") {
|
|
52483
|
-
if (!
|
|
52568
|
+
if (!fs12.existsSync(resolved)) {
|
|
52484
52569
|
throw new Error(`Cannot create new ${ext} file from XML — file must already exist: ${filepath}`);
|
|
52485
52570
|
}
|
|
52486
52571
|
if (ext === ".docx")
|
|
@@ -52488,10 +52573,10 @@ async function handleBlockSave(payload, send) {
|
|
|
52488
52573
|
else
|
|
52489
52574
|
saveXlsxContent(resolved, content);
|
|
52490
52575
|
} else {
|
|
52491
|
-
const dir =
|
|
52576
|
+
const dir = path9.dirname(resolved);
|
|
52492
52577
|
if (dir)
|
|
52493
|
-
|
|
52494
|
-
|
|
52578
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
52579
|
+
fs12.writeFileSync(resolved, content, "utf-8");
|
|
52495
52580
|
}
|
|
52496
52581
|
await send(msg.blockSaveResult(blockId, todoId, "SUCCESS", requestId));
|
|
52497
52582
|
} catch (e) {
|
|
@@ -52502,22 +52587,22 @@ async function handleGetFolders(payload, send) {
|
|
|
52502
52587
|
const { requestId, edgeId } = payload;
|
|
52503
52588
|
const rawPath = getPathOrDefault(payload.path);
|
|
52504
52589
|
try {
|
|
52505
|
-
const expandedPath =
|
|
52590
|
+
const expandedPath = path9.resolve(rawPath.replace(/^~/, process.env.HOME || "~"));
|
|
52506
52591
|
let targetPath;
|
|
52507
|
-
if (
|
|
52592
|
+
if (fs12.existsSync(expandedPath) && fs12.statSync(expandedPath).isDirectory()) {
|
|
52508
52593
|
targetPath = expandedPath;
|
|
52509
52594
|
} else {
|
|
52510
|
-
targetPath =
|
|
52595
|
+
targetPath = path9.dirname(expandedPath);
|
|
52511
52596
|
}
|
|
52512
|
-
if (!
|
|
52597
|
+
if (!fs12.existsSync(targetPath) || !fs12.statSync(targetPath).isDirectory()) {
|
|
52513
52598
|
throw new Error(`No existing ancestor for path: ${rawPath}`);
|
|
52514
52599
|
}
|
|
52515
52600
|
const folders = [];
|
|
52516
52601
|
const files = [];
|
|
52517
|
-
for (const item of
|
|
52518
|
-
const full =
|
|
52602
|
+
for (const item of fs12.readdirSync(targetPath)) {
|
|
52603
|
+
const full = path9.join(targetPath, item);
|
|
52519
52604
|
try {
|
|
52520
|
-
if (
|
|
52605
|
+
if (fs12.statSync(full).isDirectory())
|
|
52521
52606
|
folders.push(full);
|
|
52522
52607
|
else
|
|
52523
52608
|
files.push(full);
|
|
@@ -52551,10 +52636,10 @@ async function handleDeletePath(payload, send) {
|
|
|
52551
52636
|
async function handleWriteFile(payload, send, pendingBinaries) {
|
|
52552
52637
|
const { requestId, edgeId, path: dirPath, fileName, binaryId, dataBase64 } = payload;
|
|
52553
52638
|
try {
|
|
52554
|
-
const filePath =
|
|
52555
|
-
const dir =
|
|
52639
|
+
const filePath = path9.join(dirPath, fileName);
|
|
52640
|
+
const dir = path9.dirname(filePath);
|
|
52556
52641
|
if (dir)
|
|
52557
|
-
|
|
52642
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
52558
52643
|
let buffer;
|
|
52559
52644
|
if (binaryId && pendingBinaries?.has(binaryId)) {
|
|
52560
52645
|
buffer = pendingBinaries.get(binaryId);
|
|
@@ -52575,8 +52660,8 @@ async function handleCd(payload, send, edgeConfig, onConfigChange) {
|
|
|
52575
52660
|
const { requestId, edgeId } = payload;
|
|
52576
52661
|
const rawPath = getPathOrDefault(payload.path);
|
|
52577
52662
|
try {
|
|
52578
|
-
const resolved =
|
|
52579
|
-
if (!
|
|
52663
|
+
const resolved = path9.resolve(rawPath.replace(/^~/, process.env.HOME || "~"));
|
|
52664
|
+
if (!fs12.existsSync(resolved) || !fs12.statSync(resolved).isDirectory()) {
|
|
52580
52665
|
throw new Error(`Path does not exist or is not a directory: ${rawPath}`);
|
|
52581
52666
|
}
|
|
52582
52667
|
const normalized = resolved.replace(/\/+$/, "");
|
|
@@ -52631,12 +52716,12 @@ async function handleFunctionCall(payload, send, client) {
|
|
|
52631
52716
|
|
|
52632
52717
|
// src/edge.ts
|
|
52633
52718
|
function generateFingerprint() {
|
|
52634
|
-
const
|
|
52635
|
-
const
|
|
52719
|
+
const os10 = __require("os");
|
|
52720
|
+
const fs13 = __require("fs");
|
|
52636
52721
|
const identifiers = {};
|
|
52637
52722
|
if (process.platform === "linux") {
|
|
52638
52723
|
try {
|
|
52639
|
-
const mid =
|
|
52724
|
+
const mid = fs13.readFileSync("/etc/machine-id", "utf-8").trim();
|
|
52640
52725
|
if (mid)
|
|
52641
52726
|
identifiers.machine_id = mid;
|
|
52642
52727
|
} catch {}
|
|
@@ -52651,8 +52736,8 @@ function generateFingerprint() {
|
|
|
52651
52736
|
}
|
|
52652
52737
|
if (Object.keys(identifiers).length === 0) {
|
|
52653
52738
|
identifiers.platform = process.platform;
|
|
52654
|
-
identifiers.machine =
|
|
52655
|
-
identifiers.node =
|
|
52739
|
+
identifiers.machine = os10.machine?.() || os10.arch();
|
|
52740
|
+
identifiers.node = os10.hostname();
|
|
52656
52741
|
}
|
|
52657
52742
|
const keys = Object.keys(identifiers).sort();
|
|
52658
52743
|
const json = "{" + keys.map((k) => JSON.stringify(k) + ": " + JSON.stringify(identifiers[k])).join(", ") + "}";
|
|
@@ -52838,8 +52923,8 @@ class TODOforAIEdge {
|
|
|
52838
52923
|
if (edgeId && edgeId !== this.edgeId)
|
|
52839
52924
|
return;
|
|
52840
52925
|
if (payload.workspacepaths) {
|
|
52841
|
-
const
|
|
52842
|
-
payload.workspacepaths = payload.workspacepaths.filter((p10) => !FORBIDDEN_PATHS2.has(
|
|
52926
|
+
const path10 = __require("path");
|
|
52927
|
+
payload.workspacepaths = payload.workspacepaths.filter((p10) => !FORBIDDEN_PATHS2.has(path10.normalize(p10).replace(/\/+$/, "")));
|
|
52843
52928
|
}
|
|
52844
52929
|
Object.assign(this.edgeConfig, payload);
|
|
52845
52930
|
if (this.addWorkspacePath) {
|
|
@@ -53121,18 +53206,18 @@ class ServerError extends Error {
|
|
|
53121
53206
|
}
|
|
53122
53207
|
|
|
53123
53208
|
// node_modules/@todoforai/update-notifier/src/index.ts
|
|
53124
|
-
import
|
|
53125
|
-
import
|
|
53126
|
-
import
|
|
53209
|
+
import fs13 from "node:fs";
|
|
53210
|
+
import path10 from "node:path";
|
|
53211
|
+
import os10 from "node:os";
|
|
53127
53212
|
function isLinkedInstall() {
|
|
53128
53213
|
try {
|
|
53129
|
-
return !
|
|
53214
|
+
return !fs13.realpathSync(process.argv[1] || "").includes(`${path10.sep}node_modules${path10.sep}`);
|
|
53130
53215
|
} catch {
|
|
53131
53216
|
return false;
|
|
53132
53217
|
}
|
|
53133
53218
|
}
|
|
53134
53219
|
var TTL_MS = 24 * 60 * 60 * 1000;
|
|
53135
|
-
var CACHE_DIR =
|
|
53220
|
+
var CACHE_DIR = path10.join(os10.homedir(), ".config", "todoforai");
|
|
53136
53221
|
function cmpVer(a, b) {
|
|
53137
53222
|
const pa2 = a.split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
|
|
53138
53223
|
const pb2 = b.split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
|
|
@@ -53146,10 +53231,10 @@ function cmpVer(a, b) {
|
|
|
53146
53231
|
function checkForUpdates(pkg) {
|
|
53147
53232
|
if (!process.stderr.isTTY || process.env.CI || process.env.NO_UPDATE_NOTIFIER || isLinkedInstall())
|
|
53148
53233
|
return;
|
|
53149
|
-
const cacheFile =
|
|
53234
|
+
const cacheFile = path10.join(CACHE_DIR, `notifier-${encodeURIComponent(pkg.name)}.json`);
|
|
53150
53235
|
let cache = {};
|
|
53151
53236
|
try {
|
|
53152
|
-
cache = JSON.parse(
|
|
53237
|
+
cache = JSON.parse(fs13.readFileSync(cacheFile, "utf8"));
|
|
53153
53238
|
} catch {}
|
|
53154
53239
|
if (cache.latest && cmpVer(cache.latest, pkg.version) > 0) {
|
|
53155
53240
|
process.stderr.write(`
|
|
@@ -53160,42 +53245,42 @@ function checkForUpdates(pkg) {
|
|
|
53160
53245
|
}
|
|
53161
53246
|
if (Date.now() - (cache.ts ?? 0) > TTL_MS) {
|
|
53162
53247
|
try {
|
|
53163
|
-
|
|
53164
|
-
|
|
53248
|
+
fs13.mkdirSync(CACHE_DIR, { recursive: true });
|
|
53249
|
+
fs13.writeFileSync(cacheFile, JSON.stringify({ ...cache, ts: Date.now() }));
|
|
53165
53250
|
} catch {}
|
|
53166
53251
|
fetch(`https://registry.npmjs.org/${pkg.name}/latest`, { signal: AbortSignal.timeout(3000) }).then((r) => r.ok ? r.json() : null).then((j) => {
|
|
53167
53252
|
if (!j?.version)
|
|
53168
53253
|
return;
|
|
53169
|
-
|
|
53254
|
+
fs13.writeFileSync(cacheFile, JSON.stringify({ ts: Date.now(), latest: j.version }));
|
|
53170
53255
|
}).catch(() => {});
|
|
53171
53256
|
}
|
|
53172
53257
|
}
|
|
53173
53258
|
|
|
53174
53259
|
// src/index.ts
|
|
53175
53260
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
53176
|
-
import
|
|
53177
|
-
import
|
|
53178
|
-
import
|
|
53261
|
+
import fs14 from "fs";
|
|
53262
|
+
import path11 from "path";
|
|
53263
|
+
import os11 from "os";
|
|
53179
53264
|
import crypto3 from "crypto";
|
|
53180
53265
|
function readOwnPackage() {
|
|
53181
53266
|
try {
|
|
53182
|
-
const pkgPath =
|
|
53183
|
-
return JSON.parse(
|
|
53267
|
+
const pkgPath = path11.resolve(fileURLToPath2(import.meta.url), "../../package.json");
|
|
53268
|
+
return JSON.parse(fs14.readFileSync(pkgPath, "utf-8"));
|
|
53184
53269
|
} catch {
|
|
53185
53270
|
return null;
|
|
53186
53271
|
}
|
|
53187
53272
|
}
|
|
53188
53273
|
function lockPath(apiUrl, userId) {
|
|
53189
|
-
const dir =
|
|
53190
|
-
|
|
53274
|
+
const dir = path11.join(os11.homedir(), ".todoforai");
|
|
53275
|
+
fs14.mkdirSync(dir, { recursive: true });
|
|
53191
53276
|
const hash = crypto3.createHash("sha256").update(`${apiUrl}
|
|
53192
53277
|
${userId}`).digest("hex").slice(0, 12);
|
|
53193
|
-
return
|
|
53278
|
+
return path11.join(dir, `edge-${hash}.lock`);
|
|
53194
53279
|
}
|
|
53195
53280
|
function isEdgeProcess(pid) {
|
|
53196
53281
|
try {
|
|
53197
53282
|
process.kill(pid, 0);
|
|
53198
|
-
const cmdline =
|
|
53283
|
+
const cmdline = fs14.readFileSync(`/proc/${pid}/cmdline`, "utf-8");
|
|
53199
53284
|
return cmdline.includes("index.ts") || cmdline.includes("todoforai-edge");
|
|
53200
53285
|
} catch {
|
|
53201
53286
|
return false;
|
|
@@ -53203,7 +53288,7 @@ function isEdgeProcess(pid) {
|
|
|
53203
53288
|
}
|
|
53204
53289
|
function killExistingEdge(lp2) {
|
|
53205
53290
|
try {
|
|
53206
|
-
const pid = parseInt(
|
|
53291
|
+
const pid = parseInt(fs14.readFileSync(lp2, "utf-8").trim(), 10);
|
|
53207
53292
|
if (!isNaN(pid) && isEdgeProcess(pid)) {
|
|
53208
53293
|
console.log(`\x1B[33mKilling existing edge process (pid ${pid})...\x1B[0m`);
|
|
53209
53294
|
process.kill(pid, "SIGTERM");
|
|
@@ -53226,7 +53311,7 @@ function killExistingEdge(lp2) {
|
|
|
53226
53311
|
}
|
|
53227
53312
|
function acquireLock(lp2, kill = false) {
|
|
53228
53313
|
try {
|
|
53229
|
-
const pid = parseInt(
|
|
53314
|
+
const pid = parseInt(fs14.readFileSync(lp2, "utf-8").trim(), 10);
|
|
53230
53315
|
if (!isNaN(pid) && isEdgeProcess(pid)) {
|
|
53231
53316
|
if (kill) {
|
|
53232
53317
|
killExistingEdge(lp2);
|
|
@@ -53234,13 +53319,13 @@ function acquireLock(lp2, kill = false) {
|
|
|
53234
53319
|
return false;
|
|
53235
53320
|
}
|
|
53236
53321
|
} catch {}
|
|
53237
|
-
|
|
53322
|
+
fs14.writeFileSync(lp2, String(process.pid));
|
|
53238
53323
|
return true;
|
|
53239
53324
|
}
|
|
53240
53325
|
function releaseLock(lp2) {
|
|
53241
53326
|
try {
|
|
53242
|
-
if (
|
|
53243
|
-
|
|
53327
|
+
if (fs14.readFileSync(lp2, "utf-8").trim() === String(process.pid))
|
|
53328
|
+
fs14.unlinkSync(lp2);
|
|
53244
53329
|
} catch {}
|
|
53245
53330
|
}
|
|
53246
53331
|
var MIN_BUN_VERSION = "1.3.14";
|