@todoforai/edge 0.13.21 → 0.13.22
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 +107 -18
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -48153,6 +48153,27 @@ class ApiClient {
|
|
|
48153
48153
|
throw new Error(`API ${method} ${endpoint} failed: ${res.status} ${await res.text()}`);
|
|
48154
48154
|
return res.json();
|
|
48155
48155
|
}
|
|
48156
|
+
async trpcQuery(path2, input) {
|
|
48157
|
+
const base = this.apiUrl.replace(/\/api\/v1\/?$/, "").replace(/\/$/, "");
|
|
48158
|
+
const params = new URLSearchParams({
|
|
48159
|
+
batch: "1",
|
|
48160
|
+
input: JSON.stringify({ 0: input })
|
|
48161
|
+
});
|
|
48162
|
+
const res = await fetch(`${base}/trpc/api/${path2}?${params}`, {
|
|
48163
|
+
method: "GET",
|
|
48164
|
+
headers: this.headers,
|
|
48165
|
+
signal: AbortSignal.timeout(30000)
|
|
48166
|
+
});
|
|
48167
|
+
const text = await res.text();
|
|
48168
|
+
if (!res.ok)
|
|
48169
|
+
throw new Error(`API tRPC ${path2} failed: ${res.status} ${text}`);
|
|
48170
|
+
const payload = JSON.parse(text);
|
|
48171
|
+
const item = Array.isArray(payload) ? payload[0] : payload;
|
|
48172
|
+
if (item?.error)
|
|
48173
|
+
throw new Error(`API tRPC ${path2} failed: ${item.error.message || JSON.stringify(item.error)}`);
|
|
48174
|
+
const data = item?.result?.data;
|
|
48175
|
+
return data?.json !== undefined ? data.json : data;
|
|
48176
|
+
}
|
|
48156
48177
|
async validateApiKey() {
|
|
48157
48178
|
if (!this.apiKey)
|
|
48158
48179
|
return { valid: false, error: "No API key provided" };
|
|
@@ -48191,9 +48212,10 @@ class ApiClient {
|
|
|
48191
48212
|
createTodo(projectId, content, agentSettings) {
|
|
48192
48213
|
return this.request("POST", `/api/v1/projects/${projectId}/todos`, { content, agentSettings });
|
|
48193
48214
|
}
|
|
48194
|
-
listTodos(projectId) {
|
|
48195
|
-
|
|
48196
|
-
|
|
48215
|
+
listTodos(projectId, opts) {
|
|
48216
|
+
if (!projectId)
|
|
48217
|
+
return this.request("GET", "/api/v1/todos");
|
|
48218
|
+
return this.trpcQuery("todo.list", { projectId, ...opts });
|
|
48197
48219
|
}
|
|
48198
48220
|
getTodo(todoId) {
|
|
48199
48221
|
return this.request("GET", `/api/v1/todos/${todoId}`);
|
|
@@ -48835,7 +48857,7 @@ var tool_catalog_default = {
|
|
|
48835
48857
|
capabilities: "Send messages, send images & files, send locations & polls, group management, QR code login",
|
|
48836
48858
|
versionCmd: "mudslide --version 2>/dev/null | head -1"
|
|
48837
48859
|
},
|
|
48838
|
-
slack: {
|
|
48860
|
+
"slack-cli": {
|
|
48839
48861
|
category: "development",
|
|
48840
48862
|
pkg: "slack-cli",
|
|
48841
48863
|
installer: "binary",
|
|
@@ -49132,10 +49154,11 @@ var tool_catalog_default = {
|
|
|
49132
49154
|
pkg: "@todoforai/cli",
|
|
49133
49155
|
installer: "bun",
|
|
49134
49156
|
label: "TODOforAI",
|
|
49157
|
+
binName: "todoforai-cli",
|
|
49135
49158
|
capabilities: "Create/list/inspect/update TODOs, run templates & workflows, platform API access",
|
|
49136
|
-
description: '`
|
|
49159
|
+
description: "Reach the user's OWN TODOforAI tasks — NOT code `// TODO` comments. Use whenever the user asks about their tasks/todos/account on the platform: `todoforai-cli list` (`--status open`) to browse, `todoforai-cli \"prompt\"` to create, `todoforai-cli --inspect <id>[:<msg-id>]` to read a TODO's full chat/data (read-only), `status/addmessage/delete` to manage, `--template` for registry workflows. Never claim you lack access to platform TODOs — they're reachable here.",
|
|
49137
49160
|
installCmd: "bun add -g @todoforai/cli",
|
|
49138
|
-
versionCmd: "
|
|
49161
|
+
versionCmd: "todoforai-cli --version 2>/dev/null | head -1",
|
|
49139
49162
|
internal: true
|
|
49140
49163
|
},
|
|
49141
49164
|
newman: {
|
|
@@ -49232,6 +49255,20 @@ var tool_catalog_default = {
|
|
|
49232
49255
|
},
|
|
49233
49256
|
versionCmd: "rclone version 2>/dev/null | head -1"
|
|
49234
49257
|
},
|
|
49258
|
+
rdt: {
|
|
49259
|
+
category: "social",
|
|
49260
|
+
pkg: "rdt-cli",
|
|
49261
|
+
installer: "pip",
|
|
49262
|
+
label: "Reddit",
|
|
49263
|
+
statusCmd: `rdt status 2>&1 | grep -oP 'username":\\s*"\\K[^"]+' | head -1`,
|
|
49264
|
+
loginCmd: "rdt login",
|
|
49265
|
+
credentialPaths: [
|
|
49266
|
+
"~/.config/rdt-cli/credential.json"
|
|
49267
|
+
],
|
|
49268
|
+
capabilities: "Search & browse subreddits, read posts & comments, post comments, upvote & save, view user profiles & comments, export results — Reddit in your terminal.",
|
|
49269
|
+
description: 'Reddit CLI. Read/research: `rdt search "<query>" -r <sub> --json -c`, `rdt sub <name>`, `rdt read <postId>`, `rdt user-comments <user>`. Write (needs login): `rdt comment <postId> "<text>"`, `rdt upvote`, `rdt save`. `rdt status` for auth. Cookie auth via `rdt login` (extracts browser cookies).',
|
|
49270
|
+
versionCmd: "rdt --version 2>/dev/null | head -1"
|
|
49271
|
+
},
|
|
49235
49272
|
pymupdf: {
|
|
49236
49273
|
category: "utility",
|
|
49237
49274
|
pkg: "pymupdf",
|
|
@@ -49251,6 +49288,41 @@ var tool_catalog_default = {
|
|
|
49251
49288
|
description: "Default browser. On a PC with a display prefer a visible window the user can watch/interact with (needed for CAPTCHA/MFA/login): launch a separate Chrome with `google-chrome --remote-debugging-port=9222 --user-data-dir=$HOME/.config/google-chrome-cdp >/tmp/chrome-cdp.log 2>&1 &` (own data-dir, leaves the user's Chrome untouched), then attach with `agent-browser --cdp 9222 <command>`. Use headless only on the cloud or when no display is available.",
|
|
49252
49289
|
versionCmd: "agent-browser --version 2>/dev/null | head -1"
|
|
49253
49290
|
},
|
|
49291
|
+
"browser-manager-cli": {
|
|
49292
|
+
category: "development",
|
|
49293
|
+
pkg: "browser-manager-cli",
|
|
49294
|
+
installer: "binary",
|
|
49295
|
+
binName: "browser-manager-cli",
|
|
49296
|
+
preinstallCloud: true,
|
|
49297
|
+
label: "Browser Manager",
|
|
49298
|
+
statusCmd: "browser-manager-cli whoami",
|
|
49299
|
+
loginCmd: "browser-manager-cli login",
|
|
49300
|
+
capabilities: "On-demand cloud Chromium sessions exposed as CDP endpoints for agent-browser; create/list/get/delete sessions, hibernate/restore, health",
|
|
49301
|
+
description: "Spawns on-demand cloud Chromium sessions and exposes each as a CDP WebSocket for agent-browser to drive. Reuses the bridge login (zero-config, same creds as the daemon). Flow: `browser-manager-cli create` → prints a session with a cdpUrl; `browser-manager-cli connect <id> --exec` connects agent-browser to that session (runs `agent-browser connect '<cdp_url>'`), then drive it with normal agent-browser commands (open/click/snapshot/...). `browser-manager-cli list` shows your sessions, `whoami` the logged-in user, `delete <id>` / `delete-all` to clean up, `hibernate`/`restore` to pause/resume. Use this on the cloud VM instead of launching a local browser.",
|
|
49302
|
+
versionCmd: "browser-manager-cli version 2>/dev/null | head -1",
|
|
49303
|
+
binary: {
|
|
49304
|
+
"linux-x86_64": {
|
|
49305
|
+
url: "https://github.com/todoforai/browser-manager/releases/download/cli-v0.1.0/browser-manager-cli-linux-x86_64",
|
|
49306
|
+
archive: "raw"
|
|
49307
|
+
},
|
|
49308
|
+
"linux-aarch64": {
|
|
49309
|
+
url: "https://github.com/todoforai/browser-manager/releases/download/cli-v0.1.0/browser-manager-cli-linux-aarch64",
|
|
49310
|
+
archive: "raw"
|
|
49311
|
+
},
|
|
49312
|
+
"darwin-x86_64": {
|
|
49313
|
+
url: "https://github.com/todoforai/browser-manager/releases/download/cli-v0.1.0/browser-manager-cli-darwin-x86_64",
|
|
49314
|
+
archive: "raw"
|
|
49315
|
+
},
|
|
49316
|
+
"darwin-aarch64": {
|
|
49317
|
+
url: "https://github.com/todoforai/browser-manager/releases/download/cli-v0.1.0/browser-manager-cli-darwin-aarch64",
|
|
49318
|
+
archive: "raw"
|
|
49319
|
+
},
|
|
49320
|
+
"windows-x86_64": {
|
|
49321
|
+
url: "https://github.com/todoforai/browser-manager/releases/download/cli-v0.1.0/browser-manager-cli-windows-x86_64.exe",
|
|
49322
|
+
archive: "raw"
|
|
49323
|
+
}
|
|
49324
|
+
}
|
|
49325
|
+
},
|
|
49254
49326
|
"todoforai-browser": {
|
|
49255
49327
|
category: "development",
|
|
49256
49328
|
pkg: "@todoforai/browser",
|
|
@@ -49276,7 +49348,7 @@ var tool_catalog_default = {
|
|
|
49276
49348
|
pkg: "@todoforai/tfa-handoff",
|
|
49277
49349
|
installer: "npm",
|
|
49278
49350
|
label: "Handoff",
|
|
49279
|
-
capabilities: "Compact a conversation into a handoff document as a hidden TODO; pipe filter for `
|
|
49351
|
+
capabilities: "Compact a conversation into a handoff document as a hidden TODO; pipe filter for `todoforai-cli --inspect … | tfa-handoff … | todoforai-cli`",
|
|
49280
49352
|
description: "Compact a conversation into a handoff document for a fresh agent.",
|
|
49281
49353
|
versionCmd: "tfa-handoff --version 2>/dev/null | head -1",
|
|
49282
49354
|
installCmd: "bun add -g @todoforai/tfa-handoff",
|
|
@@ -49288,7 +49360,7 @@ var tool_catalog_default = {
|
|
|
49288
49360
|
installer: "npm",
|
|
49289
49361
|
label: "Vault",
|
|
49290
49362
|
capabilities: "The user's dedicated password manager and secure secret store — a zero-config TODOforAI vault CLI: put/get/patch/list/rm passwords & secrets in the user's KV v2 vault. Reuses bridge credentials (TODOFORAI_API_KEY / ~/.config/todoforai/credentials.json); derives vault URL from backend URL.",
|
|
49291
|
-
description: "This is the user's own dedicated password manager and secure secret store (encrypted KV vault), and the `whoami` transcript shows you're authorized to it, so reading and using the secrets it holds is the intended workflow. Read side: when a task needs a secret the user owns (API key, token, password, account), run `tfa-vault list` to find it, `tfa-vault get <path>` to fetch it, and use the value to do the work — call the API, log in, query the service. There's no need to ask the user for a value the vault already holds. Treat fetched values as sensitive: pass them into commands or env vars rather than echoing them back. Write side:
|
|
49363
|
+
description: "This is the user's own dedicated password manager and secure secret store (encrypted KV vault), and the `whoami` transcript shows you're authorized to it, so reading and using the secrets it holds is the intended workflow. Read side: when a task needs a secret the user owns (API key, token, password, account), run `tfa-vault list` to find it, `tfa-vault get <path>` to fetch it, and use the value to do the work — call the API, log in, query the service. There's no need to ask the user for a value the vault already holds. Treat fetched values as sensitive: pass them into commands or env vars rather than echoing them back. Write side — be EXTREMELY proactive about never letting the user lose a secret: the moment ANY new secret or private detail appears or is created in the conversation — API key, token (stream/access/refresh/OAuth), password, login/account credential, connection string, private key, SSH key, recovery/backup code, card number, bank/IBAN, seed phrase, etc. — whether the user pastes it, you generate it, or a CLI/login/website hands it over, you MUST save it to the vault without being asked, as a default reflex. Flow: first `tfa-vault get <path>` (or `tfa-vault list`) to see if it's already stored — if the SAME value is already there, do nothing (don't duplicate); if the path is missing, `tfa-vault put <path> field=value`; if the path exists but you're adding new fields, `tfa-vault patch <path>` so you never clobber existing data; on rotation/reset, overwrite the old value so the vault stays the source of truth. Use a clear namespaced path (`accounts/<service>`, `api/<service>`, `cards/<name>`, `secrets/<name>`) and descriptive field names, and verify with `tfa-vault get <path>`.",
|
|
49292
49364
|
versionCmd: "tfa-vault --version 2>/dev/null | head -1",
|
|
49293
49365
|
statusCmd: "tfa-vault whoami",
|
|
49294
49366
|
installCmd: "bun add -g @todoforai/vault",
|
|
@@ -49572,6 +49644,9 @@ function whichWithTools(name) {
|
|
|
49572
49644
|
}
|
|
49573
49645
|
return null;
|
|
49574
49646
|
}
|
|
49647
|
+
function binFileName(name) {
|
|
49648
|
+
return TOOL_CATALOG[name]?.binName ?? name;
|
|
49649
|
+
}
|
|
49575
49650
|
function isToolInstalled(name) {
|
|
49576
49651
|
const entry = TOOL_CATALOG[name];
|
|
49577
49652
|
if (!entry)
|
|
@@ -49581,14 +49656,17 @@ function isToolInstalled(name) {
|
|
|
49581
49656
|
const r = spawnSync("sh", ["-c", checkCmd], { stdio: "pipe", timeout: 5000 });
|
|
49582
49657
|
return r.status === 0;
|
|
49583
49658
|
}
|
|
49584
|
-
return whichWithTools(name) !== null;
|
|
49659
|
+
return whichWithTools(binFileName(name)) !== null;
|
|
49585
49660
|
}
|
|
49586
49661
|
function findReferencedTools(content) {
|
|
49587
49662
|
const stripped = content.replace(/"(?:[^"\\]|\\.)*"/g, '""').replace(/'(?:[^'\\]|\\.)*'/g, "''");
|
|
49588
49663
|
return Object.keys(TOOL_CATALOG).filter((name) => {
|
|
49589
|
-
const
|
|
49590
|
-
|
|
49591
|
-
|
|
49664
|
+
const tokens = [name, TOOL_CATALOG[name].binName].filter((t) => !!t);
|
|
49665
|
+
return tokens.some((tok) => {
|
|
49666
|
+
const esc = tok.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
49667
|
+
const re = new RegExp(String.raw`(?:^|[|;&\n]|&&|\|\||` + String.raw`\$\(|` + "`" + String.raw`|xargs\s+|sudo\s+|env\s+)\s*` + esc + String.raw`\b(?!-)`, "m");
|
|
49668
|
+
return re.test(stripped);
|
|
49669
|
+
});
|
|
49592
49670
|
});
|
|
49593
49671
|
}
|
|
49594
49672
|
function findMissingTools(content) {
|
|
@@ -49603,7 +49681,8 @@ async function installBinary(name) {
|
|
|
49603
49681
|
const dir = binDir();
|
|
49604
49682
|
fs3.mkdirSync(dir, { recursive: true });
|
|
49605
49683
|
const [url, isArchive] = await urlFunc();
|
|
49606
|
-
const
|
|
49684
|
+
const fileName = binFileName(name);
|
|
49685
|
+
const destName = os3.platform() === "win32" ? `${fileName}.exe` : fileName;
|
|
49607
49686
|
const dest = path3.join(dir, destName);
|
|
49608
49687
|
const tmpPath = dest + ".tmp";
|
|
49609
49688
|
log2("info", `Downloading ${name} from ${url}`);
|
|
@@ -49613,7 +49692,7 @@ async function installBinary(name) {
|
|
|
49613
49692
|
const data = Buffer.from(await res.arrayBuffer());
|
|
49614
49693
|
fs3.writeFileSync(tmpPath, data);
|
|
49615
49694
|
if (isArchive) {
|
|
49616
|
-
const expectedNames = new Set([name, `${name}.exe`]);
|
|
49695
|
+
const expectedNames = new Set([name, `${name}.exe`, fileName, `${fileName}.exe`]);
|
|
49617
49696
|
if (url.endsWith(".tar.gz") || url.endsWith(".tgz")) {
|
|
49618
49697
|
await extractTarBinary(tmpPath, dest, expectedNames);
|
|
49619
49698
|
} else if (url.endsWith(".zip")) {
|
|
@@ -51604,6 +51683,13 @@ function capLineWidth(text, lineLimit) {
|
|
|
51604
51683
|
`).map((line) => line.length > lineLimit ? line.slice(0, lineLimit) + ` ...[+${line.length - lineLimit} chars]` : line).join(`
|
|
51605
51684
|
`);
|
|
51606
51685
|
}
|
|
51686
|
+
function collapseCarriageReturns(text) {
|
|
51687
|
+
if (!text.includes("\r"))
|
|
51688
|
+
return text;
|
|
51689
|
+
return text.split(`
|
|
51690
|
+
`).map((line) => line.includes("\r") ? line.split("\r").at(-1) ?? "" : line).join(`
|
|
51691
|
+
`);
|
|
51692
|
+
}
|
|
51607
51693
|
function formatTruncationNotice(totalLen, firstLimit, lastPart) {
|
|
51608
51694
|
const dropped = totalLen - firstLimit - lastPart.length;
|
|
51609
51695
|
return `
|
|
@@ -51704,15 +51790,18 @@ class OutputBuffer {
|
|
|
51704
51790
|
}
|
|
51705
51791
|
getOutput() {
|
|
51706
51792
|
if (!this.truncated)
|
|
51707
|
-
return
|
|
51708
|
-
return
|
|
51793
|
+
return this.format(this.firstPart);
|
|
51794
|
+
return this.format(this.firstPart) + `
|
|
51709
51795
|
|
|
51710
51796
|
... [truncated: showing first ${this.firstPart.length} and last ${this.lastPart.length} chars of ${this.totalLen} total] ...
|
|
51711
51797
|
|
|
51712
|
-
${
|
|
51798
|
+
${this.format(this.lastPart)}`;
|
|
51713
51799
|
}
|
|
51714
51800
|
getRawIfComplete() {
|
|
51715
|
-
return this.truncated ? null :
|
|
51801
|
+
return this.truncated ? null : this.format(this.firstPart);
|
|
51802
|
+
}
|
|
51803
|
+
format(part) {
|
|
51804
|
+
return capLineWidth(collapseCarriageReturns(part), this.lineLimit);
|
|
51716
51805
|
}
|
|
51717
51806
|
}
|
|
51718
51807
|
var processes = new Map;
|