@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.
- package/dist/todoai.js +118 -28
- 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
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
42834
|
-
import
|
|
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
|
-
|
|
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>
|
|
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>
|
|
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
|
-
|
|
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
|
|
44946
|
-
import
|
|
44947
|
-
import
|
|
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 =
|
|
44958
|
-
|
|
44959
|
-
const logFile =
|
|
44960
|
-
const out =
|
|
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(
|
|
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
|
-
|
|
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
|
|
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}${
|
|
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
|
|
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.
|
|
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"
|