@todoforai/cli 0.1.55 → 0.1.56

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.
@@ -42745,7 +42745,7 @@ function randomTip() {
42745
42745
  return TIPS[Math.floor(Math.random() * TIPS.length)];
42746
42746
  }
42747
42747
 
42748
- // ../../../home/hm/repo/todoforai/packages/shared-api/src/api.ts
42748
+ // ../packages/shared-api/src/api.ts
42749
42749
  function restBasePath(apiKey) {
42750
42750
  return apiKey.startsWith("dst_") ? "/dst/v1" : "/api/v1";
42751
42751
  }
@@ -43169,11 +43169,11 @@ class ApiClient {
43169
43169
  return res.json();
43170
43170
  }
43171
43171
  }
43172
- // ../../../home/hm/repo/todoforai/packages/shared-api/src/frontend-ws.ts
43172
+ // ../packages/shared-api/src/frontend-ws.ts
43173
43173
  import { randomUUID } from "crypto";
43174
43174
  import WebSocket from "ws";
43175
43175
 
43176
- // ../../../home/hm/repo/todoforai/packages/shared-credentials/src/index.ts
43176
+ // ../packages/shared-credentials/src/index.ts
43177
43177
  import { readFileSync, writeFileSync, mkdirSync, chmodSync } from "node:fs";
43178
43178
  import { join, dirname } from "node:path";
43179
43179
  import { homedir, platform } from "node:os";
@@ -43213,7 +43213,7 @@ function writeCredential(apiUrl, apiKey) {
43213
43213
  writeSecure(c);
43214
43214
  }
43215
43215
 
43216
- // ../../../home/hm/repo/todoforai/packages/shared-api/src/frontend-ws.ts
43216
+ // ../packages/shared-api/src/frontend-ws.ts
43217
43217
  var log = (level, ...args) => console.log(`[frontend-ws:${level}]`, ...args);
43218
43218
 
43219
43219
  class FrontendWebSocket {
@@ -43483,7 +43483,7 @@ class FrontendWebSocket {
43483
43483
  });
43484
43484
  }
43485
43485
  }
43486
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/enums.ts
43486
+ // ../packages/shared-fbe/src/enums.ts
43487
43487
  var TodoStatus;
43488
43488
  ((TodoStatus2) => {
43489
43489
  TodoStatus2["PROPOSED"] = "PROPOSED";
@@ -43507,7 +43507,7 @@ var TodoStatus;
43507
43507
  TodoStatus2["ARCHIVED"] = "ARCHIVED";
43508
43508
  TodoStatus2["DELETED"] = "DELETED";
43509
43509
  })(TodoStatus ||= {});
43510
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/models.ts
43510
+ // ../packages/shared-fbe/src/models.ts
43511
43511
  var DEFAULT_MODEL = "anthropic:anthropic/claude-opus-5.5";
43512
43512
  var MODEL_ALIASES = {
43513
43513
  claude: DEFAULT_MODEL
@@ -43578,7 +43578,7 @@ function qualifiedModelIds(listing, filter) {
43578
43578
  }
43579
43579
  return q ? ids.filter((id) => id.toLowerCase().includes(q)) : ids;
43580
43580
  }
