@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.
Files changed (2) hide show
  1. package/dist/index.js +217 -132
  2. 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(path7, checkUnignored, mode) {
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(path7);
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 = (path7, originalPath, doThrow) => {
47729
- if (!isString(path7)) {
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 (!path7) {
47732
+ if (!path8) {
47733
47733
  return doThrow(`path must not be empty`, TypeError);
47734
47734
  }
47735
- if (checkPath.isNotRelative(path7)) {
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 = (path7) => REGEX_TEST_INVALID_PATH.test(path7);
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 path7 = originalPath && checkPath.convert(originalPath);
47771
- checkPath(path7, originalPath, this._strictPathCheck ? throwError : RETURN_FALSE);
47772
- return this._t(path7, cache, checkUnignored, slices);
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(path7) {
47775
- if (!REGEX_TEST_TRAILING_SLASH.test(path7)) {
47776
- return this.test(path7);
47774
+ checkIgnore(path8) {
47775
+ if (!REGEX_TEST_TRAILING_SLASH.test(path8)) {
47776
+ return this.test(path8);
47777
47777
  }
47778
- const slices = path7.split(SLASH).filter(Boolean);
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(path7, false, MODE_CHECK_IGNORE);
47786
+ return this._rules.test(path8, false, MODE_CHECK_IGNORE);
47787
47787
  }
47788
- _t(path7, cache, checkUnignored, slices) {
47789
- if (path7 in cache) {
47790
- return cache[path7];
47788
+ _t(path8, cache, checkUnignored, slices) {
47789
+ if (path8 in cache) {
47790
+ return cache[path8];
47791
47791
  }
47792
47792
  if (!slices) {
47793
- slices = path7.split(SLASH).filter(Boolean);
47793
+ slices = path8.split(SLASH).filter(Boolean);
47794
47794
  }
47795
47795
  slices.pop();
47796
47796
  if (!slices.length) {
47797
- return cache[path7] = this._rules.test(path7, checkUnignored, MODE_IGNORE);
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[path7] = parent.ignored ? parent : this._rules.test(path7, checkUnignored, MODE_IGNORE);
47800
+ return cache[path8] = parent.ignored ? parent : this._rules.test(path8, checkUnignored, MODE_IGNORE);
47801
47801
  }
47802
- ignores(path7) {
47803
- return this._test(path7, this._ignoreCache, false).ignored;
47802
+ ignores(path8) {
47803
+ return this._test(path8, this._ignoreCache, false).ignored;
47804
47804
  }
47805
47805
  createFilter() {
47806
- return (path7) => !this.ignores(path7);
47806
+ return (path8) => !this.ignores(path8);
47807
47807
  }
47808
47808
  filter(paths) {
47809
47809
  return makeArray(paths).filter(this.createFilter());
47810
47810
  }
47811
- test(path7) {
47812
- return this._test(path7, this._testCache, true);
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 = (path7) => checkPath(path7 && checkPath.convert(path7), path7, RETURN_FALSE);
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 = (path7) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path7) || isNotRelative(path7);
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 fs11 from "fs";
48648
+ import fs12 from "fs";
48633
48649
  import { mkdir, rm as rm2, writeFile } from "fs/promises";
48634
- import path8 from "path";
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 fs10 from "fs";
51868
- import path7 from "path";
51869
- import os8 from "os";
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 = os8.platform();
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 = fs10.readFileSync("/etc/os-release", "utf-8");
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 ${os8.release()}`;
52156
+ system2 = `Windows ${os9.release()}`;
52077
52157
  }
52078
- const shell = process.env.SHELL ? path7.basename(process.env.SHELL) : "unknown";
52079
- const mount_path = path7.join(os8.homedir(), ".todoforai", "mnt", "todoforai");
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 = path7.resolve(p10.replace(/^~/, process.env.HOME || "~"));
52124
- if (!fs10.existsSync(root) || !fs10.statSync(root).isDirectory()) {
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 = fs10.existsSync(path7.join(root, ".git"));
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 = path7.join(dir, ".gitignore");
52151
- if (fs10.existsSync(giPath)) {
52230
+ const giPath = path8.join(dir, ".gitignore");
52231
+ if (fs11.existsSync(giPath)) {
52152
52232
  try {
52153
- const relDir = path7.relative(root, dir).replace(/\\/g, "/");
52233
+ const relDir = path8.relative(root, dir).replace(/\\/g, "/");
52154
52234
  const prefix = relDir === "" || relDir === "." ? "" : relDir + "/";
52155
- for (let line of fs10.readFileSync(giPath, "utf-8").split(`
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 fs10.readdirSync(dir, { withFileTypes: true })) {
52249
+ for (const e of fs11.readdirSync(dir, { withFileTypes: true })) {
52170
52250
  if (e.isDirectory() && e.name !== ".git")
52171
- scanGitignores(path7.join(dir, e.name));
52251
+ scanGitignores(path8.join(dir, e.name));
52172
52252
  }
52173
52253
  } catch {}
52174
52254
  };
52175
52255
  scanGitignores(root);
52176
52256
  }
52177
- const lines = [path7.basename(root) + "/"];
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 = fs10.readdirSync(dirPath, { withFileTypes: true });
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 = path7.relative(root, path7.join(dirPath, e.name)).replace(/\\/g, "/");
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(path7.join(dirPath, entry.name), prefix + extension2, depth + 1);
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(path7.sep))
52229
- p10 += path7.sep;
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 = path7.resolve(getPathOrDefault(args.path).replace(/^~/, process.env.HOME || "~"));
52237
- let target = path7.resolve(name.replace(/^~/, process.env.HOME || "~"));
52238
- if (!path7.isAbsolute(name))
52239
- target = path7.join(baseDir, name.trim());
52240
- const existed = fs10.existsSync(target);
52241
- fs10.mkdirSync(target, { recursive: true });
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(path7.sep))
52244
- full += path7.sep;
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 || os8.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) => {
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 = fs10.statSync(fullPath);
52428
+ const st2 = fs11.statSync(fullPath);
52344
52429
  if (!st2.isDirectory())
52345
52430
  throw new Error(`Not a directory: ${fullPath}`);
52346
- const dirents = fs10.readdirSync(fullPath, { withFileTypes: true });
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 = fs10.lstatSync(path7.join(fullPath, d.name));
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 = path7.dirname(fullPath);
52451
+ const dir = path8.dirname(fullPath);
52367
52452
  if (dir)
52368
- fs10.mkdirSync(dir, { recursive: true });
52369
- fs10.writeFileSync(fullPath, content, "utf-8");
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 (!fs10.existsSync(fullPath))
52460
+ if (!fs11.existsSync(fullPath))
52376
52461
  throw new Error(`File not found: ${fullPath}`);
52377
- const stat = fs10.statSync(fullPath);
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 = fs10.readFileSync(fullPath);
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 (!path7.isAbsolute(target))
52398
- target = path7.join(base, target);
52399
- target = path7.resolve(target);
52400
- fs10.mkdirSync(path7.dirname(target), { recursive: true });
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
- fs10.writeFileSync(target, data);
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 (!path7.isAbsolute(target))
52432
- target = path7.join(base, target);
52433
- target = path7.resolve(target);
52434
- if (!fs10.existsSync(target))
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([fs10.readFileSync(target)]), path7.basename(target));
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 = path8.extname(resolved).toLowerCase();
52566
+ const ext = path9.extname(resolved).toLowerCase();
52482
52567
  if (ext === ".docx" || ext === ".xlsx") {
52483
- if (!fs11.existsSync(resolved)) {
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 = path8.dirname(resolved);
52576
+ const dir = path9.dirname(resolved);
52492
52577
  if (dir)
52493
- fs11.mkdirSync(dir, { recursive: true });
52494
- fs11.writeFileSync(resolved, content, "utf-8");
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 = path8.resolve(rawPath.replace(/^~/, process.env.HOME || "~"));
52590
+ const expandedPath = path9.resolve(rawPath.replace(/^~/, process.env.HOME || "~"));
52506
52591
  let targetPath;
52507
- if (fs11.existsSync(expandedPath) && fs11.statSync(expandedPath).isDirectory()) {
52592
+ if (fs12.existsSync(expandedPath) && fs12.statSync(expandedPath).isDirectory()) {
52508
52593
  targetPath = expandedPath;
52509
52594
  } else {
52510
- targetPath = path8.dirname(expandedPath);
52595
+ targetPath = path9.dirname(expandedPath);
52511
52596
  }
52512
- if (!fs11.existsSync(targetPath) || !fs11.statSync(targetPath).isDirectory()) {
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 fs11.readdirSync(targetPath)) {
52518
- const full = path8.join(targetPath, item);
52602
+ for (const item of fs12.readdirSync(targetPath)) {
52603
+ const full = path9.join(targetPath, item);
52519
52604
  try {
52520
- if (fs11.statSync(full).isDirectory())
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 = path8.join(dirPath, fileName);
52555
- const dir = path8.dirname(filePath);
52639
+ const filePath = path9.join(dirPath, fileName);
52640
+ const dir = path9.dirname(filePath);
52556
52641
  if (dir)
52557
- fs11.mkdirSync(dir, { recursive: true });
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 = path8.resolve(rawPath.replace(/^~/, process.env.HOME || "~"));
52579
- if (!fs11.existsSync(resolved) || !fs11.statSync(resolved).isDirectory()) {
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 os9 = __require("os");
52635
- const fs12 = __require("fs");
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 = fs12.readFileSync("/etc/machine-id", "utf-8").trim();
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 = os9.machine?.() || os9.arch();
52655
- identifiers.node = os9.hostname();
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 path9 = __require("path");
52842
- payload.workspacepaths = payload.workspacepaths.filter((p10) => !FORBIDDEN_PATHS2.has(path9.normalize(p10).replace(/\/+$/, "")));
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 fs12 from "node:fs";
53125
- import path9 from "node:path";
53126
- import os9 from "node:os";
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 !fs12.realpathSync(process.argv[1] || "").includes(`${path9.sep}node_modules${path9.sep}`);
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 = path9.join(os9.homedir(), ".config", "todoforai");
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 = path9.join(CACHE_DIR, `notifier-${encodeURIComponent(pkg.name)}.json`);
53234
+ const cacheFile = path10.join(CACHE_DIR, `notifier-${encodeURIComponent(pkg.name)}.json`);
53150
53235
  let cache = {};
53151
53236
  try {
53152
- cache = JSON.parse(fs12.readFileSync(cacheFile, "utf8"));
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
- fs12.mkdirSync(CACHE_DIR, { recursive: true });
53164
- fs12.writeFileSync(cacheFile, JSON.stringify({ ...cache, ts: Date.now() }));
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
- fs12.writeFileSync(cacheFile, JSON.stringify({ ts: Date.now(), latest: j.version }));
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 fs13 from "fs";
53177
- import path10 from "path";
53178
- import os10 from "os";
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 = path10.resolve(fileURLToPath2(import.meta.url), "../../package.json");
53183
- return JSON.parse(fs13.readFileSync(pkgPath, "utf-8"));
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 = path10.join(os10.homedir(), ".todoforai");
53190
- fs13.mkdirSync(dir, { recursive: true });
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 path10.join(dir, `edge-${hash}.lock`);
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 = fs13.readFileSync(`/proc/${pid}/cmdline`, "utf-8");
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(fs13.readFileSync(lp2, "utf-8").trim(), 10);
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(fs13.readFileSync(lp2, "utf-8").trim(), 10);
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
- fs13.writeFileSync(lp2, String(process.pid));
53322
+ fs14.writeFileSync(lp2, String(process.pid));
53238
53323
  return true;
53239
53324
  }
53240
53325
  function releaseLock(lp2) {
53241
53326
  try {
53242
- if (fs13.readFileSync(lp2, "utf-8").trim() === String(process.pid))
53243
- fs13.unlinkSync(lp2);
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";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@todoforai/edge",
3
- "version": "0.13.12",
3
+ "version": "0.13.14",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "todoforai-edge": "dist/index.js"