@todoforai/cli 0.1.62 → 0.1.63

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.
@@ -42675,25 +42675,53 @@ var require_dist = __commonJS((exports) => {
42675
42675
  });
42676
42676
 
42677
42677
  // src/index.ts
42678
- import { realpathSync as realpathSync2, readFileSync as readFileSync3, existsSync as existsSync2 } from "fs";
42679
- import { resolve as resolve4 } from "path";
42678
+ import { realpathSync as realpathSync2, readFileSync as readFileSync5, existsSync as existsSync4 } from "fs";
42679
+ import { resolve as resolve5 } from "path";
42680
42680
  import { fileURLToPath } from "url";
42681
- import { homedir as homedir3 } from "os";
42681
+ import { homedir as homedir5 } from "os";
42682
42682
  import path4 from "path";
42683
42683
 
42684
42684
  // node_modules/@todoforai/update-notifier/src/index.ts
42685
42685
  import fs from "node:fs";
42686
42686
  import path from "node:path";
42687
42687
  import os from "node:os";
42688
- function isLinkedInstall() {
42688
+ import { spawn, spawnSync } from "node:child_process";
42689
+ function installer() {
42690
+ let real;
42689
42691
  try {
42690
- return !fs.realpathSync(process.argv[1] || "").includes(`${path.sep}node_modules${path.sep}`);
42692
+ real = fs.realpathSync(process.argv[1] || "");
42691
42693
  } catch {
42692
- return false;
42694
+ return null;
42693
42695
  }
42696
+ if (!real.includes(`${path.sep}node_modules${path.sep}`))
42697
+ return null;
42698
+ return real.includes(path.join(".bun", "install", "global")) ? "bun" : "npm";
42694
42699
  }
42695
42700
  var TTL_MS = 24 * 60 * 60 * 1000;
42696
42701
  var CACHE_DIR = path.join(os.homedir(), ".config", "todoforai");
42702
+ var cacheFileFor = (name) => path.join(CACHE_DIR, `notifier-${encodeURIComponent(name)}.json`);
42703
+ function readCache(name) {
42704
+ try {
42705
+ return JSON.parse(fs.readFileSync(cacheFileFor(name), "utf8"));
42706
+ } catch {
42707
+ return {};
42708
+ }
42709
+ }
42710
+ function writeCache(name, cache) {
42711
+ try {
42712
+ fs.mkdirSync(CACHE_DIR, { recursive: true });
42713
+ fs.writeFileSync(cacheFileFor(name), JSON.stringify(cache));
42714
+ } catch {}
42715
+ }
42716
+ function refreshCache(name, cache) {
42717
+ if (Date.now() - (cache.ts ?? 0) <= TTL_MS)
42718
+ return;
42719
+ writeCache(name, { ...cache, ts: Date.now() });
42720
+ fetch(`https://registry.npmjs.org/${name}/latest`, { signal: AbortSignal.timeout(3000) }).then((r) => r.ok ? r.json() : null).then((j) => {
42721
+ if (j?.version)
42722
+ writeCache(name, { ...cache, ts: Date.now(), latest: j.version });
42723
+ }).catch(() => {});
42724
+ }
42697
42725
  function cmpVer(a, b) {
42698
42726
  const pa = a.split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
42699
42727
  const pb = b.split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
@@ -42705,13 +42733,11 @@ function cmpVer(a, b) {
42705
42733
  return 0;
42706
42734
  }
42707
42735
  function checkForUpdates(pkg) {
42708
- if (!process.stderr.isTTY || process.env.CI || process.env.NO_UPDATE_NOTIFIER || isLinkedInstall())
42736
+ if (!process.stderr.isTTY || process.env.CI || process.env.NO_UPDATE_NOTIFIER || !installer())
42709
42737
  return;
42710
- const cacheFile = path.join(CACHE_DIR, `notifier-${encodeURIComponent(pkg.name)}.json`);
42711
- let cache = {};
42712
- try {
42713
- cache = JSON.parse(fs.readFileSync(cacheFile, "utf8"));
42714
- } catch {}
42738
+ if (process.argv.includes("--json"))
42739
+ return;
42740
+ const cache = readCache(pkg.name);
42715
42741
  if (cache.latest && cmpVer(cache.latest, pkg.version) > 0) {
42716
42742
  process.stderr.write(`
42717
42743
  \x1B[33m Update available: \x1B[2m${pkg.version}\x1B[22m → \x1B[1m${cache.latest}\x1B[0m
@@ -42719,18 +42745,68 @@ function checkForUpdates(pkg) {
42719
42745
 
42720
42746
  `);
42721
42747
  }
42722
- if (Date.now() - (cache.ts ?? 0) > TTL_MS) {
42748
+ refreshCache(pkg.name, cache);
42749
+ }
42750
+ function backgroundUpdate(pkg) {
42751
+ const mgr = installer();
42752
+ if (process.env.CI || process.env.NO_UPDATE_NOTIFIER || !mgr)
42753
+ return;
42754
+ const cache = readCache(pkg.name);
42755
+ const latest = cache.latest;
42756
+ if (latest && cmpVer(latest, pkg.version) > 0 && cache.tried !== latest) {
42757
+ const next = { ...cache, tried: latest };
42758
+ writeCache(pkg.name, next);
42723
42759
  try {
42724
- fs.mkdirSync(CACHE_DIR, { recursive: true });
42725
- fs.writeFileSync(cacheFile, JSON.stringify({ ...cache, ts: Date.now() }));
42760
+ const args = mgr === "bun" ? ["add", "-g", `${pkg.name}@${latest}`] : ["i", "-g", `${pkg.name}@${latest}`];
42761
+ const win = process.platform === "win32";
42762
+ spawn(win ? `${mgr}.cmd` : mgr, args, { detached: true, stdio: "ignore", shell: win, windowsHide: true }).unref();
42726
42763
  } catch {}
42727
- fetch(`https://registry.npmjs.org/${pkg.name}/latest`, { signal: AbortSignal.timeout(3000) }).then((r) => r.ok ? r.json() : null).then((j) => {
42728
- if (!j?.version)
42729
- return;
42730
- fs.writeFileSync(cacheFile, JSON.stringify({ ts: Date.now(), latest: j.version }));
42731
- }).catch(() => {});
42764
+ refreshCache(pkg.name, next);
42765
+ return;
42766
+ }
42767
+ checkForUpdates(pkg);
42768
+ }
42769
+ var log = (msg) => process.stderr.write(msg + `
42770
+ `);
42771
+ function install(pkg, mgr, latest) {
42772
+ log(`\x1B[33m Updating ${pkg.name} ${pkg.version} → ${latest} ...\x1B[0m`);
42773
+ const cmd = process.platform === "win32" ? `${mgr}.cmd` : mgr;
42774
+ const args = mgr === "bun" ? ["add", "-g", `${pkg.name}@${latest}`] : ["i", "-g", `${pkg.name}@${latest}`];
42775
+ const r = spawnSync(cmd, args, { stdio: "inherit", timeout: 120000 });
42776
+ if (r.status !== 0) {
42777
+ writeCache(pkg.name, { ...readCache(pkg.name), failed: latest });
42778
+ log(`\x1B[31m Update to ${latest} failed — run manually: ${mgr} ${args.join(" ")}\x1B[0m`);
42779
+ return "failed";
42780
+ }
42781
+ log(`\x1B[32m ✓ Updated to ${latest}\x1B[0m (active from the next start)`);
42782
+ writeCache(pkg.name, { ts: Date.now(), latest });
42783
+ return "updated";
42784
+ }
42785
+ async function fetchLatest(name, timeoutMs) {
42786
+ try {
42787
+ const r = await fetch(`https://registry.npmjs.org/${name}/latest`, { signal: AbortSignal.timeout(timeoutMs) });
42788
+ return r.ok ? (await r.json())?.version : undefined;
42789
+ } catch {
42790
+ return;
42732
42791
  }
42733
42792
  }
42793
+ async function selfUpdate(pkg) {
42794
+ const mgr = installer();
42795
+ if (!mgr) {
42796
+ log(`\x1B[33mNot a package-manager install — update manually: npm i -g ${pkg.name}\x1B[0m`);
42797
+ return "unsupported";
42798
+ }
42799
+ const latest = await fetchLatest(pkg.name, 1e4);
42800
+ if (!latest) {
42801
+ log("\x1B[31mCould not reach the npm registry.\x1B[0m");
42802
+ return "failed";
42803
+ }
42804
+ if (cmpVer(latest, pkg.version) <= 0) {
42805
+ log(`\x1B[32m✓ Already up to date (${pkg.version}).\x1B[0m`);
42806
+ return "current";
42807
+ }
42808
+ return install(pkg, mgr, latest);
42809
+ }
42734
42810
 
42735
42811
  // src/tips.ts
42736
42812
  var TIPS = [
@@ -42981,6 +43057,9 @@ class ApiClient {
42981
43057
  getAgentSettings(id) {
42982
43058
  return this.request("GET", `/api/v1/agents/${id}`);
42983
43059
  }
43060
+ importSession(input) {
43061
+ return this.request("POST", "/api/v1/todos/import", input, 120000);
43062
+ }
42984
43063
  addMessage(projectId, content, agentSettings, todoId, attachments, scheduledTimestamp, groupTag, groupName) {
42985
43064
  const payload = { content, agentSettings, attachments: attachments || [] };
42986
43065
  if (todoId)
@@ -43245,7 +43324,7 @@ function writeCredential(apiUrl, apiKey) {
43245
43324
  }
43246
43325
 
43247
43326
  // ../packages/shared-api/src/frontend-ws.ts
43248
- var log = (level, ...args) => console.log(`[frontend-ws:${level}]`, ...args);
43327
+ var log2 = (level, ...args) => console.log(`[frontend-ws:${level}]`, ...args);
43249
43328
 
43250
43329
  class FrontendWebSocket {
43251
43330
  apiUrl;
@@ -43327,7 +43406,7 @@ class FrontendWebSocket {
43327
43406
  resolve(false);
43328
43407
  });
43329
43408
  sock.on("error", (err) => {
43330
- log("error", "WS error:", err.message);
43409
+ log2("error", "WS error:", err.message);
43331
43410
  if (current())
43332
43411
  this.connected = false;
43333
43412
  resolve(false);
@@ -43764,6 +43843,75 @@ var NON_SHELL_TYPES = new Set([
43764
43843
  "IOS" /* IOS */
43765
43844
  ]);
43766
43845
  // ../packages/shared-fbe/src/blocks/index.ts
43846
+ var ToolType;
43847
+ ((ToolType2) => {
43848
+ ToolType2["Read"] = "read";
43849
+ ToolType2["Create"] = "create";
43850
+ ToolType2["Write"] = "write";
43851
+ ToolType2["Edit"] = "edit";
43852
+ ToolType2["ModifyFile"] = "modify_file";
43853
+ ToolType2["Bash"] = "bash";
43854
+ ToolType2["Grep"] = "grep";
43855
+ ToolType2["List"] = "list";
43856
+ ToolType2["Skill"] = "skill";
43857
+ ToolType2["ApiGetCurrentContext"] = "api_get_current_context";
43858
+ ToolType2["ApiGetTodo"] = "api_get_todo";
43859
+ ToolType2["ApiAddTodoMessage"] = "api_add_todo_message";
43860
+ ToolType2["ApiUpdateTodoStatus"] = "api_update_todo_status";
43861
+ ToolType2["ApiDeleteTodo"] = "api_delete_todo";
43862
+ ToolType2["ApiListProjects"] = "api_list_projects";
43863
+ ToolType2["ApiGetProject"] = "api_get_project";
43864
+ ToolType2["ApiCreateProject"] = "api_create_project";
43865
+ ToolType2["ApiListProjectTodos"] = "api_list_project_todos";
43866
+ ToolType2["ApiCreateTodo"] = "api_create_todo";
43867
+ ToolType2["ApiListAgents"] = "api_list_agents";
43868
+ ToolType2["ApiGetAgent"] = "api_get_agent";
43869
+ ToolType2["ApiUpdateAgent"] = "api_update_agent";
43870
+ ToolType2["ApiListBusinessContexts"] = "api_list_business_contexts";
43871
+ ToolType2["ApiGetContextItem"] = "api_get_context_item";
43872
+ ToolType2["ApiCreateContextItem"] = "api_create_context_item";
43873
+ ToolType2["ApiUpdateContextItem"] = "api_update_context_item";
43874
+ ToolType2["ApiDeleteContextItem"] = "api_delete_context_item";
43875
+ ToolType2["ApiListEdges"] = "api_list_edges";
43876
+ ToolType2["ApiGetEdge"] = "api_get_edge";
43877
+ ToolType2["ApiListMcps"] = "api_list_mcps";
43878
+ ToolType2["ApiGetUsage"] = "api_get_usage";
43879
+ ToolType2["ApiGetBalance"] = "api_get_balance";
43880
+ ToolType2["ApiGetApiSchema"] = "api_get_api_schema";
43881
+ ToolType2["ApiListBoard"] = "api_list_board";
43882
+ ToolType2["ApiUpsertGroup"] = "api_upsert_group";
43883
+ ToolType2["ApiCreateTemplate"] = "api_create_template";
43884
+ ToolType2["ApiRecommendTemplate"] = "api_recommend_template";
43885
+ ToolType2["ImageGen"] = "image_gen";
43886
+ ToolType2["HtmlSnippet"] = "html_snippet";
43887
+ ToolType2["LivePreview"] = "live_preview";
43888
+ ToolType2["OpenBrowser"] = "open_browser";
43889
+ ToolType2["Show"] = "show";
43890
+ ToolType2["Text"] = "text";
43891
+ ToolType2["Reason"] = "reason";
43892
+ ToolType2["Error"] = "error";
43893
+ ToolType2["Compact"] = "compact";
43894
+ ToolType2["Question"] = "question";
43895
+ ToolType2["Login"] = "login_prompt";
43896
+ ToolType2["BusinessOnboarding"] = "business_onboarding";
43897
+ ToolType2["RequestMcpAccess"] = "request_mcp_access";
43898
+ ToolType2["EdgeNotRunning"] = "edge_not_running";
43899
+ ToolType2["WebFetch"] = "webfetch";
43900
+ ToolType2["GoogleSearch"] = "google_search";
43901
+ ToolType2["WebSearch"] = "web_search";
43902
+ ToolType2["VaultSearch"] = "vault_search";
43903
+ ToolType2["VaultResolve"] = "vault_resolve";
43904
+ ToolType2["VaultWrite"] = "vault_write";
43905
+ ToolType2["VaultWriteBatch"] = "vault_write_batch";
43906
+ ToolType2["VaultUpdate"] = "vault_update";
43907
+ ToolType2["Explore"] = "explore";
43908
+ ToolType2["Plan"] = "plan";
43909
+ ToolType2["Review"] = "review";
43910
+ ToolType2["DeviceList"] = "device_list";
43911
+ ToolType2["Mcp"] = "mcp";
43912
+ ToolType2["NamedTool"] = "named_tool";
43913
+ })(ToolType ||= {});
43914
+ var TOOL_TYPE_VALUES = new Set(Object.values(ToolType));
43767
43915
  var USER_INPUT_BLOCK_TYPES = new Set([
43768
43916
  "question" /* Question */,
43769
43917
  "login_prompt" /* Login */,
@@ -44445,7 +44593,7 @@ var tool_catalog_default = {
44445
44593
  installer: "npm",
44446
44594
  label: "Gmail",
44447
44595
  summary: "Read and send Gmail from your own account.",
44448
- statusCmd: "zele whoami 2>/dev/null | grep 'email:' | grep -m1 .",
44596
+ statusCmd: "zele whoami 2>/dev/null | grep -o 'email: *[^ ]*' | tr -d ' ' | paste -sd ' ' - | grep -m1 .",
44449
44597
  loginNeedsPty: true,
44450
44598
  loginCmd: "zele login --method google",
44451
44599
  oauthUrlPattern: "(https://accounts\\.google\\.com\\S+)",
@@ -44464,7 +44612,7 @@ var tool_catalog_default = {
44464
44612
  binName: "zele",
44465
44613
  label: "Google Calendar",
44466
44614
  summary: "See your Google Calendar and book, move or cancel events.",
44467
- statusCmd: "zele whoami 2>/dev/null | grep 'email:' | grep -m1 .",
44615
+ statusCmd: "zele whoami 2>/dev/null | grep -o 'email: *[^ ]*' | tr -d ' ' | paste -sd ' ' - | grep -m1 .",
44468
44616
  loginNeedsPty: true,
44469
44617
  loginCmd: "zele login --method google",
44470
44618
  oauthUrlPattern: "(https://accounts\\.google\\.com\\S+)",
@@ -44690,7 +44838,7 @@ var tool_catalog_default = {
44690
44838
  preinstallCloud: true,
44691
44839
  label: "GitHub",
44692
44840
  summary: "Work with your GitHub repos, pull requests and issues.",
44693
- statusCmd: "gh auth status 2>&1 | grep 'Logged in to' | grep -m1 .",
44841
+ statusCmd: "gh auth status 2>&1 | grep -o 'Logged in to [^ ]* [a-z]* [^ ]*' | paste -sd ' ' - | grep -m1 .",
44694
44842
  loginCmd: "gh auth login --hostname github.com --git-protocol https",
44695
44843
  oauthUrlPattern: "(https://github\\.com/login/device\\S*)",
44696
44844
  deviceCodePattern: "one-time code:\\s*([A-Z0-9]{4}-[A-Z0-9]{4})",
@@ -44707,8 +44855,8 @@ var tool_catalog_default = {
44707
44855
  installer: "npm",
44708
44856
  label: "MCP (mcporter)",
44709
44857
  summary: "Use tools from any MCP server.",
44710
- statusCmd: "mcporter list 2>/dev/null | grep -v 'No MCP servers' | grep -m1 .",
44711
- 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.",
44858
+ statusCmd: 'mcporter config list --json 2>/dev/null | node -e \'let d="";process.stdin.on("data",c=>d+=c).on("end",()=>{const s=JSON.parse(d||"{}").servers||[];if(!s.length)process.exit(1);console.log("Configured MCP servers (one line each; run `mcporter list <name>` before first use):");for(const x of s)console.log(`- ${x.name} — ${x.description?x.description+" ":""}(${x.baseUrl?new URL(x.baseUrl).host:x.command})`)})\'',
44859
+ description: "MCP servers as CLI: `mcporter list <server>` (its tools), `mcporter call <server>.<tool> key=value` (`key=@file`), `mcporter auth <server>`, `mcporter config add <name> <cmd-or-url>`.",
44712
44860
  versionCmd: "mcporter --version 2>/dev/null | sed -n 1p",
44713
44861
  preinstallJarvis: true,
44714
44862
  preinstallCloud: true
@@ -44722,7 +44870,7 @@ var tool_catalog_default = {
44722
44870
  installer: "binary",
44723
44871
  label: "GitLab",
44724
44872
  summary: "Work with your GitLab repos, merge requests and pipelines.",
44725
- statusCmd: "glab auth status 2>&1 | grep 'Logged in to' | grep -m1 .",
44873
+ statusCmd: "glab auth status 2>&1 | grep -o 'Logged in to [^ ]* [a-z]* [^ ]*' | paste -sd ' ' - | grep -m1 .",
44726
44874
  loginCmd: "glab auth login --device",
44727
44875
  credentialPaths: ["~/.config/glab-cli/config.yml"],
44728
44876
  description: "GitLab equivalent of `gh`.",
@@ -44785,7 +44933,7 @@ var tool_catalog_default = {
44785
44933
  installer: "npm",
44786
44934
  label: "Firebase",
44787
44935
  summary: "Deploy and manage Firebase hosting, database and functions.",
44788
- statusCmd: "firebase login:list 2>&1 | grep -oiE '[[:alnum:]._%+-]+@[[:alnum:].-]+\\.[[:alpha:]]{2,}' | grep -m1 .",
44936
+ statusCmd: "firebase login:list 2>&1 | grep -oiE '[[:alnum:]._%+-]+@[[:alnum:].-]+\\.[[:alpha:]]{2,}' | sort -u | paste -sd ' ' - | grep -m1 .",
44789
44937
  loginCmd: "firebase login --no-localhost --reauth",
44790
44938
  loginNeedsPty: true,
44791
44939
  stdinPaste: true,
@@ -44825,9 +44973,7 @@ var tool_catalog_default = {
44825
44973
  credentialPaths: ["~/.config/stripe/config.toml"],
44826
44974
  description: "`stripe listen` forwards webhooks locally; `stripe get/post /v1/...` for raw API.",
44827
44975
  versionCmd: "stripe --version 2>/dev/null | sed -n 1p",
44828
- deviceCodePattern: "verification code:\\s*([A-Z0-9]{4}-[A-Z0-9]{4})",
44829
- oauthUrlPattern: "(https://access\\.stripe\\.com/stripecli/\\S+)",
44830
- canStreamLogin: true
44976
+ oauthUrlPattern: "(https://dashboard\\.stripe\\.com/stripecli/confirm_auth\\S+)"
44831
44977
  },
44832
44978
  flyctl: {
44833
44979
  preinstallCloud: true,
@@ -45678,6 +45824,7 @@ var tool_catalog_default = {
45678
45824
  label: "Mailchimp",
45679
45825
  summary: "Manage Mailchimp audiences, contacts, email campaigns and reports.",
45680
45826
  loginCmd: "mailchimp-api auth --api-key <api_key>",
45827
+ oauthBroker: true,
45681
45828
  statusCmd: `mailchimp-api whoami 2>/dev/null | sed -n 's/.*"account_name"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' | grep -m1 .`,
45682
45829
  credentialPaths: [
45683
45830
  "~/.config/mailchimp-api/credentials.json"
@@ -46196,7 +46343,13 @@ import { parseArgs } from "util";
46196
46343
  // package.json
46197
46344
  var package_default = {
46198
46345
  name: "@todoforai/cli",
46199
- version: "0.1.62",
46346
+ description: "TODOforAI CLI — create and manage tasks with tfa-cli.",
46347
+ homepage: "https://todofor.ai",
46348
+ repository: {
46349
+ type: "git",
46350
+ url: "git+https://github.com/todoforai/cli.git"
46351
+ },
46352
+ version: "0.1.63",
46200
46353
  type: "module",
46201
46354
  bin: {
46202
46355
  "todoforai-cli": "bin/todoforai-cli.js",
@@ -46216,7 +46369,7 @@ var package_default = {
46216
46369
  },
46217
46370
  dependencies: {
46218
46371
  "@agentclientprotocol/sdk": "^1.4.0",
46219
- "@todoforai/update-notifier": "^0.1.0",
46372
+ "@todoforai/update-notifier": "^0.4.0",
46220
46373
  chalk: "^6.0.0",
46221
46374
  "cli-highlight": "^2.1.11",
46222
46375
  "diff-match-patch": "^1.0.5",
@@ -46258,6 +46411,7 @@ Examples:
46258
46411
  tfa-cli device list|rename|wallpaper … # Paired machines
46259
46412
  tfa-cli list [-n 30] [--cursor N] [--all] [--status S] # List todos (paginated)
46260
46413
  tfa-cli status <todo-id> <STATUS> # Update a todo's status
46414
+ tfa-cli update # Update tfa-cli itself (also auto-updates in background; NO_UPDATE_NOTIFIER=1 disables)
46261
46415
  tfa-cli delete <todo-id> # Permanently delete a todo
46262
46416
  tfa-cli addmessage <todo-id> "text" # Send a message and exit (like -r, no watch/bridge)
46263
46417
  tfa-cli show <file|-> [todo-id] # Render a local file (image/pdf/html…) in the chat; - = stdin
@@ -46269,6 +46423,7 @@ Examples:
46269
46423
  tfa-cli notify [--to <email>] "Title" "message" [--href /t/<id>] # Note to your own user, or --to a project member (Messages tab + phone push)
46270
46424
  tfa-cli claim mint --seed <projectId> [--emails a@x,b@y] [--ttl <sec>] # Mint /claim/<token> links for a project you own
46271
46425
  tfa-cli next [--direction "<text>"] # Analyzer growth recommendation cards
46426
+ tfa-cli import [claude|codex|<file>...] [--dry-run] # Import Claude Code / Codex sessions as todos
46272
46427
  tfa-cli <command> help # Details per command
46273
46428
 
46274
46429
  Options:
@@ -46359,7 +46514,7 @@ var WORD_FLAGS = {
46359
46514
  agents: "list-agents",
46360
46515
  config: "show-config"
46361
46516
  };
46362
- var HELP_SUBCOMMANDS = ["agent", "todo", "project", "brand", "device", "list", "ls", "status", "show", "open", "inbox", "notify"];
46517
+ var HELP_SUBCOMMANDS = ["agent", "todo", "project", "brand", "device", "list", "ls", "status", "show", "open", "inbox", "notify", "import"];
46363
46518
  function parseCliArgs() {
46364
46519
  const { values, positionals } = parseArgs({
46365
46520
  args: process.argv.slice(2),
@@ -46399,6 +46554,7 @@ function parseCliArgs() {
46399
46554
  to: { type: "string" },
46400
46555
  unread: { type: "boolean", default: false },
46401
46556
  limit: { type: "string" },
46557
+ days: { type: "string" },
46402
46558
  resume: { type: "string", short: "r" },
46403
46559
  continue: { type: "boolean", short: "c", default: false },
46404
46560
  "non-interactive": { type: "boolean", short: "n", default: false },
@@ -46771,7 +46927,7 @@ Cancelled
46771
46927
  import { resolve, basename } from "path";
46772
46928
 
46773
46929
  // src/ensure-bridge.ts
46774
- import { spawn, spawnSync } from "child_process";
46930
+ import { spawn as spawn2, spawnSync as spawnSync2 } from "child_process";
46775
46931
  import fs2 from "fs";
46776
46932
  import path2 from "path";
46777
46933
  import os2 from "os";
@@ -46781,7 +46937,7 @@ var INSTALL_TIMEOUT_MS = 90000;
46781
46937
  var bridgeBin = "todoforai-bridge";
46782
46938
  var bridgeBinary = () => bridgeBin;
46783
46939
  function probeBridge(bin) {
46784
- return spawnSync(bin, ["--version"], { stdio: "ignore" }).status === 0;
46940
+ return spawnSync2(bin, ["--version"], { stdio: "ignore" }).status === 0;
46785
46941
  }
46786
46942
  function hasBridge() {
46787
46943
  if (probeBridge(bridgeBin))
@@ -46796,7 +46952,7 @@ function installBridge() {
46796
46952
  if (process.platform !== "linux" && process.platform !== "darwin")
46797
46953
  return false;
46798
46954
  console.error(`\x1B[2mInstalling TODOforAI Bridge (${INSTALLER_URL})...\x1B[0m`);
46799
- const r = spawnSync("sh", ["-c", `curl -fsSL --connect-timeout 10 --max-time 30 ${INSTALLER_URL} | sh`], { stdio: ["ignore", "ignore", "inherit"], timeout: INSTALL_TIMEOUT_MS, killSignal: "SIGKILL" });
46955
+ const r = spawnSync2("sh", ["-c", `curl -fsSL --connect-timeout 10 --max-time 30 ${INSTALLER_URL} | sh`], { stdio: ["ignore", "ignore", "inherit"], timeout: INSTALL_TIMEOUT_MS, killSignal: "SIGKILL" });
46800
46956
  if (r.error?.code === "ETIMEDOUT")
46801
46957
  console.error("\x1B[33mBridge install timed out\x1B[0m");
46802
46958
  return r.status === 0 && hasBridge();
@@ -46849,7 +47005,7 @@ function bridgeWhoamiArgs(apiUrl) {
46849
47005
  return withProfile(["whoami"], apiUrl);
46850
47006
  }
46851
47007
  function bridgeDeviceId(apiUrl) {
46852
- const r = spawnSync(bridgeBin, bridgeWhoamiArgs(apiUrl), { encoding: "utf-8" });
47008
+ const r = spawnSync2(bridgeBin, bridgeWhoamiArgs(apiUrl), { encoding: "utf-8" });
46853
47009
  if (r.status !== 0)
46854
47010
  return null;
46855
47011
  const m = (r.stdout || "").match(/^Device:.*\(id:\s*([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\)/im);
@@ -46875,11 +47031,11 @@ async function enrollBridgeWithApiKey(apiUrl, apiKey) {
46875
47031
  console.error(`\x1B[33mBridge enroll: mint failed (${e?.message || e})\x1B[0m`);
46876
47032
  return false;
46877
47033
  }
46878
- const login = spawnSync(bridgeBin, [...bridgeLoginArgs(apiUrl), "--token", token], { stdio: ["ignore", "ignore", "inherit"], timeout: 30000, killSignal: "SIGKILL" });
47034
+ const login = spawnSync2(bridgeBin, [...bridgeLoginArgs(apiUrl), "--token", token], { stdio: ["ignore", "ignore", "inherit"], timeout: 30000, killSignal: "SIGKILL" });
46879
47035
  return login.status === 0;
46880
47036
  }
46881
47037
  function ensureBridgeCredentials(apiUrl, opts = {}) {
46882
- const whoami = spawnSync(bridgeBin, bridgeWhoamiArgs(apiUrl), { stdio: "ignore" });
47038
+ const whoami = spawnSync2(bridgeBin, bridgeWhoamiArgs(apiUrl), { stdio: "ignore" });
46883
47039
  if (whoami.status === 0)
46884
47040
  return true;
46885
47041
  if (opts.interactive === false) {
@@ -46887,7 +47043,7 @@ function ensureBridgeCredentials(apiUrl, opts = {}) {
46887
47043
  return false;
46888
47044
  }
46889
47045
  console.error("\x1B[2mBridge credentials not found. Starting `todoforai-bridge login`...\x1B[0m");
46890
- const login = spawnSync(bridgeBin, bridgeLoginArgs(apiUrl), { stdio: "inherit" });
47046
+ const login = spawnSync2(bridgeBin, bridgeLoginArgs(apiUrl), { stdio: "inherit" });
46891
47047
  return login.status === 0;
46892
47048
  }
46893
47049
  async function bridgeState(apiUrl, apiKey, deviceId) {
@@ -46913,7 +47069,7 @@ async function ensureBridgeRunning(apiUrl, apiKey, opts = {}) {
46913
47069
  console.error(`\x1B[2mBridge not started: \`todoforai-bridge\` was not found on PATH. Install it (curl -fsSL ${INSTALLER_URL} | sh), or pass --no-bridge (or deprecated --no-edge) to silence this.\x1B[0m`);
46914
47070
  return false;
46915
47071
  }
46916
- const hasCreds = spawnSync(bridgeBin, bridgeWhoamiArgs(apiUrl), { stdio: "ignore" }).status === 0 || await enrollBridgeWithApiKey(apiUrl, apiKey) || ensureBridgeCredentials(apiUrl, opts);
47072
+ const hasCreds = spawnSync2(bridgeBin, bridgeWhoamiArgs(apiUrl), { stdio: "ignore" }).status === 0 || await enrollBridgeWithApiKey(apiUrl, apiKey) || ensureBridgeCredentials(apiUrl, opts);
46917
47073
  if (!hasCreds) {
46918
47074
  console.error("\x1B[33mBridge not started: `todoforai-bridge login` did not complete successfully.\x1B[0m");
46919
47075
  return false;
@@ -46930,7 +47086,7 @@ async function ensureBridgeRunning(apiUrl, apiKey, opts = {}) {
46930
47086
  fs2.mkdirSync(logDir, { recursive: true });
46931
47087
  const logFile = path2.join(logDir, "bridge.log");
46932
47088
  const out = fs2.openSync(logFile, "a");
46933
- const child = spawn(bridgeBin, bridgeRunArgs(apiUrl), {
47089
+ const child = spawn2(bridgeBin, bridgeRunArgs(apiUrl), {
46934
47090
  detached: true,
46935
47091
  stdio: ["ignore", out, out]
46936
47092
  });
@@ -47164,7 +47320,7 @@ class ScopedConfig {
47164
47320
  }
47165
47321
  }
47166
47322
  // src/device-login.ts
47167
- import { spawn as spawn2 } from "child_process";
47323
+ import { spawn as spawn3 } from "child_process";
47168
47324
  class DeviceLoginError extends Error {
47169
47325
  }
47170
47326
  async function runDeviceLogin(apiUrl) {
@@ -47182,7 +47338,7 @@ async function runDeviceLogin(apiUrl) {
47182
47338
  `);
47183
47339
  try {
47184
47340
  const [cmd, args] = process.platform === "win32" ? ["cmd", ["/c", "start", "", url]] : [process.platform === "darwin" ? "open" : "xdg-open", [url]];
47185
- const child = spawn2(cmd, args, { stdio: "ignore", detached: true });
47341
+ const child = spawn3(cmd, args, { stdio: "ignore", detached: true });
47186
47342
  child.on("error", () => {});
47187
47343
  child.unref();
47188
47344
  } catch {}
@@ -50780,11 +50936,442 @@ ${message}`).digest("hex").slice(0, 16);
50780
50936
  `);
50781
50937
  }
50782
50938
 
50939
+ // src/import-command.ts
50940
+ import { statSync as statSync3 } from "fs";
50941
+ import { basename as basename3, dirname as dirname3, resolve as resolve4 } from "path";
50942
+
50943
+ // src/import/claude.ts
50944
+ import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync3, statSync } from "fs";
50945
+ import { homedir as homedir3 } from "os";
50946
+ import { join as join3 } from "path";
50947
+
50948
+ // src/import/common.ts
50949
+ import { createHash as createHash2 } from "crypto";
50950
+ var NOTE_MAX_LEN = 2000;
50951
+ var TOOL_RESULT_MAX_LEN = 4000;
50952
+ var SESSION_TITLE_MAX_LEN = 120;
50953
+ var clip = (s, max) => s.length > max ? `${s.slice(0, max)}…` : s;
50954
+ var hashContent = (s) => createHash2("sha256").update(s).digest("hex");
50955
+ function noteToolCall(name, input) {
50956
+ const lines = [`[external_agent_tool_call: ${typeof name === "string" ? name : "tool"}]`];
50957
+ const inp = input && typeof input === "object" ? input : null;
50958
+ let shown = false;
50959
+ if (inp) {
50960
+ for (const [label, keys] of [["description", ["description"]], ["command", ["command", "cmd"]], ["file", ["file_path", "path", "notebook_path"]]]) {
50961
+ const v = keys.map((k) => inp[k]).find((x) => typeof x === "string" && x);
50962
+ if (v) {
50963
+ lines.push(`${label}: ${clip(v, NOTE_MAX_LEN)}`);
50964
+ shown = true;
50965
+ }
50966
+ }
50967
+ }
50968
+ if (!shown && input !== undefined)
50969
+ lines.push(`input: ${clip(typeof input === "string" ? input : JSON.stringify(input), NOTE_MAX_LEN)}`);
50970
+ lines.push("[/external_agent_tool_call]");
50971
+ return lines.join(`
50972
+ `);
50973
+ }
50974
+ function noteToolResult(output, isError) {
50975
+ const head = isError ? "[external_agent_tool_result: error]" : "[external_agent_tool_result]";
50976
+ return `${head}
50977
+ ${clip(output.trim(), TOOL_RESULT_MAX_LEN)}
50978
+ [/external_agent_tool_result]`;
50979
+ }
50980
+ function titleFromMessages(messages, fallback = "Imported session") {
50981
+ const first = messages.find((m) => m.role === "user" && !m.content.startsWith("[external_agent_tool"))?.content ?? "";
50982
+ const line = first.split(`
50983
+ `).map((l) => l.trim()).find(Boolean) ?? "";
50984
+ return line ? clip(line, SESSION_TITLE_MAX_LEN) : fallback;
50985
+ }
50986
+
50987
+ // src/import/claude.ts
50988
+ var claudeHome = () => process.env.CLAUDE_CONFIG_DIR || join3(homedir3(), ".claude");
50989
+ function listClaudeSessionFiles(home = claudeHome()) {
50990
+ const root = join3(home, "projects");
50991
+ if (!existsSync2(root))
50992
+ return [];
50993
+ const files = [];
50994
+ for (const slug of readdirSync(root, { withFileTypes: true })) {
50995
+ if (!slug.isDirectory())
50996
+ continue;
50997
+ const dir = join3(root, slug.name);
50998
+ for (const f of readdirSync(dir))
50999
+ if (f.endsWith(".jsonl"))
51000
+ files.push(join3(dir, f));
51001
+ }
51002
+ return files;
51003
+ }
51004
+ var parseTs = (r) => {
51005
+ if (typeof r.timestamp === "string") {
51006
+ const t = Date.parse(r.timestamp);
51007
+ if (!Number.isNaN(t))
51008
+ return t;
51009
+ }
51010
+ if (typeof r.timestamp_ms === "number")
51011
+ return r.timestamp_ms;
51012
+ return;
51013
+ };
51014
+ var stripUserQuery = (s) => {
51015
+ const m = s.match(/^\s*<user_query>\s*([\s\S]*?)\s*<\/user_query>\s*$/);
51016
+ return m ? m[1] : s;
51017
+ };
51018
+ var isHarnessUserText = (s) => /^\s*<(command-name|local-command-caveat|local-command-stdout|local-command-stderr|system-reminder)>/.test(s);
51019
+ function flattenContent(content) {
51020
+ if (typeof content === "string")
51021
+ return { text: content, onlyToolResults: false };
51022
+ if (!Array.isArray(content))
51023
+ return { text: "", onlyToolResults: false };
51024
+ const parts = [];
51025
+ let toolResults = 0;
51026
+ for (const b of content) {
51027
+ if (!b || typeof b !== "object")
51028
+ continue;
51029
+ switch (b.type) {
51030
+ case "text":
51031
+ if (typeof b.text === "string" && b.text.trim())
51032
+ parts.push(b.text);
51033
+ break;
51034
+ case "tool_use":
51035
+ parts.push(noteToolCall(b.name, b.input));
51036
+ break;
51037
+ case "tool_result": {
51038
+ toolResults++;
51039
+ const inner = typeof b.content === "string" ? b.content : Array.isArray(b.content) ? b.content.map((c3) => c3?.type === "text" ? c3.text : `[${c3?.type ?? "block"}]`).join(`
51040
+ `) : "";
51041
+ parts.push(noteToolResult(inner, b.is_error === true));
51042
+ break;
51043
+ }
51044
+ case "thinking":
51045
+ case "redacted_thinking":
51046
+ break;
51047
+ default:
51048
+ parts.push(`[external unsupported block: ${b.type}]`);
51049
+ }
51050
+ }
51051
+ return { text: parts.join(`
51052
+
51053
+ `), onlyToolResults: toolResults > 0 && toolResults === content.length };
51054
+ }
51055
+ function parseClaudeSession(path3) {
51056
+ const raw = readFileSync3(path3, "utf8");
51057
+ const messages = [];
51058
+ let cwd;
51059
+ let customTitle;
51060
+ let aiTitle;
51061
+ for (const line of raw.split(`
51062
+ `)) {
51063
+ if (!line.trim())
51064
+ continue;
51065
+ let r;
51066
+ try {
51067
+ r = JSON.parse(line);
51068
+ } catch {
51069
+ continue;
51070
+ }
51071
+ if (!cwd && typeof r.cwd === "string" && r.cwd)
51072
+ cwd = r.cwd;
51073
+ if (r.type === "custom-title" && typeof r.customTitle === "string")
51074
+ customTitle = r.customTitle;
51075
+ if (r.type === "ai-title" && typeof r.aiTitle === "string")
51076
+ aiTitle = r.aiTitle;
51077
+ if (r.type !== "user" && r.type !== "assistant")
51078
+ continue;
51079
+ if (r.isMeta === true || r.isSidechain === true)
51080
+ continue;
51081
+ const { text, onlyToolResults } = flattenContent(r.message?.content);
51082
+ const role = r.type === "user" && !onlyToolResults ? "user" : "assistant";
51083
+ const content = (role === "user" ? stripUserQuery(text) : text).trim();
51084
+ if (!content || role === "user" && isHarnessUserText(content))
51085
+ continue;
51086
+ messages.push({ role, content, timestamp: parseTs(r) });
51087
+ }
51088
+ if (!cwd || !messages.some((m) => m.role === "user"))
51089
+ return null;
51090
+ const st = statSync(path3);
51091
+ return {
51092
+ kind: "claude",
51093
+ path: path3,
51094
+ cwd,
51095
+ messages,
51096
+ title: customTitle?.trim() || aiTitle?.trim() || titleFromMessages(messages),
51097
+ sha256: hashContent(raw),
51098
+ modifiedAt: st.mtimeMs
51099
+ };
51100
+ }
51101
+
51102
+ // src/import/codex.ts
51103
+ import { existsSync as existsSync3, readdirSync as readdirSync2, readFileSync as readFileSync4, statSync as statSync2 } from "fs";
51104
+ import { homedir as homedir4 } from "os";
51105
+ import { join as join4 } from "path";
51106
+ var codexHome = () => process.env.CODEX_HOME || join4(homedir4(), ".codex");
51107
+ function listCodexSessionFiles(home = codexHome()) {
51108
+ const root = join4(home, "sessions");
51109
+ if (!existsSync3(root))
51110
+ return [];
51111
+ const out = [];
51112
+ const walk = (dir) => {
51113
+ for (const e of readdirSync2(dir, { withFileTypes: true })) {
51114
+ const p = join4(dir, e.name);
51115
+ if (e.isDirectory())
51116
+ walk(p);
51117
+ else if (e.name.startsWith("rollout-") && e.name.endsWith(".jsonl"))
51118
+ out.push(p);
51119
+ }
51120
+ };
51121
+ walk(root);
51122
+ return out;
51123
+ }
51124
+ function readCodexTitles(home = codexHome()) {
51125
+ const titles = new Map;
51126
+ const idx = join4(home, "session_index.jsonl");
51127
+ if (!existsSync3(idx))
51128
+ return titles;
51129
+ for (const line of readFileSync4(idx, "utf8").split(`
51130
+ `)) {
51131
+ try {
51132
+ const r = JSON.parse(line);
51133
+ if (r?.id && typeof r.thread_name === "string")
51134
+ titles.set(r.id, r.thread_name);
51135
+ } catch {}
51136
+ }
51137
+ return titles;
51138
+ }
51139
+ var HARNESS_TAGS = ["environment_context", "recommended_plugins", "user_instructions", "permissions_instructions", "turn_aborted", "collaboration_mode_instructions"];
51140
+ var isHarnessBlock = (s) => {
51141
+ const m = /^\s*<([a-z_]+)>[\s\S]*<\/\1>\s*$/.exec(s);
51142
+ return !!m && HARNESS_TAGS.includes(m[1]);
51143
+ };
51144
+ var partsText = (content, dropHarness = false) => Array.isArray(content) ? content.map((c3) => typeof c3?.text === "string" ? c3.text : "").filter((t) => t.trim() && !(dropHarness && isHarnessBlock(t))).join(`
51145
+
51146
+ `) : typeof content === "string" ? content : "";
51147
+ var outputText = (output) => {
51148
+ if (typeof output === "string") {
51149
+ try {
51150
+ const parsed = JSON.parse(output);
51151
+ if (Array.isArray(parsed))
51152
+ return partsText(parsed);
51153
+ } catch {}
51154
+ return output;
51155
+ }
51156
+ return partsText(output);
51157
+ };
51158
+ function parseCodexSession(path3, titles = readCodexTitles()) {
51159
+ const raw = readFileSync4(path3, "utf8");
51160
+ const messages = [];
51161
+ let cwd;
51162
+ let sessionId;
51163
+ for (const line of raw.split(`
51164
+ `)) {
51165
+ if (!line.trim())
51166
+ continue;
51167
+ let r;
51168
+ try {
51169
+ r = JSON.parse(line);
51170
+ } catch {
51171
+ continue;
51172
+ }
51173
+ const ts = typeof r.timestamp === "string" ? Date.parse(r.timestamp) : NaN;
51174
+ const timestamp = Number.isNaN(ts) ? undefined : ts;
51175
+ if (r.type === "session_meta") {
51176
+ cwd = cwd || r.payload?.cwd;
51177
+ sessionId = sessionId || r.payload?.session_id || r.payload?.id;
51178
+ continue;
51179
+ }
51180
+ if (r.type !== "response_item")
51181
+ continue;
51182
+ const p = r.payload ?? {};
51183
+ switch (p.type) {
51184
+ case "message": {
51185
+ if (p.role !== "user" && p.role !== "assistant")
51186
+ break;
51187
+ const content = partsText(p.content, p.role === "user").trim();
51188
+ if (content)
51189
+ messages.push({ role: p.role, content, timestamp });
51190
+ break;
51191
+ }
51192
+ case "function_call":
51193
+ case "custom_tool_call": {
51194
+ let input = p.arguments ?? p.input;
51195
+ if (typeof input === "string") {
51196
+ try {
51197
+ input = JSON.parse(input);
51198
+ } catch {}
51199
+ }
51200
+ messages.push({ role: "assistant", content: noteToolCall(p.name, input), timestamp });
51201
+ break;
51202
+ }
51203
+ case "function_call_output":
51204
+ case "custom_tool_call_output":
51205
+ messages.push({ role: "assistant", content: noteToolResult(outputText(p.output), false), timestamp });
51206
+ break;
51207
+ default:
51208
+ break;
51209
+ }
51210
+ }
51211
+ if (!cwd || !messages.some((m) => m.role === "user"))
51212
+ return null;
51213
+ const st = statSync2(path3);
51214
+ return {
51215
+ kind: "codex",
51216
+ path: path3,
51217
+ cwd,
51218
+ messages,
51219
+ title: sessionId && titles.get(sessionId)?.trim() || titleFromMessages(messages),
51220
+ sha256: hashContent(raw),
51221
+ modifiedAt: st.mtimeMs
51222
+ };
51223
+ }
51224
+
51225
+ // src/import-command.ts
51226
+ var DEFAULT_MAX_AGE_DAYS = 30;
51227
+ var DEFAULT_MAX_COUNT = 50;
51228
+ var SOURCES = ["claude", "codex"];
51229
+ function printImportHelp() {
51230
+ process.stderr.write(`
51231
+ tfa-cli import — import Claude Code / Codex sessions as todos
51232
+
51233
+ Usage:
51234
+ tfa-cli import [claude|codex] [flags]
51235
+ tfa-cli import <session.jsonl>... [flags]
51236
+
51237
+ Flags:
51238
+ --project <id> Target project (default: current default project)
51239
+ -a, --agent <id|name> Agent for every imported todo (default: match the session cwd, else your default agent)
51240
+ --days <n> Only sessions modified in the last n days (default: ${DEFAULT_MAX_AGE_DAYS}; 0 = all)
51241
+ --limit <n> Max sessions per source, newest first (default: ${DEFAULT_MAX_COUNT}; 0 = all)
51242
+ --dry-run Parse and list, write nothing (no login needed)
51243
+ --json Machine-readable output
51244
+ -h, --help Show this help
51245
+
51246
+ Sources on this machine:
51247
+ Claude Code ${claudeHome()}/projects/*/*.jsonl
51248
+ Codex ${codexHome()}/sessions/**/rollout-*.jsonl
51249
+ `);
51250
+ }
51251
+ var codexTitles;
51252
+ function safeParse(kind, file) {
51253
+ try {
51254
+ return kind === "claude" ? parseClaudeSession(file) : parseCodexSession(file, codexTitles ??= readCodexTitles());
51255
+ } catch {
51256
+ return null;
51257
+ }
51258
+ }
51259
+ function collect(kinds, days, limit) {
51260
+ const cutoff = days > 0 ? Date.now() - days * 86400000 : 0;
51261
+ return kinds.flatMap((kind) => {
51262
+ const files = kind === "claude" ? listClaudeSessionFiles() : listCodexSessionFiles();
51263
+ const sessions = files.map((f) => ({ f, mtime: statSync3(f).mtimeMs })).filter((x) => x.mtime >= cutoff).sort((a, b) => b.mtime - a.mtime).map((x) => safeParse(kind, x.f)).filter((s) => !!s);
51264
+ return limit > 0 ? sessions.slice(0, limit) : sessions;
51265
+ });
51266
+ }
51267
+ async function agentForCwd(api, cwd, fallback, cache) {
51268
+ for (let dir = cwd;; dir = dirname3(dir)) {
51269
+ const hit = cache.get(dir);
51270
+ if (hit)
51271
+ return hit;
51272
+ const matches = await api.listAgentSettings({ workspacePath: dir }).catch(() => []);
51273
+ if (matches.length) {
51274
+ cache.set(dir, matches[0].id);
51275
+ return matches[0].id;
51276
+ }
51277
+ if (dirname3(dir) === dir)
51278
+ break;
51279
+ }
51280
+ cache.set(cwd, fallback);
51281
+ return fallback;
51282
+ }
51283
+ async function importCommand(api, positionals, args, scopedProject, defaultAgentId) {
51284
+ const days = args.days !== undefined ? Number(args.days) : DEFAULT_MAX_AGE_DAYS;
51285
+ const limit = args.limit !== undefined ? Number(args.limit) : DEFAULT_MAX_COUNT;
51286
+ const json = !!args.json;
51287
+ const ops = positionals.slice(1);
51288
+ const named = ops.filter((o) => SOURCES.includes(o));
51289
+ const files = ops.filter((o) => !SOURCES.includes(o)).map((f) => resolve4(f));
51290
+ const skipped = [];
51291
+ const sessions = files.length ? files.flatMap((f) => {
51292
+ const kind = named[0] ?? (basename3(f).startsWith("rollout-") ? "codex" : "claude");
51293
+ const s = safeParse(kind, f);
51294
+ if (!s)
51295
+ skipped.push(f);
51296
+ return s ? [s] : [];
51297
+ }) : collect(named.length ? named : SOURCES, days, limit);
51298
+ if (!json)
51299
+ for (const f of skipped)
51300
+ process.stderr.write(`${YELLOW}skip ${f}: not a readable session${RESET}
51301
+ `);
51302
+ if (args["dry-run"]) {
51303
+ const rows = sessions.map((s) => ({ kind: s.kind, title: s.title, cwd: s.cwd, messages: s.messages.length, path: s.path, modifiedAt: s.modifiedAt }));
51304
+ if (json) {
51305
+ console.log(JSON.stringify({ sessions: rows, skipped }));
51306
+ return;
51307
+ }
51308
+ for (const r of rows)
51309
+ process.stderr.write(`${CYAN}${r.kind.padEnd(7)}${RESET} ${r.title} ${DIM}${r.messages} msgs · ${r.cwd}${RESET}
51310
+ `);
51311
+ process.stderr.write(`${DIM}${rows.length} session(s) — dry run, nothing written${RESET}
51312
+ `);
51313
+ return;
51314
+ }
51315
+ if (!api)
51316
+ throw new Error("import: not authenticated");
51317
+ const projectId = args.project || scopedProject;
51318
+ if (!projectId) {
51319
+ process.stderr.write(`${RED}No project — pass --project <id>${RESET}
51320
+ `);
51321
+ process.exit(2);
51322
+ }
51323
+ let fallbackAgent = defaultAgentId;
51324
+ if (args.agent || !fallbackAgent) {
51325
+ const agents = await api.listAgentSettings();
51326
+ fallbackAgent = args.agent ? agents.find((a) => a.id === args.agent || a.name === args.agent)?.id : agents[0]?.id;
51327
+ if (!fallbackAgent) {
51328
+ process.stderr.write(`${RED}Agent not found — pass --agent <id>${RESET}
51329
+ `);
51330
+ process.exit(2);
51331
+ }
51332
+ }
51333
+ const agentCache = new Map;
51334
+ const results = [];
51335
+ for (const s of sessions) {
51336
+ const agentSettingsId = args.agent ? fallbackAgent : await agentForCwd(api, s.cwd, fallbackAgent, agentCache);
51337
+ try {
51338
+ const r = await api.importSession({
51339
+ projectId,
51340
+ agentSettingsId,
51341
+ title: s.title,
51342
+ messages: s.messages,
51343
+ source: { kind: s.kind, path: s.path, sha256: s.sha256, cwd: s.cwd }
51344
+ });
51345
+ results.push({ ...r, kind: s.kind, title: s.title, path: s.path });
51346
+ if (!json) {
51347
+ const mark = r.outcome === "unchanged" ? `${DIM}=` : `${GREEN}✓`;
51348
+ process.stderr.write(`${mark} ${r.outcome.padEnd(9)}${RESET} ${s.title} ${DIM}${r.messageCount} msgs · ${r.todoId}${RESET}
51349
+ `);
51350
+ }
51351
+ } catch (e) {
51352
+ results.push({ kind: s.kind, title: s.title, path: s.path, error: e.message });
51353
+ if (!json)
51354
+ process.stderr.write(`${RED}✗ failed ${RESET} ${s.title} ${DIM}${e.message}${RESET}
51355
+ `);
51356
+ }
51357
+ }
51358
+ const failed = results.filter((r) => r.error).length;
51359
+ if (json)
51360
+ console.log(JSON.stringify({ imported: results, total: results.length, skipped }));
51361
+ else {
51362
+ const count = (o) => results.filter((r) => r.outcome === o).length;
51363
+ process.stderr.write(`${GREEN}Imported ${count("created")} new, ${count("updated")} updated${failed ? `, ${RED}${failed} failed` : ""}${RESET}
51364
+ `);
51365
+ }
51366
+ if (failed)
51367
+ process.exitCode = 1;
51368
+ }
51369
+
50783
51370
  // src/index.ts
50784
51371
  import { randomUUID as randomUUID3 } from "crypto";
50785
51372
 
50786
51373
  // src/ensure-bridge.ts
50787
- import { spawn as spawn3, spawnSync as spawnSync2 } from "child_process";
51374
+ import { spawn as spawn4, spawnSync as spawnSync3 } from "child_process";
50788
51375
  import fs3 from "fs";
50789
51376
  import path3 from "path";
50790
51377
  import os4 from "os";
@@ -50793,7 +51380,7 @@ var INSTALL_PREFIX2 = process.env.TODOFORAI_PREFIX || path3.join(os4.homedir(),
50793
51380
  var INSTALL_TIMEOUT_MS2 = 90000;
50794
51381
  var bridgeBin2 = "todoforai-bridge";
50795
51382
  function probeBridge2(bin) {
50796
- return spawnSync2(bin, ["--version"], { stdio: "ignore" }).status === 0;
51383
+ return spawnSync3(bin, ["--version"], { stdio: "ignore" }).status === 0;
50797
51384
  }
50798
51385
  function hasBridge2() {
50799
51386
  if (probeBridge2(bridgeBin2))
@@ -50808,7 +51395,7 @@ function installBridge2() {
50808
51395
  if (process.platform !== "linux" && process.platform !== "darwin")
50809
51396
  return false;
50810
51397
  console.error(`\x1B[2mInstalling TODOforAI Bridge (${INSTALLER_URL2})...\x1B[0m`);
50811
- const r = spawnSync2("sh", ["-c", `curl -fsSL --connect-timeout 10 --max-time 30 ${INSTALLER_URL2} | sh`], { stdio: ["ignore", "ignore", "inherit"], timeout: INSTALL_TIMEOUT_MS2, killSignal: "SIGKILL" });
51398
+ const r = spawnSync3("sh", ["-c", `curl -fsSL --connect-timeout 10 --max-time 30 ${INSTALLER_URL2} | sh`], { stdio: ["ignore", "ignore", "inherit"], timeout: INSTALL_TIMEOUT_MS2, killSignal: "SIGKILL" });
50812
51399
  if (r.error?.code === "ETIMEDOUT")
50813
51400
  console.error("\x1B[33mBridge install timed out\x1B[0m");
50814
51401
  return r.status === 0 && hasBridge2();
@@ -50861,7 +51448,7 @@ function bridgeWhoamiArgs2(apiUrl) {
50861
51448
  return withProfile2(["whoami"], apiUrl);
50862
51449
  }
50863
51450
  function bridgeDeviceId2(apiUrl) {
50864
- const r = spawnSync2(bridgeBin2, bridgeWhoamiArgs2(apiUrl), { encoding: "utf-8" });
51451
+ const r = spawnSync3(bridgeBin2, bridgeWhoamiArgs2(apiUrl), { encoding: "utf-8" });
50865
51452
  if (r.status !== 0)
50866
51453
  return null;
50867
51454
  const m = (r.stdout || "").match(/^Device:.*\(id:\s*([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\)/im);
@@ -50887,11 +51474,11 @@ async function enrollBridgeWithApiKey2(apiUrl, apiKey) {
50887
51474
  console.error(`\x1B[33mBridge enroll: mint failed (${e?.message || e})\x1B[0m`);
50888
51475
  return false;
50889
51476
  }
50890
- const login = spawnSync2(bridgeBin2, [...bridgeLoginArgs2(apiUrl), "--token", token], { stdio: ["ignore", "ignore", "inherit"], timeout: 30000, killSignal: "SIGKILL" });
51477
+ const login = spawnSync3(bridgeBin2, [...bridgeLoginArgs2(apiUrl), "--token", token], { stdio: ["ignore", "ignore", "inherit"], timeout: 30000, killSignal: "SIGKILL" });
50891
51478
  return login.status === 0;
50892
51479
  }
50893
51480
  function ensureBridgeCredentials2(apiUrl, opts = {}) {
50894
- const whoami = spawnSync2(bridgeBin2, bridgeWhoamiArgs2(apiUrl), { stdio: "ignore" });
51481
+ const whoami = spawnSync3(bridgeBin2, bridgeWhoamiArgs2(apiUrl), { stdio: "ignore" });
50895
51482
  if (whoami.status === 0)
50896
51483
  return true;
50897
51484
  if (opts.interactive === false) {
@@ -50899,7 +51486,7 @@ function ensureBridgeCredentials2(apiUrl, opts = {}) {
50899
51486
  return false;
50900
51487
  }
50901
51488
  console.error("\x1B[2mBridge credentials not found. Starting `todoforai-bridge login`...\x1B[0m");
50902
- const login = spawnSync2(bridgeBin2, bridgeLoginArgs2(apiUrl), { stdio: "inherit" });
51489
+ const login = spawnSync3(bridgeBin2, bridgeLoginArgs2(apiUrl), { stdio: "inherit" });
50903
51490
  return login.status === 0;
50904
51491
  }
50905
51492
  async function bridgeState2(apiUrl, apiKey, deviceId) {
@@ -50916,7 +51503,7 @@ async function waitForBridgeOnline2(apiUrl, apiKey, deviceId, timeoutMs = 5000)
50916
51503
  const state = await bridgeState2(apiUrl, apiKey, deviceId);
50917
51504
  if (state !== "offline")
50918
51505
  return state === "online";
50919
- await new Promise((resolve4) => setTimeout(resolve4, 150));
51506
+ await new Promise((resolve5) => setTimeout(resolve5, 150));
50920
51507
  } while (Date.now() < deadline);
50921
51508
  return false;
50922
51509
  }
@@ -50925,7 +51512,7 @@ async function ensureBridgeRunning2(apiUrl, apiKey, opts = {}) {
50925
51512
  console.error(`\x1B[2mBridge not started: \`todoforai-bridge\` was not found on PATH. Install it (curl -fsSL ${INSTALLER_URL2} | sh), or pass --no-bridge (or deprecated --no-edge) to silence this.\x1B[0m`);
50926
51513
  return false;
50927
51514
  }
50928
- const hasCreds = spawnSync2(bridgeBin2, bridgeWhoamiArgs2(apiUrl), { stdio: "ignore" }).status === 0 || await enrollBridgeWithApiKey2(apiUrl, apiKey) || ensureBridgeCredentials2(apiUrl, opts);
51515
+ const hasCreds = spawnSync3(bridgeBin2, bridgeWhoamiArgs2(apiUrl), { stdio: "ignore" }).status === 0 || await enrollBridgeWithApiKey2(apiUrl, apiKey) || ensureBridgeCredentials2(apiUrl, opts);
50929
51516
  if (!hasCreds) {
50930
51517
  console.error("\x1B[33mBridge not started: `todoforai-bridge login` did not complete successfully.\x1B[0m");
50931
51518
  return false;
@@ -50942,7 +51529,7 @@ async function ensureBridgeRunning2(apiUrl, apiKey, opts = {}) {
50942
51529
  fs3.mkdirSync(logDir, { recursive: true });
50943
51530
  const logFile = path3.join(logDir, "bridge.log");
50944
51531
  const out = fs3.openSync(logFile, "a");
50945
- const child = spawn3(bridgeBin2, bridgeRunArgs2(apiUrl), {
51532
+ const child = spawn4(bridgeBin2, bridgeRunArgs2(apiUrl), {
50946
51533
  detached: true,
50947
51534
  stdio: ["ignore", out, out]
50948
51535
  });
@@ -50967,7 +51554,7 @@ async function ensureBridgeRunning2(apiUrl, apiKey, opts = {}) {
50967
51554
  }
50968
51555
 
50969
51556
  // src/isolated.ts
50970
- import { spawn as spawn4 } from "child_process";
51557
+ import { spawn as spawn5 } from "child_process";
50971
51558
  async function mintMayflyToken(apiUrl, apiKey, todoId) {
50972
51559
  const res = await fetch(`${apiUrl}${restBasePath(apiKey)}/cli/mayfly/token`, {
50973
51560
  method: "POST",
@@ -50998,7 +51585,7 @@ async function spawnMayflyBridge(apiUrl, todoId, workspace, opts = {}) {
50998
51585
  delete env2[p + n];
50999
51586
  env2.TODOFORAI_MAYFLY_TOKEN = sessionToken;
51000
51587
  }
51001
- const child = spawn4(bridgeBinary(), args, { stdio: ["ignore", "pipe", "pipe"], env: env2 });
51588
+ const child = spawn5(bridgeBinary(), args, { stdio: ["ignore", "pipe", "pipe"], env: env2 });
51002
51589
  let stopped = false;
51003
51590
  const stop = () => {
51004
51591
  if (stopped)
@@ -51092,9 +51679,7 @@ var CLIENT_METHODS = {
51092
51679
  terminal_release: "terminal/release",
51093
51680
  terminal_wait_for_exit: "terminal/wait_for_exit",
51094
51681
  terminal_kill: "terminal/kill",
51095
- mcp_connect: "mcp/connect",
51096
51682
  mcp_message: "mcp/message",
51097
- mcp_disconnect: "mcp/disconnect",
51098
51683
  elicitation_create: "elicitation/create",
51099
51684
  elicitation_complete: "elicitation/complete"
51100
51685
  };
@@ -51147,7 +51732,7 @@ __export(exports_external, {
51147
51732
  setErrorMap: () => setErrorMap,
51148
51733
  set: () => set,
51149
51734
  safeParseAsync: () => safeParseAsync2,
51150
- safeParse: () => safeParse2,
51735
+ safeParse: () => safeParse3,
51151
51736
  safeEncodeAsync: () => safeEncodeAsync2,
51152
51737
  safeEncode: () => safeEncode2,
51153
51738
  safeDecodeAsync: () => safeDecodeAsync2,
@@ -51384,7 +51969,7 @@ __export(exports_core2, {
51384
51969
  stripTabAndNewline: () => stripTabAndNewline,
51385
51970
  standardProps: () => standardProps,
51386
51971
  safeParseAsync: () => safeParseAsync,
51387
- safeParse: () => safeParse,
51972
+ safeParse: () => safeParse2,
51388
51973
  safeEncodeAsync: () => safeEncodeAsync,
51389
51974
  safeEncode: () => safeEncode,
51390
51975
  safeDecodeAsync: () => safeDecodeAsync,
@@ -52880,7 +53465,7 @@ var _safeParse = (_Err) => (schema, value, _ctx) => {
52880
53465
  }
52881
53466
  return result.issues.length ? failure(_Err, result.issues, ctx) : { success: true, data: result.value };
52882
53467
  };
52883
- var safeParse = /* @__PURE__ */ _safeParse($ZodRealError);
53468
+ var safeParse2 = /* @__PURE__ */ _safeParse($ZodRealError);
52884
53469
  function failure(Err, issues, ctx) {
52885
53470
  let error;
52886
53471
  return {
@@ -55068,7 +55653,7 @@ function handleIntersectionResults(result, left, right) {
55068
55653
  const unrecKeys = new Map;
55069
55654
  let unrecIssue;
55070
55655
  const keyIssues = new Map;
55071
- const collect = (iss, side) => {
55656
+ const collect2 = (iss, side) => {
55072
55657
  let keys;
55073
55658
  if (iss.code === "unrecognized_keys" && !iss.path?.length) {
55074
55659
  unrecIssue ?? (unrecIssue = iss);
@@ -55089,11 +55674,11 @@ function handleIntersectionResults(result, left, right) {
55089
55674
  return true;
55090
55675
  };
55091
55676
  for (const iss of left.issues) {
55092
- if (!collect(iss, "l"))
55677
+ if (!collect2(iss, "l"))
55093
55678
  result.issues.push(iss);
55094
55679
  }
55095
55680
  for (const iss of right.issues) {
55096
- if (!collect(iss, "r"))
55681
+ if (!collect2(iss, "r"))
55097
55682
  result.issues.push(iss);
55098
55683
  }
55099
55684
  const bothKeys = [...unrecKeys].filter(([, f]) => f.l && f.r).map(([k]) => k);
@@ -56109,7 +56694,7 @@ var recursive = /* @__PURE__ */ new WeakMap;
56109
56694
  var NONE = 0;
56110
56695
  var ASSUMED = 1;
56111
56696
  var PROVEN = 2;
56112
- function isRecursive(inst, stack, resolve4) {
56697
+ function isRecursive(inst, stack, resolve5) {
56113
56698
  const cached2 = recursive.get(inst);
56114
56699
  if (cached2 !== undefined)
56115
56700
  return cached2 ? PROVEN : NONE;
@@ -56119,7 +56704,7 @@ function isRecursive(inst, stack, resolve4) {
56119
56704
  let result = NONE;
56120
56705
  const check = (child) => {
56121
56706
  if (result !== PROVEN && child?._zod) {
56122
- const answer = isRecursive(child, stack, resolve4);
56707
+ const answer = isRecursive(child, stack, resolve5);
56123
56708
  if (answer > result)
56124
56709
  result = answer;
56125
56710
  }
@@ -56130,7 +56715,7 @@ function isRecursive(inst, stack, resolve4) {
56130
56715
  const desc = Object.getOwnPropertyDescriptor(sh, key);
56131
56716
  if (spread && !desc.enumerable)
56132
56717
  continue;
56133
- const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve4) : NONE;
56718
+ const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve5) : NONE;
56134
56719
  if (child > answer)
56135
56720
  answer = child;
56136
56721
  }
@@ -56193,7 +56778,7 @@ function isRecursive(inst, stack, resolve4) {
56193
56778
  check(def.output);
56194
56779
  break;
56195
56780
  case "lazy": {
56196
- const inner = def._cachedInner ?? (resolve4 ? inst._zod.innerType : undefined);
56781
+ const inner = def._cachedInner ?? (resolve5 ? inst._zod.innerType : undefined);
56197
56782
  merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
56198
56783
  break;
56199
56784
  }
@@ -68039,7 +68624,7 @@ var ZodRealError = /* @__PURE__ */ $constructor("ZodError", initializer2, undefi
68039
68624
  // node_modules/zod/v4/classic/parse.js
68040
68625
  var parse3 = /* @__PURE__ */ _parse(ZodRealError);
68041
68626
  var parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
68042
- var safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
68627
+ var safeParse3 = /* @__PURE__ */ _safeParse(ZodRealError);
68043
68628
  var safeParseAsync2 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
68044
68629
  var encode2 = /* @__PURE__ */ _encode(ZodRealError);
68045
68630
  var decode2 = /* @__PURE__ */ _decode(ZodRealError);
@@ -68179,7 +68764,7 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
68179
68764
  return await parseAsync2(this, data, params, { callee: _parseAsync2 });
68180
68765
  },
68181
68766
  safeParse(data, params) {
68182
- return safeParse2(this, data, params);
68767
+ return safeParse3(this, data, params);
68183
68768
  },
68184
68769
  async safeParseAsync(data, params) {
68185
68770
  return safeParseAsync2(this, data, params);
@@ -71043,27 +71628,16 @@ var zCreateElicitationRequest = preserveCustomPayload(intersection(union([
71043
71628
  })
71044
71629
  })), "mode", ["form", "url"]);
71045
71630
  var zMcpServerAcpId = string2();
71046
- var zConnectMcpRequest = object({
71047
- serverId: zMcpServerAcpId,
71048
- _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
71049
- return;
71050
- })
71051
- });
71052
- var zMcpConnectionId = string2();
71631
+ var zMcpRequestId = string2();
71053
71632
  var zMessageMcpRequest = object({
71054
- connectionId: zMcpConnectionId,
71633
+ serverId: zMcpServerAcpId,
71634
+ requestId: zMcpRequestId,
71055
71635
  method: string2(),
71056
71636
  params: record(string2(), unknown()).nullish(),
71057
71637
  _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
71058
71638
  return;
71059
71639
  })
71060
71640
  });
71061
- var zDisconnectMcpRequest = object({
71062
- connectionId: zMcpConnectionId,
71063
- _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
71064
- return;
71065
- })
71066
- });
71067
71641
  var zExtRequest = unknown();
71068
71642
  var zAgentRequest = object({
71069
71643
  id: zRequestId,
@@ -71078,9 +71652,7 @@ var zAgentRequest = object({
71078
71652
  zWaitForTerminalExitRequest,
71079
71653
  zKillTerminalRequest,
71080
71654
  zCreateElicitationRequest,
71081
- zConnectMcpRequest,
71082
71655
  zMessageMcpRequest,
71083
- zDisconnectMcpRequest,
71084
71656
  zExtRequest
71085
71657
  ]).nullish()
71086
71658
  });
@@ -71776,7 +72348,6 @@ var zCloseNesResponse = object({
71776
72348
  })
71777
72349
  });
71778
72350
  var zExtResponse = unknown();
71779
- var zMessageMcpResponse = unknown();
71780
72351
  var zErrorCode = union([
71781
72352
  literal(-32700),
71782
72353
  literal(-32600),
@@ -71822,8 +72393,7 @@ var zAgentResponse = union([
71822
72393
  zStartNesResponse,
71823
72394
  zSuggestNesResponse,
71824
72395
  zCloseNesResponse,
71825
- zExtResponse,
71826
- zMessageMcpResponse
72396
+ zExtResponse
71827
72397
  ])
71828
72398
  }),
71829
72399
  object({
@@ -72041,6 +72611,108 @@ var zCompactionSummaryChunk = object({
72041
72611
  return;
72042
72612
  })
72043
72613
  });
72614
+ var zSessionCancelCapabilities = object({
72615
+ _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
72616
+ return;
72617
+ })
72618
+ });
72619
+ var zSubagentSessionCapabilities = object({
72620
+ cancel: defaultOnError(zSessionCancelCapabilities.nullish(), () => {
72621
+ return;
72622
+ }),
72623
+ _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
72624
+ return;
72625
+ })
72626
+ });
72627
+ var zRunningStateUpdate = object({
72628
+ _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
72629
+ return;
72630
+ })
72631
+ });
72632
+ var zIdleStateUpdate = object({
72633
+ stopReason: defaultOnError(zStopReason.nullish(), () => {
72634
+ return;
72635
+ }),
72636
+ usage: defaultOnError(zUsage.nullish(), () => {
72637
+ return;
72638
+ }),
72639
+ _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
72640
+ return;
72641
+ })
72642
+ });
72643
+ var zRequiresActionStateUpdate = object({
72644
+ _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
72645
+ return;
72646
+ })
72647
+ });
72648
+ var zUnknownStateUpdate = object({
72649
+ _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
72650
+ return;
72651
+ })
72652
+ });
72653
+ var zStateUpdate = preserveCustomPayload(union([
72654
+ zRunningStateUpdate.and(object({
72655
+ state: literal("running")
72656
+ })),
72657
+ zIdleStateUpdate.and(object({
72658
+ state: literal("idle")
72659
+ })),
72660
+ zRequiresActionStateUpdate.and(object({
72661
+ state: literal("requires_action")
72662
+ })),
72663
+ zUnknownStateUpdate.and(object({
72664
+ state: literal("unknown")
72665
+ })),
72666
+ excludeKnownTags(object({
72667
+ state: string2()
72668
+ }), "state", ["idle", "requires_action", "running", "unknown"])
72669
+ ]), "state", ["idle", "requires_action", "running", "unknown"]);
72670
+ var zSubagentUpdate = object({
72671
+ sessionId: zSessionId,
72672
+ title: defaultOnError(string2().nullish(), () => {
72673
+ return;
72674
+ }),
72675
+ description: defaultOnError(string2().nullish(), () => {
72676
+ return;
72677
+ }),
72678
+ capabilities: defaultOnError(zSubagentSessionCapabilities.nullish(), () => {
72679
+ return;
72680
+ }),
72681
+ state: defaultOnError(zStateUpdate.nullish(), () => {
72682
+ return;
72683
+ }),
72684
+ _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
72685
+ return;
72686
+ })
72687
+ });
72688
+ var zSessionMessage = object({
72689
+ messageId: zMessageId,
72690
+ senderSessionId: defaultOnError(zSessionId.nullish(), () => {
72691
+ return;
72692
+ }),
72693
+ recipientSessionId: defaultOnError(zSessionId.nullish(), () => {
72694
+ return;
72695
+ }),
72696
+ content: defaultOnError(vecSkipError(zContentBlock).nullish(), () => {
72697
+ return;
72698
+ }),
72699
+ _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
72700
+ return;
72701
+ })
72702
+ });
72703
+ var zSessionMessageChunk = object({
72704
+ messageId: zMessageId,
72705
+ senderSessionId: defaultOnError(zSessionId.nullish(), () => {
72706
+ return;
72707
+ }),
72708
+ recipientSessionId: defaultOnError(zSessionId.nullish(), () => {
72709
+ return;
72710
+ }),
72711
+ content: zContentBlock,
72712
+ _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
72713
+ return;
72714
+ })
72715
+ });
72044
72716
  var zSessionUpdate = union([
72045
72717
  zContentChunk.and(object({
72046
72718
  sessionUpdate: literal("user_message_chunk")
@@ -72089,6 +72761,15 @@ var zSessionUpdate = union([
72089
72761
  })),
72090
72762
  zCompactionSummaryChunk.and(object({
72091
72763
  sessionUpdate: literal("compaction_summary_chunk")
72764
+ })),
72765
+ zSubagentUpdate.and(object({
72766
+ sessionUpdate: literal("subagent_update")
72767
+ })),
72768
+ zSessionMessage.and(object({
72769
+ sessionUpdate: literal("session_message")
72770
+ })),
72771
+ zSessionMessageChunk.and(object({
72772
+ sessionUpdate: literal("session_message_chunk")
72092
72773
  }))
72093
72774
  ]);
72094
72775
  var zSessionNotification = object({
@@ -72104,23 +72785,12 @@ var zCompleteElicitationNotification = object({
72104
72785
  return;
72105
72786
  })
72106
72787
  });
72107
- var zMessageMcpNotification = object({
72108
- connectionId: zMcpConnectionId,
72109
- method: string2(),
72110
- params: defaultOnError(record(string2(), unknown()).nullish(), () => {
72111
- return;
72112
- }),
72113
- _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
72114
- return;
72115
- })
72116
- });
72117
72788
  var zExtNotification = unknown();
72118
72789
  var zAgentNotification = object({
72119
72790
  method: string2(),
72120
72791
  params: union([
72121
72792
  zSessionNotification,
72122
72793
  zCompleteElicitationNotification,
72123
- zMessageMcpNotification,
72124
72794
  zExtNotification
72125
72795
  ]).nullish()
72126
72796
  });
@@ -72160,6 +72830,11 @@ var zClientSessionCapabilities = object({
72160
72830
  return;
72161
72831
  })
72162
72832
  });
72833
+ var zSubagentCapabilities = object({
72834
+ _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
72835
+ return;
72836
+ })
72837
+ });
72163
72838
  var zPlanCapabilities = object({
72164
72839
  _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
72165
72840
  return;
@@ -72227,6 +72902,9 @@ var zClientCapabilities = object({
72227
72902
  session: defaultOnError(zClientSessionCapabilities.nullish(), () => {
72228
72903
  return;
72229
72904
  }),
72905
+ subagents: defaultOnError(zSubagentCapabilities.nullish(), () => {
72906
+ return;
72907
+ }),
72230
72908
  plan: defaultOnError(zPlanCapabilities.nullish(), () => {
72231
72909
  return;
72232
72910
  }),
@@ -72580,7 +73258,6 @@ var zClientRequest = object({
72580
73258
  zStartNesRequest,
72581
73259
  zSuggestNesRequest,
72582
73260
  zCloseNesRequest,
72583
- zMessageMcpRequest,
72584
73261
  zExtRequest
72585
73262
  ]).nullish()
72586
73263
  });
@@ -72695,17 +73372,29 @@ var zCreateElicitationResponse = preserveCustomPayload(intersection(union([
72695
73372
  return;
72696
73373
  })
72697
73374
  })), "action", ["accept", "cancel", "decline"]);
72698
- var zConnectMcpResponse = object({
72699
- connectionId: zMcpConnectionId,
72700
- _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
72701
- return;
72702
- })
73375
+ var zMcpError = looseObject({
73376
+ code: int().min(-2147483648, {
73377
+ error: "Invalid value: Expected int32 to be >= -2147483648"
73378
+ }).max(2147483647, {
73379
+ error: "Invalid value: Expected int32 to be <= 2147483647"
73380
+ }),
73381
+ message: string2(),
73382
+ data: unknown().optional()
72703
73383
  });
72704
- var zDisconnectMcpResponse = object({
72705
- _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
72706
- return;
73384
+ var zMessageMcpResponse = union([
73385
+ object({
73386
+ result: unknown(),
73387
+ _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
73388
+ return;
73389
+ })
73390
+ }),
73391
+ object({
73392
+ error: zMcpError,
73393
+ _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
73394
+ return;
73395
+ })
72707
73396
  })
72708
- });
73397
+ ]);
72709
73398
  var zClientResponse = union([
72710
73399
  object({
72711
73400
  id: zRequestId,
@@ -72719,8 +73408,6 @@ var zClientResponse = union([
72719
73408
  zWaitForTerminalExitResponse,
72720
73409
  zKillTerminalResponse,
72721
73410
  zCreateElicitationResponse,
72722
- zConnectMcpResponse,
72723
- zDisconnectMcpResponse,
72724
73411
  zMessageMcpResponse,
72725
73412
  zExtResponse
72726
73413
  ])
@@ -72809,6 +73496,15 @@ var zRejectNesNotification = object({
72809
73496
  return;
72810
73497
  })
72811
73498
  });
73499
+ var zMessageMcpNotification = object({
73500
+ serverId: zMcpServerAcpId,
73501
+ requestId: zMcpRequestId,
73502
+ method: string2(),
73503
+ params: record(string2(), unknown()).nullish(),
73504
+ _meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
73505
+ return;
73506
+ })
73507
+ });
72812
73508
  var zClientNotification = object({
72813
73509
  method: string2(),
72814
73510
  params: union([
@@ -73176,11 +73872,11 @@ class Connection {
73176
73872
  prepareRequest(method, params, mapResponse, options = {}) {
73177
73873
  const id = this.nextRequestId++;
73178
73874
  let cancel = () => {};
73179
- const response = new Promise((resolve4, reject) => {
73875
+ const response = new Promise((resolve5, reject) => {
73180
73876
  const pendingResponse = {
73181
73877
  resolve: (value) => {
73182
73878
  try {
73183
- resolve4(mapResponse ? mapResponse(value) : value);
73879
+ resolve5(mapResponse ? mapResponse(value) : value);
73184
73880
  } catch (error62) {
73185
73881
  reject(error62);
73186
73882
  }
@@ -73231,8 +73927,8 @@ class Connection {
73231
73927
  this.stream = stream;
73232
73928
  this.staticHandlers = handlers;
73233
73929
  this.allowBatches = options?.allowBatches ?? true;
73234
- this.closedPromise = new Promise((resolve4) => {
73235
- this.abortController.signal.addEventListener("abort", () => resolve4());
73930
+ this.closedPromise = new Promise((resolve5) => {
73931
+ this.abortController.signal.addEventListener("abort", () => resolve5());
73236
73932
  });
73237
73933
  this.receive();
73238
73934
  }
@@ -73826,6 +74522,10 @@ var zGuardElicitationPropertySchemaInteger = zIntegerPropertySchema.and(object({
73826
74522
  var zGuardElicitationPropertySchemaBoolean = zBooleanPropertySchema.and(object({ type: literal("boolean") }));
73827
74523
  var zGuardElicitationPropertySchemaArray = zMultiSelectPropertySchema.and(object({ type: literal("array") }));
73828
74524
  var zGuardMultiSelectItemsString = zStringMultiSelectItems.and(object({ type: literal("string") }));
74525
+ var zGuardStateUpdateRunning = zRunningStateUpdate.and(object({ state: literal("running") }));
74526
+ var zGuardStateUpdateIdle = zIdleStateUpdate.and(object({ state: literal("idle") }));
74527
+ var zGuardStateUpdateRequiresAction = zRequiresActionStateUpdate.and(object({ state: literal("requires_action") }));
74528
+ var zGuardStateUpdateUnknown = zUnknownStateUpdate.and(object({ state: literal("unknown") }));
73829
74529
  var zGuardCreateElicitationResponseAccept = zElicitationAcceptAction.and(object({ action: literal("accept") }));
73830
74530
  var zGuardCreateElicitationResponseDecline = object({
73831
74531
  action: literal("decline")
@@ -74120,8 +74820,8 @@ class AsyncQueue {
74120
74820
  if (this.failed) {
74121
74821
  return Promise.reject(this.failure);
74122
74822
  }
74123
- return new Promise((resolve4, reject) => {
74124
- this.waiters.push({ resolve: resolve4, reject });
74823
+ return new Promise((resolve5, reject) => {
74824
+ this.waiters.push({ resolve: resolve5, reject });
74125
74825
  });
74126
74826
  }
74127
74827
  }
@@ -74849,7 +75549,7 @@ function classifyBlock2(info) {
74849
75549
  }
74850
75550
 
74851
75551
  // src/device-login.ts
74852
- import { spawn as spawn5 } from "child_process";
75552
+ import { spawn as spawn6 } from "child_process";
74853
75553
  class DeviceLoginError2 extends Error {
74854
75554
  }
74855
75555
  async function runDeviceLogin2(apiUrl) {
@@ -74867,7 +75567,7 @@ async function runDeviceLogin2(apiUrl) {
74867
75567
  `);
74868
75568
  try {
74869
75569
  const [cmd, args] = process.platform === "win32" ? ["cmd", ["/c", "start", "", url2]] : [process.platform === "darwin" ? "open" : "xdg-open", [url2]];
74870
- const child = spawn5(cmd, args, { stdio: "ignore", detached: true });
75570
+ const child = spawn6(cmd, args, { stdio: "ignore", detached: true });
74871
75571
  child.on("error", () => {});
74872
75572
  child.unref();
74873
75573
  } catch {}
@@ -74897,7 +75597,7 @@ async function runDeviceLogin2(apiUrl) {
74897
75597
  }
74898
75598
 
74899
75599
  // src/acp.ts
74900
- var log2 = (...a) => process.stderr.write(`[acp] ${a.join(" ")}
75600
+ var log3 = (...a) => process.stderr.write(`[acp] ${a.join(" ")}
74901
75601
  `);
74902
75602
  var ACP_KIND = { create: "edit", edit: "edit", read: "read", search: "search", shell: "execute" };
74903
75603
  var toolTitle = (info) => {
@@ -74973,7 +75673,7 @@ class TodoforaiAgent {
74973
75673
  }
74974
75674
  this.api = new ApiClient(this.apiUrl, this.apiKey);
74975
75675
  this.ws = ws;
74976
- log2(`ready (${this.apiUrl})`);
75676
+ log3(`ready (${this.apiUrl})`);
74977
75677
  })();
74978
75678
  }
74979
75679
  async requireAuth() {
@@ -75018,7 +75718,7 @@ class TodoforaiAgent {
75018
75718
  const agent2 = await this.resolveAgent(cwd);
75019
75719
  const todoId = randomUUID2();
75020
75720
  this.sessions.set(todoId, { todoId, projectId, agent: agent2 });
75021
- log2(`session ${todoId} agent=${agent2.name} cwd=${cwd}`);
75721
+ log3(`session ${todoId} agent=${agent2.name} cwd=${cwd}`);
75022
75722
  return { sessionId: todoId, modes: await this.modes(agent2) };
75023
75723
  }
75024
75724
  async setSessionMode(p) {
@@ -75029,7 +75729,7 @@ class TodoforaiAgent {
75029
75729
  if (!agent2)
75030
75730
  throw RequestError.invalidParams(`unknown agent ${p.modeId}`);
75031
75731
  s.agent = agent2;
75032
- log2(`session ${s.todoId} agent=${agent2.name}`);
75732
+ log3(`session ${s.todoId} agent=${agent2.name}`);
75033
75733
  this.conn.sessionUpdate({ sessionId: p.sessionId, update: { sessionUpdate: "current_mode_update", currentModeId: agent2.id } });
75034
75734
  return {};
75035
75735
  }
@@ -75039,7 +75739,7 @@ class TodoforaiAgent {
75039
75739
  return;
75040
75740
  s.turn.cancelled = true;
75041
75741
  if (s.turn.started && !await this.ws.sendInterrupt(s.projectId, s.todoId))
75042
- log2("interrupt not delivered (socket down)");
75742
+ log3("interrupt not delivered (socket down)");
75043
75743
  }
75044
75744
  async prompt(p) {
75045
75745
  const s = this.sessions.get(p.sessionId);
@@ -75054,7 +75754,7 @@ ${b.resource.text}
75054
75754
  </file>
75055
75755
  ` : "").join("");
75056
75756
  const sessionId = p.sessionId;
75057
- const update = (u) => this.conn.sessionUpdate({ sessionId, update: u }).catch((e) => log2("update failed", e?.message));
75757
+ const update = (u) => this.conn.sessionUpdate({ sessionId, update: u }).catch((e) => log3("update failed", e?.message));
75058
75758
  const blocks4 = new Map;
75059
75759
  const view = (id) => blocks4.get(id) ?? blocks4.set(id, new BlockView).get(id);
75060
75760
  const announce = (id, b) => {
@@ -75088,9 +75788,9 @@ ${b.resource.text}
75088
75788
  return;
75089
75789
  const ok = choice === "allow_once" || choice === "allow_remember" ? await this.ws.sendBlockApproval(s.todoId, messageId, id, choice, choice === "allow_remember" ? patterns : undefined) : await this.ws.sendBlockDeny(s.todoId, messageId, id);
75090
75790
  if (!ok)
75091
- log2(`approval for ${id} not delivered (socket down)`);
75791
+ log3(`approval for ${id} not delivered (socket down)`);
75092
75792
  } catch (e) {
75093
- log2("permission request failed", e?.message);
75793
+ log3("permission request failed", e?.message);
75094
75794
  }
75095
75795
  };
75096
75796
  const onEvent = (type, payload) => {
@@ -75166,18 +75866,18 @@ ${b.resource.text}
75166
75866
  async function runAcp(apiUrl, apiKey, opts) {
75167
75867
  console.log = (...a) => process.stderr.write(a.map(String).join(" ") + `
75168
75868
  `);
75169
- const eof = new Promise((resolve4) => {
75170
- process.stdin.once("end", resolve4);
75171
- process.stdin.once("close", resolve4);
75172
- process.stdin.once("error", resolve4);
75869
+ const eof = new Promise((resolve5) => {
75870
+ process.stdin.once("end", resolve5);
75871
+ process.stdin.once("close", resolve5);
75872
+ process.stdin.once("error", resolve5);
75173
75873
  });
75174
75874
  const stream = ndJsonStream2(Writable.toWeb(process.stdout), Readable.toWeb(process.stdin));
75175
75875
  let agent2;
75176
75876
  new AgentSideConnection((conn) => agent2 = new TodoforaiAgent(conn, apiUrl, apiKey, opts), stream);
75177
75877
  if (apiKey)
75178
- agent2.connect().catch((e) => log2("connect failed:", e?.message));
75878
+ agent2.connect().catch((e) => log3("connect failed:", e?.message));
75179
75879
  else
75180
- log2("not logged in — waiting for authenticate");
75880
+ log3("not logged in — waiting for authenticate");
75181
75881
  await eof;
75182
75882
  await agent2.close();
75183
75883
  }
@@ -75270,13 +75970,15 @@ function installSignalHandlers() {
75270
75970
  }
75271
75971
 
75272
75972
  // src/index.ts
75973
+ var ownPkg;
75273
75974
  try {
75274
- const pkgPath = path4.resolve(fileURLToPath(import.meta.url), "../../package.json");
75275
- checkForUpdates(JSON.parse(readFileSync3(pkgPath, "utf-8")));
75975
+ ownPkg = JSON.parse(readFileSync5(path4.resolve(fileURLToPath(import.meta.url), "../../package.json"), "utf-8"));
75976
+ if (process.argv[2] !== "update")
75977
+ backgroundUpdate(ownPkg);
75276
75978
  } catch {}
75277
75979
  var aliasTodoId = (alias) => typeof alias === "string" && alias.includes(":") ? alias.slice(0, alias.indexOf(":")) : undefined;
75278
75980
  function formatPathWithTilde(path5) {
75279
- const home = homedir3();
75981
+ const home = homedir5();
75280
75982
  return path5.startsWith(home) ? path5.replace(home, "~") : path5;
75281
75983
  }
75282
75984
  function promptArg(words) {
@@ -75386,6 +76088,10 @@ async function main() {
75386
76088
  console.log(VERSION);
75387
76089
  process.exit(0);
75388
76090
  }
76091
+ if (positionals[0] === "update") {
76092
+ const r = ownPkg ? await selfUpdate(ownPkg) : "unsupported";
76093
+ process.exit(r === "updated" || r === "current" ? 0 : 1);
76094
+ }
75389
76095
  if (positionals[0] === "status" && args.help) {
75390
76096
  printStatusHelp();
75391
76097
  process.exit(0);
@@ -75422,11 +76128,19 @@ async function main() {
75422
76128
  printNotifyHelp();
75423
76129
  process.exit(0);
75424
76130
  }
76131
+ if (positionals[0] === "import" && args.help) {
76132
+ printImportHelp();
76133
+ process.exit(0);
76134
+ }
76135
+ if (positionals[0] === "import" && args["dry-run"]) {
76136
+ await importCommand(null, positionals, args);
76137
+ return;
76138
+ }
75425
76139
  if ((positionals[0] === "list" || positionals[0] === "ls") && args.help) {
75426
76140
  printListTodosHelp();
75427
76141
  process.exit(0);
75428
76142
  }
75429
- if (args.help && !["list", "ls", "agent", "todo", "project", "brand", "device", "inbox", "notify"].includes(positionals[0])) {
76143
+ if (args.help && !["list", "ls", "agent", "todo", "project", "brand", "device", "inbox", "notify", "import"].includes(positionals[0])) {
75430
76144
  printUsage();
75431
76145
  process.exit(0);
75432
76146
  }
@@ -75455,7 +76169,7 @@ async function main() {
75455
76169
  }
75456
76170
  if (args["reset-config"]) {
75457
76171
  const { unlinkSync } = await import("fs");
75458
- if (existsSync2(cfg.path)) {
76172
+ if (existsSync4(cfg.path)) {
75459
76173
  unlinkSync(cfg.path);
75460
76174
  console.log(`Configuration reset: ${formatPathWithTilde(cfg.path)}`);
75461
76175
  } else
@@ -75565,6 +76279,10 @@ async function main() {
75565
76279
  await notifyCommand(api2, positionals, args, scopedProject);
75566
76280
  return;
75567
76281
  }
76282
+ if (positionals[0] === "import") {
76283
+ await importCommand(api2, positionals, args, scopedProject, cfgScope.data.default_agent_settings?.id);
76284
+ return;
76285
+ }
75568
76286
  if (positionals[0] === "delete") {
75569
76287
  const todoId = positionals[1];
75570
76288
  if (!todoId) {
@@ -75678,13 +76396,13 @@ async function main() {
75678
76396
  }
75679
76397
  name = "stdin";
75680
76398
  } else {
75681
- const abs = resolve4(filePath);
75682
- if (!existsSync2(abs)) {
76399
+ const abs = resolve5(filePath);
76400
+ if (!existsSync4(abs)) {
75683
76401
  process.stderr.write(`${RED3}File not found: ${filePath}${RESET2}
75684
76402
  `);
75685
76403
  process.exit(1);
75686
76404
  }
75687
- blob = new Blob([readFileSync3(abs)], { type: getMimeTypeFromFilename(abs) || undefined });
76405
+ blob = new Blob([readFileSync5(abs)], { type: getMimeTypeFromFilename(abs) || undefined });
75688
76406
  name = path4.basename(filePath);
75689
76407
  }
75690
76408
  const res = await api2.showFile(todoId, blob, name, {
@@ -76016,7 +76734,7 @@ Resumed: ${CYAN2}${getFrontendUrl(apiUrl, todoId)}${RESET2}
76016
76734
  const wsReady = ws ? ws.connect() : null;
76017
76735
  const bridgeReady = !args["no-bridge"] && !args["no-watch"] && !args.isolated ? ensureBridgeRunning2(apiUrl, apiKey) : null;
76018
76736
  const isolatedTodoId = args.isolated ? randomUUID3() : undefined;
76019
- const mayfly = isolatedTodoId ? await spawnMayflyBridge(apiUrl, isolatedTodoId, realpathSync2(resolve4(args.path || ".")), { debug: !!args.debug, apiKey }) : null;
76737
+ const mayfly = isolatedTodoId ? await spawnMayflyBridge(apiUrl, isolatedTodoId, realpathSync2(resolve5(args.path || ".")), { debug: !!args.debug, apiKey }) : null;
76020
76738
  if (mayfly) {
76021
76739
  process.stderr.write(`${DIM2}Isolated bridge:${RESET2} ${CYAN2}mayfly-${isolatedTodoId}${RESET2}
76022
76740
  `);
@@ -76048,7 +76766,7 @@ Resumed: ${CYAN2}${getFrontendUrl(apiUrl, todoId)}${RESET2}
76048
76766
  cfgScope.setDefaultAgent(getDisplayName(preMatchedAgent), preMatchedAgent);
76049
76767
  } else {
76050
76768
  const pathArg = args.path || ".";
76051
- const resolved = realpathSync2(resolve4(pathArg));
76769
+ const resolved = realpathSync2(resolve5(pathArg));
76052
76770
  const matches = await api2.listAgentSettings({ workspacePath: resolved });
76053
76771
  if (matches.length > 0) {
76054
76772
  preMatchedAgent = matches[0];
@@ -76121,7 +76839,7 @@ Resumed: ${CYAN2}${getFrontendUrl(apiUrl, todoId)}${RESET2}
76121
76839
  if (args.model)
76122
76840
  agent2 = { ...agent2, model: args.model };
76123
76841
  if (args["raw-sysmsg"]) {
76124
- const sysmsg = readFileSync3(resolve4(args["raw-sysmsg"]), "utf-8");
76842
+ const sysmsg = readFileSync5(resolve5(args["raw-sysmsg"]), "utf-8");
76125
76843
  agent2 = { ...agent2, systemMessage: sysmsg, systemMessageMode: "raw" };
76126
76844
  }
76127
76845
  if (args["allow-all"]) {