43581
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/billing.ts
43581
+ // ../packages/shared-fbe/src/billing.ts
43582
43582
  var USAGE_WINDOWS = {
43583
43583
  SESSION_MS: 5 * 60 * 60 * 1000,
43584
43584
  WEEK_MS: 7 * 24 * 60 * 60 * 1000,
@@ -43586,7 +43586,7 @@ var USAGE_WINDOWS = {
43586
43586
  SESSION_FACTOR: 1 / 5
43587
43587
  };
43588
43588
  var NEVER_SCHEDULED_TIMESTAMP = 8640000000000000;
43589
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/mimetypes.json
43589
+ // ../packages/shared-fbe/src/mimetypes.json
43590
43590
  var mimetypes_default = {
43591
43591
  conversionProfiles: {
43592
43592
  to_jpeg_90: { toMime: "image/jpeg", toExt: "jpg", quality: 0.9 }
@@ -43679,7 +43679,7 @@ var mimetypes_default = {
43679
43679
  }
43680
43680
  };
43681
43681
 
43682
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/attachmentUtils.ts
43682
+ // ../packages/shared-fbe/src/attachmentUtils.ts
43683
43683
  var MCP_TEXT_MIME = Object.entries(mimetypes_default.aliases).find(([, type]) => type === "mcp_text")[0];
43684
43684
  var MCP_AUDIO_MIME = Object.entries(mimetypes_default.aliases).find(([, type]) => type === "mcp_audio")[0];
43685
43685
  var AttachmentType = Object.fromEntries(Object.keys(mimetypes_default.types).map((k) => [k.toUpperCase(), k]));
@@ -43719,7 +43719,7 @@ for (const [ext, entry] of Object.entries(mimetypes_default.extensions)) {
43719
43719
  if (!MIME_TO_EXT[mime])
43720
43720
  MIME_TO_EXT[mime] = ext;
43721
43721
  }
43722
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/edgeTypes.ts
43722
+ // ../packages/shared-fbe/src/edgeTypes.ts
43723
43723
  var NON_SHELL_TYPES = new Set([
43724
43724
  "WEB_EXTENSION" /* WEB_EXTENSION */,
43725
43725
  "EXTENSION" /* EXTENSION */,
@@ -43727,7 +43727,7 @@ var NON_SHELL_TYPES = new Set([
43727
43727
  "ANDROID" /* ANDROID */,
43728
43728
  "IOS" /* IOS */
43729
43729
  ]);
43730
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/blocks/index.ts
43730
+ // ../packages/shared-fbe/src/blocks/index.ts
43731
43731
  var USER_INPUT_BLOCK_TYPES = new Set([
43732
43732
  "question" /* Question */,
43733
43733
  "login_prompt" /* Login */,
@@ -43781,7 +43781,7 @@ var FILE_TOOL_TYPES = new Set([
43781
43781
  "edit" /* Edit */,
43782
43782
  "modify_file" /* ModifyFile */
43783
43783
  ]);
43784
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/channels.ts
43784
+ // ../packages/shared-fbe/src/channels.ts
43785
43785
  var privateSuffix = (privateOwnerId) => privateOwnerId ? `:private:${privateOwnerId}` : "";
43786
43786
  var SERVER_TO_FRONTENDS = {
43787
43787
  task: {
@@ -43871,7 +43871,7 @@ var SERVER_TO_FRONTENDS = {
43871
43871
  function_call_request: (userId) => `${"FUNCTION_CALL_REQUEST_AGENT" /* FUNCTION_CALL_REQUEST_AGENT */}:frontend:${userId}`
43872
43872
  }
43873
43873
  };
43874
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/REST_types.ts
43874
+ // ../packages/shared-fbe/src/REST_types.ts
43875
43875
  var MANUAL_CHANNEL = "Manual";
43876
43876
  function manualAnswersOf(sources) {
43877
43877
  const manual = sources?.find((s) => s.channel === MANUAL_CHANNEL);
@@ -43883,7 +43883,7 @@ function manualAnswersOf(sources) {
43883
43883
  }
43884
43884
  var manualSamples = (answers) => Object.entries(answers).filter(([, a]) => a.trim()).map(([prompt, text]) => ({ prompt, text: text.trim() }));
43885
43885
  var senderLabel = (s) => s.kind === "team" ? `${s.name} · TODO for AI team` : `${s.name} · your agent`;
43886
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/templateBody.ts
43886
+ // ../packages/shared-fbe/src/templateBody.ts
43887
43887
  var USER_HEADINGS = new Set([
43888
43888
  "your task",
43889
43889
  "your tasks",
@@ -43892,7 +43892,7 @@ var USER_HEADINGS = new Set([
43892
43892
  "steps",
43893
43893
  "data needed"
43894
43894
  ]);
43895
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/bashPatterns.ts
43895
+ // ../packages/shared-fbe/src/bashPatterns.ts
43896
43896
  function splitShellCommands(input) {
43897
43897
  const parts = [];
43898
43898
  let current = "";
@@ -44134,7 +44134,7 @@ function getBlockServerId(block) {
44134
44134
  return prefix ? prefix.slice(0, -1) : "*";
44135
44135
  }
44136
44136
 
44137
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/permissionUtils.ts
44137
+ // ../packages/shared-fbe/src/permissionUtils.ts
44138
44138
  function parsePattern(pattern) {
44139
44139
  const colonIndex = pattern.indexOf(":");
44140
44140
  if (colonIndex === -1)
@@ -44235,7 +44235,7 @@ function getBlockNewPatterns(block, permissions) {
44235
44235
  }
44236
44236
  return pairs.filter(({ raw, pattern }) => !isPatternAllowed(permissions, pattern) && !allow.some((rule) => bashRuleMatchesCmd(rule, serverId, raw))).map(({ pattern }) => pattern);
44237
44237
  }
44238
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/systemAgents.ts
44238
+ // ../packages/shared-fbe/src/systemAgents.ts
44239
44239
  var BUSINESS_ANALYZER_AGENT = {
44240
44240
  id: "00000000-0000-0000-0000-202601013151",
44241
44241
  name: "Business Analyzer",
@@ -44381,7 +44381,7 @@ var SYSTEM_AGENTS = {
44381
44381
  [ONBOARDING_AGENT.id]: ONBOARDING_AGENT
44382
44382
  };
44383
44383
  var RECOMMEND_STEP = "Recommend growth TODOs for this project: materialize the ones you genuinely believe fit " + "as proposal cards on the board (api_recommend_template, one call per recommendation). " + "No quota — fewer good cards beat padding.";
44384
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/outputLimits.ts
44384
+ // ../packages/shared-fbe/src/outputLimits.ts
44385
44385
  var MAX_LINE_LEN = 300;
44386
44386
  var STREAM_FIRST = 1e4;
44387
44387
  var STREAM_LAST = 1e4;
@@ -44392,7 +44392,1500 @@ var OUTPUT_POLICIES = {
44392
44392
  full: { firstLimit: Infinity, lastLimit: 0, hardCap: RUN_OUTPUT_CAP, lineLimit: MAX_LINE_LEN },
44393
44393
  raw: { firstLimit: Infinity, lastLimit: 0, hardCap: Infinity, lineLimit: Infinity }
44394
44394
  };
44395
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/model_promos.json
44395
+ // ../packages/shared-fbe/src/tool_catalog.json
44396
+ var tool_catalog_default = {
44397
+ zele: {
44398
+ category: "email",
44399
+ pkg: "zele",
44400
+ installer: "npm",
44401
+ label: "Gmail",
44402
+ summary: "Read and send Gmail from your own account.",
44403
+ statusCmd: "zele whoami 2>/dev/null | grep 'email:' | grep -m1 .",
44404
+ loginNeedsPty: true,
44405
+ loginCmd: "zele login --method google",
44406
+ oauthUrlPattern: "(https://accounts\\.google\\.com\\S+)",
44407
+ oauthCallbackPort: 8089,
44408
+ credentialPaths: ["~/.zele/sqlite.db"],
44409
+ versionCmd: "zele --version 2>/dev/null | sed -n 1p",
44410
+ preinstallCloud: true,
44411
+ preinstallJarvis: true,
44412
+ description: "Gmail (multi-account, OAuth login): inbox, search, send, reply, contacts. Google Calendar via `zele cal`: list/create/update/delete events (Meet links, recurrence), respond to invites, free/busy."
44413
+ },
44414
+ "zele-calendar": {
44415
+ preinstallCloud: true,
44416
+ category: "utility",
44417
+ pkg: "zele",
44418
+ installer: "npm",
44419
+ binName: "zele",
44420
+ label: "Google Calendar",
44421
+ summary: "See your Google Calendar and book, move or cancel events.",
44422
+ statusCmd: "zele whoami 2>/dev/null | grep 'email:' | grep -m1 .",
44423
+ loginNeedsPty: true,
44424
+ loginCmd: "zele login --method google",
44425
+ oauthUrlPattern: "(https://accounts\\.google\\.com\\S+)",
44426
+ oauthCallbackPort: 8089,
44427
+ credentialPaths: ["~/.zele/sqlite.db"],
44428
+ versionCmd: "zele --version 2>/dev/null | sed -n 1p",
44429
+ preinstallJarvis: true,
44430
+ description: "Google Calendar via `zele cal`: list calendars and events, create/update/delete events with Google Meet links, recurrence and reminders, respond to invites, free/busy."
44431
+ },
44432
+ xurl: {
44433
+ category: "social",
44434
+ pkg: "@xdevplatform/xurl",
44435
+ installer: "npm",
44436
+ label: "X",
44437
+ summary: "Post to X and read timelines, replies and DMs.",
44438
+ statusCmd: `xurl whoami 2>&1 | sed -n 's/.*"username"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' | grep -m10 .`,
44439
+ loginCmd: "xurl auth oauth2",
44440
+ loginTerminalHint: "X needs your own developer app first: create one at developer.x.com (callback `http://localhost:8080/callback`), run `xurl auth apps add tfa --client-id <id> --client-secret <secret>`, then `xurl auth oauth2`.",
44441
+ oauthUrlPattern: "(https://(?:twitter|x)\\.com/i/oauth2\\S+)",
44442
+ oauthCallbackPort: 8080,
44443
+ credentialPaths: ["~/.xurl"],
44444
+ description: "Raw X API access via `xurl <method> <path>`.",
44445
+ versionCmd: "xurl version 2>/dev/null | sed -n 1p",
44446
+ preinstallJarvis: true,
44447
+ preinstallCloud: true
44448
+ },
44449
+ "linkedin-api": {
44450
+ preinstallCloud: true,
44451
+ category: "social",
44452
+ pkg: "@todoforai/linkedin-api",
44453
+ installer: "npm",
44454
+ label: "LinkedIn",
44455
+ summary: "Read LinkedIn profiles and send messages and connection requests.",
44456
+ statusCmd: `linkedin-api whoami 2>/dev/null | sed -n 's/.*"publicId"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' | grep -m10 .`,
44457
+ loginCmd: "linkedin-api auth <li_at> <jsessionid>",
44458
+ credentialPaths: ["~/.config/linkedin-api/credentials.json"],
44459
+ description: "LinkedIn Voyager API CLI for profiles, conversations, DMs, and connections.",
44460
+ versionCmd: "linkedin-api --version 2>/dev/null | sed -n 1p"
44461
+ },
44462
+ "figma-api": {
44463
+ category: "design",
44464
+ pkg: "@todoforai/figma-api",
44465
+ installer: "npm",
44466
+ label: "Figma",
44467
+ summary: "Read Figma files, export images and leave comments.",
44468
+ statusCmd: `figma-api me 2>/dev/null | sed -n 's/.*"email"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' | grep -m10 .`,
44469
+ loginCmd: "figma-api auth <token>",
44470
+ credentialPaths: ["~/.config/figma-api/credentials.json"],
44471
+ description: "Figma REST API CLI. File commands take a file key or Figma URL. Canvas writes (frames/text/shapes) use `figma-api run` via the plugin bridge. Run `figma-api <cmd> --help` for params.",
44472
+ versionCmd: "figma-api --version 2>/dev/null | sed -n 1p"
44473
+ },
44474
+ "slack-cli": {
44475
+ preinstallCloud: true,
44476
+ cloudInstallCmd: "curl -fsSL https://github.com/slackapi/slack-cli/releases/download/v4.2.0/slack_cli_4.2.0_linux_amd64.tar.gz | tar -xz -C /tmp bin/slack && install -m0755 /tmp/bin/slack /usr/local/bin/slack-cli && rm -rf /tmp/bin",
44477
+ cloudVerifyCmd: "slack-cli --version",
44478
+ category: "social",
44479
+ pkg: "slack-cli",
44480
+ installer: "binary",
44481
+ label: "Slack",
44482
+ summary: "Work with Slack workspaces and apps.",
44483
+ statusCmd: "slack-cli auth list 2>&1 | grep 'Team' >/dev/null && echo authenticated",
44484
+ loginCmd: "slack-cli login",
44485
+ loginTerminalHint: "Run `slack-cli login` in a terminal on this host, paste the `/slackauthticket …` command it prints into any Slack channel, then type the challenge code Slack shows you back into the terminal.",
44486
+ credentialPaths: ["~/.slack/credentials.json"],
44487
+ description: "Invoked as `slack-cli` to avoid colliding with the Slack desktop app’s `slack` binary.",
44488
+ versionCmd: "slack-cli version 2>/dev/null | sed -n 1p",
44489
+ binName: "slack-cli",
44490
+ binary: {
44491
+ "linux-x86_64": {
44492
+ url: "https://github.com/slackapi/slack-cli/releases/download/v4.2.0/slack_cli_4.2.0_linux_amd64.tar.gz",
44493
+ archive: "tar.gz",
44494
+ extract: "bin/slack"
44495
+ },
44496
+ "linux-aarch64": {
44497
+ url: "https://github.com/slackapi/slack-cli/releases/download/v4.2.0/slack_cli_4.2.0_linux_arm64.tar.gz",
44498
+ archive: "tar.gz",
44499
+ extract: "bin/slack"
44500
+ },
44501
+ "darwin-x86_64": {
44502
+ url: "https://github.com/slackapi/slack-cli/releases/download/v4.2.0/slack_cli_4.2.0_macOS_amd64.tar.gz",
44503
+ archive: "tar.gz",
44504
+ extract: "bin/slack"
44505
+ },
44506
+ "darwin-aarch64": {
44507
+ url: "https://github.com/slackapi/slack-cli/releases/download/v4.2.0/slack_cli_4.2.0_macOS_arm64.tar.gz",
44508
+ archive: "tar.gz",
44509
+ extract: "bin/slack"
44510
+ },
44511
+ "windows-x86_64": {
44512
+ url: "https://github.com/slackapi/slack-cli/releases/download/v4.2.0/slack_cli_4.2.0_windows_64-bit.zip",
44513
+ archive: "zip",
44514
+ extract: "bin/slack.exe"
44515
+ }
44516
+ }
44517
+ },
44518
+ "telegram-send": {
44519
+ preinstallCloud: true,
44520
+ packages: ["telegram-send==0.39.2"],
44521
+ category: "social",
44522
+ pkg: "telegram-send",
44523
+ installer: "pip",
44524
+ label: "Telegram",
44525
+ summary: "Send Telegram messages, photos and files.",
44526
+ loginCmd: `t=<bot_token>; c=$(curl -sf "https://api.telegram.org/bot$t/getUpdates" | python3 -c "import json,sys; u=[x for x in json.load(sys.stdin)['result'] if 'message' in x]; print(u[-1]['message']['chat']['id'])" 2>/dev/null) || { echo "No message from you yet: open your bot in Telegram, send it any message, then retry"; exit 1; }; mkdir -p "$HOME/.config" && printf '[telegram]\\ntoken = %s\\nchat_id = %s\\n' "$t" "$c" > "$HOME/.config/telegram-send.conf" && telegram-send "Connected to TODOforAI"`,
44527
+ credentialPaths: ["~/.config/telegram-send.conf"],
44528
+ versionCmd: "telegram-send --version 2>/dev/null | sed -n 1p",
44529
+ statusCmd: "test -f ~/.config/telegram-send.conf && echo authenticated",
44530
+ description: "Send messages, send files & images, send video & audio, Markdown/HTML formatting, channel & group support"
44531
+ },
44532
+ "meta-ads": {
44533
+ preinstallCloud: true,
44534
+ packages: ["meta-ads==1.1.0"],
44535
+ category: "marketing",
44536
+ pkg: "meta-ads",
44537
+ installer: "pip",
44538
+ label: "Meta Ads",
44539
+ summary: "Run Facebook and Instagram ad campaigns and see how they perform.",
44540
+ binName: "meta",
44541
+ statusCmd: `out=$(meta auth status 2>&1); rc=$?; printf '%s\\n' "$out" | grep -m1 .; exit $rc`,
44542
+ versionCmd: "meta --version 2>/dev/null | sed -n 1p",
44543
+ description: "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. No raw/passthrough mode; for arbitrary Graph API calls with a Page token use `facebook-pages-api request <method> <path>`."
44544
+ },
44545
+ "elevenlabs-api": {
44546
+ preinstallCloud: true,
44547
+ category: "media",
44548
+ pkg: "@todoforai/elevenlabs-api",
44549
+ installer: "npm",
44550
+ label: "ElevenLabs",
44551
+ summary: "Turn text into natural speech, in many voices and languages.",
44552
+ versionCmd: "elevenlabs-api --version 2>/dev/null | sed -n 1p",
44553
+ statusCmd: 'test -f ~/.config/todoforai/elevenlabs.json -o -n "$ELEVENLABS_API_KEY" && echo authenticated',
44554
+ loginCmd: "elevenlabs-api auth <api_key>",
44555
+ credentialPaths: ["~/.config/todoforai/elevenlabs.json"],
44556
+ description: "Text-to-speech, voice cloning, multiple languages."
44557
+ },
44558
+ ffmpeg: {
44559
+ commodity: true,
44560
+ category: "media",
44561
+ pkg: "ffmpeg",
44562
+ installer: "system",
44563
+ label: "FFmpeg",
44564
+ summary: "Convert, trim and resize video and audio files.",
44565
+ cloudAptPackages: ["ffmpeg"],
44566
+ preinstallCloud: true,
44567
+ description: "Media swiss-army knife: `ffmpeg -i in.mp4 out.webm`; `ffprobe` for metadata.",
44568
+ versionCmd: "ffmpeg -version 2>/dev/null | sed -n 1p"
44569
+ },
44570
+ "tfa-imagegen": {
44571
+ preinstallCloud: true,
44572
+ category: "media",
44573
+ pkg: "@todoforai/image-api",
44574
+ installer: "npm",
44575
+ label: "Image Gen",
44576
+ summary: "Generate and edit images from a description.",
44577
+ platformAuth: true,
44578
+ versionCmd: "tfa-imagegen --version 2>/dev/null | sed -n 1p",
44579
+ credentialPaths: ["~/.config/todoforai/credentials.json"],
44580
+ description: "AI image generation & editing via TODOFORAI backend (gpt-image, nano-banana, nano-banana-pro, mai-image-2.6)"
44581
+ },
44582
+ "suno-api": {
44583
+ preinstallCloud: true,
44584
+ category: "media",
44585
+ pkg: "@todoforai/suno-api",
44586
+ installer: "npm",
44587
+ label: "Suno",
44588
+ summary: "Generate music and songs from a prompt.",
44589
+ versionCmd: "suno-api --version 2>/dev/null | sed -n 1p",
44590
+ statusCmd: 'test -f ~/.config/todoforai/suno.json -o -n "$SUNO_API_KEY" && echo authenticated',
44591
+ loginCmd: "suno-api auth <api_key>",
44592
+ credentialPaths: [
44593
+ "~/.config/todoforai/suno.json"
44594
+ ],
44595
+ description: "AI music generation, custom lyrics, multiple genres."
44596
+ },
44597
+ ntn: {
44598
+ preinstallCloud: true,
44599
+ category: "utility",
44600
+ pkg: "ntn",
44601
+ installer: "npm",
44602
+ label: "Notion",
44603
+ summary: "Read and update Notion pages and databases.",
44604
+ statusCmd: "ntn doctor 2>&1 | grep -E 'Token valid\\s+✔' >/dev/null && echo authenticated",
44605
+ loginCmd: "ntn login",
44606
+ loginNeedsPty: true,
44607
+ oauthUrlPattern: "(https://www\\.notion\\.so/workers/cli-login\\S+)",
44608
+ sessionIdPattern: "verificationCode=([A-Z0-9-]{5,12})",
44609
+ credentialPaths: ["~/.config/notion"],
44610
+ versionCmd: "ntn --version 2>/dev/null | sed -n 1p",
44611
+ description: "Official Notion CLI: raw API calls (`ntn api <path>`), page/data-source management, file uploads, Workers deploy."
44612
+ },
44613
+ "perplexity-api": {
44614
+ preinstallCloud: true,
44615
+ category: "utility",
44616
+ pkg: "@todoforai/perplexity-api",
44617
+ installer: "npm",
44618
+ label: "Perplexity",
44619
+ summary: "Ask questions and get answers researched from the web.",
44620
+ versionCmd: "perplexity-api --version 2>/dev/null | sed -n 1p",
44621
+ statusCmd: 'test -f ~/.config/todoforai/perplexity.json && echo authenticated || test -n "$PERPLEXITY_API_KEY" && echo authenticated',
44622
+ loginCmd: "perplexity-api auth <api_key>",
44623
+ credentialPaths: ["~/.config/todoforai/perplexity.json"],
44624
+ description: "AI-powered web search, chat completions, async chat, embeddings and agent runs"
44625
+ },
44626
+ gh: {
44627
+ category: "development",
44628
+ pkg: "gh",
44629
+ installer: "binary",
44630
+ preinstallCloud: true,
44631
+ label: "GitHub",
44632
+ summary: "Work with your GitHub repos, pull requests and issues.",
44633
+ statusCmd: "gh auth status 2>&1 | grep 'Logged in to' | grep -m1 .",
44634
+ loginCmd: "gh auth login --hostname github.com --git-protocol https",
44635
+ oauthUrlPattern: "(https://github\\.com/login/device\\S*)",
44636
+ deviceCodePattern: "one-time code:\\s*([A-Z0-9]{4}-[A-Z0-9]{4})",
44637
+ canStreamLogin: true,
44638
+ logoutCmd: "gh auth logout --hostname github.com --user {{ACCOUNT}}",
44639
+ credentialPaths: ["~/.config/gh/hosts.yml"],
44640
+ description: "Prefer `gh` over raw GitHub API calls.",
44641
+ versionCmd: "gh --version 2>/dev/null | sed -n 1p",
44642
+ preinstallJarvis: true
44643
+ },
44644
+ mcporter: {
44645
+ category: "development",
44646
+ pkg: "mcporter",
44647
+ installer: "npm",
44648
+ label: "MCP (mcporter)",
44649
+ summary: "Use tools from any MCP server.",
44650
+ statusCmd: "mcporter list 2>/dev/null | grep -v 'No MCP servers' | grep -m1 .",
44651
+ description: "MCP servers as CLI: `mcporter list [server] [--schema]`, `mcporter call <server>.<tool> key=value` (`key=@file`), `mcporter config add <name> <cmd-or-url>`, `mcporter auth <server>`. `--help` for more.",
44652
+ versionCmd: "mcporter --version 2>/dev/null | sed -n 1p",
44653
+ preinstallJarvis: true,
44654
+ preinstallCloud: true
44655
+ },
44656
+ glab: {
44657
+ category: "development",
44658
+ pkg: "glab",
44659
+ installer: "binary",
44660
+ label: "GitLab",
44661
+ summary: "Work with your GitLab repos, merge requests and pipelines.",
44662
+ statusCmd: "glab auth status 2>&1 | grep 'Logged in to' | grep -m1 .",
44663
+ loginCmd: "glab auth login --device",
44664
+ credentialPaths: ["~/.config/glab-cli/config.yml"],
44665
+ description: "GitLab equivalent of `gh`.",
44666
+ versionCmd: "glab --version 2>/dev/null | sed -n 1p",
44667
+ deviceCodePattern: "one-time code: ([A-Z0-9-]+)",
44668
+ oauthUrlPattern: "(https://gitlab\\.com/oauth/device)",
44669
+ canStreamLogin: true
44670
+ },
44671
+ vercel: {
44672
+ preinstallCloud: true,
44673
+ category: "deployment",
44674
+ pkg: "vercel",
44675
+ installer: "npm",
44676
+ label: "Vercel",
44677
+ summary: "Deploy websites to Vercel and manage them.",
44678
+ statusCmd: "vercel whoami 2>/dev/null | tr -d '\\r' | grep -m1 .",
44679
+ loginCmd: "vercel login",
44680
+ credentialPaths: ["~/.local/share/com.vercel.cli/auth.json"],
44681
+ description: "`vercel deploy`; manage env vars, domains, preview URLs.",
44682
+ versionCmd: "vercel --version 2>/dev/null | sed -n 1p",
44683
+ deviceCodePattern: "user_code=([A-Z0-9-]+)",
44684
+ oauthUrlPattern: "(https://vercel\\.com/oauth/device\\S*)",
44685
+ canStreamLogin: true
44686
+ },
44687
+ eas: {
44688
+ category: "deployment",
44689
+ pkg: "eas-cli",
44690
+ installer: "npm",
44691
+ label: "Expo EAS",
44692
+ summary: "Build, update and submit mobile apps with Expo.",
44693
+ statusCmd: `out=$(eas whoami 2>/dev/null) && printf '%s\\n' "$out" | tr -d '\\r' | grep -m1 .`,
44694
+ loginCmd: "eas login --browser",
44695
+ logoutCmd: "eas logout",
44696
+ oauthUrlPattern: "(https://expo\\.dev/(?:sso-)?login\\?\\S+)",
44697
+ canStreamLogin: true,
44698
+ credentialPaths: ["~/.expo/state.json"],
44699
+ description: "Expo Application Services for React Native apps: `eas update --channel <c>` ships a JS-only OTA, `eas build -p ios --profile production --auto-submit` (`-p all` for both) makes a native build and sends it to TestFlight / Play. `eas build:list`, `eas update:list` and `eas submit` inspect or re-submit existing builds. An OTA only reaches installs whose runtimeVersion matches, so a native version bump needs a real build. The browser login binds to a RANDOM loopback port, so it only completes in a browser on the same host; on a remote/headless host set EXPO_TOKEN (Account -> Access tokens) instead. EXPO_TOKEN (Account -> Access tokens) works in CI instead of a login.",
44700
+ versionCmd: "eas --version 2>/dev/null | sed -n 1p"
44701
+ },
44702
+ netlify: {
44703
+ category: "deployment",
44704
+ pkg: "netlify-cli",
44705
+ installer: "npm",
44706
+ label: "Netlify",
44707
+ summary: "Deploy websites to Netlify and manage them.",
44708
+ statusCmd: `netlify api getCurrentUser 2>&1 | sed -n 's/.*"email"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' | grep -m10 .`,
44709
+ loginCmd: "netlify login",
44710
+ credentialPaths: ["~/.netlify/config.json"],
44711
+ description: "`netlify deploy --prod` for production; manage env vars, forms, identity.",
44712
+ versionCmd: "netlify --version 2>/dev/null | sed -n 1p",
44713
+ oauthUrlPattern: "(https://app\\.netlify\\.com/authorize\\S+)",
44714
+ canStreamLogin: true
44715
+ },
44716
+ firebase: {
44717
+ preinstallCloud: true,
44718
+ category: "deployment",
44719
+ pkg: "firebase-tools",
44720
+ installer: "npm",
44721
+ label: "Firebase",
44722
+ summary: "Deploy and manage Firebase hosting, database and functions.",
44723
+ statusCmd: "firebase login:list 2>&1 | grep -oiE '[[:alnum:]._%+-]+@[[:alnum:].-]+\\.[[:alpha:]]{2,}' | grep -m1 .",
44724
+ loginCmd: "firebase login --no-localhost --reauth",
44725
+ loginNeedsPty: true,
44726
+ stdinPaste: true,
44727
+ credentialPaths: ["~/.config/configstore/firebase-tools.json"],
44728
+ description: "Deploy hosting/functions, manage Firestore/RTDB rules and data, auth users, emulators.",
44729
+ versionCmd: "firebase --version 2>/dev/null | sed -n 1p",
44730
+ oauthUrlPattern: "(https://auth\\.firebase\\.tools/login\\S+)",
44731
+ sessionIdPattern: "session ID:\\s*([0-9A-Za-z]{4,8})"
44732
+ },
44733
+ wrangler: {
44734
+ preinstallCloud: true,
44735
+ category: "deployment",
44736
+ pkg: "wrangler",
44737
+ installer: "npm",
44738
+ label: "Cloudflare",
44739
+ summary: "Deploy and manage Cloudflare Workers and Pages.",
44740
+ statusCmd: "wrangler whoami 2>&1 | grep -oiE '[[:alnum:]._%+-]+@[[:alnum:].-]+\\.[[:alpha:]]{2,}' | grep -m1 .",
44741
+ loginCmd: "wrangler login",
44742
+ credentialPaths: ["~/.config/.wrangler/config/default.toml"],
44743
+ description: "Tail logs with `wrangler tail`. Use `cloudflared` for tunnels.",
44744
+ versionCmd: "wrangler --version 2>/dev/null | sed -n 1p",
44745
+ oauthUrlPattern: "(https://dash\\.cloudflare\\.com/oauth2/auth\\S+)",
44746
+ oauthCallbackPort: 8976
44747
+ },
44748
+ stripe: {
44749
+ preinstallCloud: true,
44750
+ cloudInstallCmd: "curl -fsSL https://github.com/stripe/stripe-cli/releases/download/v1.50.10/stripe_1.50.10_linux_x86_64.tar.gz | tar -xz -C /usr/local/bin stripe",
44751
+ cloudVerifyCmd: "stripe --version",
44752
+ category: "payments",
44753
+ pkg: "stripe",
44754
+ installer: "binary",
44755
+ label: "Stripe",
44756
+ summary: "Look up Stripe payments, customers and subscriptions.",
44757
+ statusCmd: "stripe config --list 2>/dev/null | sed -n 's/^account_id[[:space:]]*=[[:space:]]*.\\([^'\\'']*\\).*/\\1/p' | grep -m10 .",
44758
+ loginCmd: "stripe login",
44759
+ loginNeedsPty: true,
44760
+ credentialPaths: ["~/.config/stripe/config.toml"],
44761
+ description: "`stripe listen` forwards webhooks locally; `stripe get/post /v1/...` for raw API.",
44762
+ versionCmd: "stripe --version 2>/dev/null | sed -n 1p",
44763
+ deviceCodePattern: "verification code:\\s*([A-Z0-9]{4}-[A-Z0-9]{4})",
44764
+ oauthUrlPattern: "(https://access\\.stripe\\.com/stripecli/\\S+)",
44765
+ canStreamLogin: true
44766
+ },
44767
+ flyctl: {
44768
+ category: "cloud",
44769
+ pkg: "flyctl",
44770
+ installer: "binary",
44771
+ label: "Fly.io",
44772
+ summary: "Deploy and scale apps on Fly.io.",
44773
+ statusCmd: "flyctl auth whoami 2>/dev/null | tr -d '\\r' | grep -m1 .",
44774
+ loginCmd: "flyctl auth login -t <access_token>",
44775
+ credentialPaths: ["~/.fly/config.yml"],
44776
+ description: "`flyctl deploy` from app dir; manage Postgres/volumes/machines/secrets.",
44777
+ versionCmd: "flyctl version 2>/dev/null | sed -n 1p"
44778
+ },
44779
+ supabase: {
44780
+ preinstallCloud: true,
44781
+ cloudInstallCmd: "curl -fsSL https://github.com/supabase/cli/releases/download/v2.117.0/supabase_2.117.0_linux_amd64.tar.gz | tar -xz -C /usr/local/bin supabase",
44782
+ cloudVerifyCmd: "supabase --version",
44783
+ category: "cloud",
44784
+ pkg: "supabase",
44785
+ installer: "binary",
44786
+ label: "Supabase",
44787
+ summary: "Manage your Supabase database, auth and storage.",
44788
+ statusCmd: "supabase projects list >/dev/null 2>&1 && echo authenticated",
44789
+ loginCmd: "supabase login --token <access_token>",
44790
+ credentialPaths: ["~/.config/supabase/access-token"],
44791
+ description: "Link to cloud project; runs/migrates local Postgres.",
44792
+ versionCmd: "supabase --version 2>/dev/null | sed -n 1p"
44793
+ },
44794
+ railway: {
44795
+ category: "cloud",
44796
+ pkg: "@railway/cli",
44797
+ installer: "npm",
44798
+ label: "Railway",
44799
+ summary: "Deploy and manage apps and databases on Railway.",
44800
+ statusCmd: `out=$(RAILWAY_NO_TELEMETRY=1 railway whoami 2>&1); rc=$?; printf '%s\\n' "$out" | grep -m1 .; exit $rc`,
44801
+ loginCmd: "railway login --browserless",
44802
+ credentialPaths: ["~/.railway/config.json"],
44803
+ description: "`railway up` to deploy current dir.",
44804
+ versionCmd: "railway --version 2>/dev/null | sed -n 1p",
44805
+ deviceCodePattern: "user_code=([A-Z0-9-]+)",
44806
+ oauthUrlPattern: "(https://railway\\.com/activate\\S*)",
44807
+ canStreamLogin: true
44808
+ },
44809
+ shopify: {
44810
+ preinstallCloud: true,
44811
+ category: "ecommerce",
44812
+ pkg: "@shopify/cli",
44813
+ installer: "npm",
44814
+ label: "Shopify",
44815
+ summary: "Build and manage Shopify stores and themes.",
44816
+ loginCmd: "shopify auth login --alias tfa",
44817
+ credentialPaths: ["~/.config/shopify-cli-kit-nodejs/config.json"],
44818
+ versionCmd: `node -p "require(require('fs').realpathSync(require('child_process').execSync('command -v shopify',{encoding:'utf8'}).trim()).replace(/\\/bin\\/[^/]*$/, '/package.json')).version" 2>/dev/null`,
44819
+ statusCmd: `python3 -c "import json,os,sys;p=os.path.expanduser('~/.config/shopify-cli-kit-nodejs/config.json');sys.exit(0 if json.load(open(p)).get('session') else 1)" 2>/dev/null && echo authenticated`,
44820
+ deviceCodePattern: "verification code: ([A-Z0-9-]+)",
44821
+ oauthUrlPattern: "(https://accounts\\.shopify\\.com/activate-with-code\\S*)",
44822
+ canStreamLogin: true,
44823
+ description: "Theme development, app scaffolding, store management"
44824
+ },
44825
+ "shop-app": {
44826
+ preinstallCloud: true,
44827
+ category: "ecommerce",
44828
+ pkg: "@todoforai/shop-app",
44829
+ installer: "npm",
44830
+ label: "Shop",
44831
+ summary: "Search products and compare prices across Shopify stores.",
44832
+ description: "Shop.app product search across Shopify stores. `shop-app search '<query>' --ships-to HU -n 10` returns products with price, rating, URL, and variants. `shop-app similar <variantId>` finds lookalikes.",
44833
+ versionCmd: "shop-app --version 2>/dev/null | sed -n 1p"
44834
+ },
44835
+ "datadog-ci": {
44836
+ category: "monitoring",
44837
+ pkg: "@datadog/datadog-ci",
44838
+ installer: "npm",
44839
+ label: "Datadog",
44840
+ summary: "Send test results and releases to Datadog.",
44841
+ versionCmd: "datadog-ci version 2>/dev/null | sed -n 1p",
44842
+ statusCmd: 'test -n "$DATADOG_API_KEY" && echo authenticated',
44843
+ description: "CI test visibility, sourcemap uploads, deployment tracking."
44844
+ },
44845
+ "sentry-cli": {
44846
+ preinstallCloud: true,
44847
+ category: "monitoring",
44848
+ pkg: "@sentry/cli",
44849
+ installer: "npm",
44850
+ label: "Sentry",
44851
+ summary: "Manage Sentry releases and error tracking.",
44852
+ statusCmd: "sentry-cli info --no-defaults >/dev/null 2>&1 && echo authenticated",
44853
+ loginCmd: "sentry-cli login --auth-token <auth_token>",
44854
+ credentialPaths: ["~/.sentryclirc"],
44855
+ description: "`sentry-cli releases new <version>`.",
44856
+ versionCmd: "sentry-cli --version 2>/dev/null | sed -n 1p"
44857
+ },
44858
+ "tfa-cli": {
44859
+ category: "utility",
44860
+ pkg: "@todoforai/cli",
44861
+ installer: "npm",
44862
+ label: "TODOforAI",
44863
+ summary: "Create and follow up on your TODOs, and show results in the chat.",
44864
+ description: 'Manage the user\'s OWN TODOforAI tasks (not code `// TODO` comments). Delegate/spin off work: `tfa-cli "prompt"` creates a real TODO with its own agent and chat (`-n` wait for completion, `--no-watch` fire-and-forget, `--project/--agent/--model`, `--resume <id>`, `addmessage <id> "text"`). Inspect: `list [--status open]`, `--inspect <id>`. Edit any todo without opening it: `status <id> DONE|READY|ARCHIVED|POSTPONED|CANCELLED|DELETED` (close, reopen, shelve, trash — `todo restore <id>` undoes a delete) and `todo set <id|-> title=… group=… star=true schedule=<unix-ms> agent=… brand=…` (own todo fields). Both take ONE id, so a loop over `list --json | jq -r \'.items[].id\'` is how you close, retitle, refile or archive MANY todos at once; `project set|settings|groups …` (name, settings, todo groups), `agent create|update <agent> model=… sysmsg=…` (permissions/MCP/device wiring and delete are refused from an agent shell). Surface results into chat: `show <file|-> [todo-id]` (renders by mimetype; `--card <name>` via project renderer; `--alias <name>` updates in place), `open <url>` embeds a live preview. Notifications: `inbox [needs-you|messages|activity] [--unread]` reads the user\'s bell feed (what finished/failed/needs them while away), `inbox seen [tab]` marks it read; `notify "Title" "message" [--href /t/<id>]` leaves a note in the user\'s Messages tab + phone push — recipient is ALWAYS the key\'s own user (no --to; cannot message teammates or anyone else), shown as from you, same text is delivered once, max 10/day, use for things they must see later (not chat replies). This is the ONLY way to display a local file (image, pdf, html) in the chat: markdown `![](path.png)` with a local/relative path does NOT resolve to workspace files or attachments and 404s in the browser. `--template` for registry workflows.',
44865
+ installCmd: "npm install -g @todoforai/cli",
44866
+ versionCmd: "tfa-cli --version 2>/dev/null | sed -n 1p",
44867
+ preinstallCloud: true,
44868
+ preinstallJarvis: true,
44869
+ aliases: ["todoforai-cli", "todoai"]
44870
+ },
44871
+ curl: {
44872
+ commodity: true,
44873
+ category: "networking",
44874
+ pkg: "curl",
44875
+ installer: "system",
44876
+ label: "Web Request",
44877
+ summary: "Fetch URLs and call web APIs.",
44878
+ binName: "curl",
44879
+ description: "HTTP/HTTPS/FTP client: GET/POST/PUT/DELETE, headers, auth, file upload/download, follow redirects, cookies, TLS.",
44880
+ versionCmd: "curl --version 2>/dev/null | sed -n 1p | cut -d' ' -f1-2",
44881
+ preinstallCloud: true,
44882
+ internal: true,
44883
+ preinstallJarvis: true
44884
+ },
44885
+ cloudflared: {
44886
+ preinstallCloud: true,
44887
+ cloudInstallCmd: "curl -fsSL https://github.com/cloudflare/cloudflared/releases/download/2026.9.0/cloudflared-linux-amd64 -o /usr/local/bin/cloudflared && chmod 0755 /usr/local/bin/cloudflared",
44888
+ cloudVerifyCmd: "cloudflared --version",
44889
+ commodity: true,
44890
+ category: "networking",
44891
+ pkg: "cloudflared",
44892
+ installer: "binary",
44893
+ label: "Tunnel",
44894
+ summary: "Put a local app on a public web address.",
44895
+ description: "`cloudflared tunnel --url http://localhost:<port>` prints a public https URL.",
44896
+ versionCmd: "cloudflared --version 2>/dev/null | sed -n 1p"
44897
+ },
44898
+ vault: {
44899
+ category: "security",
44900
+ pkg: "vault",
44901
+ installer: "binary",
44902
+ label: "HashiCorp Vault",
44903
+ summary: "Read and manage secrets in HashiCorp Vault.",
44904
+ statusCmd: "vault token lookup >/dev/null 2>&1 && echo authenticated",
44905
+ loginCmd: "vault login <token>",
44906
+ credentialPaths: ["~/.vault-token"],
44907
+ versionCmd: "vault --version 2>/dev/null | sed -n '1s/ (.*//p'",
44908
+ description: "HashiCorp Vault secrets management and dynamic credentials."
44909
+ },
44910
+ rclone: {
44911
+ category: "cloud",
44912
+ pkg: "rclone",
44913
+ installer: "binary",
44914
+ preinstallCloud: true,
44915
+ binary: {
44916
+ "linux-x86_64": { url: "https://github.com/todoforai/rclone-backend/releases/download/v0.1.6/rclone-linux-amd64.tar.gz", archive: "tar.gz", extract: "rclone" },
44917
+ "linux-aarch64": { url: "https://github.com/todoforai/rclone-backend/releases/download/v0.1.6/rclone-linux-arm64.tar.gz", archive: "tar.gz", extract: "rclone" },
44918
+ "darwin-x86_64": { url: "https://github.com/todoforai/rclone-backend/releases/download/v0.1.6/rclone-darwin-amd64.tar.gz", archive: "tar.gz", extract: "rclone" },
44919
+ "darwin-aarch64": { url: "https://github.com/todoforai/rclone-backend/releases/download/v0.1.6/rclone-darwin-arm64.tar.gz", archive: "tar.gz", extract: "rclone" },
44920
+ "windows-x86_64": { url: "https://github.com/todoforai/rclone-backend/releases/download/v0.1.6/rclone-windows-amd64.zip", archive: "zip", extract: "rclone.exe" }
44921
+ },
44922
+ label: "Cloud Storage",
44923
+ summary: "Move files between Google Drive, Dropbox, OneDrive, S3 and more.",
44924
+ statusCmd: "rclone listremotes --long 2>/dev/null | tr -s ' ' | grep -v ' todoforai *$' | grep -m20 .",
44925
+ loginCmd: "rclone config",
44926
+ loginTerminalHint: "Connect a storage from its own tile (Google Drive, OneDrive, Dropbox…). For other backends run `rclone config` in a terminal on this host.",
44927
+ oauthUrlPattern: "(https?://127\\.0\\.0\\.1:\\d+/auth\\?\\S+)",
44928
+ oauthCallbackPort: 53682,
44929
+ credentialPaths: ["~/.config/rclone/rclone.conf"],
44930
+ subProviders: {
44931
+ gdrive: {
44932
+ label: "Google Drive",
44933
+ authType: "oauth",
44934
+ connectCmd: "rclone config create {{REMOTE}} drive",
44935
+ remoteName: "gdrive",
44936
+ rcloneType: "drive",
44937
+ userInfoCmd: `TOKEN=$(rclone config dump 2>/dev/null | python3 -c "import json,sys; print(json.loads(json.load(sys.stdin)['{{REMOTE}}']['token'])['access_token'])") && curl -sf 'https://www.googleapis.com/drive/v3/about?fields=user' -H "Authorization: Bearer $TOKEN" | python3 -c "import json,sys; print(json.load(sys.stdin)['user']['emailAddress'])" 2>/dev/null`
44938
+ },
44939
+ onedrive: {
44940
+ label: "OneDrive",
44941
+ authType: "oauth",
44942
+ connectCmd: "rclone config create {{REMOTE}} onedrive",
44943
+ remoteName: "onedrive",
44944
+ rcloneType: "onedrive",
44945
+ userInfoCmd: `TOKEN=$(rclone config dump 2>/dev/null | python3 -c "import json,sys; print(json.loads(json.load(sys.stdin)['{{REMOTE}}']['token'])['access_token'])") && curl -sf 'https://graph.microsoft.com/v1.0/me' -H "Authorization: Bearer $TOKEN" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('mail') or d.get('userPrincipalName',''))" 2>/dev/null`
44946
+ },
44947
+ dropbox: {
44948
+ label: "Dropbox",
44949
+ authType: "oauth",
44950
+ connectCmd: "rclone config create {{REMOTE}} dropbox",
44951
+ remoteName: "dropbox",
44952
+ rcloneType: "dropbox",
44953
+ userInfoCmd: `TOKEN=$(rclone config dump 2>/dev/null | python3 -c "import json,sys; print(json.loads(json.load(sys.stdin)['{{REMOTE}}']['token'])['access_token'])") && curl -sf -X POST 'https://api.dropboxapi.com/2/users/get_current_account' -H "Authorization: Bearer $TOKEN" | python3 -c "import json,sys; print(json.load(sys.stdin)['email'])" 2>/dev/null`
44954
+ },
44955
+ s3: {
44956
+ label: "Amazon S3",
44957
+ authType: "credentials",
44958
+ connectCmd: "rclone config create {{REMOTE}} s3",
44959
+ remoteName: "s3",
44960
+ rcloneType: "s3"
44961
+ }
44962
+ },
44963
+ versionCmd: "rclone version 2>/dev/null | sed -n 1p",
44964
+ preinstallJarvis: true,
44965
+ description: "Access Google Drive, OneDrive, Dropbox, S3, and 40+ cloud providers. List, copy, sync, move, and mount files; use `rclone config create <name> <provider>` to connect."
44966
+ },
44967
+ aws: {
44968
+ preinstallCloud: true,
44969
+ cloudInstallCmd: "curl -fsSL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o /tmp/awscli.zip && unzip -qo /tmp/awscli.zip -d /tmp && /tmp/aws/install --update && rm -rf /tmp/aws /tmp/awscli.zip",
44970
+ cloudVerifyCmd: "aws --version",
44971
+ category: "cloud",
44972
+ pkg: "awscli",
44973
+ installer: "system",
44974
+ label: "AWS",
44975
+ summary: "Manage your AWS account and services.",
44976
+ installCmd: `mkdir -p "$HOME/.todoforai/tools/bin"; if [ "$(uname -s)" = Darwin ]; then curl -fsSL https://awscli.amazonaws.com/AWSCLIV2.pkg -o /tmp/AWSCLIV2.pkg && printf '<?xml version="1.0" encoding="UTF-8"?>\\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\\n<plist version="1.0"><array><dict><key>choiceAttribute</key><string>customLocation</string><key>attributeSetting</key><string>%s</string><key>choiceIdentifier</key><string>default</string></dict></array></plist>\\n' "$HOME/.todoforai/tools" > /tmp/aws-choices.xml && installer -pkg /tmp/AWSCLIV2.pkg -target CurrentUserHomeDirectory -applyChoiceChangesXML /tmp/aws-choices.xml && mkdir -p "$HOME/.todoforai/tools/bin" && ln -sf "$HOME/.todoforai/tools/aws-cli/aws" "$HOME/.todoforai/tools/bin/aws" && ln -sf "$HOME/.todoforai/tools/aws-cli/aws_completer" "$HOME/.todoforai/tools/bin/aws_completer"; rc=$?; rm -f /tmp/AWSCLIV2.pkg /tmp/aws-choices.xml; exit $rc; else ARCH=$(uname -m); case "$ARCH" in arm64|aarch64) ARCH=aarch64;; *) ARCH=x86_64;; esac; curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-$ARCH.zip" -o /tmp/awscli.zip && rm -rf /tmp/aws && unzip -qo /tmp/awscli.zip -d /tmp && /tmp/aws/install --update --install-dir "$HOME/.todoforai/tools/aws-cli" --bin-dir "$HOME/.todoforai/tools/bin"; rc=$?; rm -rf /tmp/aws /tmp/awscli.zip; exit $rc; fi`,
44977
+ statusCmd: "aws sts get-caller-identity --query Arn --output text 2>/dev/null | sed 's/.*\\///' | grep -m1 .",
44978
+ loginCmd: "aws configure set aws_access_key_id <access_key_id> && aws configure set aws_secret_access_key <secret_access_key> && aws configure set region <region>",
44979
+ credentialPaths: ["~/.aws/credentials", "~/.aws/config", "~/.aws/sso/cache"],
44980
+ description: "Official AWS CLI v2, installed user-locally into ~/.todoforai/tools (no sudo; Linux x86_64/aarch64 + macOS). Auth via `aws configure` (access keys) or `aws configure sso` + `aws sso login` (browser device flow).",
44981
+ versionCmd: "aws --version 2>/dev/null | sed -n 1p",
44982
+ uninstallCmd: 'rm -rf "$HOME/.todoforai/tools/aws-cli" "$HOME/.todoforai/tools/bin/aws" "$HOME/.todoforai/tools/bin/aws_completer"; hash -r 2>/dev/null; ! command -v aws >/dev/null 2>&1 || { echo "aws is still on PATH: $(command -v aws) — not installed by TODOforAI, remove it with the package manager that installed it (snap/apt/brew/sudo)"; exit 1; }'
44983
+ },
44984
+ gcloud: {
44985
+ category: "cloud",
44986
+ pkg: "google-cloud-sdk",
44987
+ installer: "system",
44988
+ label: "Google Cloud",
44989
+ summary: "Manage your Google Cloud projects and services.",
44990
+ installCmd: 'curl -sSL https://sdk.cloud.google.com | bash -s -- --disable-prompts && mkdir -p "$HOME/.todoforai/tools/bin" && ln -sf "$HOME/google-cloud-sdk/bin/gcloud" "$HOME/.todoforai/tools/bin/gcloud"',
44991
+ statusCmd: `gcloud auth list --filter=status:ACTIVE --format="value(account)" 2>/dev/null | tr -d '\\r' | grep -m1 .`,
44992
+ loginCmd: "gcloud auth login --no-launch-browser",
44993
+ loginNeedsPty: true,
44994
+ stdinPaste: true,
44995
+ oauthUrlPattern: "(https://accounts\\.google\\.com/o/oauth2/auth\\S+)",
44996
+ credentialPaths: ["~/.config/gcloud"],
44997
+ description: "Official Google Cloud CLI. `gcloud auth login --no-launch-browser` prints the OAuth URL and waits for the pasted verification code.",
44998
+ versionCmd: "gcloud --version 2>/dev/null | sed -n 1p",
44999
+ uninstallCmd: 'rm -rf "$HOME/google-cloud-sdk" "$HOME/.todoforai/tools/bin/gcloud"; hash -r 2>/dev/null; ! command -v gcloud >/dev/null 2>&1 || { echo "gcloud is still on PATH: $(command -v gcloud)"; exit 1; }',
45000
+ updateCmd: "gcloud components update --quiet"
45001
+ },
45002
+ az: {
45003
+ category: "cloud",
45004
+ pkg: "azure-cli",
45005
+ installer: "pip",
45006
+ label: "Azure",
45007
+ summary: "Manage your Microsoft Azure resources.",
45008
+ binName: "az",
45009
+ statusCmd: "az account show --query user.name -o tsv 2>/dev/null | tr -d '\\r' | grep -m1 .",
45010
+ loginCmd: "az login --use-device-code",
45011
+ oauthUrlPattern: "(https://login\\.microsoft\\.com/device\\S*)",
45012
+ deviceCodePattern: "enter the code ([A-Z0-9]+)",
45013
+ canStreamLogin: true,
45014
+ credentialPaths: ["~/.azure"],
45015
+ description: "Official Azure CLI. Device-code login: prints login.microsoft.com/device + a code, then polls — no callback port.",
45016
+ versionCmd: `az version --query '"azure-cli"' -o tsv 2>/dev/null | sed -n 1p`
45017
+ },
45018
+ doctl: {
45019
+ preinstallCloud: true,
45020
+ cloudInstallCmd: "curl -fsSL https://github.com/digitalocean/doctl/releases/download/v1.168.0/doctl-1.168.0-linux-amd64.tar.gz | tar -xz -C /usr/local/bin doctl",
45021
+ cloudVerifyCmd: "doctl version",
45022
+ category: "cloud",
45023
+ pkg: "doctl",
45024
+ installer: "binary",
45025
+ label: "DigitalOcean",
45026
+ summary: "Manage your DigitalOcean servers and apps.",
45027
+ statusCmd: "doctl account get --format Email --no-header 2>/dev/null | tr -d '\\r' | grep -m1 .",
45028
+ loginCmd: "doctl auth init -t <access_token>",
45029
+ loginNeedsPty: true,
45030
+ credentialPaths: ["~/.config/doctl/config.yaml"],
45031
+ description: "Official DigitalOcean CLI. `doctl auth init` prompts for an API token from cloud.digitalocean.com/account/api/tokens.",
45032
+ versionCmd: "doctl version 2>/dev/null | sed -n 1p"
45033
+ },
45034
+ rdt: {
45035
+ preinstallCloud: true,
45036
+ packages: ["rdt-cli==0.4.1"],
45037
+ category: "social",
45038
+ pkg: "rdt-cli",
45039
+ installer: "pip",
45040
+ label: "Reddit",
45041
+ summary: "Search Reddit, read threads and post comments.",
45042
+ statusCmd: `rdt status 2>&1 | sed -n 's/.*"username"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' | grep -m10 .`,
45043
+ loginCmd: "rdt login",
45044
+ loginTerminalHint: "Log in to reddit.com in a browser on this host (Chrome/Firefox), then run `rdt login`: it imports that browser's Reddit cookies.",
45045
+ credentialPaths: ["~/.config/rdt-cli/credential.json"],
45046
+ description: 'Reddit CLI. Read: `rdt search "<query>" -r <sub> --json -c`, `rdt sub <name>`, `rdt read <postId>`, `rdt user-comments <user>`. Write: `rdt comment <postId> "<text>"`, `rdt upvote`, `rdt save`.',
45047
+ versionCmd: "rdt --version 2>/dev/null | sed -n 1p"
45048
+ },
45049
+ pymupdf: {
45050
+ category: "utility",
45051
+ pkg: "pymupdf",
45052
+ packages: ["pymupdf==1.28.2"],
45053
+ installer: "pip",
45054
+ label: "PDF",
45055
+ summary: "Read, edit, merge and split PDF files.",
45056
+ versionCmd: "{ python -c 'import pymupdf; print(pymupdf.__version__)' || python3 -c 'import pymupdf; print(pymupdf.__version__)' || py -c 'import pymupdf; print(pymupdf.__version__)'; } 2>/dev/null",
45057
+ preinstallCloud: true,
45058
+ cloudVerifyCmd: "python3 -c 'import pymupdf'",
45059
+ preinstallJarvis: true,
45060
+ description: "PDF text editing, extraction, merge, split. Call via `python3 -c`."
45061
+ },
45062
+ pyhanko: {
45063
+ category: "security",
45064
+ pkg: "pyhanko-cli",
45065
+ packages: ["pyhanko-cli==0.5.0", "pyHanko[pkcs11,image-support,opentype]==0.37.0"],
45066
+ installer: "pip",
45067
+ binName: "pyhanko",
45068
+ label: "PDF Signing",
45069
+ summary: "Digitally sign and verify PDFs with a certificate (PAdES, timestamps, smart cards).",
45070
+ versionCmd: "pyhanko --version 2>/dev/null | sed -n 1p",
45071
+ preinstallCloud: true,
45072
+ cloudVerifyCmd: "pyhanko --version",
45073
+ preinstallJarvis: true,
45074
+ description: "Cryptographic PDF signing/validation (PAdES B-B..B-LTA). Sign: `pyhanko sign addsig --field Sig1 [--timestamp-url <tsa>] pkcs12 --passfile pass.txt in.pdf out.pdf cert.p12`; smart card/eID: `... pkcs11 --lib <pkcs11.so> in.pdf out.pdf`; verify: `pyhanko sign validate --pretty-print [--trust ca.pem] out.pdf`; list fields: `pyhanko sign list`. The signer's cert/key comes from the user (vault); self-signed certs validate only with `--trust`. Not for click-to-sign workflows."
45075
+ },
45076
+ anydoc: {
45077
+ category: "utility",
45078
+ pkg: "@firecrawl/anydoc",
45079
+ installer: "npm",
45080
+ binName: "anydoc",
45081
+ label: "Doc to Markdown",
45082
+ summary: "Turn Word, PowerPoint, Excel and other documents into clean text.",
45083
+ description: "Office/rich docs (docx/pptx/xlsx/odt/rtf/epub/csv) → Markdown, fully local. `anydoc file.docx` → stdout, `-o out.md` writes, `anydoc - --format csv < stdin`. Prefer over raw XML extraction for reading; one-way, no OCR for scanned PDFs.",
45084
+ versionCmd: "anydoc --version 2>/dev/null | sed -n 1p",
45085
+ preinstallCloud: true,
45086
+ preinstallJarvis: true
45087
+ },
45088
+ "agent-browser": {
45089
+ category: "development",
45090
+ pkg: "agent-browser@0.30.1",
45091
+ installer: "npm",
45092
+ preinstallCloud: true,
45093
+ label: "Browser",
45094
+ summary: "Browse websites automatically: click, type, read and screenshot.",
45095
+ description: "Browser automation over CDP (`open`/`snapshot`/`click`/`type`/`fill`/`read`/`screenshot`/`eval`). `connect '<url>'` to a listed live browser (prefer the user's real Chrome), verify with `snapshot`; if empty, `close` (own session only) and reconnect once. NEVER `close --all`. Shared browser: `tab new` for your own tab, `tab <id>` before each command. No URL listed: cloud → browser-manager-cli; PC with display → Chrome `--remote-debugging-port=9222`, attach `--cdp 9222`.",
45096
+ versionCmd: "agent-browser --version 2>/dev/null | sed -n 1p",
45097
+ preinstallJarvis: true
45098
+ },
45099
+ "browser-manager-cli": {
45100
+ category: "development",
45101
+ pkg: "browser-manager-cli",
45102
+ installer: "binary",
45103
+ binName: "browser-manager-cli",
45104
+ preinstallCloud: true,
45105
+ label: "Browser Manager",
45106
+ summary: "Start browsers in the cloud for automated browsing.",
45107
+ platformAuth: true,
45108
+ description: "Spawns cloud Chromium sessions, each exposed as a CDP WebSocket for agent-browser to drive. `create` prints one line ending in a cdpUrl — pass it straight to `agent-browser connect '<cdpUrl>'` (connect the cdpUrl, not the Chrome debug port). `list`/`get <id>`, `delete <id>`/`delete-all`, `hibernate`/`restore`. Sessions run stealth Chromium that reads as a real desktop browser. For sites that block datacenter IPs, route through a proxy: `create --proxy socks5://host:port [--proxy-user U --proxy-pass P]`. Use this on the cloud VM instead of launching a local browser.",
45109
+ versionCmd: "browser-manager-cli version 2>/dev/null | sed -n 1p",
45110
+ binary: {
45111
+ "linux-x86_64": {
45112
+ url: "https://github.com/todoforai/browser-manager/releases/download/cli-v0.1.1/browser-manager-cli-linux-x86_64",
45113
+ archive: "raw"
45114
+ },
45115
+ "linux-aarch64": {
45116
+ url: "https://github.com/todoforai/browser-manager/releases/download/cli-v0.1.1/browser-manager-cli-linux-aarch64",
45117
+ archive: "raw"
45118
+ },
45119
+ "darwin-x86_64": {
45120
+ url: "https://github.com/todoforai/browser-manager/releases/download/cli-v0.1.1/browser-manager-cli-darwin-x86_64",
45121
+ archive: "raw"
45122
+ },
45123
+ "darwin-aarch64": {
45124
+ url: "https://github.com/todoforai/browser-manager/releases/download/cli-v0.1.1/browser-manager-cli-darwin-aarch64",
45125
+ archive: "raw"
45126
+ },
45127
+ "windows-x86_64": {
45128
+ url: "https://github.com/todoforai/browser-manager/releases/download/cli-v0.1.1/browser-manager-cli-windows-x86_64.exe",
45129
+ archive: "raw"
45130
+ }
45131
+ },
45132
+ preinstallJarvis: true
45133
+ },
45134
+ "todoforai-browser": {
45135
+ category: "development",
45136
+ pkg: "@todoforai/browser",
45137
+ aliases: ["tfa-browser"],
45138
+ installer: "npm",
45139
+ preinstallCloud: true,
45140
+ label: "Browser (Extension)",
45141
+ summary: "Drive your own browser through the TODOforAI extension.",
45142
+ versionCmd: `node -p "require(require('fs').realpathSync(require('child_process').execSync('command -v todoforai-browser',{encoding:'utf8'}).trim()).replace(/\\/dist\\/index\\.js$/, '/package.json')).version" 2>/dev/null`,
45143
+ internal: true,
45144
+ preinstallJarvis: true,
45145
+ description: "Browser automation via extension (non-headless), web scraping, accessibility tree snapshots, screenshots, PDF generation"
45146
+ },
45147
+ "tfa-explore": {
45148
+ preinstallCloud: true,
45149
+ category: "development",
45150
+ pkg: "@todoforai/tfa-explore",
45151
+ installer: "npm",
45152
+ label: "Explore",
45153
+ summary: "Send a helper agent to explore a codebase and report back.",
45154
+ platformAuth: true,
45155
+ description: 'Sub-agent codebase exploration in its own context, you get only the answer: `tfa-explore "where is auth handled?" [--repo <path>]`. Prefer over manual multi-file searching.',
45156
+ versionCmd: "tfa-explore --version 2>/dev/null | sed -n 1p",
45157
+ installCmd: "npm install -g @todoforai/tfa-explore",
45158
+ internal: true
45159
+ },
45160
+ "tfa-review": {
45161
+ preinstallCloud: true,
45162
+ category: "development",
45163
+ pkg: "@todoforai/tfa-review",
45164
+ installer: "npm",
45165
+ label: "Review",
45166
+ summary: "Send a helper agent to review your code changes.",
45167
+ platformAuth: true,
45168
+ description: 'Sub-agent review of a git diff in its own context: `tfa-review "<goal>" [--repo <path>] [--against <ref>]` (default: uncommitted). Run before calling a non-trivial change done.',
45169
+ versionCmd: "tfa-review --version 2>/dev/null | sed -n 1p",
45170
+ installCmd: "npm install -g @todoforai/tfa-review",
45171
+ internal: true
45172
+ },
45173
+ "tfa-summary": {
45174
+ preinstallCloud: true,
45175
+ category: "development",
45176
+ pkg: "@todoforai/tfa-summary",
45177
+ installer: "npm",
45178
+ label: "Summary",
45179
+ summary: "Summarize files or long output with a helper agent.",
45180
+ platformAuth: true,
45181
+ description: 'Sub-agent summary so raw text never enters your context: `cat big.log | tfa-summary "what failed?"`, or `-f <file>` (repeatable).',
45182
+ versionCmd: "tfa-summary --version 2>/dev/null | sed -n 1p",
45183
+ installCmd: "npm install -g @todoforai/tfa-summary",
45184
+ internal: true
45185
+ },
45186
+ "tfa-handoff": {
45187
+ preinstallCloud: true,
45188
+ category: "development",
45189
+ pkg: "@todoforai/tfa-handoff",
45190
+ installer: "npm",
45191
+ label: "Handoff",
45192
+ summary: "Turn a long conversation into a short handover note.",
45193
+ platformAuth: true,
45194
+ description: "Compact a conversation into a handoff document for a fresh agent.",
45195
+ versionCmd: "tfa-handoff --version 2>/dev/null | sed -n 1p",
45196
+ installCmd: "npm install -g @todoforai/tfa-handoff",
45197
+ internal: true
45198
+ },
45199
+ "tfa-wait": {
45200
+ category: "development",
45201
+ pkg: "@todoforai/tfa-wait",
45202
+ installer: "npm",
45203
+ label: "Wait",
45204
+ summary: "Wait for a time or an event, then continue the task.",
45205
+ platformAuth: true,
45206
+ description: "Schedule a wake-up: `tfa-wait '<expr>' \"<message>\"` — expr is a time (`3h`, `daily@9:00`), a webhook, or a command's output; the message arrives later as a new chat message. Wait for a long job: `tfa-wait 'bench || 6h' \"Done: exit {{payload.exit}}\"` then `tfa-wait run '<cmd>' --pipe bench --on-exit &` (each stdout line = event; cancelling kills the command). Never pgrep/sleep poll loops.",
45207
+ versionCmd: "tfa-wait --version 2>/dev/null | sed -n 1p",
45208
+ installCmd: "npm install -g @todoforai/tfa-wait",
45209
+ preinstallCloud: true,
45210
+ internal: true,
45211
+ preinstallJarvis: true
45212
+ },
45213
+ "tfa-vault": {
45214
+ category: "security",
45215
+ pkg: "@todoforai/tfa-vault",
45216
+ installer: "npm",
45217
+ label: "Vault",
45218
+ summary: "Your password and secret store.",
45219
+ platformAuth: true,
45220
+ description: "The user's encrypted secret vault — using its secrets is the intended workflow. READ: when a task needs a key/token/password the user owns, `tfa-vault list` then `get <path>`; don't ask for what's already stored; never echo values. WRITE proactively: any new secret in the conversation (pasted, generated, from a login) → `put <path> field=value` (`patch` adds fields; `put` refuses an existing path — `put --force` replaces all fields on rotation). Paths: `accounts/<svc>`, `api/<svc>`, `secrets/<name>`.",
45221
+ versionCmd: "tfa-vault --version 2>/dev/null | sed -n 1p",
45222
+ installCmd: "npm install -g @todoforai/tfa-vault",
45223
+ preinstallCloud: true,
45224
+ preinstallJarvis: true
45225
+ },
45226
+ "tfa-settings": {
45227
+ category: "utility",
45228
+ pkg: "@todoforai/tfa-settings",
45229
+ installer: "npm",
45230
+ label: "Settings",
45231
+ summary: "Change your TODOforAI app preferences from the shell.",
45232
+ platformAuth: true,
45233
+ description: "The user's TODOforAI app preferences (AppSettings): `list`, `get <key>`, `set key=value …`, `keys` (documented keys). Use when asked to change theme, list style, tool-block density, thinking traces, sounds/toasts, preview columns, wallpaper etc. Values are JSON when parseable. Consent/credential/escalation keys (shellExecution, notifications, analytics, keyboard bindings, vault provider, billing address) are refused from an agent shell — tell the user to change those in Settings.",
45234
+ versionCmd: "tfa-settings --version 2>/dev/null | sed -n 1p",
45235
+ installCmd: "npm install -g @todoforai/tfa-settings",
45236
+ preinstallCloud: true,
45237
+ preinstallJarvis: true
45238
+ },
45239
+ "tfa-memory": {
45240
+ category: "productivity",
45241
+ pkg: "@todoforai/tfa-memory",
45242
+ installer: "npm",
45243
+ label: "Memory",
45244
+ summary: "Your long-term memory of notes, facts and past TODOs.",
45245
+ platformAuth: true,
45246
+ description: 'User\'s long-term memory (notes/procedures/decisions, address `source/ref`) plus every past TODO message (read-only, `todo/<todoId>:<messageId>`). READ: `search "<topic>" --mode fused` first (`lexical` = all words newest first, `semantic` = meaning; `--source todo` / `--todo <id>` narrow). stderr prints `N row(s) contain a query word` — if N exceeds what you saw, page with `--exclude <address>`. `get <address>` = full row, `around <address> --before N --after N` = surrounding dialogue. Before answering from memory, search once more with your draft\'s key facts. WRITE durable facts proactively: `add <source>/<ref> "text"` (same address updates in place; short source names like deploy-notes, preferences). `sources` lists them.',
45247
+ versionCmd: "tfa-memory --version 2>/dev/null | sed -n 1p",
45248
+ installCmd: "npm install -g @todoforai/tfa-memory",
45249
+ preinstallCloud: true,
45250
+ preinstallJarvis: true
45251
+ },
45252
+ "todoregistry-cli": {
45253
+ category: "development",
45254
+ pkg: "@todoforai/todoregistry-cli",
45255
+ installer: "npm",
45256
+ label: "TODO Registry",
45257
+ summary: "Browse ready-made business task templates.",
45258
+ description: "Reusable business task templates (SEO, email, CRM, ads, social, …): `search <q>`, `get <id>`, `list [category]`, `categories`, `create --name … --description … --body @prompt.md`. To recommend a template, don't create a todo directly — `tfa-cli recommend --template <id> --project <projectId>`.",
45259
+ versionCmd: "todoregistry-cli --version 2>/dev/null | sed -n 1p",
45260
+ installCmd: "npm install -g @todoforai/todoregistry-cli",
45261
+ preinstallCloud: true,
45262
+ internal: true,
45263
+ preinstallJarvis: true
45264
+ },
45265
+ "tfa-surface": {
45266
+ preinstallCloud: true,
45267
+ category: "utility",
45268
+ pkg: "@todoforai/tfa-surface",
45269
+ installer: "npm",
45270
+ label: "Surface",
45271
+ summary: "See and control what is on your TODOforAI screen.",
45272
+ platformAuth: true,
45273
+ description: "The user's live UI from the shell. Everything on screen is a SURFACE holding one ref (a todo id, `<todoId>:<alias>` = a shown artifact, or a url). `describe` lists them (kind, id, ref, focus, embedded-browser CDP URL; `--json`). `open overlay <todoId>` (full page), `open window <ref>` (floating), `open panel changes|preview|browser|terminal [--url]` (a todo's side panel), `open card <ref> [--title] [--group <slug>]` (a persisted board card every member sees); `close|focus <kind> <id>`. Persistent state (plans, reports, live status) → `show chat.panel <todoId> \"...md\"` (stdin ok; re-show updates in place), `clear` removes; events go in chat. `card add|list|get|rm <name>` = project HTML renderers. Exit 2 = no frontend connected.",
45274
+ versionCmd: "tfa-surface --version 2>/dev/null | sed -n 1p",
45275
+ installCmd: "npm install -g @todoforai/tfa-surface",
45276
+ internal: true
45277
+ },
45278
+ bun: {
45279
+ commodity: true,
45280
+ category: "development",
45281
+ pkg: "bun",
45282
+ installer: "system",
45283
+ label: "JS/TS Runtime",
45284
+ summary: "Run JavaScript and TypeScript code, fast.",
45285
+ versionCmd: "bun --version 2>/dev/null",
45286
+ preinstallCloud: true,
45287
+ cloudInstallCmd: "export BUN_INSTALL=/usr/local && curl -fsSL https://bun.sh/install | bash && ln -sf /usr/local/bin/bun /usr/local/bin/bunx",
45288
+ cloudVerifyCmd: "bun --version",
45289
+ internal: true,
45290
+ preinstallJarvis: true,
45291
+ description: "Run JavaScript/TypeScript, install packages, run tests (`bun`, `bunx`)."
45292
+ },
45293
+ bunx: {
45294
+ commodity: true,
45295
+ category: "development",
45296
+ pkg: "bunx",
45297
+ installer: "system",
45298
+ label: "Bun Package Runner",
45299
+ summary: "Run a JavaScript package without installing it.",
45300
+ versionCmd: "bunx --version 2>/dev/null",
45301
+ preinstallCloud: true,
45302
+ cloudVerifyCmd: "bunx --version",
45303
+ internal: true,
45304
+ description: "Run package binaries with Bun."
45305
+ },
45306
+ node: {
45307
+ commodity: true,
45308
+ category: "development",
45309
+ pkg: "node",
45310
+ installer: "system",
45311
+ label: "JavaScript Runtime",
45312
+ summary: "Run JavaScript code.",
45313
+ versionCmd: "node -p 'process.version' 2>/dev/null",
45314
+ preinstallCloud: true,
45315
+ cloudInstallCmd: "curl -fsSL https://deb.nodesource.com/setup_24.x | bash -",
45316
+ cloudAptPackages: ["nodejs"],
45317
+ cloudVerifyCmd: "node --version",
45318
+ internal: true,
45319
+ preinstallJarvis: true,
45320
+ description: "Run Node.js scripts."
45321
+ },
45322
+ python3: {
45323
+ commodity: true,
45324
+ category: "development",
45325
+ pkg: "python3",
45326
+ installer: "system",
45327
+ label: "Python",
45328
+ summary: "Run Python code.",
45329
+ versionCmd: "{ python3 --version || python --version || py --version; } 2>/dev/null | sed -n 1p",
45330
+ preinstallCloud: true,
45331
+ cloudAptPackages: ["python3"],
45332
+ cloudVerifyCmd: "python3 --version",
45333
+ internal: true,
45334
+ preinstallJarvis: true,
45335
+ description: "Run Python scripts."
45336
+ },
45337
+ npm: {
45338
+ commodity: true,
45339
+ category: "development",
45340
+ pkg: "npm",
45341
+ installer: "system",
45342
+ label: "Node Package Manager",
45343
+ summary: "Install JavaScript packages.",
45344
+ versionCmd: "npm --version 2>/dev/null",
45345
+ preinstallCloud: true,
45346
+ cloudVerifyCmd: "npm --version",
45347
+ internal: true,
45348
+ description: "Install Node packages and run package scripts."
45349
+ },
45350
+ npx: {
45351
+ commodity: true,
45352
+ category: "development",
45353
+ pkg: "npx",
45354
+ installer: "system",
45355
+ label: "Node Package Runner",
45356
+ summary: "Run a JavaScript package without installing it.",
45357
+ versionCmd: "npx --version 2>/dev/null",
45358
+ preinstallCloud: true,
45359
+ cloudVerifyCmd: "npx --version",
45360
+ internal: true,
45361
+ description: "Run npm package binaries."
45362
+ },
45363
+ pip3: {
45364
+ preinstallCloud: true,
45365
+ cloudAptPackages: ["python3-pip"],
45366
+ cloudVerifyCmd: "pip3 --version",
45367
+ commodity: true,
45368
+ category: "development",
45369
+ pkg: "pip3",
45370
+ installer: "system",
45371
+ label: "Python Package Installer",
45372
+ summary: "Install Python packages.",
45373
+ versionCmd: "pip3 --version 2>/dev/null | sed -n 1p | cut -d' ' -f1-2",
45374
+ internal: true,
45375
+ description: "Install Python packages."
45376
+ },
45377
+ uv: {
45378
+ commodity: true,
45379
+ category: "development",
45380
+ pkg: "uv",
45381
+ installer: "system",
45382
+ label: "Python Package Manager",
45383
+ summary: "Install Python packages and manage environments, fast.",
45384
+ versionCmd: "uv --version 2>/dev/null",
45385
+ preinstallCloud: true,
45386
+ cloudInstallCmd: "curl -LsSf https://astral.sh/uv/0.9.6/install.sh | env UV_INSTALL_DIR=/usr/local/bin sh",
45387
+ cloudVerifyCmd: "uv --version",
45388
+ internal: true,
45389
+ description: "Manage Python dependencies, environments, tools, and scripts (`uv`, `uvx`)."
45390
+ },
45391
+ uvx: {
45392
+ commodity: true,
45393
+ category: "development",
45394
+ pkg: "uvx",
45395
+ installer: "system",
45396
+ label: "Python Tool Runner",
45397
+ summary: "Run a Python tool without installing it.",
45398
+ versionCmd: "uvx --version 2>/dev/null",
45399
+ preinstallCloud: true,
45400
+ cloudVerifyCmd: "uvx --version",
45401
+ internal: true,
45402
+ description: "Run Python tools in isolated environments."
45403
+ },
45404
+ ripgrep: {
45405
+ commodity: true,
45406
+ category: "development",
45407
+ pkg: "ripgrep",
45408
+ installer: "binary",
45409
+ label: "Search",
45410
+ summary: "Search text across files, very fast.",
45411
+ description: "Fast recursive grep with regex, .gitignore-aware, parallel, unicode-correct",
45412
+ versionCmd: "rg --version 2>/dev/null | sed -n 1p",
45413
+ preinstallCloud: true,
45414
+ binary: {
45415
+ "linux-x86_64": {
45416
+ url: "https://github.com/BurntSushi/ripgrep/releases/download/14.1.1/ripgrep-14.1.1-x86_64-unknown-linux-musl.tar.gz",
45417
+ archive: "tar.gz",
45418
+ extract: "ripgrep-14.1.1-x86_64-unknown-linux-musl/rg"
45419
+ },
45420
+ "linux-aarch64": {
45421
+ url: "https://github.com/BurntSushi/ripgrep/releases/download/14.1.1/ripgrep-14.1.1-aarch64-unknown-linux-gnu.tar.gz",
45422
+ archive: "tar.gz",
45423
+ extract: "ripgrep-14.1.1-aarch64-unknown-linux-gnu/rg"
45424
+ },
45425
+ "darwin-x86_64": {
45426
+ url: "https://github.com/BurntSushi/ripgrep/releases/download/14.1.1/ripgrep-14.1.1-x86_64-apple-darwin.tar.gz",
45427
+ archive: "tar.gz",
45428
+ extract: "ripgrep-14.1.1-x86_64-apple-darwin/rg"
45429
+ },
45430
+ "darwin-aarch64": {
45431
+ url: "https://github.com/BurntSushi/ripgrep/releases/download/14.1.1/ripgrep-14.1.1-aarch64-apple-darwin.tar.gz",
45432
+ archive: "tar.gz",
45433
+ extract: "ripgrep-14.1.1-aarch64-apple-darwin/rg"
45434
+ },
45435
+ "windows-x86_64": {
45436
+ url: "https://github.com/BurntSushi/ripgrep/releases/download/14.1.1/ripgrep-14.1.1-x86_64-pc-windows-msvc.zip",
45437
+ archive: "zip",
45438
+ extract: "ripgrep-14.1.1-x86_64-pc-windows-msvc/rg.exe"
45439
+ }
45440
+ },
45441
+ binName: "rg",
45442
+ internal: true,
45443
+ preinstallJarvis: true
45444
+ },
45445
+ "ast-grep": {
45446
+ category: "development",
45447
+ pkg: "ast-grep",
45448
+ installer: "binary",
45449
+ label: "Structural Search",
45450
+ summary: "Search and rewrite code by its structure, not just text.",
45451
+ description: 'Use when regex cannot distinguish syntax from text: `ast-grep -p "foo($$$)" -l ts` finds real calls while ignoring strings and comments; add `--rewrite "..."` for codemods. Prefer `rg` for literal or token search.',
45452
+ versionCmd: "ast-grep --version 2>/dev/null | sed -n 1p",
45453
+ preinstallCloud: true,
45454
+ binary: {
45455
+ "linux-x86_64": {
45456
+ url: "https://github.com/ast-grep/ast-grep/releases/download/0.44.1/app-x86_64-unknown-linux-gnu.zip",
45457
+ archive: "zip",
45458
+ extract: "ast-grep"
45459
+ },
45460
+ "linux-aarch64": {
45461
+ url: "https://github.com/ast-grep/ast-grep/releases/download/0.44.1/app-aarch64-unknown-linux-gnu.zip",
45462
+ archive: "zip",
45463
+ extract: "ast-grep"
45464
+ },
45465
+ "darwin-x86_64": {
45466
+ url: "https://github.com/ast-grep/ast-grep/releases/download/0.44.1/app-x86_64-apple-darwin.zip",
45467
+ archive: "zip",
45468
+ extract: "ast-grep"
45469
+ },
45470
+ "darwin-aarch64": {
45471
+ url: "https://github.com/ast-grep/ast-grep/releases/download/0.44.1/app-aarch64-apple-darwin.zip",
45472
+ archive: "zip",
45473
+ extract: "ast-grep"
45474
+ },
45475
+ "windows-x86_64": {
45476
+ url: "https://github.com/ast-grep/ast-grep/releases/download/0.44.1/app-x86_64-pc-windows-msvc.zip",
45477
+ archive: "zip",
45478
+ extract: "ast-grep.exe"
45479
+ }
45480
+ },
45481
+ binName: "ast-grep",
45482
+ internal: true,
45483
+ preinstallJarvis: true
45484
+ },
45485
+ fd: {
45486
+ commodity: true,
45487
+ category: "development",
45488
+ pkg: "fd-find",
45489
+ installer: "binary",
45490
+ label: "Find Files",
45491
+ summary: "Find files and folders by name.",
45492
+ description: "Fast user-friendly find replacement: regex by default, .gitignore-aware, parallel",
45493
+ versionCmd: "fd --version 2>/dev/null | sed -n 1p",
45494
+ preinstallCloud: true,
45495
+ binary: {
45496
+ "linux-x86_64": {
45497
+ url: "https://github.com/sharkdp/fd/releases/download/v10.2.0/fd-v10.2.0-x86_64-unknown-linux-musl.tar.gz",
45498
+ archive: "tar.gz",
45499
+ extract: "fd-v10.2.0-x86_64-unknown-linux-musl/fd"
45500
+ },
45501
+ "linux-aarch64": {
45502
+ url: "https://github.com/sharkdp/fd/releases/download/v10.2.0/fd-v10.2.0-aarch64-unknown-linux-gnu.tar.gz",
45503
+ archive: "tar.gz",
45504
+ extract: "fd-v10.2.0-aarch64-unknown-linux-gnu/fd"
45505
+ },
45506
+ "darwin-x86_64": {
45507
+ url: "https://github.com/sharkdp/fd/releases/download/v10.2.0/fd-v10.2.0-x86_64-apple-darwin.tar.gz",
45508
+ archive: "tar.gz",
45509
+ extract: "fd-v10.2.0-x86_64-apple-darwin/fd"
45510
+ },
45511
+ "darwin-aarch64": {
45512
+ url: "https://github.com/sharkdp/fd/releases/download/v10.2.0/fd-v10.2.0-aarch64-apple-darwin.tar.gz",
45513
+ archive: "tar.gz",
45514
+ extract: "fd-v10.2.0-aarch64-apple-darwin/fd"
45515
+ },
45516
+ "windows-x86_64": {
45517
+ url: "https://github.com/sharkdp/fd/releases/download/v10.2.0/fd-v10.2.0-x86_64-pc-windows-msvc.zip",
45518
+ archive: "zip",
45519
+ extract: "fd-v10.2.0-x86_64-pc-windows-msvc/fd.exe"
45520
+ }
45521
+ },
45522
+ binName: "fd",
45523
+ internal: true,
45524
+ preinstallJarvis: true
45525
+ },
45526
+ jq: {
45527
+ commodity: true,
45528
+ category: "development",
45529
+ pkg: "jq",
45530
+ installer: "binary",
45531
+ label: "JSON",
45532
+ summary: "Read and reshape JSON data.",
45533
+ description: "Command-line JSON processor: query, filter, transform, format JSON streams",
45534
+ versionCmd: "jq --version 2>/dev/null | sed -n 1p",
45535
+ preinstallCloud: true,
45536
+ binary: {
45537
+ "linux-x86_64": {
45538
+ url: "https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-amd64",
45539
+ archive: "raw"
45540
+ },
45541
+ "linux-aarch64": {
45542
+ url: "https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-arm64",
45543
+ archive: "raw"
45544
+ },
45545
+ "darwin-x86_64": {
45546
+ url: "https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-macos-amd64",
45547
+ archive: "raw"
45548
+ },
45549
+ "darwin-aarch64": {
45550
+ url: "https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-macos-arm64",
45551
+ archive: "raw"
45552
+ },
45553
+ "windows-x86_64": {
45554
+ url: "https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-windows-amd64.exe",
45555
+ archive: "raw"
45556
+ }
45557
+ },
45558
+ binName: "jq",
45559
+ internal: true,
45560
+ preinstallJarvis: true
45561
+ },
45562
+ patch: {
45563
+ commodity: true,
45564
+ category: "development",
45565
+ pkg: "patch",
45566
+ installer: "system",
45567
+ preinstallCloud: true,
45568
+ label: "Apply Diff",
45569
+ summary: "Apply a diff to files.",
45570
+ description: "Apply unified/context diff patches to files; reverse, dry-run, fuzzy matching",
45571
+ versionCmd: "patch --version 2>/dev/null | sed -n 1p",
45572
+ binName: "patch",
45573
+ internal: true,
45574
+ preinstallJarvis: true
45575
+ },
45576
+ sed: {
45577
+ commodity: true,
45578
+ category: "development",
45579
+ pkg: "sed",
45580
+ installer: "system",
45581
+ preinstallCloud: true,
45582
+ label: "Replace Text",
45583
+ summary: "Find and replace text in files.",
45584
+ description: "Stream editor: in-place text substitution, line filtering, scripted edits",
45585
+ versionCmd: "sed --version 2>/dev/null | sed -n 1p",
45586
+ binName: "sed",
45587
+ internal: true,
45588
+ preinstallJarvis: true
45589
+ },
45590
+ grep: {
45591
+ commodity: true,
45592
+ category: "development",
45593
+ pkg: "grep",
45594
+ installer: "system",
45595
+ preinstallCloud: true,
45596
+ label: "Search Text",
45597
+ summary: "Search for text in files.",
45598
+ description: "Search plain text for lines matching a regex: recursive, fixed-string, context, invert, count",
45599
+ versionCmd: "grep --version 2>/dev/null | sed -n 1p",
45600
+ binName: "grep",
45601
+ internal: true,
45602
+ preinstallJarvis: true
45603
+ },
45604
+ "wordpress-api": {
45605
+ preinstallCloud: true,
45606
+ category: "development",
45607
+ pkg: "@todoforai/wordpress-api",
45608
+ installer: "npm",
45609
+ label: "WordPress",
45610
+ summary: "Read and publish WordPress posts and pages.",
45611
+ statusCmd: `wordpress-api whoami 2>/dev/null | sed -n 's/.*"slug"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' | grep -m10 .`,
45612
+ loginCmd: "wordpress-api auth --site <url> --user <username> --password <app_password>",
45613
+ credentialPaths: ["~/.config/wordpress-api/credentials.json"],
45614
+ description: "WordPress REST API CLI. `wordpress-api auth --site https://example.com --user <user> --password '<application password>'` (application password, not the login password). Reading published content needs no auth. `posts list|get|create|update|delete`, `pages`, `media`, `categories`. `posts create` saves a draft unless --status publish. On Elementor/JetEngine sites content.rendered comes back empty — fetch the post's public URL for the body.",
45615
+ versionCmd: "wordpress-api --version 2>/dev/null | sed -n 1p"
45616
+ },
45617
+ "facebook-pages-api": {
45618
+ preinstallCloud: true,
45619
+ category: "social",
45620
+ pkg: "@todoforai/facebook-pages-api",
45621
+ installer: "npm",
45622
+ label: "Facebook Pages",
45623
+ summary: "Post to your Facebook Page and handle comments.",
45624
+ statusCmd: `facebook-pages-api whoami 2>/dev/null | sed -n 's/.*"name"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' | grep -m10 .`,
45625
+ loginCmd: "facebook-pages-api auth --page-id <id> --page-token <token>",
45626
+ credentialPaths: ["~/.config/facebook-pages-api/credentials.json"],
45627
+ description: "Facebook Pages CLI (Meta Graph API). `auth --page-id <id> --page-token <token>` (or env FB_PAGE_ID/FB_PAGE_TOKEN). `feed`, `comments`, `insights`, `conversations`, `media`, and `request <GET|POST|DELETE> <path> [--data <json>]` = any Graph edge with the page token attached (use instead of curl). Writes are live: `feed create --published false` for tests; `comments reply` posts publicly — get human approval. Follower totals: `whoami --fields followers_count,fan_count` (many classic insights metrics are retired). `--help` for subcommands.",
45628
+ versionCmd: "facebook-pages-api --version 2>/dev/null | sed -n 1p"
45629
+ },
45630
+ "ews-api": {
45631
+ category: "email",
45632
+ pkg: "ews-api",
45633
+ installer: "pip",
45634
+ label: "Exchange (EWS)",
45635
+ summary: "Read and write mail on a company Exchange server.",
45636
+ statusCmd: `ews-api whoami 2>/dev/null | sed -n 's/.*"email"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' | grep -m10 .`,
45637
+ loginCmd: "ews-api auth --email <email> --username <username> --server <server> --password <password>",
45638
+ credentialPaths: ["~/.config/ews-api/credentials.json"],
45639
+ description: "On-prem Microsoft Exchange mail over EWS (cloud/M365 → outlook-api). `auth --email <e> --username 'DOMAIN\\\\user' --server <host>` (NTLM; password prompt or `--password-stdin`; --server required). Multi-mailbox: `whoami`, `--account <email>`/EWS_ACCOUNT, `default`, `logout`; EWS_EMAIL/EWS_USERNAME/EWS_PASSWORD/EWS_SERVER for unattended runs. `list`, `search <q>`, `read <id>`, `draft`, `reply <id>` — draft/reply stay in Drafts unless --send. Password stored plaintext in ~/.config/ews-api (0600); re-auth after rotation.",
45640
+ versionCmd: "ews-api --version 2>/dev/null | sed -n 1p",
45641
+ logoutCmd: "ews-api logout {{ACCOUNT}}"
45642
+ },
45643
+ "outlook-api": {
45644
+ preinstallCloud: true,
45645
+ category: "email",
45646
+ pkg: "@todoforai/outlook-api",
45647
+ installer: "npm",
45648
+ label: "Outlook (Graph)",
45649
+ summary: "Read and write your Outlook mail.",
45650
+ statusCmd: `outlook-api whoami 2>/dev/null | sed -n 's/.*"userPrincipalName"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' | grep -m10 .`,
45651
+ loginCmd: "outlook-api auth",
45652
+ credentialPaths: ["~/.config/outlook-api/config.json"],
45653
+ description: "Outlook/Hotmail/M365 mail over Microsoft Graph (on-prem Exchange → ews-api). `auth` = device-code flow; `--tenant consumers` (default, personal) | `organizations`. list/search/read/attachments are read-only; `draft`/`reply` stay in Drafts unless --send; `send <draftId>`. `get <path>` = raw Graph GET. JSON out.",
45654
+ versionCmd: "outlook-api --version 2>/dev/null | sed -n 1p",
45655
+ deviceCodePattern: "enter the code ([A-Z0-9]+)",
45656
+ oauthUrlPattern: "(https://(?:www\\.microsoft\\.com/link|login\\.microsoft\\.com/device))",
45657
+ canStreamLogin: true
45658
+ },
45659
+ neonctl: {
45660
+ category: "database",
45661
+ pkg: "neonctl",
45662
+ installer: "npm",
45663
+ label: "Neon Postgres",
45664
+ summary: "Manage your Neon Postgres databases and branches.",
45665
+ statusCmd: `test -f ~/.config/neon/credentials.json && neonctl me --output json 2>/dev/null | sed -n 's/.*"email"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' | grep -m10 .`,
45666
+ loginCmd: "neonctl auth",
45667
+ oauthUrlPattern: "(https://oauth2\\.neon\\.tech/oauth2/auth\\S+)",
45668
+ credentialPaths: ["~/.config/neon/credentials.json"],
45669
+ description: "Manage Neon Postgres branches and run SQL: `neonctl projects list`, `neonctl branches create`, `neonctl connection-string`. Aliased as `neon`.",
45670
+ versionCmd: "neonctl --version 2>/dev/null | sed -n 1p",
45671
+ aliases: ["neon"],
45672
+ canStreamLogin: true
45673
+ },
45674
+ m365: {
45675
+ preinstallCloud: true,
45676
+ category: "productivity",
45677
+ pkg: "@pnp/cli-microsoft365",
45678
+ installer: "npm",
45679
+ label: "Microsoft 365",
45680
+ summary: "Work with Microsoft 365 mail, Teams, SharePoint and users.",
45681
+ statusCmd: `m365 status --output text 2>/dev/null | tr -d '"' | grep -vi 'logged out' | grep -m1 .`,
45682
+ loginCmd: "m365 login --authType deviceCode --appId 04b07795-8ddb-461a-bbee-02f9e1bf7b46",
45683
+ deviceCodePattern: "enter the code ([A-Z0-9]{8,}) to authenticate",
45684
+ oauthUrlPattern: "open the page (https://\\S+) and enter",
45685
+ credentialPaths: ["~/.cli-m365-msal.json", "~/.cli-m365-connection.json"],
45686
+ description: "Microsoft 365 from the shell: `m365 outlook message list`, `m365 teams team list`, `m365 spo site list`. Device-code login; add `--output json` for parseable output.",
45687
+ versionCmd: `m365 version 2>/dev/null | tr -d '"' | sed -n 1p`
45688
+ },
45689
+ hubspot: {
45690
+ preinstallCloud: true,
45691
+ category: "marketing",
45692
+ pkg: "@hubspot/cli",
45693
+ installer: "npm",
45694
+ label: "HubSpot",
45695
+ summary: "Work with your HubSpot contacts, deals and content.",
45696
+ binName: "hs",
45697
+ statusCmd: "hs account list >/dev/null 2>&1 && echo authenticated",
45698
+ loginCmd: "hs account auth",
45699
+ oauthUrlPattern: "(https://app\\.hubspot\\.com/l/personal-access-key\\S+)",
45700
+ loginNeedsPty: true,
45701
+ credentialPaths: ["~/.hscli/config.yml"],
45702
+ description: "Invoked as `hs`. `hs api <endpoint>` makes authenticated calls to any HubSpot API (contacts, deals, companies) — prefer it over raw curl.",
45703
+ versionCmd: "hs --version 2>/dev/null | sed -n 1p",
45704
+ canStreamLogin: true
45705
+ },
45706
+ "posthog-cli": {
45707
+ preinstallCloud: true,
45708
+ category: "monitoring",
45709
+ pkg: "@posthog/cli",
45710
+ installer: "npm",
45711
+ label: "PostHog",
45712
+ summary: "Query PostHog product analytics and manage feature flags.",
45713
+ statusCmd: `grep -q '"token"' "\${POSTHOG_HOME:-$HOME/.posthog}/credentials.json" 2>/dev/null && echo authenticated`,
45714
+ loginCmd: "posthog-cli login",
45715
+ loginTerminalHint: "Interactive only: run `posthog-cli login` in a terminal on this host (it asks for host, project and a personal API key), or set `POSTHOG_CLI_API_KEY` + `POSTHOG_CLI_PROJECT_ID`.",
45716
+ credentialPaths: ["~/.posthog/credentials.json"],
45717
+ description: "Official PostHog CLI. `posthog-cli api tools` lists the agent-first API tool catalog, `posthog-cli api call <tool> '<json>'` runs one (SQL queries, insights, flags). Also uploads sourcemaps/dSYM. Env alternative: POSTHOG_CLI_API_KEY + POSTHOG_CLI_PROJECT_ID.",
45718
+ versionCmd: "posthog-cli --version 2>/dev/null | sed -n 1p"
45719
+ },
45720
+ canva: {
45721
+ category: "design",
45722
+ pkg: "@canva/cli",
45723
+ installer: "npm",
45724
+ label: "Canva",
45725
+ summary: "Build and deploy Canva apps.",
45726
+ statusCmd: "test -s ~/.canva-cli/credentials && echo authenticated",
45727
+ loginCmd: "canva login --mode manual --lite",
45728
+ loginNeedsPty: true,
45729
+ stdinPaste: true,
45730
+ credentialPaths: ["~/.canva-cli/credentials"],
45731
+ description: "Official Canva CLI — app-development focused: `canva apps create/list/preview`. `canva mcp` starts the Canva Developer MCP server. For design/export automation use the Canva Connect REST API.",
45732
+ versionCmd: "canva --version 2>/dev/null | sed -n 1p",
45733
+ oauthUrlPattern: "OPEN_URL: (https://www\\.canva\\.com/api/oauth/authorize\\S+)"
45734
+ },
45735
+ webflow: {
45736
+ category: "development",
45737
+ pkg: "@webflow/webflow-cli",
45738
+ installer: "npm",
45739
+ label: "Webflow",
45740
+ summary: "Manage Webflow sites, CMS content and assets.",
45741
+ statusCmd: "webflow auth status --skip-update-check >/dev/null 2>&1 && echo authenticated",
45742
+ loginCmd: "webflow auth login --skip-update-check",
45743
+ loginNeedsPty: true,
45744
+ oauthUrlPattern: "(https://webflow\\.com/oauth/webflow/initiate\\S+)",
45745
+ credentialPaths: ["~/.config/webflow"],
45746
+ description: "Manage Webflow sites from the shell: `webflow sites list`, `webflow cms ...`, `webflow assets ...`. Add `--skip-update-check` in scripts.",
45747
+ versionCmd: "webflow --version 2>/dev/null | sed -n 1p"
45748
+ },
45749
+ readwise: {
45750
+ category: "productivity",
45751
+ pkg: "@readwise/cli",
45752
+ installer: "npm",
45753
+ label: "Readwise",
45754
+ summary: "Search and save articles and highlights in Readwise.",
45755
+ statusCmd: "readwise whoami >/dev/null 2>&1 && readwise whoami 2>/dev/null | sed 's/\\x1b\\[[0-9;]*m//g' | grep -m1 .",
45756
+ loginCmd: "readwise login",
45757
+ credentialPaths: ["~/.readwise-cli.json"],
45758
+ description: "Official Readwise/Reader CLI. `readwise search <query>`, `readwise list`, `readwise save <url>`; supports JSON output for piping and a read-only mode for agents. Token login for CI: `readwise login-with-token <token>` (get one at readwise.io/access_token).",
45759
+ versionCmd: "readwise --version 2>/dev/null | sed -n 1p",
45760
+ oauthUrlPattern: "OPEN_URL: (https://readwise\\.io/o/authorize\\S+)",
45761
+ oauthCallbackPort: 6274
45762
+ },
45763
+ granola: {
45764
+ preinstallCloud: true,
45765
+ category: "productivity",
45766
+ pkg: "granola-cli",
45767
+ installer: "npm",
45768
+ binName: "granola",
45769
+ label: "Granola",
45770
+ summary: "Read your Granola meeting notes and transcripts.",
45771
+ statusCmd: `granola auth status -o json 2>/dev/null | sed -n 's/.*"authenticated": *true.*/authenticated/p' | grep -m1 .`,
45772
+ loginCmd: "granola auth login",
45773
+ loginTerminalHint: "Imports the Granola desktop app's session: install Granola on this host, sign in there, then run `granola auth login`.",
45774
+ credentialPaths: ["~/.config/keyring", "~/.config/granola"],
45775
+ versionCmd: "granola --version 2>/dev/null | sed -n 1p",
45776
+ description: "Community Granola CLI (read-only). `granola meeting list [-l N] [--since <date>] [-s <query>] [-a <attendee>] -o json`, `granola meeting notes|enhanced|transcript <id>`, `granola meeting export <id>`; `granola folder list`, `granola workspace list`. `-o json|yaml|toon` for piping. Login imports credentials from the installed Granola desktop app (`granola auth login`) — desktop app must be logged in on the same machine; transcripts need a paid Granola plan."
45777
+ },
45778
+ trello: {
45779
+ preinstallCloud: true,
45780
+ category: "productivity",
45781
+ pkg: "trello-cli",
45782
+ installer: "npm",
45783
+ binName: "trello",
45784
+ label: "Trello",
45785
+ summary: "Manage your Trello boards, lists and cards.",
45786
+ statusCmd: "trello board:list --format json </dev/null >/dev/null 2>&1 && echo authenticated",
45787
+ loginCmd: "trello auth:api-key <key> && trello auth:token <token>",
45788
+ credentialPaths: [
45789
+ "~/.trello-cli"
45790
+ ],
45791
+ versionCmd: "trello --version 2>/dev/null | sed -n 1p",
45792
+ description: "Community Trello CLI (mheap/trello-cli, no official one exists). Auth is a Trello API key + token from https://trello.com/app-key — `trello auth:api-key <key>` then `trello auth:token <token>`. `board:list`, `list:list --board <name>`, `card:list --board <b> --list <l>`, `card:create --board <b> --list <l> --name <n> [--description ..] [--due <date>]`, `card:move`, `card:comment`, `label:*`, `search <q>`. Add `--format json` for piping. Names resolve via a local cache; run `trello board:list` once after login to warm it."
45793
+ },
45794
+ mapps: {
45795
+ category: "development",
45796
+ pkg: "@mondaycom/apps-cli",
45797
+ installer: "npm",
45798
+ label: "monday.com",
45799
+ summary: "Build and deploy monday.com apps.",
45800
+ statusCmd: "grep -qsE '[A-Za-z0-9]' ~/.config/mapps/.mappsrc ~/.mappsrc && echo authenticated",
45801
+ loginCmd: "mapps init -t <api_token>",
45802
+ credentialPaths: ["~/.config/mapps/.mappsrc", "~/.mappsrc"],
45803
+ description: "Invoked as `mapps` — app development and monday-code deployments only; `mapps init -t <token>` stores a monday.com API token in ~/.mappsrc. To read/write board DATA use the monday.com GraphQL API (api.monday.com/v2) with that same token.",
45804
+ versionCmd: "mapps --version 2>/dev/null | sed -n 1p"
45805
+ },
45806
+ "exa-cli": {
45807
+ preinstallCloud: true,
45808
+ category: "utility",
45809
+ pkg: "exa-cli",
45810
+ installer: "npm",
45811
+ label: "Exa Search",
45812
+ summary: "Search the web and pull page contents, built for AI.",
45813
+ binName: "exa",
45814
+ statusCmd: 'test -n "$EXA_API_KEY" && echo authenticated',
45815
+ credentialPaths: [],
45816
+ description: "Invoked as `exa`. `exa search <query>`, `exa answer <question>`, `exa contents <url>`, `exa find-similar <url>` — JSON by default. Needs EXA_API_KEY in the environment (get one at dashboard.exa.ai); store it in the vault.",
45817
+ versionCmd: "exa --version 2>/dev/null | sed -n 1p"
45818
+ },
45819
+ mobbin: {
45820
+ category: "design",
45821
+ pkg: "mobbin",
45822
+ installer: "npm",
45823
+ label: "Mobbin",
45824
+ summary: "Browse real app and website design examples.",
45825
+ statusCmd: "mobbin auth print-cookie 2>/dev/null | grep -E '[A-Za-z0-9]' >/dev/null && echo authenticated",
45826
+ loginCmd: "mobbin auth save-cookie",
45827
+ loginTerminalHint: "Log in to mobbin.com in a browser on this host, then run `mobbin auth save-cookie`: it imports that browser's cookies.",
45828
+ credentialPaths: ["~/.config/mobbin/cookie.txt", "~/.config/mobbin/storage-state.json"],
45829
+ description: 'Unofficial CLI over Mobbin\'s undocumented web endpoints. `mobbin search --query "login" --platform ios`. Auth reuses browser cookies: log into mobbin.com in Chrome, then `mobbin auth save-cookie`.',
45830
+ versionCmd: "mobbin --version 2>/dev/null | sed -n '1,2p' | tr '\\n' ' '"
45831
+ },
45832
+ "blender-mcp": {
45833
+ preinstallCloud: true,
45834
+ packages: ["blender-mcp==1.9.1"],
45835
+ category: "design",
45836
+ pkg: "blender-mcp",
45837
+ installer: "pip",
45838
+ label: "Blender",
45839
+ summary: "Model, texture and render 3D scenes in a running Blender.",
45840
+ statusCmd: `command -v blender-mcp >/dev/null && mcporter call blender.get_addon_status --output json 2>/dev/null | grep -o '"blender_version": "[^"]*"' | grep -m1 .`,
45841
+ loginNoBrowser: true,
45842
+ loginTerminalHint: "Needs Blender (blender.org) open on this host: in Blender, Edit → Preferences → Add-ons, enable `Blender MCP`, then press N in the 3D view → BlenderMCP tab → Connect / Start MCP server. Then press Connect here.",
45843
+ loginCmd: `blender-mcp install-addon >/dev/null 2>&1; command -v mcporter >/dev/null 2>&1 || npm install -g --prefix "$HOME/.local" mcporter; mcporter config add blender --command blender-mcp --env BLENDER_MCP_DISABLE_TELEMETRY=1 --description 'Blender 3D via ahujasid/blender-mcp addon' --scope home`,
45844
+ logoutCmd: "cd ~ && mcporter config remove blender",
45845
+ credentialPaths: ["~/.mcporter/mcporter.json"],
45846
+ description: "Blender 3D via the ahujasid/blender-mcp server through mcporter: `mcporter list blender --schema`, `mcporter call blender.<tool> key=value` (`code=@file.py`; every tool needs `user_prompt`). Workhorse: execute_blender_code (any bpy Python); also scene/object info, viewport screenshot (`--save-images <dir>`), PolyHaven/Sketchfab import. Needs a GUI Blender with the addon server started (socket :9876; headless has none). 'Could not connect' → `blender-mcp install-addon`, enable in Preferences → Add-ons, N-panel → Start MCP Server (scripted: `blender --python s.py`, s.py registers a `bpy.app.timers` calling `bpy.ops.blendermcp.start_server()`). Code runs unguarded: save first (`bpy.ops.wm.save_mainfile()`), approve destructive ops.",
45847
+ versionCmd: `{ python -c 'from importlib.metadata import version; print(version("blender-mcp"))' || python3 -c 'from importlib.metadata import version; print(version("blender-mcp"))'; } 2>/dev/null`
45848
+ },
45849
+ "google-ads": {
45850
+ category: "marketing",
45851
+ pkg: "google-ads",
45852
+ packages: [
45853
+ "google-ads==32.0.0"
45854
+ ],
45855
+ installer: "pip",
45856
+ label: "Google Ads",
45857
+ summary: "Query and manage Google Ads campaigns, keywords and conversions.",
45858
+ loginCmd: `printf 'developer_token: %s\\nclient_id: %s\\nclient_secret: %s\\nrefresh_token: %s\\nlogin_customer_id: %s\\nuse_proto_plus: true\\n' <developer_token> <client_id> <client_secret> <refresh_token> <mcc_id_digits_only> > "$HOME/google-ads.yaml" && python3 -c 'from google.ads.googleads.client import GoogleAdsClient; GoogleAdsClient.load_from_storage(); print("ok")'`,
45859
+ credentialPaths: [
45860
+ "~/google-ads.yaml"
45861
+ ],
45862
+ statusCmd: `python3 -c 'from google.ads.googleads.client import GoogleAdsClient; c=GoogleAdsClient.load_from_storage(); print(c.login_customer_id or "authenticated")' 2>/dev/null | grep -m1 .`,
45863
+ versionCmd: "python3 -c 'import google.ads.googleads as g; print(g.VERSION)' 2>/dev/null",
45864
+ cloudVerifyCmd: "python3 -c 'import google.ads.googleads'",
45865
+ description: "Official Google Ads API client library (Python) — there is no official CLI, so call it via `python3 -c` or a script. Config `~/google-ads.yaml` (developer_token, client_id/secret, refresh_token, login_customer_id = MCC digits). Mint refresh_token with the bundled `google-oauthlib-tool --client-secrets <json> --scope https://www.googleapis.com/auth/adwords --save --headless` (or examples/authentication/generate_user_credentials.py). Read: `client.get_service('GoogleAdsService').search_stream(customer_id=<digits>, query=<GAQL>)`. Write: `<X>Service.mutate_<x>s(customer_id, operations, validate_only=True)` first, then real. Keyword ideas: `KeywordPlanIdeaService.generate_keyword_ideas`. Offline conversions: `ConversionUploadService.upload_click_conversions`. Customer ids are digits without dashes."
45866
+ },
45867
+ "cua-driver": {
45868
+ category: "development",
45869
+ pkg: "cua-driver",
45870
+ installer: "system",
45871
+ label: "Desktop Control",
45872
+ summary: "Click, type and read native desktop apps without taking over the mouse or focus.",
45873
+ installCmd: 'curl -fsSL https://cua.ai/driver/install.sh | CUA_DRIVER_NO_MODIFY_PATH=1 CUA_DRIVER_BIN_DIR="$HOME/.todoforai/tools/bin" bash',
45874
+ uninstallCmd: 'curl -fsSL https://cua.ai/driver/uninstall.sh | bash; rm -f "$HOME/.todoforai/tools/bin/cua-driver" "$HOME/.todoforai/tools/bin/cua-cursor-theme"; hash -r 2>/dev/null; ! command -v cua-driver >/dev/null 2>&1 || { echo "cua-driver is still on PATH: $(command -v cua-driver)"; exit 1; }',
45875
+ installCmdWindows: "powershell.exe -NoProfile -ExecutionPolicy Bypass -Command '$ProgressPreference='\\''SilentlyContinue'\\''; $ErrorActionPreference='\\''Stop'\\''; [Net.ServicePointManager]::SecurityProtocol=[Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12; $t=Join-Path $env:USERPROFILE '\\''.todoforai\\tools'\\''; $d=Join-Path $t '\\''bin'\\''; New-Item -ItemType Directory -Force -Path $d | Out-Null; $env:CUA_DRIVER_RS_INSTALL_DIR=Join-Path $t '\\''cua-driver\\bin'\\''; $f=Join-Path $env:TEMP '\\''cua-driver-install.ps1'\\''; Invoke-RestMethod -UseBasicParsing https://cua.ai/driver/install.ps1 | Set-Content -LiteralPath $f -Encoding UTF8; & $f -NoAutoStart -NoPathUpdate; if($LASTEXITCODE){exit $LASTEXITCODE}; $u=New-Object Text.UTF8Encoding $false; [IO.File]::WriteAllText((Join-Path $d '\\''cua-driver'\\''), \"#!/bin/sh`nexec `\"`$(dirname `\"`$0`\")/../cua-driver/bin/cua-driver.exe`\" `\"`$@`\"`n\", $u); [IO.File]::WriteAllText((Join-Path $d '\\''cua-driver.cmd'\\''), \"@echo off`r`n`\"%~dp0..\\cua-driver\\bin\\cua-driver.exe`\" %*`r`n\", $u)'",
45876
+ uninstallCmdWindows: "powershell.exe -NoProfile -ExecutionPolicy Bypass -Command '$ErrorActionPreference='\\''Continue'\\''; $t=Join-Path $env:USERPROFILE '\\''.todoforai\\tools'\\''; $d=Join-Path $t '\\''bin'\\''; $j=Join-Path $t '\\''cua-driver\\bin'\\''; $exe=Join-Path $j '\\''cua-driver.exe'\\''; if(Test-Path -LiteralPath $exe){& $exe stop 2>$null | Out-Null}; Stop-Process -Name cua-driver -Force -ErrorAction SilentlyContinue; $env:CUA_DRIVER_RS_UNINSTALL_FORCE='\\''1'\\''; $env:CUA_DRIVER_RS_INSTALL_DIR=$j; Invoke-RestMethod -UseBasicParsing https://cua.ai/driver/uninstall.ps1 | Invoke-Expression; Remove-Item -Force -ErrorAction SilentlyContinue (Join-Path $d '\\''cua-driver'\\''), (Join-Path $d '\\''cua-driver.cmd'\\''); if(Test-Path -LiteralPath $j){[IO.Directory]::Delete($j,$false)}; Remove-Item -Recurse -Force -ErrorAction SilentlyContinue (Join-Path $t '\\''cua-driver'\\'')'",
45877
+ versionCmd: "cua-driver --version 2>/dev/null | sed -n 1p",
45878
+ description: 'Native desktop automation (macOS/Windows/Linux X11; Wayland only via AT-SPI, no window screenshots) through the accessibility tree — actions land in the BACKGROUND without moving the user\'s focus or pointer. Needs a daemon: `cua-driver status || (cua-driver serve --no-overlay >/dev/null 2>&1 &)`; on macOS grant permissions first with `cua-driver permissions grant`; on Windows the daemon must run in the interactive desktop session (`cua-driver autostart enable` registers a logon task). Loop: `cua-driver call list_windows \'{}\'` → pid+window_id; `cua-driver call get_window_state \'{"pid":P,"window_id":W,"include_screenshot":false}\'` → `elements[]` with `element_token`; act with `cua-driver call click \'{"pid":P,"window_id":W,"element_token":"s..:N"}\'`, `type_text {..,"text":".."}`, `hotkey {..,"keys":["ctrl","s"]}`, `press_key`, `scroll`, `invoke_menu`. Tokens are snapshot-bound: re-run get_window_state after EVERY action (stale token = refusal). Window screenshot: add `--screenshot-out-file out.png` (`max_dimension` to shrink). Responses say `effect:unverifiable` — verify from a fresh tree, not from the click reply. `delivery_mode:"foreground"` steals focus; use only when asked. Chrome/Electron trees are near-empty — use agent-browser for web pages. `cua-driver list-tools` / `describe <tool>` for the full surface; `cua-driver mcp` exposes the same over stdio MCP.'
45879
+ }
45880
+ };
45881
+
45882
+ // ../packages/shared-fbe/src/toolCatalog.ts
45883
+ var TOOL_CATALOG = tool_catalog_default;
45884
+ // ../packages/shared-fbe/src/toolInstallCommand.ts
45885
+ var KEY_OF = new Map(Object.entries(TOOL_CATALOG).map(([k, e]) => [e, k]));
45886
+ var NODE_MIN_MAJOR = 24;
45887
+ var NODE_OK = `command -v npm >/dev/null 2>&1 && node -e 'process.exit(+process.versions.node.split(".")[0]>=${NODE_MIN_MAJOR}?0:1)' >/dev/null 2>&1`;
45888
+ // ../packages/shared-fbe/src/model_promos.json
44396
45889
  var model_promos_default = {
44397
45890
  _doc: [
44398
45891
  "Single source of truth for TODOforAI promotional model discounts.",
@@ -44434,10 +45927,10 @@ var model_promos_default = {
44434
45927
  ]
44435
45928
  };
44436
45929
 
44437
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/modelPromos.ts
45930
+ // ../packages/shared-fbe/src/modelPromos.ts
44438
45931
  var BOOST_FACTOR = model_promos_default.boost_remaining_price_factor;
44439
45932
  var MODEL_PROMOS = model_promos_default.promos;
44440
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/realtime/topics.ts
45933
+ // ../packages/shared-fbe/src/realtime/topics.ts
44441
45934
  var TOPICS = {
44442
45935
  ["todo:new" /* NEW_TODO */]: {
44443
45936
  channel: (p) => SERVER_TO_FRONTENDS.project.new_todo(p.projectId, p.privateOwnerId),
@@ -44604,12 +46097,12 @@ var TOPICS = {
44604
46097
  audience: "frontend"
44605
46098
  }
44606
46099
  };
44607
- // ../../../home/hm/repo/todoforai/packages/shared-fbe/src/modelNames.ts
46100
+ // ../packages/shared-fbe/src/modelNames.ts
44608
46101
  var LEGACY_MODEL_MAPPING = {
44609
46102
  claude: DEFAULT_MODEL.slice(DEFAULT_MODEL.indexOf(":") + 1),
44610
46103
  "gemini-pro": "google/gemini-3.1-pro-preview"
44611
46104
  };
44612
- // ../../../home/hm/repo/todoforai/packages/shared-credentials/src/index.ts
46105
+ // ../packages/shared-credentials/src/index.ts
44613
46106
  function normalizeApiUrl2(url) {
44614
46107
  if (url.startsWith("localhost"))
44615
46108
  return `http://${url}`;
@@ -44623,7 +46116,7 @@ import { parseArgs } from "util";
44623
46116
  // package.json
44624
46117
  var package_default = {
44625
46118
  name: "@todoforai/cli",
44626
- version: "0.1.55",
46119
+ version: "0.1.56",
44627
46120
  type: "module",
44628
46121
  bin: {
44629
46122
  "todoforai-cli": "bin/todoforai-cli.js",