@todoforai/cli 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/todoai.js +118 -28
  2. package/package.json +2 -1
package/dist/todoai.js CHANGED
@@ -41805,15 +41805,15 @@ var require_route = __commonJS((exports, module) => {
41805
41805
  };
41806
41806
  }
41807
41807
  function wrapConversion(toModel, graph) {
41808
- const path2 = [graph[toModel].parent, toModel];
41808
+ const path3 = [graph[toModel].parent, toModel];
41809
41809
  let fn = conversions[graph[toModel].parent][toModel];
41810
41810
  let cur = graph[toModel].parent;
41811
41811
  while (graph[cur].parent) {
41812
- path2.unshift(graph[cur].parent);
41812
+ path3.unshift(graph[cur].parent);
41813
41813
  fn = link(conversions[graph[cur].parent][cur], fn);
41814
41814
  cur = graph[cur].parent;
41815
41815
  }
41816
- fn.conversion = path2;
41816
+ fn.conversion = path3;
41817
41817
  return fn;
41818
41818
  }
41819
41819
  module.exports = function(fromModel) {
@@ -42039,7 +42039,7 @@ var require_has_flag = __commonJS((exports, module) => {
42039
42039
 
42040
42040
  // node_modules/supports-color/index.js
42041
42041
  var require_supports_color = __commonJS((exports, module) => {
42042
- var os2 = __require("os");
42042
+ var os3 = __require("os");
42043
42043
  var tty = __require("tty");
42044
42044
  var hasFlag = require_has_flag();
42045
42045
  var { env } = process;
@@ -42087,7 +42087,7 @@ var require_supports_color = __commonJS((exports, module) => {
42087
42087
  return min;
42088
42088
  }
42089
42089
  if (process.platform === "win32") {
42090
- const osRelease = os2.release().split(".");
42090
+ const osRelease = os3.release().split(".");
42091
42091
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
42092
42092
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
42093
42093
  }
@@ -42661,9 +42661,62 @@ var require_dist = __commonJS((exports) => {
42661
42661
  });
42662
42662
 
42663
42663
  // src/index.ts
42664
- import { realpathSync } from "fs";
42664
+ import { realpathSync, readFileSync as readFileSync3 } from "fs";
42665
42665
  import { resolve as resolve3 } from "path";
42666
+ import { fileURLToPath } from "url";
42666
42667
  import { homedir as homedir3 } from "os";
42668
+ import path4 from "path";
42669
+
42670
+ // node_modules/@todoforai/update-notifier/src/index.ts
42671
+ import fs from "fs";
42672
+ import path from "path";
42673
+ import os from "os";
42674
+ function isLinkedInstall() {
42675
+ try {
42676
+ return !fs.realpathSync(process.argv[1] || "").includes(`${path.sep}node_modules${path.sep}`);
42677
+ } catch {
42678
+ return false;
42679
+ }
42680
+ }
42681
+ var TTL_MS = 24 * 60 * 60 * 1000;
42682
+ var CACHE_DIR = path.join(os.homedir(), ".config", "todoforai");
42683
+ function cmpVer(a, b) {
42684
+ const pa = a.split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
42685
+ const pb = b.split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
42686
+ for (let i = 0;i < Math.max(pa.length, pb.length); i++) {
42687
+ const d = (pa[i] ?? 0) - (pb[i] ?? 0);
42688
+ if (d)
42689
+ return d;
42690
+ }
42691
+ return 0;
42692
+ }
42693
+ function checkForUpdates(pkg) {
42694
+ if (!process.stderr.isTTY || process.env.CI || process.env.NO_UPDATE_NOTIFIER || isLinkedInstall())
42695
+ return;
42696
+ const cacheFile = path.join(CACHE_DIR, `notifier-${encodeURIComponent(pkg.name)}.json`);
42697
+ let cache = {};
42698
+ try {
42699
+ cache = JSON.parse(fs.readFileSync(cacheFile, "utf8"));
42700
+ } catch {}
42701
+ if (cache.latest && cmpVer(cache.latest, pkg.version) > 0) {
42702
+ process.stderr.write(`
42703
+ \x1B[33m Update available: \x1B[2m${pkg.version}\x1B[22m \u2192 \x1B[1m${cache.latest}\x1B[0m
42704
+ ` + `\x1B[33m Run:\x1B[0m npm i -g ${pkg.name}
42705
+
42706
+ `);
42707
+ }
42708
+ if (Date.now() - (cache.ts ?? 0) > TTL_MS) {
42709
+ try {
42710
+ fs.mkdirSync(CACHE_DIR, { recursive: true });
42711
+ fs.writeFileSync(cacheFile, JSON.stringify({ ...cache, ts: Date.now() }));
42712
+ } catch {}
42713
+ fetch(`https://registry.npmjs.org/${pkg.name}/latest`, { signal: AbortSignal.timeout(3000) }).then((r) => r.ok ? r.json() : null).then((j) => {
42714
+ if (!j?.version)
42715
+ return;
42716
+ fs.writeFileSync(cacheFile, JSON.stringify({ ts: Date.now(), latest: j.version }));
42717
+ }).catch(() => {});
42718
+ }
42719
+ }
42667
42720
 
42668
42721
  // src/tips.ts
42669
42722
  var TIPS = [
@@ -42830,8 +42883,8 @@ class ApiClient {
42830
42883
  import WebSocket from "ws";
42831
42884
 
42832
42885
  // ../edge/bun/src/config.ts
42833
- import path from "path";
42834
- import os from "os";
42886
+ import path2 from "path";
42887
+ import os2 from "os";
42835
42888
  function normalizeApiUrl(url) {
42836
42889
  if (url.startsWith("localhost"))
42837
42890
  return `http://${url}`;
@@ -42840,7 +42893,18 @@ function normalizeApiUrl(url) {
42840
42893
  return url;
42841
42894
  }
42842
42895
  var SUBCOMMANDS = new Set(["login", "logout"]);
42843
- var CREDENTIALS_PATH = path.join(os.homedir(), ".todoforai", "credentials.json");
42896
+ function credentialsPath() {
42897
+ const sys = os2.platform();
42898
+ if (sys === "win32") {
42899
+ return path2.join(os2.homedir(), "AppData", "Roaming", "todoforai", "credentials.json");
42900
+ }
42901
+ if (sys === "darwin") {
42902
+ return path2.join(os2.homedir(), "Library", "Application Support", "todoforai", "credentials.json");
42903
+ }
42904
+ const xdg = process.env.XDG_CONFIG_HOME || path2.join(os2.homedir(), ".config");
42905
+ return path2.join(xdg, "todoforai", "credentials.json");
42906
+ }
42907
+ var CREDENTIALS_PATH = credentialsPath();
42844
42908
 
42845
42909
  // ../edge/bun/src/frontend-ws.ts
42846
42910
  var log = (level, ...args) => console.log(`[frontend-ws:${level}]`, ...args);
@@ -43051,6 +43115,7 @@ var package_default = {
43051
43115
  postinstall: "rm -rf node_modules/@todoforai/edge && ln -s ../../../edge/bun node_modules/@todoforai/edge"
43052
43116
  },
43053
43117
  dependencies: {
43118
+ "@todoforai/update-notifier": "^0.1.0",
43054
43119
  "cli-highlight": "^2.1.11",
43055
43120
  "diff-match-patch": "^1.0.5",
43056
43121
  ws: "^8.18.0"
@@ -43088,7 +43153,8 @@ Usage:
43088
43153
  todoai --path /my/project "Fix bug" # Explicit workspace path
43089
43154
  todoai -c # Resume last todo
43090
43155
  todoai --resume <todo-id> # Resume specific todo
43091
- todoai --inspect <todo-id> # Print full chat log (read-only)
43156
+ todoai --inspect <todo-id>[:<msg-id>] # Print full chat log (read-only); :<msg-id> truncates inclusive
43157
+ todoai --inspect :<msg-id> # Same, using $TODOFORAI_TODO_ID from edge env
43092
43158
  todoai --template <id> [--input k=v] # Start from a registry template
43093
43159
  todoai --list-agents # List available agents and exit
43094
43160
 
@@ -43099,7 +43165,7 @@ Options:
43099
43165
  --list-agents List available agents (name, id, workspace paths) and exit
43100
43166
  --api-url <url> API URL
43101
43167
  --api-key <key> API key
43102
- --inspect, -i <todo-id> Print full chat log (read-only, no interactive)
43168
+ --inspect, -i [<todo-id>][:<msg-id>] Print full chat log; empty todo-id uses $TODOFORAI_TODO_ID
43103
43169
  --template, -t <id> Start from a registry template
43104
43170
  --input <key=value> Template input (repeatable)
43105
43171
  --resume, -r [todo-id] Resume existing todo
@@ -43770,7 +43836,7 @@ function printLogo() {
43770
43836
  }
43771
43837
 
43772
43838
  // src/inspect.ts
43773
- function printFullChat(todo, frontendUrl) {
43839
+ function printFullChat(todo, frontendUrl, untilMessageId) {
43774
43840
  const statusColors = {
43775
43841
  DONE: GREEN,
43776
43842
  READY: GREEN,
@@ -43794,10 +43860,22 @@ function printFullChat(todo, frontendUrl) {
43794
43860
  `);
43795
43861
  if (todo.agentSettingsId)
43796
43862
  process.stderr.write(`${DIM}Agent:${RESET} ${todo.agentSettingsId}
43863
+ `);
43864
+ if (untilMessageId)
43865
+ process.stderr.write(`${DIM}Until:${RESET} ${untilMessageId}
43797
43866
  `);
43798
43867
  process.stderr.write("\u2500".repeat(60) + `
43799
43868
  `);
43800
- const messages = todo.messages || [];
43869
+ let messages = todo.messages || [];
43870
+ if (untilMessageId) {
43871
+ const idx = messages.findIndex((m) => m.id === untilMessageId);
43872
+ if (idx < 0) {
43873
+ process.stderr.write(`${RED}Error: message ${untilMessageId} not found in todo${RESET}
43874
+ `);
43875
+ process.exit(2);
43876
+ }
43877
+ messages = messages.slice(0, idx + 1);
43878
+ }
43801
43879
  if (!messages.length) {
43802
43880
  process.stderr.write(`${DIM}(no messages)${RESET}
43803
43881
  `);
@@ -44942,9 +45020,9 @@ async function listAgentsCommand(api, opts) {
44942
45020
 
44943
45021
  // src/ensure-edge.ts
44944
45022
  import { spawn, spawnSync } from "child_process";
44945
- import fs from "fs";
44946
- import path2 from "path";
44947
- import os2 from "os";
45023
+ import fs2 from "fs";
45024
+ import path3 from "path";
45025
+ import os3 from "os";
44948
45026
  function hasBunx() {
44949
45027
  const probe = spawnSync(process.platform === "win32" ? "where" : "which", ["bunx"], { stdio: "ignore" });
44950
45028
  return probe.status === 0;
@@ -44954,10 +45032,10 @@ function ensureEdgeRunning(apiUrl, apiKey) {
44954
45032
  console.error("\x1B[2mEdge daemon not started: `bunx` is missing. Install Bun from https://bun.sh to enable it, or pass --no-edge to silence this.\x1B[0m");
44955
45033
  return;
44956
45034
  }
44957
- const logDir = path2.join(os2.homedir(), ".todoforai");
44958
- fs.mkdirSync(logDir, { recursive: true });
44959
- const logFile = path2.join(logDir, "edge.log");
44960
- const out = fs.openSync(logFile, "a");
45035
+ const logDir = path3.join(os3.homedir(), ".todoforai");
45036
+ fs2.mkdirSync(logDir, { recursive: true });
45037
+ const logFile = path3.join(logDir, "edge.log");
45038
+ const out = fs2.openSync(logFile, "a");
44961
45039
  const child = spawn("bunx", ["@todoforai/edge", "--api-url", apiUrl, "--api-key", apiKey], {
44962
45040
  detached: true,
44963
45041
  stdio: ["ignore", out, out]
@@ -44975,7 +45053,7 @@ function ensureEdgeRunning(apiUrl, apiKey) {
44975
45053
  const pid = child.pid;
44976
45054
  if (!pid)
44977
45055
  return;
44978
- const shortLog = logFile.replace(os2.homedir(), "~");
45056
+ const shortLog = logFile.replace(os3.homedir(), "~");
44979
45057
  setTimeout(() => {
44980
45058
  if (!exited) {
44981
45059
  console.error(`\x1B[2mStarted edge daemon (pid ${pid}), logs: ${shortLog}\x1B[0m`);
@@ -44990,9 +45068,13 @@ function ensureEdgeRunning(apiUrl, apiKey) {
44990
45068
  }
44991
45069
 
44992
45070
  // src/index.ts
44993
- function formatPathWithTilde(path3) {
45071
+ try {
45072
+ const pkgPath = path4.resolve(fileURLToPath(import.meta.url), "../../package.json");
45073
+ checkForUpdates(JSON.parse(readFileSync3(pkgPath, "utf-8")));
45074
+ } catch {}
45075
+ function formatPathWithTilde(path5) {
44994
45076
  const home = homedir3();
44995
- return path3.startsWith(home) ? path3.replace(home, "~") : path3;
45077
+ return path5.startsWith(home) ? path5.replace(home, "~") : path5;
44996
45078
  }
44997
45079
  function getFrontendUrl(apiUrl, projectId, todoId) {
44998
45080
  if (apiUrl.includes("localhost:4000") || apiUrl.includes("127.0.0.1:4000")) {
@@ -45104,12 +45186,13 @@ Cancelled by user (Ctrl+C)
45104
45186
  const loginApi = new ApiClient(apiUrl, "");
45105
45187
  const { code, url, expiresIn } = await loginApi.initDeviceLogin("cli");
45106
45188
  const userCode = new URL(url).searchParams.get("user_code") || code.slice(-8).toUpperCase();
45189
+ const formattedCode = userCode.length === 8 ? `${userCode.slice(0, 4)}-${userCode.slice(4)}` : userCode;
45107
45190
  process.stderr.write(`
45108
45191
  \uD83D\uDD11 Open this URL to authorize:
45109
45192
  `);
45110
45193
  process.stderr.write(`${CYAN}${url}${RESET}
45111
45194
  `);
45112
- process.stderr.write(`Verification code: ${BRIGHT_WHITE}${userCode}${RESET}
45195
+ process.stderr.write(`Verification code: ${BRIGHT_WHITE}${formattedCode}${RESET}
45113
45196
 
45114
45197
  `);
45115
45198
  try {
@@ -45154,7 +45237,7 @@ Cancelled by user (Ctrl+C)
45154
45237
  await deviceLogin();
45155
45238
  return;
45156
45239
  }
45157
- let apiKey = args["api-key"] || getEnv("API_KEY") || readCredential(apiUrl) || "";
45240
+ let apiKey = args["api-key"] || getEnv("API_TOKEN") || getEnv("API_KEY") || readCredential(apiUrl) || "";
45158
45241
  if (!apiKey) {
45159
45242
  apiKey = await deviceLogin();
45160
45243
  }
@@ -45163,10 +45246,17 @@ Cancelled by user (Ctrl+C)
45163
45246
  await listAgentsCommand(api, { json: !!args.json, formatPath: formatPathWithTilde });
45164
45247
  return;
45165
45248
  }
45166
- if (args.inspect) {
45167
- const todoId = args.inspect;
45249
+ if (args.inspect !== undefined) {
45250
+ const raw = String(args.inspect);
45251
+ const [rawTodoId, untilMessageId] = raw.includes(":") ? raw.split(":", 2) : [raw, undefined];
45252
+ const todoId = rawTodoId || getEnv("TODO_ID");
45253
+ if (!todoId) {
45254
+ process.stderr.write(`${RED}Error: --inspect requires a todoId (or $TODOFORAI_TODO_ID env var)${RESET}
45255
+ `);
45256
+ process.exit(2);
45257
+ }
45168
45258
  const todo2 = await api.getTodo(todoId);
45169
- printFullChat(todo2, getFrontendUrl(apiUrl, todo2.projectId, todoId));
45259
+ printFullChat(todo2, getFrontendUrl(apiUrl, todo2.projectId, todoId), untilMessageId || undefined);
45170
45260
  return;
45171
45261
  }
45172
45262
  if (process.stderr.isTTY)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@todoforai/cli",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "todoai": "dist/todoai.js"
@@ -15,6 +15,7 @@
15
15
  "dev": "bun run src/index.ts"
16
16
  },
17
17
  "dependencies": {
18
+ "@todoforai/update-notifier": "^0.1.0",
18
19
  "cli-highlight": "^2.1.11",
19
20
  "diff-match-patch": "^1.0.5",
20
21
  "ws": "^8.18.0"