@todoforai/edge 0.13.19 → 0.13.20
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 +113 -162
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -48145,7 +48145,7 @@ class ApiClient {
|
|
|
48145
48145
|
}
|
|
48146
48146
|
async request(method, endpoint, body) {
|
|
48147
48147
|
const url = `${this.apiUrl}${endpoint}`;
|
|
48148
|
-
const opts = { method, headers: this.headers };
|
|
48148
|
+
const opts = { method, headers: this.headers, signal: AbortSignal.timeout(30000) };
|
|
48149
48149
|
if (body)
|
|
48150
48150
|
opts.body = JSON.stringify(body);
|
|
48151
48151
|
const res = await fetch(url, opts);
|
|
@@ -48772,7 +48772,6 @@ var tool_catalog_default = {
|
|
|
48772
48772
|
"~/.zele/sqlite.db"
|
|
48773
48773
|
],
|
|
48774
48774
|
capabilities: "Read inbox, search/send/reply email, email addresses — multi-account Gmail, OAuth browser login for setup.",
|
|
48775
|
-
description: "Use for anything Gmail: reading the user's inbox, searching mail, sending or replying to email. Multi-account, OAuth login via `zele login`.",
|
|
48776
48775
|
versionCmd: "zele --version 2>/dev/null | head -1"
|
|
48777
48776
|
},
|
|
48778
48777
|
xurl: {
|
|
@@ -48786,7 +48785,7 @@ var tool_catalog_default = {
|
|
|
48786
48785
|
"~/.xurl"
|
|
48787
48786
|
],
|
|
48788
48787
|
capabilities: "Post tweets, reply & quote, read timelines, search tweets, like & repost, follow/unfollow, DMs, media uploads",
|
|
48789
|
-
description: "
|
|
48788
|
+
description: "Authenticated raw X API access via `xurl <method> <path>`; login `xurl auth oauth2`.",
|
|
48790
48789
|
versionCmd: "xurl --version 2>/dev/null | head -1"
|
|
48791
48790
|
},
|
|
48792
48791
|
"tiktok-uploader": {
|
|
@@ -48799,7 +48798,6 @@ var tool_catalog_default = {
|
|
|
48799
48798
|
"~/.tiktok/cookies.txt"
|
|
48800
48799
|
],
|
|
48801
48800
|
capabilities: "Upload videos, batch uploads, schedule posts, custom covers, hashtags & mentions",
|
|
48802
|
-
description: "Upload videos to TikTok, schedule posts, set covers and hashtags.",
|
|
48803
48801
|
versionCmd: "pip show tiktok-uploader 2>/dev/null | grep -oP 'Version: \\K.*'"
|
|
48804
48802
|
},
|
|
48805
48803
|
instagrapi: {
|
|
@@ -48808,7 +48806,6 @@ var tool_catalog_default = {
|
|
|
48808
48806
|
installer: "pip",
|
|
48809
48807
|
label: "Instagram",
|
|
48810
48808
|
capabilities: "Upload photos & reels, post stories, send DMs, like & comment, manage followers",
|
|
48811
|
-
description: "Instagram automation: upload photos/reels, stories, DMs, likes, follower management.",
|
|
48812
48809
|
versionCmd: "pip show instagrapi 2>/dev/null | grep -oP 'Version: \\K.*'"
|
|
48813
48810
|
},
|
|
48814
48811
|
mudslide: {
|
|
@@ -48822,7 +48819,6 @@ var tool_catalog_default = {
|
|
|
48822
48819
|
"~/.local/share/mudslide"
|
|
48823
48820
|
],
|
|
48824
48821
|
capabilities: "Send messages, send images & files, send locations & polls, group management, QR code login",
|
|
48825
|
-
description: "Use to send WhatsApp messages/files/media/locations/polls from CLI. QR-code login via `mudslide login`.",
|
|
48826
48822
|
versionCmd: "mudslide --version 2>/dev/null | head -1"
|
|
48827
48823
|
},
|
|
48828
48824
|
slack: {
|
|
@@ -48836,7 +48832,7 @@ var tool_catalog_default = {
|
|
|
48836
48832
|
"~/.slack/credentials.json"
|
|
48837
48833
|
],
|
|
48838
48834
|
capabilities: "Build & deploy Slack apps, manage workspaces & triggers, run datastore queries, tail logs — official Slack CLI.",
|
|
48839
|
-
description: "
|
|
48835
|
+
description: "`slack-cli login` to auth. Invoked as `slack-cli` to avoid colliding with the Slack desktop app's `slack` binary.",
|
|
48840
48836
|
versionCmd: "slack-cli version 2>/dev/null | head -1",
|
|
48841
48837
|
binName: "slack-cli",
|
|
48842
48838
|
binary: {
|
|
@@ -48877,18 +48873,8 @@ var tool_catalog_default = {
|
|
|
48877
48873
|
"~/.config/telegram-send/telegram-send.conf"
|
|
48878
48874
|
],
|
|
48879
48875
|
capabilities: "Send messages, send files & images, send video & audio, Markdown/HTML formatting, channel & group support",
|
|
48880
|
-
description: "Send Telegram messages and files from CLI via a bot.",
|
|
48881
48876
|
versionCmd: "telegram-send --version 2>/dev/null | head -1"
|
|
48882
48877
|
},
|
|
48883
|
-
"apollo-api": {
|
|
48884
|
-
category: "marketing",
|
|
48885
|
-
pkg: "@todoforai/apollo-api",
|
|
48886
|
-
installer: "npm",
|
|
48887
|
-
label: "Apollo",
|
|
48888
|
-
capabilities: "Lead search & enrichment, email sequences, CRM sync",
|
|
48889
|
-
description: "Use for B2B prospecting: search Apollo's people/company DB, enrich leads with emails/titles/companies, manage sequences and CRM data. Needs APOLLO_API_KEY.",
|
|
48890
|
-
versionCmd: "apollo-api --version 2>/dev/null | head -1"
|
|
48891
|
-
},
|
|
48892
48878
|
"meta-ads": {
|
|
48893
48879
|
category: "marketing",
|
|
48894
48880
|
pkg: "meta-ads",
|
|
@@ -48896,7 +48882,6 @@ var tool_catalog_default = {
|
|
|
48896
48882
|
label: "Meta Ads",
|
|
48897
48883
|
statusCmd: "meta auth status 2>&1",
|
|
48898
48884
|
capabilities: "Meta/Facebook & Instagram ad campaigns: campaigns/adsets/ads CRUD, insights & reporting, catalog/product-feed/product-set/product-item, ad creatives, datasets (pixels), pages — Marketing API via the official `meta` CLI.",
|
|
48899
|
-
description: "Manage Meta/Facebook & Instagram ad campaigns, insights, creatives, and catalogs.",
|
|
48900
48885
|
versionCmd: "meta --version 2>/dev/null | head -1"
|
|
48901
48886
|
},
|
|
48902
48887
|
"elevenlabs-api": {
|
|
@@ -48904,8 +48889,7 @@ var tool_catalog_default = {
|
|
|
48904
48889
|
pkg: "@todoforai/elevenlabs-api",
|
|
48905
48890
|
installer: "npm",
|
|
48906
48891
|
label: "ElevenLabs",
|
|
48907
|
-
capabilities: "Text-to-speech, voice cloning, multiple languages",
|
|
48908
|
-
description: "Use to generate speech audio from text, clone voices, or list voices. Needs ELEVENLABS_API_KEY.",
|
|
48892
|
+
capabilities: "Text-to-speech, voice cloning, multiple languages. Needs ELEVENLABS_API_KEY.",
|
|
48909
48893
|
versionCmd: "elevenlabs-api --version 2>/dev/null | head -1"
|
|
48910
48894
|
},
|
|
48911
48895
|
"codex-imagegen-api": {
|
|
@@ -48914,7 +48898,6 @@ var tool_catalog_default = {
|
|
|
48914
48898
|
installer: "npm",
|
|
48915
48899
|
label: "Image Gen",
|
|
48916
48900
|
capabilities: "AI image generation & editing via TODOFORAI backend (gpt-image)",
|
|
48917
|
-
description: "Generate or edit images with AI.",
|
|
48918
48901
|
versionCmd: "codex-imagegen-api --version 2>/dev/null | head -1"
|
|
48919
48902
|
},
|
|
48920
48903
|
"suno-api": {
|
|
@@ -48922,8 +48905,7 @@ var tool_catalog_default = {
|
|
|
48922
48905
|
pkg: "@todoforai/suno-api",
|
|
48923
48906
|
installer: "npm",
|
|
48924
48907
|
label: "Suno",
|
|
48925
|
-
capabilities: "AI music generation, custom lyrics, multiple genres",
|
|
48926
|
-
description: "Use to generate music/songs from a prompt or custom lyrics. Needs SUNO_API_KEY.",
|
|
48908
|
+
capabilities: "AI music generation, custom lyrics, multiple genres. Needs SUNO_API_KEY.",
|
|
48927
48909
|
versionCmd: "suno-api --version 2>/dev/null | head -1"
|
|
48928
48910
|
},
|
|
48929
48911
|
ntn: {
|
|
@@ -48937,7 +48919,6 @@ var tool_catalog_default = {
|
|
|
48937
48919
|
"~/.config/notion"
|
|
48938
48920
|
],
|
|
48939
48921
|
capabilities: "Official Notion CLI: workspace-wide OAuth login, raw API calls (`ntn api <path>`), page/datasource management, file uploads, Workers deploy.",
|
|
48940
|
-
description: "Read, create, and update Notion pages and databases.",
|
|
48941
48922
|
versionCmd: "ntn --version 2>/dev/null | head -1"
|
|
48942
48923
|
},
|
|
48943
48924
|
"perplexity-api": {
|
|
@@ -48946,7 +48927,6 @@ var tool_catalog_default = {
|
|
|
48946
48927
|
installer: "npm",
|
|
48947
48928
|
label: "Perplexity",
|
|
48948
48929
|
capabilities: "AI-powered web search, chat completions, async chat, embeddings and agent runs",
|
|
48949
|
-
description: "Web-grounded AI search with citations. Use when you need fresh information beyond training cutoff.",
|
|
48950
48930
|
versionCmd: "perplexity-api --version 2>/dev/null | head -1"
|
|
48951
48931
|
},
|
|
48952
48932
|
gh: {
|
|
@@ -48961,7 +48941,7 @@ var tool_catalog_default = {
|
|
|
48961
48941
|
"~/.config/gh/hosts.yml"
|
|
48962
48942
|
],
|
|
48963
48943
|
capabilities: "Repos, PRs & issues, actions & releases, gists & SSH keys",
|
|
48964
|
-
description: "
|
|
48944
|
+
description: "Prefer `gh` over raw GitHub API calls.",
|
|
48965
48945
|
versionCmd: "gh --version 2>/dev/null | head -1"
|
|
48966
48946
|
},
|
|
48967
48947
|
glab: {
|
|
@@ -48975,7 +48955,7 @@ var tool_catalog_default = {
|
|
|
48975
48955
|
"~/.config/glab-cli/config.yml"
|
|
48976
48956
|
],
|
|
48977
48957
|
capabilities: "Repos, MRs & issues, CI/CD pipelines, releases",
|
|
48978
|
-
description: "
|
|
48958
|
+
description: "GitLab equivalent of `gh`.",
|
|
48979
48959
|
versionCmd: "glab --version 2>/dev/null | head -1"
|
|
48980
48960
|
},
|
|
48981
48961
|
vercel: {
|
|
@@ -48989,7 +48969,7 @@ var tool_catalog_default = {
|
|
|
48989
48969
|
"~/.local/share/com.vercel.cli/auth.json"
|
|
48990
48970
|
],
|
|
48991
48971
|
capabilities: "Deploy & preview, environment variables, domain management",
|
|
48992
|
-
description: "
|
|
48972
|
+
description: "`vercel deploy`; manage env vars, domains, preview URLs.",
|
|
48993
48973
|
versionCmd: "vercel --version 2>/dev/null | head -1"
|
|
48994
48974
|
},
|
|
48995
48975
|
netlify: {
|
|
@@ -49003,7 +48983,7 @@ var tool_catalog_default = {
|
|
|
49003
48983
|
"~/.netlify/config.json"
|
|
49004
48984
|
],
|
|
49005
48985
|
capabilities: "Deploy & preview, serverless functions, forms & identity",
|
|
49006
|
-
description: "
|
|
48986
|
+
description: "`netlify deploy --prod` for production; manage env vars, forms, identity.",
|
|
49007
48987
|
versionCmd: "netlify --version 2>/dev/null | head -1"
|
|
49008
48988
|
},
|
|
49009
48989
|
firebase: {
|
|
@@ -49017,7 +48997,7 @@ var tool_catalog_default = {
|
|
|
49017
48997
|
"~/.config/configstore/firebase-tools.json"
|
|
49018
48998
|
],
|
|
49019
48999
|
capabilities: "Hosting & deploy, Firestore & Realtime DB, auth & functions",
|
|
49020
|
-
description: "
|
|
49000
|
+
description: "Deploy hosting/functions, manage Firestore/RTDB rules and data, auth users, emulators.",
|
|
49021
49001
|
versionCmd: "firebase --version 2>/dev/null | head -1"
|
|
49022
49002
|
},
|
|
49023
49003
|
wrangler: {
|
|
@@ -49031,7 +49011,7 @@ var tool_catalog_default = {
|
|
|
49031
49011
|
"~/.config/.wrangler/config/default.toml"
|
|
49032
49012
|
],
|
|
49033
49013
|
capabilities: "Workers & Pages deploy, KV & D1 storage, R2 & Queues",
|
|
49034
|
-
description: "
|
|
49014
|
+
description: "Tail logs with `wrangler tail`. Use `cloudflared` for tunnels.",
|
|
49035
49015
|
versionCmd: "wrangler --version 2>/dev/null | head -1"
|
|
49036
49016
|
},
|
|
49037
49017
|
stripe: {
|
|
@@ -49045,7 +49025,7 @@ var tool_catalog_default = {
|
|
|
49045
49025
|
"~/.config/stripe/config.toml"
|
|
49046
49026
|
],
|
|
49047
49027
|
capabilities: "Payments & subscriptions, webhook testing, invoice management",
|
|
49048
|
-
description: "
|
|
49028
|
+
description: "`stripe listen` forwards webhooks locally; `stripe get/post /v1/...` for raw API.",
|
|
49049
49029
|
versionCmd: "stripe --version 2>/dev/null | head -1"
|
|
49050
49030
|
},
|
|
49051
49031
|
flyctl: {
|
|
@@ -49059,7 +49039,7 @@ var tool_catalog_default = {
|
|
|
49059
49039
|
"~/.fly/config.yml"
|
|
49060
49040
|
],
|
|
49061
49041
|
capabilities: "Deploy containers globally, Postgres & volumes, auto-scaling",
|
|
49062
|
-
description: "
|
|
49042
|
+
description: "`flyctl deploy` from app dir; manage Postgres/volumes/machines/secrets.",
|
|
49063
49043
|
versionCmd: "flyctl version 2>/dev/null | head -1"
|
|
49064
49044
|
},
|
|
49065
49045
|
supabase: {
|
|
@@ -49073,7 +49053,7 @@ var tool_catalog_default = {
|
|
|
49073
49053
|
"~/.config/supabase/access-token"
|
|
49074
49054
|
],
|
|
49075
49055
|
capabilities: "Postgres database, auth & storage, edge functions",
|
|
49076
|
-
description: "
|
|
49056
|
+
description: "Link to cloud project; runs/migrates local Postgres.",
|
|
49077
49057
|
versionCmd: "supabase --version 2>/dev/null | head -1"
|
|
49078
49058
|
},
|
|
49079
49059
|
railway: {
|
|
@@ -49087,7 +49067,7 @@ var tool_catalog_default = {
|
|
|
49087
49067
|
"~/.railway/config.json"
|
|
49088
49068
|
],
|
|
49089
49069
|
capabilities: "Deploy apps & databases, environment management, auto-scaling",
|
|
49090
|
-
description: "
|
|
49070
|
+
description: "`railway up` to deploy current dir.",
|
|
49091
49071
|
versionCmd: "railway --version 2>/dev/null | head -1"
|
|
49092
49072
|
},
|
|
49093
49073
|
shopify: {
|
|
@@ -49100,16 +49080,23 @@ var tool_catalog_default = {
|
|
|
49100
49080
|
"~/.config/shopify/config.json"
|
|
49101
49081
|
],
|
|
49102
49082
|
capabilities: "Theme development, app scaffolding, store management",
|
|
49103
|
-
description: "Use for Shopify dev: scaffold/develop themes and apps, push/pull themes, run dev server against a store.",
|
|
49104
49083
|
versionCmd: "shopify version 2>/dev/null | head -1"
|
|
49105
49084
|
},
|
|
49085
|
+
"shop-app": {
|
|
49086
|
+
category: "ecommerce",
|
|
49087
|
+
pkg: "@todoforai/shop-app",
|
|
49088
|
+
installer: "npm",
|
|
49089
|
+
label: "Shop",
|
|
49090
|
+
capabilities: "Product search & price comparison across Shopify stores",
|
|
49091
|
+
description: "Shop.app product search across Shopify stores (no auth). `shop-app search '<query>' --ships-to HU -n 10` returns products with price, rating, URL, variants. `shop-app similar <variantId>` for lookalikes.",
|
|
49092
|
+
versionCmd: "shop-app --version 2>/dev/null | head -1"
|
|
49093
|
+
},
|
|
49106
49094
|
"datadog-ci": {
|
|
49107
49095
|
category: "monitoring",
|
|
49108
49096
|
pkg: "@datadog/datadog-ci",
|
|
49109
49097
|
installer: "npm",
|
|
49110
49098
|
label: "Datadog",
|
|
49111
|
-
capabilities: "CI test visibility, sourcemap uploads, deployment tracking",
|
|
49112
|
-
description: "Use in CI to upload test results/sourcemaps/coverage to Datadog and mark deployments. Needs DATADOG_API_KEY.",
|
|
49099
|
+
capabilities: "CI test visibility, sourcemap uploads, deployment tracking. Needs DATADOG_API_KEY.",
|
|
49113
49100
|
versionCmd: "datadog-ci version 2>/dev/null | head -1"
|
|
49114
49101
|
},
|
|
49115
49102
|
"sentry-cli": {
|
|
@@ -49123,7 +49110,7 @@ var tool_catalog_default = {
|
|
|
49123
49110
|
"~/.sentryclirc"
|
|
49124
49111
|
],
|
|
49125
49112
|
capabilities: "Release management, sourcemap uploads, error monitoring",
|
|
49126
|
-
description: "
|
|
49113
|
+
description: "`sentry-cli releases new <version>`.",
|
|
49127
49114
|
versionCmd: "sentry-cli --version 2>/dev/null | head -1"
|
|
49128
49115
|
},
|
|
49129
49116
|
todoai: {
|
|
@@ -49132,7 +49119,7 @@ var tool_catalog_default = {
|
|
|
49132
49119
|
installer: "bun",
|
|
49133
49120
|
label: "TODOforAI",
|
|
49134
49121
|
capabilities: "Create/list/inspect/update TODOs, run templates & workflows, platform API access",
|
|
49135
|
-
description:
|
|
49122
|
+
description: '`todoai list` (`--status open`) to browse, `todoai "prompt"` to create, `--inspect <id>` to read a chat log, `status/addmessage/delete` to manage, `--template` for registry workflows.',
|
|
49136
49123
|
installCmd: "bun add -g @todoforai/cli",
|
|
49137
49124
|
versionCmd: "todoai --version 2>/dev/null | head -1",
|
|
49138
49125
|
internal: true
|
|
@@ -49143,7 +49130,7 @@ var tool_catalog_default = {
|
|
|
49143
49130
|
installer: "npm",
|
|
49144
49131
|
label: "Postman",
|
|
49145
49132
|
capabilities: "Run API test collections, CI/CD integration, HTML reports",
|
|
49146
|
-
description: "
|
|
49133
|
+
description: "`newman run <collection.json> -e <env.json>`.",
|
|
49147
49134
|
versionCmd: "newman --version 2>/dev/null | head -1"
|
|
49148
49135
|
},
|
|
49149
49136
|
curl: {
|
|
@@ -49164,22 +49151,20 @@ var tool_catalog_default = {
|
|
|
49164
49151
|
installer: "binary",
|
|
49165
49152
|
label: "Tunnel",
|
|
49166
49153
|
capabilities: "Tunnel to localhost, expose local services, zero-trust access",
|
|
49167
|
-
description: "
|
|
49154
|
+
description: "`cloudflared tunnel --url http://localhost:<port>` prints a public https URL.",
|
|
49168
49155
|
versionCmd: "cloudflared --version 2>/dev/null | head -1"
|
|
49169
49156
|
},
|
|
49170
49157
|
vault: {
|
|
49171
49158
|
category: "security",
|
|
49172
49159
|
pkg: "vault",
|
|
49173
49160
|
installer: "binary",
|
|
49174
|
-
preinstallCloud: true,
|
|
49175
49161
|
label: "HashiCorp Vault",
|
|
49176
49162
|
statusCmd: "vault token lookup >/dev/null 2>&1 && echo authenticated",
|
|
49177
49163
|
loginCmd: "vault login",
|
|
49178
49164
|
credentialPaths: [
|
|
49179
49165
|
"~/.vault-token"
|
|
49180
49166
|
],
|
|
49181
|
-
capabilities: "Secrets management, dynamic credentials",
|
|
49182
|
-
description: "HashiCorp Vault CLI — only for Terraform/vals/ecosystem integrations that expect it. For all credential read/write tasks use `tfa-vault` instead. Needs VAULT_ADDR + VAULT_TOKEN.",
|
|
49167
|
+
capabilities: "Secrets management, dynamic credentials. Needs VAULT_ADDR + VAULT_TOKEN; for credential read/write use `tfa-vault` instead.",
|
|
49183
49168
|
versionCmd: "vault --version 2>/dev/null | head -1"
|
|
49184
49169
|
},
|
|
49185
49170
|
rclone: {
|
|
@@ -49194,7 +49179,6 @@ var tool_catalog_default = {
|
|
|
49194
49179
|
"~/.config/rclone/rclone.conf"
|
|
49195
49180
|
],
|
|
49196
49181
|
capabilities: "Access Google Drive, OneDrive, Dropbox, S3 and 40+ cloud providers. List, copy, sync, move, mount files as virtual filesystem (FUSE). Use 'rclone config create <name> <provider>' to connect (opens browser for OAuth).",
|
|
49197
|
-
description: "Access cloud storage (Google Drive, OneDrive, Dropbox, S3, 40+ providers). List, copy, sync, or mount files.",
|
|
49198
49182
|
subProviders: {
|
|
49199
49183
|
gdrive: {
|
|
49200
49184
|
label: "Google Drive",
|
|
@@ -49239,8 +49223,7 @@ var tool_catalog_default = {
|
|
|
49239
49223
|
pkg: "pymupdf",
|
|
49240
49224
|
installer: "pip",
|
|
49241
49225
|
label: "PDF",
|
|
49242
|
-
capabilities: "PDF text editing, extraction, merge, split",
|
|
49243
|
-
description: "Read, edit, merge, or split PDFs programmatically. Call via `python3 -c`.",
|
|
49226
|
+
capabilities: "PDF text editing, extraction, merge, split. Call via `python3 -c`.",
|
|
49244
49227
|
versionCmd: "python3 -c 'import pymupdf; print(pymupdf.__version__)' 2>/dev/null",
|
|
49245
49228
|
preinstallCloud: true
|
|
49246
49229
|
},
|
|
@@ -49251,16 +49234,16 @@ var tool_catalog_default = {
|
|
|
49251
49234
|
preinstallCloud: true,
|
|
49252
49235
|
label: "Browser",
|
|
49253
49236
|
capabilities: "Headless browser automation, web scraping, accessibility tree snapshots, screenshots, PDF generation",
|
|
49254
|
-
description: "
|
|
49237
|
+
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.",
|
|
49255
49238
|
versionCmd: "agent-browser --version 2>/dev/null | head -1"
|
|
49256
49239
|
},
|
|
49257
49240
|
"todoforai-browser": {
|
|
49258
49241
|
category: "development",
|
|
49259
49242
|
pkg: "@todoforai/browser",
|
|
49260
49243
|
installer: "npm",
|
|
49244
|
+
preinstallCloud: true,
|
|
49261
49245
|
label: "Browser (Extension)",
|
|
49262
49246
|
capabilities: "Browser automation via extension (non-headless), web scraping, accessibility tree snapshots, screenshots, PDF generation",
|
|
49263
|
-
description: "Drives the user's real browser via the extension. Use when the task needs the user's actual logged-in session, cookies, or MFA.",
|
|
49264
49247
|
versionCmd: `node -p "require(require('child_process').execSync('which todoforai-browser',{encoding:'utf8'}).trim().replace(/\\/dist\\/index\\.js$/, '/package.json')).version" 2>/dev/null`,
|
|
49265
49248
|
internal: true
|
|
49266
49249
|
},
|
|
@@ -49270,55 +49253,19 @@ var tool_catalog_default = {
|
|
|
49270
49253
|
installer: "npm",
|
|
49271
49254
|
label: "Sub-agent",
|
|
49272
49255
|
capabilities: "Spawn a TODO for AI sub-agent (FluidAgent) from the CLI; pipe stdin in, get an answer out",
|
|
49273
|
-
description: "Spawn a sub-agent for a focused task. Pipe context via stdin.",
|
|
49274
49256
|
versionCmd: "todoforai-subagent --version 2>/dev/null | head -1",
|
|
49275
49257
|
installCmd: "bun add -g @todoforai/subagent",
|
|
49276
49258
|
internal: true
|
|
49277
49259
|
},
|
|
49278
|
-
"
|
|
49279
|
-
category: "development",
|
|
49280
|
-
pkg: "@todoforai/summary",
|
|
49281
|
-
installer: "npm",
|
|
49282
|
-
label: "Summarize (Lite)",
|
|
49283
|
-
capabilities: "Summarize files or piped input via a sub-agent",
|
|
49284
|
-
description: "Summarize files or piped content via a sub-agent.",
|
|
49285
|
-
versionCmd: "todoforai-summary --version 2>/dev/null | head -1",
|
|
49286
|
-
installCmd: "bun add -g @todoforai/summary",
|
|
49287
|
-
internal: true
|
|
49288
|
-
},
|
|
49289
|
-
"tfa-explore": {
|
|
49260
|
+
"tfa-handoff": {
|
|
49290
49261
|
category: "development",
|
|
49291
|
-
pkg: "@todoforai/tfa-
|
|
49262
|
+
pkg: "@todoforai/tfa-handoff",
|
|
49292
49263
|
installer: "npm",
|
|
49293
|
-
label: "
|
|
49294
|
-
capabilities: "
|
|
49295
|
-
description: "
|
|
49296
|
-
versionCmd: "tfa-
|
|
49297
|
-
installCmd: "bun add -g @todoforai/tfa-
|
|
49298
|
-
preinstallCloud: true,
|
|
49299
|
-
internal: true
|
|
49300
|
-
},
|
|
49301
|
-
"tfa-review": {
|
|
49302
|
-
category: "development",
|
|
49303
|
-
pkg: "@todoforai/tfa-review",
|
|
49304
|
-
installer: "npm",
|
|
49305
|
-
label: "Review",
|
|
49306
|
-
capabilities: "Review a git diff as a real TODO: read-only agent assesses goal, finds issues, suggests simpler approaches",
|
|
49307
|
-
description: "Review a git diff with a read-only sub-agent.",
|
|
49308
|
-
versionCmd: "tfa-review --version 2>/dev/null | head -1",
|
|
49309
|
-
installCmd: "bun add -g @todoforai/tfa-review",
|
|
49310
|
-
preinstallCloud: true,
|
|
49311
|
-
internal: true
|
|
49312
|
-
},
|
|
49313
|
-
"tfa-summary": {
|
|
49314
|
-
category: "development",
|
|
49315
|
-
pkg: "@todoforai/tfa-summary",
|
|
49316
|
-
installer: "npm",
|
|
49317
|
-
label: "Summarize",
|
|
49318
|
-
capabilities: "Summarize files or piped input as a real TODO with no-tools sub-agent",
|
|
49319
|
-
description: "Summarize files or piped content as a visible TODO.",
|
|
49320
|
-
versionCmd: "tfa-summary --version 2>/dev/null | head -1",
|
|
49321
|
-
installCmd: "bun add -g @todoforai/tfa-summary",
|
|
49264
|
+
label: "Handoff",
|
|
49265
|
+
capabilities: "Compact a conversation into a handoff document as a hidden TODO; pipe filter for `todoai --inspect … | tfa-handoff … | todoai`",
|
|
49266
|
+
description: "Compact a conversation into a handoff document for a fresh agent.",
|
|
49267
|
+
versionCmd: "tfa-handoff --version 2>/dev/null | head -1",
|
|
49268
|
+
installCmd: "bun add -g @todoforai/tfa-handoff",
|
|
49322
49269
|
internal: true
|
|
49323
49270
|
},
|
|
49324
49271
|
"tfa-vault": {
|
|
@@ -49326,8 +49273,8 @@ var tool_catalog_default = {
|
|
|
49326
49273
|
pkg: "@todoforai/vault",
|
|
49327
49274
|
installer: "npm",
|
|
49328
49275
|
label: "Vault",
|
|
49329
|
-
capabilities: "
|
|
49330
|
-
description: "
|
|
49276
|
+
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.",
|
|
49277
|
+
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: when you obtain, generate, or rotate a secret and it isn't saved, store it with `tfa-vault put <path> field=value` (use `patch` to add fields without clobbering; overwrite on rotation so the vault stays source of truth). Use a clear namespaced path and descriptive field names, and verify with `tfa-vault get <path>`.",
|
|
49331
49278
|
versionCmd: "tfa-vault --version 2>/dev/null | head -1",
|
|
49332
49279
|
statusCmd: "tfa-vault whoami",
|
|
49333
49280
|
installCmd: "bun add -g @todoforai/vault",
|
|
@@ -51610,9 +51557,10 @@ var STREAM_FIRST = 1e4;
|
|
|
51610
51557
|
var STREAM_LAST = 1e4;
|
|
51611
51558
|
var RUN_OUTPUT_CAP = 256 * 1024;
|
|
51612
51559
|
var OUTPUT_POLICIES = {
|
|
51613
|
-
safe: { firstLimit: STREAM_FIRST, lastLimit: STREAM_LAST, hardCap: STREAM_FIRST + STREAM_LAST },
|
|
51614
|
-
|
|
51615
|
-
|
|
51560
|
+
safe: { firstLimit: STREAM_FIRST, lastLimit: STREAM_LAST, hardCap: STREAM_FIRST + STREAM_LAST, lineLimit: MAX_LINE_LEN },
|
|
51561
|
+
wide: { firstLimit: STREAM_FIRST, lastLimit: STREAM_LAST, hardCap: STREAM_FIRST + STREAM_LAST, lineLimit: Infinity },
|
|
51562
|
+
full: { firstLimit: Infinity, lastLimit: 0, hardCap: RUN_OUTPUT_CAP, lineLimit: MAX_LINE_LEN },
|
|
51563
|
+
raw: { firstLimit: Infinity, lastLimit: 0, hardCap: Infinity, lineLimit: Infinity }
|
|
51616
51564
|
};
|
|
51617
51565
|
var DEFAULT_OUTPUT_MODE = "safe";
|
|
51618
51566
|
function resolveOutputPolicy(mode) {
|
|
@@ -51635,6 +51583,13 @@ function truncateLines(text, { maxLines = MAX_RESULT_LINES, maxLineLen = MAX_LIN
|
|
|
51635
51583
|
... (output truncated)`;
|
|
51636
51584
|
return output;
|
|
51637
51585
|
}
|
|
51586
|
+
function capLineWidth(text, lineLimit) {
|
|
51587
|
+
if (!isFinite(lineLimit))
|
|
51588
|
+
return text;
|
|
51589
|
+
return text.split(`
|
|
51590
|
+
`).map((line) => line.length > lineLimit ? line.slice(0, lineLimit) + ` ...[+${line.length - lineLimit} chars]` : line).join(`
|
|
51591
|
+
`);
|
|
51592
|
+
}
|
|
51638
51593
|
function formatTruncationNotice(totalLen, firstLimit, lastPart) {
|
|
51639
51594
|
const dropped = totalLen - firstLimit - lastPart.length;
|
|
51640
51595
|
return `
|
|
@@ -51697,9 +51652,11 @@ class OutputBuffer {
|
|
|
51697
51652
|
truncMsgSent = false;
|
|
51698
51653
|
headLimit;
|
|
51699
51654
|
lastLimit;
|
|
51655
|
+
lineLimit;
|
|
51700
51656
|
constructor(policy = OUTPUT_POLICIES[DEFAULT_OUTPUT_MODE]) {
|
|
51701
51657
|
this.headLimit = Math.min(policy.firstLimit, policy.hardCap);
|
|
51702
51658
|
this.lastLimit = Math.min(policy.lastLimit, policy.hardCap - this.headLimit);
|
|
51659
|
+
this.lineLimit = policy.lineLimit;
|
|
51703
51660
|
}
|
|
51704
51661
|
append(text) {
|
|
51705
51662
|
this.totalLen += text.length;
|
|
@@ -51733,15 +51690,15 @@ class OutputBuffer {
|
|
|
51733
51690
|
}
|
|
51734
51691
|
getOutput() {
|
|
51735
51692
|
if (!this.truncated)
|
|
51736
|
-
return this.firstPart;
|
|
51737
|
-
return this.firstPart + `
|
|
51693
|
+
return capLineWidth(this.firstPart, this.lineLimit);
|
|
51694
|
+
return capLineWidth(this.firstPart, this.lineLimit) + `
|
|
51738
51695
|
|
|
51739
51696
|
... [truncated: showing first ${this.firstPart.length} and last ${this.lastPart.length} chars of ${this.totalLen} total] ...
|
|
51740
51697
|
|
|
51741
|
-
${this.lastPart}`;
|
|
51698
|
+
${capLineWidth(this.lastPart, this.lineLimit)}`;
|
|
51742
51699
|
}
|
|
51743
51700
|
getRawIfComplete() {
|
|
51744
|
-
return this.truncated ? null : this.firstPart;
|
|
51701
|
+
return this.truncated ? null : capLineWidth(this.firstPart, this.lineLimit);
|
|
51745
51702
|
}
|
|
51746
51703
|
}
|
|
51747
51704
|
var processes = new Map;
|
|
@@ -52624,7 +52581,7 @@ register("read_file_base64", async (args) => {
|
|
|
52624
52581
|
return { path: fullPath, base64: data.toString("base64"), bytes: data.length };
|
|
52625
52582
|
});
|
|
52626
52583
|
register("search_files", async (args) => {
|
|
52627
|
-
const { pattern, path: p10 = ".", cwd = args.root_path ?? "", head = 100, max_count = 5, glob: globPattern = "", ignore_case = true } = args;
|
|
52584
|
+
const { pattern, path: p10 = ".", cwd = args.root_path ?? "", head = 100, max_count = 5, glob: globPattern = "", ignore_case = true, output: outputMode = DEFAULT_OUTPUT_MODE } = args;
|
|
52628
52585
|
const { execSync: execWhich } = await import("child_process");
|
|
52629
52586
|
const whichCmd = process.platform === "win32" ? "where" : "which";
|
|
52630
52587
|
const which = (bin) => {
|
|
@@ -52703,7 +52660,7 @@ register("search_files", async (args) => {
|
|
|
52703
52660
|
output = lines.join(`
|
|
52704
52661
|
`);
|
|
52705
52662
|
}
|
|
52706
|
-
return { result: truncateLines(output, { maxLines: head }) };
|
|
52663
|
+
return { result: truncateLines(output, { maxLines: head, maxLineLen: resolveOutputPolicy(outputMode).lineLimit }) };
|
|
52707
52664
|
}
|
|
52708
52665
|
if (code === 1)
|
|
52709
52666
|
return { result: "No matches found." };
|
|
@@ -53006,6 +52963,8 @@ class TODOforAIEdge {
|
|
|
53006
52963
|
browserExtensionBridge;
|
|
53007
52964
|
stopping = false;
|
|
53008
52965
|
reconnectTimer;
|
|
52966
|
+
wakeReconnect;
|
|
52967
|
+
connectedAt = 0;
|
|
53009
52968
|
edgeConfig = {
|
|
53010
52969
|
id: "",
|
|
53011
52970
|
name: "Name uninitialized",
|
|
@@ -53288,23 +53247,22 @@ class TODOforAIEdge {
|
|
|
53288
53247
|
console.log(`[warn] Unknown message type: ${msgType}`);
|
|
53289
53248
|
}
|
|
53290
53249
|
}
|
|
53291
|
-
startHeartbeat(onStale) {
|
|
53250
|
+
startHeartbeat(ws2, onStale) {
|
|
53292
53251
|
this.stopHeartbeat();
|
|
53293
53252
|
let pongReceived = true;
|
|
53294
|
-
|
|
53253
|
+
ws2.on("pong", () => {
|
|
53295
53254
|
pongReceived = true;
|
|
53296
53255
|
});
|
|
53297
53256
|
this.heartbeatTimer = setInterval(() => {
|
|
53298
53257
|
if (!pongReceived) {
|
|
53299
53258
|
console.log("[warn] No pong received, terminating stale connection");
|
|
53300
|
-
|
|
53301
|
-
this.ws?.terminate();
|
|
53259
|
+
ws2.terminate();
|
|
53302
53260
|
onStale();
|
|
53303
53261
|
return;
|
|
53304
53262
|
}
|
|
53305
53263
|
pongReceived = false;
|
|
53306
53264
|
try {
|
|
53307
|
-
|
|
53265
|
+
ws2.ping();
|
|
53308
53266
|
} catch {}
|
|
53309
53267
|
}, 30000);
|
|
53310
53268
|
}
|
|
@@ -53319,20 +53277,30 @@ class TODOforAIEdge {
|
|
|
53319
53277
|
const url = `${this.wsUrl}?fingerprint=${encodeURIComponent(this.fingerprint)}`;
|
|
53320
53278
|
if (this.debug)
|
|
53321
53279
|
console.log(`[info] Connecting to ${url}`);
|
|
53322
|
-
|
|
53280
|
+
const ws2 = new wrapper_default(url, [this.api.apiKey], {
|
|
53323
53281
|
maxPayload: 5 * 1024 * 1024,
|
|
53324
53282
|
rejectUnauthorized: false
|
|
53325
53283
|
});
|
|
53326
|
-
this.ws
|
|
53327
|
-
|
|
53328
|
-
|
|
53329
|
-
|
|
53284
|
+
this.ws = ws2;
|
|
53285
|
+
let settled = false;
|
|
53286
|
+
const settle = (fn2) => {
|
|
53287
|
+
if (settled)
|
|
53288
|
+
return;
|
|
53289
|
+
settled = true;
|
|
53290
|
+
if (this.ws === ws2) {
|
|
53291
|
+
this.stopHeartbeat();
|
|
53330
53292
|
this.connected = false;
|
|
53331
53293
|
this.ws = null;
|
|
53332
|
-
|
|
53333
|
-
|
|
53294
|
+
}
|
|
53295
|
+
fn2();
|
|
53296
|
+
};
|
|
53297
|
+
ws2.on("open", () => {
|
|
53298
|
+
this.connected = true;
|
|
53299
|
+
this.connectedAt = Date.now();
|
|
53300
|
+
console.log("[info] WebSocket connected");
|
|
53301
|
+
this.startHeartbeat(ws2, () => settle(() => resolve(0)));
|
|
53334
53302
|
});
|
|
53335
|
-
|
|
53303
|
+
ws2.on("message", (data, isBinary) => {
|
|
53336
53304
|
if (isBinary) {
|
|
53337
53305
|
const frame = data instanceof Buffer ? new Uint8Array(data) : new Uint8Array(data);
|
|
53338
53306
|
this.storeBinaryFrame(frame);
|
|
@@ -53340,36 +53308,30 @@ class TODOforAIEdge {
|
|
|
53340
53308
|
}
|
|
53341
53309
|
this.handleMessage(data.toString()).catch((e) => {
|
|
53342
53310
|
if (e instanceof AuthenticationError || e instanceof ServerError) {
|
|
53343
|
-
|
|
53344
|
-
reject(e);
|
|
53311
|
+
ws2.close();
|
|
53312
|
+
settle(() => reject(e));
|
|
53345
53313
|
} else {
|
|
53346
53314
|
console.error("[handler error]", e);
|
|
53347
53315
|
}
|
|
53348
53316
|
});
|
|
53349
53317
|
});
|
|
53350
|
-
|
|
53351
|
-
this.stopHeartbeat();
|
|
53352
|
-
this.connected = false;
|
|
53353
|
-
this.ws = null;
|
|
53318
|
+
ws2.on("close", (code, reason) => {
|
|
53354
53319
|
const reasonText = reason?.toString() || "<empty>";
|
|
53355
|
-
|
|
53356
|
-
console.log(`[info] WebSocket closed code=${code} clean=${clean} reason=${reasonText}`);
|
|
53320
|
+
console.log(`[info] WebSocket closed code=${code} clean=${code === 1000} reason=${reasonText}`);
|
|
53357
53321
|
if (code === 4001) {
|
|
53358
53322
|
console.log(`\x1B[33m[info] ${reasonText}. Not reconnecting.\x1B[0m`);
|
|
53359
53323
|
console.log(`\x1B[33m[info] To replace the existing connection, restart with: todoforai-edge --kill\x1B[0m`);
|
|
53360
|
-
reject(new ServerError(reasonText));
|
|
53324
|
+
settle(() => reject(new ServerError(reasonText)));
|
|
53361
53325
|
} else if (code === 4002) {
|
|
53362
53326
|
console.log(`\x1B[33m[info] ${reasonText}. This instance was replaced by a new connection.\x1B[0m`);
|
|
53363
|
-
reject(new ServerError(reasonText));
|
|
53327
|
+
settle(() => reject(new ServerError(reasonText)));
|
|
53364
53328
|
} else {
|
|
53365
|
-
resolve();
|
|
53329
|
+
settle(() => resolve(code));
|
|
53366
53330
|
}
|
|
53367
53331
|
});
|
|
53368
|
-
|
|
53369
|
-
|
|
53370
|
-
|
|
53371
|
-
this.ws = null;
|
|
53372
|
-
reject(err2);
|
|
53332
|
+
ws2.on("error", (err2) => {
|
|
53333
|
+
console.error(`[error] WebSocket error: ${err2.message}`);
|
|
53334
|
+
settle(() => resolve(0));
|
|
53373
53335
|
});
|
|
53374
53336
|
});
|
|
53375
53337
|
}
|
|
@@ -53379,45 +53341,34 @@ class TODOforAIEdge {
|
|
|
53379
53341
|
} catch {}
|
|
53380
53342
|
this.fingerprint = generateFingerprint();
|
|
53381
53343
|
console.log(`\x1B[36m\x1B[1m\uD83D\uDC46 Fingerprint:\x1B[0m ${this.fingerprint}`);
|
|
53382
|
-
const maxAttempts = 20;
|
|
53383
53344
|
let attempt = 0;
|
|
53384
|
-
while (
|
|
53385
|
-
console.log(`[info] Connecting (
|
|
53345
|
+
while (!this.stopping) {
|
|
53346
|
+
console.log(`[info] Connecting${attempt > 0 ? ` (retry ${attempt})` : ""}`);
|
|
53347
|
+
this.connectedAt = 0;
|
|
53386
53348
|
try {
|
|
53387
53349
|
await this.connect();
|
|
53388
|
-
if (this.stopping)
|
|
53389
|
-
break;
|
|
53390
|
-
attempt = 0;
|
|
53391
53350
|
} catch (e) {
|
|
53392
|
-
|
|
53393
|
-
|
|
53394
|
-
|
|
53395
|
-
}
|
|
53396
|
-
if (e instanceof ServerError) {
|
|
53397
|
-
console.error(`\x1B[31mServer error: ${e.message}\x1B[0m`);
|
|
53398
|
-
break;
|
|
53399
|
-
}
|
|
53400
|
-
attempt++;
|
|
53401
|
-
console.error(`[error] Connection error: ${e.message}`);
|
|
53402
|
-
} finally {
|
|
53403
|
-
this.connected = false;
|
|
53404
|
-
this.ws = null;
|
|
53405
|
-
}
|
|
53406
|
-
if (attempt > 0 && attempt < maxAttempts && !this.stopping) {
|
|
53407
|
-
const delay = Math.min(4 + attempt, 20);
|
|
53408
|
-
console.log(`[info] Reconnecting in ${delay}s...`);
|
|
53409
|
-
await new Promise((r) => {
|
|
53410
|
-
this.reconnectTimer = setTimeout(r, delay * 1000);
|
|
53411
|
-
});
|
|
53351
|
+
const label = e instanceof AuthenticationError ? "Authentication failed" : "Server error";
|
|
53352
|
+
console.error(`\x1B[31m${label}: ${e.message}\x1B[0m`);
|
|
53353
|
+
break;
|
|
53412
53354
|
}
|
|
53413
|
-
|
|
53414
|
-
|
|
53415
|
-
|
|
53355
|
+
if (this.stopping)
|
|
53356
|
+
break;
|
|
53357
|
+
if (this.connectedAt && Date.now() - this.connectedAt > 60000)
|
|
53358
|
+
attempt = 0;
|
|
53359
|
+
attempt++;
|
|
53360
|
+
const delay = Math.min(2 * 2 ** Math.min(attempt - 1, 4), 30);
|
|
53361
|
+
console.log(`[info] Reconnecting in ${delay}s...`);
|
|
53362
|
+
await new Promise((r) => {
|
|
53363
|
+
this.wakeReconnect = r;
|
|
53364
|
+
this.reconnectTimer = setTimeout(r, delay * 1000);
|
|
53365
|
+
});
|
|
53416
53366
|
}
|
|
53417
53367
|
}
|
|
53418
53368
|
stop() {
|
|
53419
53369
|
this.stopping = true;
|
|
53420
53370
|
clearTimeout(this.reconnectTimer);
|
|
53371
|
+
this.wakeReconnect?.();
|
|
53421
53372
|
this.stopHeartbeat();
|
|
53422
53373
|
this.browserExtensionBridge.stop();
|
|
53423
53374
|
this.frontendWs?.close();
|