@todoforai/cli 0.1.61 → 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.
- package/README.md +25 -31
- package/dist/todoforai-cli.js +1087 -208
- package/package.json +8 -2
package/dist/todoforai-cli.js
CHANGED
|
@@ -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
|
|
42679
|
-
import { resolve as
|
|
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
|
|
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
|
-
|
|
42688
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
42689
|
+
function installer() {
|
|
42690
|
+
let real;
|
|
42689
42691
|
try {
|
|
42690
|
-
|
|
42692
|
+
real = fs.realpathSync(process.argv[1] || "");
|
|
42691
42693
|
} catch {
|
|
42692
|
-
return
|
|
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 ||
|
|
42736
|
+
if (!process.stderr.isTTY || process.env.CI || process.env.NO_UPDATE_NOTIFIER || !installer())
|
|
42709
42737
|
return;
|
|
42710
|
-
|
|
42711
|
-
|
|
42712
|
-
|
|
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,17 +42745,67 @@ function checkForUpdates(pkg) {
|
|
|
42719
42745
|
|
|
42720
42746
|
`);
|
|
42721
42747
|
}
|
|
42722
|
-
|
|
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
|
-
|
|
42725
|
-
|
|
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
|
-
|
|
42728
|
-
|
|
42729
|
-
return;
|
|
42730
|
-
fs.writeFileSync(cacheFile, JSON.stringify({ ts: Date.now(), latest: j.version }));
|
|
42731
|
-
}).catch(() => {});
|
|
42764
|
+
refreshCache(pkg.name, next);
|
|
42765
|
+
return;
|
|
42732
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;
|
|
42791
|
+
}
|
|
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);
|
|
42733
42809
|
}
|
|
42734
42810
|
|
|
42735
42811
|
// src/tips.ts
|
|
@@ -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)
|
|
@@ -43055,6 +43134,19 @@ class ApiClient {
|
|
|
43055
43134
|
throw new Error(`API GET /resources/show failed: ${res.status} ${await res.text()}`);
|
|
43056
43135
|
return res.json();
|
|
43057
43136
|
}
|
|
43137
|
+
async shareShow(todoId, key) {
|
|
43138
|
+
const url = `${this.apiUrl}${restBasePath(this.apiKey)}/resources/show/${encodeURIComponent(todoId)}/${encodeURIComponent(key)}/share`;
|
|
43139
|
+
const res = await fetch(url, { method: "POST", headers: { "x-api-key": this.apiKey }, signal: AbortSignal.timeout(30000) });
|
|
43140
|
+
if (!res.ok)
|
|
43141
|
+
throw new Error(`API POST /resources/show/share failed: ${res.status} ${await res.text()}`);
|
|
43142
|
+
return res.json();
|
|
43143
|
+
}
|
|
43144
|
+
async unshareShow(todoId, key) {
|
|
43145
|
+
const url = `${this.apiUrl}${restBasePath(this.apiKey)}/resources/show/${encodeURIComponent(todoId)}/${encodeURIComponent(key)}/share`;
|
|
43146
|
+
const res = await fetch(url, { method: "DELETE", headers: { "x-api-key": this.apiKey }, signal: AbortSignal.timeout(30000) });
|
|
43147
|
+
if (!res.ok)
|
|
43148
|
+
throw new Error(`API DELETE /resources/show/share failed: ${res.status} ${await res.text()}`);
|
|
43149
|
+
}
|
|
43058
43150
|
async removeShow(todoId, key) {
|
|
43059
43151
|
const url = `${this.apiUrl}${restBasePath(this.apiKey)}/resources/show/${encodeURIComponent(todoId)}/${encodeURIComponent(key)}`;
|
|
43060
43152
|
const res = await fetch(url, {
|
|
@@ -43232,7 +43324,7 @@ function writeCredential(apiUrl, apiKey) {
|
|
|
43232
43324
|
}
|
|
43233
43325
|
|
|
43234
43326
|
// ../packages/shared-api/src/frontend-ws.ts
|
|
43235
|
-
var
|
|
43327
|
+
var log2 = (level, ...args) => console.log(`[frontend-ws:${level}]`, ...args);
|
|
43236
43328
|
|
|
43237
43329
|
class FrontendWebSocket {
|
|
43238
43330
|
apiUrl;
|
|
@@ -43314,7 +43406,7 @@ class FrontendWebSocket {
|
|
|
43314
43406
|
resolve(false);
|
|
43315
43407
|
});
|
|
43316
43408
|
sock.on("error", (err) => {
|
|
43317
|
-
|
|
43409
|
+
log2("error", "WS error:", err.message);
|
|
43318
43410
|
if (current())
|
|
43319
43411
|
this.connected = false;
|
|
43320
43412
|
resolve(false);
|
|
@@ -43597,6 +43689,11 @@ function qualifiedModelIds(listing, filter) {
|
|
|
43597
43689
|
return q ? ids.filter((id) => id.toLowerCase().includes(q)) : ids;
|
|
43598
43690
|
}
|
|
43599
43691
|
// ../packages/shared-fbe/src/billing.ts
|
|
43692
|
+
var HOBBY_ALLOWED = new Set([
|
|
43693
|
+
"anthropic/claude-sonnet-5.5",
|
|
43694
|
+
"anthropic/claude-sonnet-5",
|
|
43695
|
+
"anthropic/claude-haiku-4.5"
|
|
43696
|
+
]);
|
|
43600
43697
|
var USAGE_WINDOWS = {
|
|
43601
43698
|
SESSION_MS: 5 * 60 * 60 * 1000,
|
|
43602
43699
|
WEEK_MS: 7 * 24 * 60 * 60 * 1000,
|
|
@@ -43746,6 +43843,75 @@ var NON_SHELL_TYPES = new Set([
|
|
|
43746
43843
|
"IOS" /* IOS */
|
|
43747
43844
|
]);
|
|
43748
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));
|
|
43749
43915
|
var USER_INPUT_BLOCK_TYPES = new Set([
|
|
43750
43916
|
"question" /* Question */,
|
|
43751
43917
|
"login_prompt" /* Login */,
|
|
@@ -43901,6 +44067,15 @@ function manualAnswersOf(sources) {
|
|
|
43901
44067
|
}
|
|
43902
44068
|
var manualSamples = (answers) => Object.entries(answers).filter(([, a]) => a.trim()).map(([prompt, text]) => ({ prompt, text: text.trim() }));
|
|
43903
44069
|
var senderLabel = (s) => s.kind === "team" ? `${s.name} · TODO for AI team` : s.kind === "member" ? `${s.name} · teammate` : `${s.name} · your agent`;
|
|
44070
|
+
// ../packages/shared-fbe/src/jarvisEvents.ts
|
|
44071
|
+
var STATE = {
|
|
44072
|
+
["READY" /* READY */]: "agent ended its run and handed back; not opened yet",
|
|
44073
|
+
["READY_CHECKED" /* READY_CHECKED */]: "agent ended its run and handed back; its window was opened",
|
|
44074
|
+
["DONE" /* DONE */]: "done and closed",
|
|
44075
|
+
["ERROR" /* ERROR */]: "failed; not opened yet",
|
|
44076
|
+
["ERROR_CHECKED" /* ERROR_CHECKED */]: "failed; its window was opened",
|
|
44077
|
+
["WAITING_FOR_USER" /* WAITING_FOR_USER */]: "blocked, waiting on the user's answer or approval"
|
|
44078
|
+
};
|
|
43904
44079
|
// ../packages/shared-fbe/src/templateBody.ts
|
|
43905
44080
|
var USER_HEADINGS = new Set([
|
|
43906
44081
|
"your task",
|
|
@@ -44418,7 +44593,7 @@ var tool_catalog_default = {
|
|
|
44418
44593
|
installer: "npm",
|
|
44419
44594
|
label: "Gmail",
|
|
44420
44595
|
summary: "Read and send Gmail from your own account.",
|
|
44421
|
-
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 .",
|
|
44422
44597
|
loginNeedsPty: true,
|
|
44423
44598
|
loginCmd: "zele login --method google",
|
|
44424
44599
|
oauthUrlPattern: "(https://accounts\\.google\\.com\\S+)",
|
|
@@ -44437,7 +44612,7 @@ var tool_catalog_default = {
|
|
|
44437
44612
|
binName: "zele",
|
|
44438
44613
|
label: "Google Calendar",
|
|
44439
44614
|
summary: "See your Google Calendar and book, move or cancel events.",
|
|
44440
|
-
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 .",
|
|
44441
44616
|
loginNeedsPty: true,
|
|
44442
44617
|
loginCmd: "zele login --method google",
|
|
44443
44618
|
oauthUrlPattern: "(https://accounts\\.google\\.com\\S+)",
|
|
@@ -44478,6 +44653,7 @@ var tool_catalog_default = {
|
|
|
44478
44653
|
versionCmd: "linkedin-api --version 2>/dev/null | sed -n 1p"
|
|
44479
44654
|
},
|
|
44480
44655
|
"figma-api": {
|
|
44656
|
+
preinstallCloud: true,
|
|
44481
44657
|
category: "design",
|
|
44482
44658
|
pkg: "@todoforai/figma-api",
|
|
44483
44659
|
installer: "npm",
|
|
@@ -44612,6 +44788,20 @@ var tool_catalog_default = {
|
|
|
44612
44788
|
],
|
|
44613
44789
|
description: "AI music generation, custom lyrics, multiple genres."
|
|
44614
44790
|
},
|
|
44791
|
+
"tfa-suno": {
|
|
44792
|
+
preinstallCloud: true,
|
|
44793
|
+
category: "media",
|
|
44794
|
+
pkg: "@todoforai/suno-api",
|
|
44795
|
+
installer: "npm",
|
|
44796
|
+
label: "Suno (TODOforAI)",
|
|
44797
|
+
summary: "Generate music and songs from a prompt, billed to your TODOforAI credit.",
|
|
44798
|
+
platformAuth: true,
|
|
44799
|
+
versionCmd: "tfa-suno --version 2>/dev/null | sed -n 1p",
|
|
44800
|
+
credentialPaths: [
|
|
44801
|
+
"~/.config/todoforai/credentials.json"
|
|
44802
|
+
],
|
|
44803
|
+
description: "Suno music generation via TODOforAI — no Suno key needed, billed to the user's TODOforAI credit (generate $0.12 for 2 songs, refunded if the task fails). Same commands as suno-api: `generate [prompt] [--customMode --lyrics <file> --style --title] [--instrumental] [--model V6]` polls until done and prints audio URLs; `--no-poll` + `details <taskId> [--wait]`; `stems`, `midi`, `lyrics-ts`, `replace-section`. Audio URLs expire after 14 days — download the mp3s you keep. Prefer this over suno-api unless the user has their own sunoapi.org key."
|
|
44804
|
+
},
|
|
44615
44805
|
ntn: {
|
|
44616
44806
|
preinstallCloud: true,
|
|
44617
44807
|
category: "utility",
|
|
@@ -44648,7 +44838,7 @@ var tool_catalog_default = {
|
|
|
44648
44838
|
preinstallCloud: true,
|
|
44649
44839
|
label: "GitHub",
|
|
44650
44840
|
summary: "Work with your GitHub repos, pull requests and issues.",
|
|
44651
|
-
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 .",
|
|
44652
44842
|
loginCmd: "gh auth login --hostname github.com --git-protocol https",
|
|
44653
44843
|
oauthUrlPattern: "(https://github\\.com/login/device\\S*)",
|
|
44654
44844
|
deviceCodePattern: "one-time code:\\s*([A-Z0-9]{4}-[A-Z0-9]{4})",
|
|
@@ -44665,19 +44855,22 @@ var tool_catalog_default = {
|
|
|
44665
44855
|
installer: "npm",
|
|
44666
44856
|
label: "MCP (mcporter)",
|
|
44667
44857
|
summary: "Use tools from any MCP server.",
|
|
44668
|
-
statusCmd:
|
|
44669
|
-
description: "MCP servers as CLI: `mcporter list
|
|
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>`.",
|
|
44670
44860
|
versionCmd: "mcporter --version 2>/dev/null | sed -n 1p",
|
|
44671
44861
|
preinstallJarvis: true,
|
|
44672
44862
|
preinstallCloud: true
|
|
44673
44863
|
},
|
|
44674
44864
|
glab: {
|
|
44865
|
+
preinstallCloud: true,
|
|
44866
|
+
cloudInstallCmd: "curl -fsSL https://gitlab.com/gitlab-org/cli/-/releases/v1.119.0/downloads/glab_1.119.0_linux_amd64.tar.gz | tar -xz -C /tmp bin/glab && install -m0755 /tmp/bin/glab /usr/local/bin/glab",
|
|
44867
|
+
cloudVerifyCmd: "glab --version",
|
|
44675
44868
|
category: "development",
|
|
44676
44869
|
pkg: "glab",
|
|
44677
44870
|
installer: "binary",
|
|
44678
44871
|
label: "GitLab",
|
|
44679
44872
|
summary: "Work with your GitLab repos, merge requests and pipelines.",
|
|
44680
|
-
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 .",
|
|
44681
44874
|
loginCmd: "glab auth login --device",
|
|
44682
44875
|
credentialPaths: ["~/.config/glab-cli/config.yml"],
|
|
44683
44876
|
description: "GitLab equivalent of `gh`.",
|
|
@@ -44703,6 +44896,7 @@ var tool_catalog_default = {
|
|
|
44703
44896
|
canStreamLogin: true
|
|
44704
44897
|
},
|
|
44705
44898
|
eas: {
|
|
44899
|
+
preinstallCloud: true,
|
|
44706
44900
|
category: "deployment",
|
|
44707
44901
|
pkg: "eas-cli",
|
|
44708
44902
|
installer: "npm",
|
|
@@ -44718,6 +44912,7 @@ var tool_catalog_default = {
|
|
|
44718
44912
|
versionCmd: "eas --version 2>/dev/null | sed -n 1p"
|
|
44719
44913
|
},
|
|
44720
44914
|
netlify: {
|
|
44915
|
+
preinstallCloud: true,
|
|
44721
44916
|
category: "deployment",
|
|
44722
44917
|
pkg: "netlify-cli",
|
|
44723
44918
|
installer: "npm",
|
|
@@ -44738,7 +44933,7 @@ var tool_catalog_default = {
|
|
|
44738
44933
|
installer: "npm",
|
|
44739
44934
|
label: "Firebase",
|
|
44740
44935
|
summary: "Deploy and manage Firebase hosting, database and functions.",
|
|
44741
|
-
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 .",
|
|
44742
44937
|
loginCmd: "firebase login --no-localhost --reauth",
|
|
44743
44938
|
loginNeedsPty: true,
|
|
44744
44939
|
stdinPaste: true,
|
|
@@ -44778,11 +44973,12 @@ var tool_catalog_default = {
|
|
|
44778
44973
|
credentialPaths: ["~/.config/stripe/config.toml"],
|
|
44779
44974
|
description: "`stripe listen` forwards webhooks locally; `stripe get/post /v1/...` for raw API.",
|
|
44780
44975
|
versionCmd: "stripe --version 2>/dev/null | sed -n 1p",
|
|
44781
|
-
|
|
44782
|
-
oauthUrlPattern: "(https://access\\.stripe\\.com/stripecli/\\S+)",
|
|
44783
|
-
canStreamLogin: true
|
|
44976
|
+
oauthUrlPattern: "(https://dashboard\\.stripe\\.com/stripecli/confirm_auth\\S+)"
|
|
44784
44977
|
},
|
|
44785
44978
|
flyctl: {
|
|
44979
|
+
preinstallCloud: true,
|
|
44980
|
+
cloudInstallCmd: "curl -fsSL https://github.com/superfly/flyctl/releases/download/v0.4.108/flyctl_0.4.108_Linux_x86_64.tar.gz | tar -xz -C /usr/local/bin flyctl",
|
|
44981
|
+
cloudVerifyCmd: "flyctl version",
|
|
44786
44982
|
category: "cloud",
|
|
44787
44983
|
pkg: "flyctl",
|
|
44788
44984
|
installer: "binary",
|
|
@@ -44810,6 +45006,7 @@ var tool_catalog_default = {
|
|
|
44810
45006
|
versionCmd: "supabase --version 2>/dev/null | sed -n 1p"
|
|
44811
45007
|
},
|
|
44812
45008
|
railway: {
|
|
45009
|
+
preinstallCloud: true,
|
|
44813
45010
|
category: "cloud",
|
|
44814
45011
|
pkg: "@railway/cli",
|
|
44815
45012
|
installer: "npm",
|
|
@@ -44851,6 +45048,7 @@ var tool_catalog_default = {
|
|
|
44851
45048
|
versionCmd: "shop-app --version 2>/dev/null | sed -n 1p"
|
|
44852
45049
|
},
|
|
44853
45050
|
"datadog-ci": {
|
|
45051
|
+
preinstallCloud: true,
|
|
44854
45052
|
category: "monitoring",
|
|
44855
45053
|
pkg: "@datadog/datadog-ci",
|
|
44856
45054
|
installer: "npm",
|
|
@@ -44879,7 +45077,7 @@ var tool_catalog_default = {
|
|
|
44879
45077
|
installer: "npm",
|
|
44880
45078
|
label: "TODOforAI",
|
|
44881
45079
|
summary: "Create and follow up on your TODOs, and show results in the chat.",
|
|
44882
|
-
description: 'Manage the user\'s OWN TODOforAI tasks (not code `// TODO` comments). Delegate/spin off work: `tfa-cli "prompt"` creates a real TODO with its own agent and chat (`-n` wait for completion, `--no-watch` fire-and-forget, `--project/--agent/--model`, `--resume <id>`, `addmessage <id> "text"`). Inspect: `list [--status open]`, `--inspect <id>`. Edit any todo without opening it: `status <id> DONE|READY|ARCHIVED|POSTPONED|CANCELLED|DELETED` (close, reopen, shelve, trash — `todo restore <id>` undoes a delete) and `todo set <id|-> title=… group=… star=true schedule=<unix-ms> agent=… brand=…` (own todo fields). Both take ONE id, so a loop over `list --json | jq -r \'.items[].id\'` is how you close, retitle, refile or archive MANY todos at once; `project set|settings|groups …` (name, settings, todo groups), `agent create|update <agent> model=… sysmsg=…` (permissions/MCP/device wiring and delete are refused from an agent shell). Surface results into chat: `show <file|-> [todo-id]` (renders by mimetype; `--card <name>` via project renderer; `--alias <name>` updates in place), `open <url>` embeds a live preview. Notifications: `inbox [needs-you|messages|activity] [--unread]` reads the user\'s bell feed (what finished/failed/needs them while away), `inbox seen [tab]` marks it read; `notify "Title" "message" [--href /t/<id>]` leaves a note in the user\'s Messages tab + phone push (shown as from you); `--to <email>` reaches a member of the current project instead (`project members` lists them, 20/day) — nobody else; same text is delivered once, max 10/day to the user, use for things they must see later (not chat replies). This is the ONLY way to display a local file (image, pdf, html) in the chat: markdown `` with a local/relative path does NOT resolve to workspace files or attachments and 404s in the browser. `--template` for registry workflows.',
|
|
45080
|
+
description: 'Manage the user\'s OWN TODOforAI tasks (not code `// TODO` comments). Delegate/spin off work: `tfa-cli "prompt"` creates a real TODO with its own agent and chat (`-n` wait for completion, `--no-watch` fire-and-forget, `--project/--agent/--model`, `--resume <id>`, `addmessage <id> "text"`). Inspect: `list [--status open]`, `--inspect <id>`. Edit any todo without opening it: `status <id> DONE|READY|ARCHIVED|POSTPONED|CANCELLED|DELETED` (close, reopen, shelve, trash — `todo restore <id>` undoes a delete) and `todo set <id|-> title=… group=… star=true schedule=<unix-ms> agent=… brand=…` (own todo fields). Both take ONE id, so a loop over `list --json | jq -r \'.items[].id\'` is how you close, retitle, refile or archive MANY todos at once; `project set|settings|groups …` (name, settings, todo groups), `agent create|update <agent> model=… sysmsg=…` (permissions/MCP/device wiring and delete are refused from an agent shell). Surface results into chat: `show <file|-> [todo-id]` (renders by mimetype, private to the todo\'s readers; `--card <name>` via project renderer; `--alias <name>` updates in place, `--alias <todoId>:<name>` updates another todo\'s artifact; `show share <ref>` makes it public and prints the link, `show unshare <ref>` makes it private again), `open <url>` embeds a live preview. Pick by where the output lives: read once → plain reply; interactive, this chat only → `html_snippet`; kept/revised later → `show --alias`, then `show share` only if someone outside needs a link; format the user asked for (pptx, docx…) → `show` the file. Notifications: `inbox [needs-you|messages|activity] [--unread]` reads the user\'s bell feed (what finished/failed/needs them while away), `inbox seen [tab]` marks it read; `notify "Title" "message" [--href /t/<id>]` leaves a note in the user\'s Messages tab + phone push (shown as from you); `--to <email>` reaches a member of the current project instead (`project members` lists them, 20/day) — nobody else; same text is delivered once, max 10/day to the user, use for things they must see later (not chat replies). This is the ONLY way to display a local file (image, pdf, html) in the chat: markdown `` with a local/relative path does NOT resolve to workspace files or attachments and 404s in the browser. `--template` for registry workflows.',
|
|
44883
45081
|
installCmd: "npm install -g @todoforai/cli",
|
|
44884
45082
|
versionCmd: "tfa-cli --version 2>/dev/null | sed -n 1p",
|
|
44885
45083
|
preinstallCloud: true,
|
|
@@ -45006,7 +45204,7 @@ var tool_catalog_default = {
|
|
|
45006
45204
|
label: "Google Cloud",
|
|
45007
45205
|
summary: "Manage your Google Cloud projects and services.",
|
|
45008
45206
|
needsPython: true,
|
|
45009
|
-
installCmd: `curl -fsSL https://dl.google.com/dl/cloudsdk/channels/rapid/google-cloud-
|
|
45207
|
+
installCmd: `case "$(uname -s)-$(uname -m)" in Darwin-arm64) p=darwin-arm;; Darwin-*) p=darwin-x86_64;; Linux-aarch64|Linux-arm64) p=linux-arm;; *) p=linux-x86_64;; esac && tmp="$HOME/.gcloud-new.$$" && rm -rf "$tmp" && mkdir -p "$tmp" && curl -fsSL "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-$p.tar.gz" | tar -xzC "$tmp" && rm -rf "$HOME/google-cloud-sdk" && mv "$tmp/google-cloud-sdk" "$HOME/google-cloud-sdk" && rm -rf "$tmp" && mkdir -p "$HOME/.todoforai/tools/bin" && rm -f "$HOME/.todoforai/tools/bin/gcloud" && printf '#!/bin/sh\\nCLOUDSDK_PYTHON="\${CLOUDSDK_PYTHON:-%s}" exec "$HOME/google-cloud-sdk/bin/gcloud" "$@"\\n' "$py" > "$HOME/.todoforai/tools/bin/gcloud" && chmod +x "$HOME/.todoforai/tools/bin/gcloud"`,
|
|
45010
45208
|
statusCmd: `gcloud auth list --filter=status:ACTIVE --format="value(account)" 2>/dev/null | tr -d '\\r' | grep -m1 .`,
|
|
45011
45209
|
loginCmd: "gcloud auth login --no-launch-browser",
|
|
45012
45210
|
loginNeedsPty: true,
|
|
@@ -45015,8 +45213,7 @@ var tool_catalog_default = {
|
|
|
45015
45213
|
credentialPaths: ["~/.config/gcloud"],
|
|
45016
45214
|
description: "Official Google Cloud CLI. `gcloud auth login --no-launch-browser` prints the OAuth URL and waits for the pasted verification code.",
|
|
45017
45215
|
versionCmd: "gcloud --version 2>/dev/null | sed -n 1p",
|
|
45018
|
-
uninstallCmd: 'rm -rf "$HOME/google-cloud-sdk" "$HOME/.todoforai/tools/bin/gcloud"; hash -r 2>/dev/null; ! command -v gcloud >/dev/null 2>&1 || { echo "gcloud is still on PATH: $(command -v gcloud)"; exit 1; }'
|
|
45019
|
-
updateCmd: "gcloud components update --quiet"
|
|
45216
|
+
uninstallCmd: 'rm -rf "$HOME/google-cloud-sdk" "$HOME/.todoforai/tools/bin/gcloud"; hash -r 2>/dev/null; ! command -v gcloud >/dev/null 2>&1 || { echo "gcloud is still on PATH: $(command -v gcloud)"; exit 1; }'
|
|
45020
45217
|
},
|
|
45021
45218
|
az: {
|
|
45022
45219
|
category: "cloud",
|
|
@@ -45150,19 +45347,6 @@ var tool_catalog_default = {
|
|
|
45150
45347
|
},
|
|
45151
45348
|
preinstallJarvis: true
|
|
45152
45349
|
},
|
|
45153
|
-
"todoforai-browser": {
|
|
45154
|
-
category: "development",
|
|
45155
|
-
pkg: "@todoforai/browser",
|
|
45156
|
-
aliases: ["tfa-browser"],
|
|
45157
|
-
installer: "npm",
|
|
45158
|
-
preinstallCloud: true,
|
|
45159
|
-
label: "Browser (Extension)",
|
|
45160
|
-
summary: "Drive your own browser through the TODOforAI extension.",
|
|
45161
|
-
versionCmd: `node -p "require(require('fs').realpathSync(require('child_process').execSync('command -v todoforai-browser',{encoding:'utf8'}).trim()).replace(/\\/dist\\/index\\.js$/, '/package.json')).version" 2>/dev/null`,
|
|
45162
|
-
internal: true,
|
|
45163
|
-
preinstallJarvis: true,
|
|
45164
|
-
description: "Browser automation via extension (non-headless), web scraping, accessibility tree snapshots, screenshots, PDF generation"
|
|
45165
|
-
},
|
|
45166
45350
|
"tfa-explore": {
|
|
45167
45351
|
preinstallCloud: true,
|
|
45168
45352
|
category: "development",
|
|
@@ -45633,6 +45817,21 @@ var tool_catalog_default = {
|
|
|
45633
45817
|
description: "WordPress REST API CLI. `wordpress-api auth --site https://example.com --user <user> --password '<application password>'` (application password, not the login password). Reading published content needs no auth. `posts list|get|create|update|delete`, `pages`, `media`, `categories`. `posts create` saves a draft unless --status publish. On Elementor/JetEngine sites content.rendered comes back empty — fetch the post's public URL for the body.",
|
|
45634
45818
|
versionCmd: "wordpress-api --version 2>/dev/null | sed -n 1p"
|
|
45635
45819
|
},
|
|
45820
|
+
"mailchimp-api": {
|
|
45821
|
+
category: "marketing",
|
|
45822
|
+
pkg: "@todoforai/mailchimp-api",
|
|
45823
|
+
installer: "npm",
|
|
45824
|
+
label: "Mailchimp",
|
|
45825
|
+
summary: "Manage Mailchimp audiences, contacts, email campaigns and reports.",
|
|
45826
|
+
loginCmd: "mailchimp-api auth --api-key <api_key>",
|
|
45827
|
+
oauthBroker: true,
|
|
45828
|
+
statusCmd: `mailchimp-api whoami 2>/dev/null | sed -n 's/.*"account_name"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' | grep -m1 .`,
|
|
45829
|
+
credentialPaths: [
|
|
45830
|
+
"~/.config/mailchimp-api/credentials.json"
|
|
45831
|
+
],
|
|
45832
|
+
versionCmd: "mailchimp-api --version 2>/dev/null | sed -n 1p",
|
|
45833
|
+
description: "Independent CLI over the official Mailchimp Marketing API: 155 endpoint commands for lists (email audiences), members (contacts; email or MD5), tags, segments, merge fields, interests, notes/events, campaigns/content/tests/scheduling, templates, reports, assets, landing pages, classic automations, journey triggers, webhooks and batches. JSON output; --data JSON|@file|-; --schema; --all pagination. Every write requires --yes; use --dry-run first. Raw request METHOD /path covers other Marketing endpoints. API-key auth, not OAuth onboarding. Plan/API restrictions apply; no Transactional/Mandrill or Open Commerce. Run --help for limits and consent cautions."
|
|
45834
|
+
},
|
|
45636
45835
|
"facebook-pages-api": {
|
|
45637
45836
|
preinstallCloud: true,
|
|
45638
45837
|
category: "social",
|
|
@@ -45647,8 +45846,10 @@ var tool_catalog_default = {
|
|
|
45647
45846
|
versionCmd: "facebook-pages-api --version 2>/dev/null | sed -n 1p"
|
|
45648
45847
|
},
|
|
45649
45848
|
"ews-api": {
|
|
45849
|
+
preinstallCloud: true,
|
|
45650
45850
|
category: "email",
|
|
45651
45851
|
pkg: "ews-api",
|
|
45852
|
+
packages: ["ews-api==0.2.0"],
|
|
45652
45853
|
installer: "pip",
|
|
45653
45854
|
label: "Exchange (EWS)",
|
|
45654
45855
|
summary: "Read and write mail on a company Exchange server.",
|
|
@@ -45676,6 +45877,7 @@ var tool_catalog_default = {
|
|
|
45676
45877
|
canStreamLogin: true
|
|
45677
45878
|
},
|
|
45678
45879
|
neonctl: {
|
|
45880
|
+
preinstallCloud: true,
|
|
45679
45881
|
category: "database",
|
|
45680
45882
|
pkg: "neonctl",
|
|
45681
45883
|
installer: "npm",
|
|
@@ -45698,7 +45900,7 @@ var tool_catalog_default = {
|
|
|
45698
45900
|
label: "Microsoft 365",
|
|
45699
45901
|
summary: "Work with Microsoft 365 mail, Teams, SharePoint and users.",
|
|
45700
45902
|
statusCmd: `m365 status --output text 2>/dev/null | tr -d '"' | grep -vi 'logged out' | grep -m1 .`,
|
|
45701
|
-
loginCmd: "m365 login --authType deviceCode --appId
|
|
45903
|
+
loginCmd: "m365 login --authType deviceCode --appId 14d82eec-204b-4c2f-b7e8-296a70dab67e",
|
|
45702
45904
|
deviceCodePattern: "enter the code ([A-Z0-9]{8,}) to authenticate",
|
|
45703
45905
|
oauthUrlPattern: "open the page (https://\\S+) and enter",
|
|
45704
45906
|
credentialPaths: ["~/.cli-m365-msal.json", "~/.cli-m365-connection.json"],
|
|
@@ -45737,6 +45939,7 @@ var tool_catalog_default = {
|
|
|
45737
45939
|
versionCmd: "posthog-cli --version 2>/dev/null | sed -n 1p"
|
|
45738
45940
|
},
|
|
45739
45941
|
canva: {
|
|
45942
|
+
preinstallCloud: true,
|
|
45740
45943
|
category: "design",
|
|
45741
45944
|
pkg: "@canva/cli",
|
|
45742
45945
|
installer: "npm",
|
|
@@ -45752,6 +45955,7 @@ var tool_catalog_default = {
|
|
|
45752
45955
|
oauthUrlPattern: "OPEN_URL: (https://www\\.canva\\.com/api/oauth/authorize\\S+)"
|
|
45753
45956
|
},
|
|
45754
45957
|
webflow: {
|
|
45958
|
+
preinstallCloud: true,
|
|
45755
45959
|
category: "development",
|
|
45756
45960
|
pkg: "@webflow/webflow-cli",
|
|
45757
45961
|
installer: "npm",
|
|
@@ -45766,6 +45970,7 @@ var tool_catalog_default = {
|
|
|
45766
45970
|
versionCmd: "webflow --version 2>/dev/null | sed -n 1p"
|
|
45767
45971
|
},
|
|
45768
45972
|
readwise: {
|
|
45973
|
+
preinstallCloud: true,
|
|
45769
45974
|
category: "productivity",
|
|
45770
45975
|
pkg: "@readwise/cli",
|
|
45771
45976
|
installer: "npm",
|
|
@@ -45836,6 +46041,7 @@ var tool_catalog_default = {
|
|
|
45836
46041
|
versionCmd: "exa --version 2>/dev/null | sed -n 1p"
|
|
45837
46042
|
},
|
|
45838
46043
|
mobbin: {
|
|
46044
|
+
preinstallCloud: true,
|
|
45839
46045
|
category: "design",
|
|
45840
46046
|
pkg: "mobbin",
|
|
45841
46047
|
installer: "npm",
|
|
@@ -45866,6 +46072,7 @@ var tool_catalog_default = {
|
|
|
45866
46072
|
versionCmd: "{ python -c 'import sys; from importlib.metadata import version; print(version(sys.argv[1]))' blender-mcp || python3 -c 'import sys; from importlib.metadata import version; print(version(sys.argv[1]))' blender-mcp; } 2>/dev/null"
|
|
45867
46073
|
},
|
|
45868
46074
|
"google-ads": {
|
|
46075
|
+
preinstallCloud: true,
|
|
45869
46076
|
category: "marketing",
|
|
45870
46077
|
pkg: "google-ads",
|
|
45871
46078
|
packages: [
|
|
@@ -45935,6 +46142,7 @@ var model_promos_default = {
|
|
|
45935
46142
|
{ family: "gpt-5-6-sol", rate: 0.85, starts: "2026-08-26", ends: "2026-09-13" },
|
|
45936
46143
|
{ family: "gpt-5-6-sol", rate: 0.8, starts: "2026-09-14", ends: "2026-11-21" },
|
|
45937
46144
|
{ family: "gpt-6-sol", rate: 0.8, starts: "2026-09-22", ends: "2026-11-21" },
|
|
46145
|
+
{ family: "gpt-6-1-sol", rate: 0.8, starts: "2026-09-29", ends: "2026-11-21" },
|
|
45938
46146
|
{ family: "gpt-6-luna", rate: 0.8, starts: "2026-09-22", ends: "2026-11-21" },
|
|
45939
46147
|
{ family: "gpt-6-astra", rate: 0.85, starts: "2026-09-05", ends: "2026-09-13", boostable: false },
|
|
45940
46148
|
{ family: "gpt-6-astra", rate: 0.8, starts: "2026-09-14", ends: "2026-11-21", boostable: false },
|
|
@@ -46135,7 +46343,13 @@ import { parseArgs } from "util";
|
|
|
46135
46343
|
// package.json
|
|
46136
46344
|
var package_default = {
|
|
46137
46345
|
name: "@todoforai/cli",
|
|
46138
|
-
|
|
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",
|
|
46139
46353
|
type: "module",
|
|
46140
46354
|
bin: {
|
|
46141
46355
|
"todoforai-cli": "bin/todoforai-cli.js",
|
|
@@ -46155,7 +46369,7 @@ var package_default = {
|
|
|
46155
46369
|
},
|
|
46156
46370
|
dependencies: {
|
|
46157
46371
|
"@agentclientprotocol/sdk": "^1.4.0",
|
|
46158
|
-
"@todoforai/update-notifier": "^0.
|
|
46372
|
+
"@todoforai/update-notifier": "^0.4.0",
|
|
46159
46373
|
chalk: "^6.0.0",
|
|
46160
46374
|
"cli-highlight": "^2.1.11",
|
|
46161
46375
|
"diff-match-patch": "^1.0.5",
|
|
@@ -46197,6 +46411,7 @@ Examples:
|
|
|
46197
46411
|
tfa-cli device list|rename|wallpaper … # Paired machines
|
|
46198
46412
|
tfa-cli list [-n 30] [--cursor N] [--all] [--status S] # List todos (paginated)
|
|
46199
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)
|
|
46200
46415
|
tfa-cli delete <todo-id> # Permanently delete a todo
|
|
46201
46416
|
tfa-cli addmessage <todo-id> "text" # Send a message and exit (like -r, no watch/bridge)
|
|
46202
46417
|
tfa-cli show <file|-> [todo-id] # Render a local file (image/pdf/html…) in the chat; - = stdin
|
|
@@ -46208,6 +46423,7 @@ Examples:
|
|
|
46208
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)
|
|
46209
46424
|
tfa-cli claim mint --seed <projectId> [--emails a@x,b@y] [--ttl <sec>] # Mint /claim/<token> links for a project you own
|
|
46210
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
|
|
46211
46427
|
tfa-cli <command> help # Details per command
|
|
46212
46428
|
|
|
46213
46429
|
Options:
|
|
@@ -46247,15 +46463,27 @@ Usage:
|
|
|
46247
46463
|
tfa-cli show <file|-> [todo-id] Render a file by mimetype (- reads stdin)
|
|
46248
46464
|
[--title T] [--alias A] [--mime M] [--card <name>] [--link] [--json]
|
|
46249
46465
|
--link: compact download chip instead of inline render
|
|
46250
|
-
Prints "<todoId>:<alias|id>
|
|
46251
|
-
--alias updates the block in place
|
|
46252
|
-
|
|
46466
|
+
Prints "<todoId>:<alias|id>". Private: visible to whoever can read the todo.
|
|
46467
|
+
Re-showing with the same --alias updates the block in place (new version)
|
|
46468
|
+
--alias <todoId>:<alias> updates that todo's block instead,
|
|
46469
|
+
so a later chat can revise an artifact made elsewhere
|
|
46470
|
+
tfa-cli show share <ref|alias> Make it public; prints its link (serves the latest version)
|
|
46471
|
+
tfa-cli show unshare <ref|alias> Make it private again (the link stops working)
|
|
46472
|
+
tfa-cli show rm <ref|alias> Take it down (block, link, every version)
|
|
46253
46473
|
tfa-cli show list [todo-id] List show blocks (ref, title, mime/url, card)
|
|
46254
46474
|
[--project <id>] [--card <name>] [--json]
|
|
46255
46475
|
no todo-id + --project (or $TODOFORAI_PROJECT_ID) = every todo
|
|
46256
46476
|
tfa-cli open <url> [todo-id] Live http(s) url as a preview [--title T] [--alias A] [--json]
|
|
46257
46477
|
|
|
46258
46478
|
todo-id defaults to $TODOFORAI_TODO_ID (agent shell) or the last todo this CLI touched.
|
|
46479
|
+
|
|
46480
|
+
When to use what:
|
|
46481
|
+
read once, move on → plain chat reply
|
|
46482
|
+
interactive, this chat only → html_snippet (can exec/connect/chat back)
|
|
46483
|
+
keep / revise later → show <file> --alias <name> (versioned, private)
|
|
46484
|
+
someone outside needs it → show share <alias> (public link, revocable)
|
|
46485
|
+
a live web page → open <url>
|
|
46486
|
+
a format the user asked for → show the file (pptx, docx, xlsx, pdf…)
|
|
46259
46487
|
`);
|
|
46260
46488
|
}
|
|
46261
46489
|
var STATUS_HELP = {
|
|
@@ -46286,7 +46514,7 @@ var WORD_FLAGS = {
|
|
|
46286
46514
|
agents: "list-agents",
|
|
46287
46515
|
config: "show-config"
|
|
46288
46516
|
};
|
|
46289
|
-
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"];
|
|
46290
46518
|
function parseCliArgs() {
|
|
46291
46519
|
const { values, positionals } = parseArgs({
|
|
46292
46520
|
args: process.argv.slice(2),
|
|
@@ -46326,6 +46554,7 @@ function parseCliArgs() {
|
|
|
46326
46554
|
to: { type: "string" },
|
|
46327
46555
|
unread: { type: "boolean", default: false },
|
|
46328
46556
|
limit: { type: "string" },
|
|
46557
|
+
days: { type: "string" },
|
|
46329
46558
|
resume: { type: "string", short: "r" },
|
|
46330
46559
|
continue: { type: "boolean", short: "c", default: false },
|
|
46331
46560
|
"non-interactive": { type: "boolean", short: "n", default: false },
|
|
@@ -46698,7 +46927,7 @@ Cancelled
|
|
|
46698
46927
|
import { resolve, basename } from "path";
|
|
46699
46928
|
|
|
46700
46929
|
// src/ensure-bridge.ts
|
|
46701
|
-
import { spawn, spawnSync } from "child_process";
|
|
46930
|
+
import { spawn as spawn2, spawnSync as spawnSync2 } from "child_process";
|
|
46702
46931
|
import fs2 from "fs";
|
|
46703
46932
|
import path2 from "path";
|
|
46704
46933
|
import os2 from "os";
|
|
@@ -46708,7 +46937,7 @@ var INSTALL_TIMEOUT_MS = 90000;
|
|
|
46708
46937
|
var bridgeBin = "todoforai-bridge";
|
|
46709
46938
|
var bridgeBinary = () => bridgeBin;
|
|
46710
46939
|
function probeBridge(bin) {
|
|
46711
|
-
return
|
|
46940
|
+
return spawnSync2(bin, ["--version"], { stdio: "ignore" }).status === 0;
|
|
46712
46941
|
}
|
|
46713
46942
|
function hasBridge() {
|
|
46714
46943
|
if (probeBridge(bridgeBin))
|
|
@@ -46723,7 +46952,7 @@ function installBridge() {
|
|
|
46723
46952
|
if (process.platform !== "linux" && process.platform !== "darwin")
|
|
46724
46953
|
return false;
|
|
46725
46954
|
console.error(`\x1B[2mInstalling TODOforAI Bridge (${INSTALLER_URL})...\x1B[0m`);
|
|
46726
|
-
const r =
|
|
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" });
|
|
46727
46956
|
if (r.error?.code === "ETIMEDOUT")
|
|
46728
46957
|
console.error("\x1B[33mBridge install timed out\x1B[0m");
|
|
46729
46958
|
return r.status === 0 && hasBridge();
|
|
@@ -46776,7 +47005,7 @@ function bridgeWhoamiArgs(apiUrl) {
|
|
|
46776
47005
|
return withProfile(["whoami"], apiUrl);
|
|
46777
47006
|
}
|
|
46778
47007
|
function bridgeDeviceId(apiUrl) {
|
|
46779
|
-
const r =
|
|
47008
|
+
const r = spawnSync2(bridgeBin, bridgeWhoamiArgs(apiUrl), { encoding: "utf-8" });
|
|
46780
47009
|
if (r.status !== 0)
|
|
46781
47010
|
return null;
|
|
46782
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);
|
|
@@ -46802,11 +47031,11 @@ async function enrollBridgeWithApiKey(apiUrl, apiKey) {
|
|
|
46802
47031
|
console.error(`\x1B[33mBridge enroll: mint failed (${e?.message || e})\x1B[0m`);
|
|
46803
47032
|
return false;
|
|
46804
47033
|
}
|
|
46805
|
-
const login =
|
|
47034
|
+
const login = spawnSync2(bridgeBin, [...bridgeLoginArgs(apiUrl), "--token", token], { stdio: ["ignore", "ignore", "inherit"], timeout: 30000, killSignal: "SIGKILL" });
|
|
46806
47035
|
return login.status === 0;
|
|
46807
47036
|
}
|
|
46808
47037
|
function ensureBridgeCredentials(apiUrl, opts = {}) {
|
|
46809
|
-
const whoami =
|
|
47038
|
+
const whoami = spawnSync2(bridgeBin, bridgeWhoamiArgs(apiUrl), { stdio: "ignore" });
|
|
46810
47039
|
if (whoami.status === 0)
|
|
46811
47040
|
return true;
|
|
46812
47041
|
if (opts.interactive === false) {
|
|
@@ -46814,7 +47043,7 @@ function ensureBridgeCredentials(apiUrl, opts = {}) {
|
|
|
46814
47043
|
return false;
|
|
46815
47044
|
}
|
|
46816
47045
|
console.error("\x1B[2mBridge credentials not found. Starting `todoforai-bridge login`...\x1B[0m");
|
|
46817
|
-
const login =
|
|
47046
|
+
const login = spawnSync2(bridgeBin, bridgeLoginArgs(apiUrl), { stdio: "inherit" });
|
|
46818
47047
|
return login.status === 0;
|
|
46819
47048
|
}
|
|
46820
47049
|
async function bridgeState(apiUrl, apiKey, deviceId) {
|
|
@@ -46840,7 +47069,7 @@ async function ensureBridgeRunning(apiUrl, apiKey, opts = {}) {
|
|
|
46840
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`);
|
|
46841
47070
|
return false;
|
|
46842
47071
|
}
|
|
46843
|
-
const hasCreds =
|
|
47072
|
+
const hasCreds = spawnSync2(bridgeBin, bridgeWhoamiArgs(apiUrl), { stdio: "ignore" }).status === 0 || await enrollBridgeWithApiKey(apiUrl, apiKey) || ensureBridgeCredentials(apiUrl, opts);
|
|
46844
47073
|
if (!hasCreds) {
|
|
46845
47074
|
console.error("\x1B[33mBridge not started: `todoforai-bridge login` did not complete successfully.\x1B[0m");
|
|
46846
47075
|
return false;
|
|
@@ -46857,7 +47086,7 @@ async function ensureBridgeRunning(apiUrl, apiKey, opts = {}) {
|
|
|
46857
47086
|
fs2.mkdirSync(logDir, { recursive: true });
|
|
46858
47087
|
const logFile = path2.join(logDir, "bridge.log");
|
|
46859
47088
|
const out = fs2.openSync(logFile, "a");
|
|
46860
|
-
const child =
|
|
47089
|
+
const child = spawn2(bridgeBin, bridgeRunArgs(apiUrl), {
|
|
46861
47090
|
detached: true,
|
|
46862
47091
|
stdio: ["ignore", out, out]
|
|
46863
47092
|
});
|
|
@@ -47091,7 +47320,7 @@ class ScopedConfig {
|
|
|
47091
47320
|
}
|
|
47092
47321
|
}
|
|
47093
47322
|
// src/device-login.ts
|
|
47094
|
-
import { spawn as
|
|
47323
|
+
import { spawn as spawn3 } from "child_process";
|
|
47095
47324
|
class DeviceLoginError extends Error {
|
|
47096
47325
|
}
|
|
47097
47326
|
async function runDeviceLogin(apiUrl) {
|
|
@@ -47109,7 +47338,7 @@ async function runDeviceLogin(apiUrl) {
|
|
|
47109
47338
|
`);
|
|
47110
47339
|
try {
|
|
47111
47340
|
const [cmd, args] = process.platform === "win32" ? ["cmd", ["/c", "start", "", url]] : [process.platform === "darwin" ? "open" : "xdg-open", [url]];
|
|
47112
|
-
const child =
|
|
47341
|
+
const child = spawn3(cmd, args, { stdio: "ignore", detached: true });
|
|
47113
47342
|
child.on("error", () => {});
|
|
47114
47343
|
child.unref();
|
|
47115
47344
|
} catch {}
|
|
@@ -48308,7 +48537,7 @@ var createBuilder = (self, _styler, _isEmpty) => {
|
|
|
48308
48537
|
return applyStyle(builder, "" + arguments_[0]);
|
|
48309
48538
|
}
|
|
48310
48539
|
if (arguments_.length === 2) {
|
|
48311
|
-
return applyStyle(builder, arguments_[0]
|
|
48540
|
+
return applyStyle(builder, `${arguments_[0] ?? ""} ${arguments_[1] ?? ""}`);
|
|
48312
48541
|
}
|
|
48313
48542
|
return applyStyle(builder, arguments_.join(" "));
|
|
48314
48543
|
};
|
|
@@ -50707,11 +50936,442 @@ ${message}`).digest("hex").slice(0, 16);
|
|
|
50707
50936
|
`);
|
|
50708
50937
|
}
|
|
50709
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
|
+
|
|
50710
51370
|
// src/index.ts
|
|
50711
51371
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
50712
51372
|
|
|
50713
51373
|
// src/ensure-bridge.ts
|
|
50714
|
-
import { spawn as
|
|
51374
|
+
import { spawn as spawn4, spawnSync as spawnSync3 } from "child_process";
|
|
50715
51375
|
import fs3 from "fs";
|
|
50716
51376
|
import path3 from "path";
|
|
50717
51377
|
import os4 from "os";
|
|
@@ -50720,7 +51380,7 @@ var INSTALL_PREFIX2 = process.env.TODOFORAI_PREFIX || path3.join(os4.homedir(),
|
|
|
50720
51380
|
var INSTALL_TIMEOUT_MS2 = 90000;
|
|
50721
51381
|
var bridgeBin2 = "todoforai-bridge";
|
|
50722
51382
|
function probeBridge2(bin) {
|
|
50723
|
-
return
|
|
51383
|
+
return spawnSync3(bin, ["--version"], { stdio: "ignore" }).status === 0;
|
|
50724
51384
|
}
|
|
50725
51385
|
function hasBridge2() {
|
|
50726
51386
|
if (probeBridge2(bridgeBin2))
|
|
@@ -50735,7 +51395,7 @@ function installBridge2() {
|
|
|
50735
51395
|
if (process.platform !== "linux" && process.platform !== "darwin")
|
|
50736
51396
|
return false;
|
|
50737
51397
|
console.error(`\x1B[2mInstalling TODOforAI Bridge (${INSTALLER_URL2})...\x1B[0m`);
|
|
50738
|
-
const r =
|
|
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" });
|
|
50739
51399
|
if (r.error?.code === "ETIMEDOUT")
|
|
50740
51400
|
console.error("\x1B[33mBridge install timed out\x1B[0m");
|
|
50741
51401
|
return r.status === 0 && hasBridge2();
|
|
@@ -50788,7 +51448,7 @@ function bridgeWhoamiArgs2(apiUrl) {
|
|
|
50788
51448
|
return withProfile2(["whoami"], apiUrl);
|
|
50789
51449
|
}
|
|
50790
51450
|
function bridgeDeviceId2(apiUrl) {
|
|
50791
|
-
const r =
|
|
51451
|
+
const r = spawnSync3(bridgeBin2, bridgeWhoamiArgs2(apiUrl), { encoding: "utf-8" });
|
|
50792
51452
|
if (r.status !== 0)
|
|
50793
51453
|
return null;
|
|
50794
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);
|
|
@@ -50814,11 +51474,11 @@ async function enrollBridgeWithApiKey2(apiUrl, apiKey) {
|
|
|
50814
51474
|
console.error(`\x1B[33mBridge enroll: mint failed (${e?.message || e})\x1B[0m`);
|
|
50815
51475
|
return false;
|
|
50816
51476
|
}
|
|
50817
|
-
const login =
|
|
51477
|
+
const login = spawnSync3(bridgeBin2, [...bridgeLoginArgs2(apiUrl), "--token", token], { stdio: ["ignore", "ignore", "inherit"], timeout: 30000, killSignal: "SIGKILL" });
|
|
50818
51478
|
return login.status === 0;
|
|
50819
51479
|
}
|
|
50820
51480
|
function ensureBridgeCredentials2(apiUrl, opts = {}) {
|
|
50821
|
-
const whoami =
|
|
51481
|
+
const whoami = spawnSync3(bridgeBin2, bridgeWhoamiArgs2(apiUrl), { stdio: "ignore" });
|
|
50822
51482
|
if (whoami.status === 0)
|
|
50823
51483
|
return true;
|
|
50824
51484
|
if (opts.interactive === false) {
|
|
@@ -50826,7 +51486,7 @@ function ensureBridgeCredentials2(apiUrl, opts = {}) {
|
|
|
50826
51486
|
return false;
|
|
50827
51487
|
}
|
|
50828
51488
|
console.error("\x1B[2mBridge credentials not found. Starting `todoforai-bridge login`...\x1B[0m");
|
|
50829
|
-
const login =
|
|
51489
|
+
const login = spawnSync3(bridgeBin2, bridgeLoginArgs2(apiUrl), { stdio: "inherit" });
|
|
50830
51490
|
return login.status === 0;
|
|
50831
51491
|
}
|
|
50832
51492
|
async function bridgeState2(apiUrl, apiKey, deviceId) {
|
|
@@ -50843,7 +51503,7 @@ async function waitForBridgeOnline2(apiUrl, apiKey, deviceId, timeoutMs = 5000)
|
|
|
50843
51503
|
const state = await bridgeState2(apiUrl, apiKey, deviceId);
|
|
50844
51504
|
if (state !== "offline")
|
|
50845
51505
|
return state === "online";
|
|
50846
|
-
await new Promise((
|
|
51506
|
+
await new Promise((resolve5) => setTimeout(resolve5, 150));
|
|
50847
51507
|
} while (Date.now() < deadline);
|
|
50848
51508
|
return false;
|
|
50849
51509
|
}
|
|
@@ -50852,7 +51512,7 @@ async function ensureBridgeRunning2(apiUrl, apiKey, opts = {}) {
|
|
|
50852
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`);
|
|
50853
51513
|
return false;
|
|
50854
51514
|
}
|
|
50855
|
-
const hasCreds =
|
|
51515
|
+
const hasCreds = spawnSync3(bridgeBin2, bridgeWhoamiArgs2(apiUrl), { stdio: "ignore" }).status === 0 || await enrollBridgeWithApiKey2(apiUrl, apiKey) || ensureBridgeCredentials2(apiUrl, opts);
|
|
50856
51516
|
if (!hasCreds) {
|
|
50857
51517
|
console.error("\x1B[33mBridge not started: `todoforai-bridge login` did not complete successfully.\x1B[0m");
|
|
50858
51518
|
return false;
|
|
@@ -50869,7 +51529,7 @@ async function ensureBridgeRunning2(apiUrl, apiKey, opts = {}) {
|
|
|
50869
51529
|
fs3.mkdirSync(logDir, { recursive: true });
|
|
50870
51530
|
const logFile = path3.join(logDir, "bridge.log");
|
|
50871
51531
|
const out = fs3.openSync(logFile, "a");
|
|
50872
|
-
const child =
|
|
51532
|
+
const child = spawn4(bridgeBin2, bridgeRunArgs2(apiUrl), {
|
|
50873
51533
|
detached: true,
|
|
50874
51534
|
stdio: ["ignore", out, out]
|
|
50875
51535
|
});
|
|
@@ -50894,7 +51554,7 @@ async function ensureBridgeRunning2(apiUrl, apiKey, opts = {}) {
|
|
|
50894
51554
|
}
|
|
50895
51555
|
|
|
50896
51556
|
// src/isolated.ts
|
|
50897
|
-
import { spawn as
|
|
51557
|
+
import { spawn as spawn5 } from "child_process";
|
|
50898
51558
|
async function mintMayflyToken(apiUrl, apiKey, todoId) {
|
|
50899
51559
|
const res = await fetch(`${apiUrl}${restBasePath(apiKey)}/cli/mayfly/token`, {
|
|
50900
51560
|
method: "POST",
|
|
@@ -50925,7 +51585,7 @@ async function spawnMayflyBridge(apiUrl, todoId, workspace, opts = {}) {
|
|
|
50925
51585
|
delete env2[p + n];
|
|
50926
51586
|
env2.TODOFORAI_MAYFLY_TOKEN = sessionToken;
|
|
50927
51587
|
}
|
|
50928
|
-
const child =
|
|
51588
|
+
const child = spawn5(bridgeBinary(), args, { stdio: ["ignore", "pipe", "pipe"], env: env2 });
|
|
50929
51589
|
let stopped = false;
|
|
50930
51590
|
const stop = () => {
|
|
50931
51591
|
if (stopped)
|
|
@@ -51019,9 +51679,7 @@ var CLIENT_METHODS = {
|
|
|
51019
51679
|
terminal_release: "terminal/release",
|
|
51020
51680
|
terminal_wait_for_exit: "terminal/wait_for_exit",
|
|
51021
51681
|
terminal_kill: "terminal/kill",
|
|
51022
|
-
mcp_connect: "mcp/connect",
|
|
51023
51682
|
mcp_message: "mcp/message",
|
|
51024
|
-
mcp_disconnect: "mcp/disconnect",
|
|
51025
51683
|
elicitation_create: "elicitation/create",
|
|
51026
51684
|
elicitation_complete: "elicitation/complete"
|
|
51027
51685
|
};
|
|
@@ -51074,7 +51732,7 @@ __export(exports_external, {
|
|
|
51074
51732
|
setErrorMap: () => setErrorMap,
|
|
51075
51733
|
set: () => set,
|
|
51076
51734
|
safeParseAsync: () => safeParseAsync2,
|
|
51077
|
-
safeParse: () =>
|
|
51735
|
+
safeParse: () => safeParse3,
|
|
51078
51736
|
safeEncodeAsync: () => safeEncodeAsync2,
|
|
51079
51737
|
safeEncode: () => safeEncode2,
|
|
51080
51738
|
safeDecodeAsync: () => safeDecodeAsync2,
|
|
@@ -51311,7 +51969,7 @@ __export(exports_core2, {
|
|
|
51311
51969
|
stripTabAndNewline: () => stripTabAndNewline,
|
|
51312
51970
|
standardProps: () => standardProps,
|
|
51313
51971
|
safeParseAsync: () => safeParseAsync,
|
|
51314
|
-
safeParse: () =>
|
|
51972
|
+
safeParse: () => safeParse2,
|
|
51315
51973
|
safeEncodeAsync: () => safeEncodeAsync,
|
|
51316
51974
|
safeEncode: () => safeEncode,
|
|
51317
51975
|
safeDecodeAsync: () => safeDecodeAsync,
|
|
@@ -52807,7 +53465,7 @@ var _safeParse = (_Err) => (schema, value, _ctx) => {
|
|
|
52807
53465
|
}
|
|
52808
53466
|
return result.issues.length ? failure(_Err, result.issues, ctx) : { success: true, data: result.value };
|
|
52809
53467
|
};
|
|
52810
|
-
var
|
|
53468
|
+
var safeParse2 = /* @__PURE__ */ _safeParse($ZodRealError);
|
|
52811
53469
|
function failure(Err, issues, ctx) {
|
|
52812
53470
|
let error;
|
|
52813
53471
|
return {
|
|
@@ -54995,7 +55653,7 @@ function handleIntersectionResults(result, left, right) {
|
|
|
54995
55653
|
const unrecKeys = new Map;
|
|
54996
55654
|
let unrecIssue;
|
|
54997
55655
|
const keyIssues = new Map;
|
|
54998
|
-
const
|
|
55656
|
+
const collect2 = (iss, side) => {
|
|
54999
55657
|
let keys;
|
|
55000
55658
|
if (iss.code === "unrecognized_keys" && !iss.path?.length) {
|
|
55001
55659
|
unrecIssue ?? (unrecIssue = iss);
|
|
@@ -55016,11 +55674,11 @@ function handleIntersectionResults(result, left, right) {
|
|
|
55016
55674
|
return true;
|
|
55017
55675
|
};
|
|
55018
55676
|
for (const iss of left.issues) {
|
|
55019
|
-
if (!
|
|
55677
|
+
if (!collect2(iss, "l"))
|
|
55020
55678
|
result.issues.push(iss);
|
|
55021
55679
|
}
|
|
55022
55680
|
for (const iss of right.issues) {
|
|
55023
|
-
if (!
|
|
55681
|
+
if (!collect2(iss, "r"))
|
|
55024
55682
|
result.issues.push(iss);
|
|
55025
55683
|
}
|
|
55026
55684
|
const bothKeys = [...unrecKeys].filter(([, f]) => f.l && f.r).map(([k]) => k);
|
|
@@ -56024,7 +56682,7 @@ class $ZodCyclicError extends Error {
|
|
|
56024
56682
|
this.name = "ZodCyclicError";
|
|
56025
56683
|
}
|
|
56026
56684
|
}
|
|
56027
|
-
var
|
|
56685
|
+
var STATE2 = "~memo";
|
|
56028
56686
|
var NO_ISSUES = [];
|
|
56029
56687
|
function isRef(value) {
|
|
56030
56688
|
return value !== null && typeof value === "object";
|
|
@@ -56036,7 +56694,7 @@ var recursive = /* @__PURE__ */ new WeakMap;
|
|
|
56036
56694
|
var NONE = 0;
|
|
56037
56695
|
var ASSUMED = 1;
|
|
56038
56696
|
var PROVEN = 2;
|
|
56039
|
-
function isRecursive(inst, stack,
|
|
56697
|
+
function isRecursive(inst, stack, resolve5) {
|
|
56040
56698
|
const cached2 = recursive.get(inst);
|
|
56041
56699
|
if (cached2 !== undefined)
|
|
56042
56700
|
return cached2 ? PROVEN : NONE;
|
|
@@ -56046,7 +56704,7 @@ function isRecursive(inst, stack, resolve4) {
|
|
|
56046
56704
|
let result = NONE;
|
|
56047
56705
|
const check = (child) => {
|
|
56048
56706
|
if (result !== PROVEN && child?._zod) {
|
|
56049
|
-
const answer = isRecursive(child, stack,
|
|
56707
|
+
const answer = isRecursive(child, stack, resolve5);
|
|
56050
56708
|
if (answer > result)
|
|
56051
56709
|
result = answer;
|
|
56052
56710
|
}
|
|
@@ -56057,7 +56715,7 @@ function isRecursive(inst, stack, resolve4) {
|
|
|
56057
56715
|
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
56058
56716
|
if (spread && !desc.enumerable)
|
|
56059
56717
|
continue;
|
|
56060
|
-
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack,
|
|
56718
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve5) : NONE;
|
|
56061
56719
|
if (child > answer)
|
|
56062
56720
|
answer = child;
|
|
56063
56721
|
}
|
|
@@ -56120,7 +56778,7 @@ function isRecursive(inst, stack, resolve4) {
|
|
|
56120
56778
|
check(def.output);
|
|
56121
56779
|
break;
|
|
56122
56780
|
case "lazy": {
|
|
56123
|
-
const inner = def._cachedInner ?? (
|
|
56781
|
+
const inner = def._cachedInner ?? (resolve5 ? inst._zod.innerType : undefined);
|
|
56124
56782
|
merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
56125
56783
|
break;
|
|
56126
56784
|
}
|
|
@@ -56234,10 +56892,10 @@ var memo = {
|
|
|
56234
56892
|
const input = payload.value;
|
|
56235
56893
|
if (!isRef(input))
|
|
56236
56894
|
return base(payload, ctx);
|
|
56237
|
-
let state = ctx[
|
|
56895
|
+
let state = ctx[STATE2];
|
|
56238
56896
|
if (!state) {
|
|
56239
56897
|
state = { buckets: new WeakMap, backEdges: undefined };
|
|
56240
|
-
ctx[
|
|
56898
|
+
ctx[STATE2] = state;
|
|
56241
56899
|
}
|
|
56242
56900
|
let bucket;
|
|
56243
56901
|
if (lastCtx === ctx) {
|
|
@@ -56286,7 +56944,7 @@ function memoizer() {
|
|
|
56286
56944
|
return memo;
|
|
56287
56945
|
}
|
|
56288
56946
|
function isBackEdge(ctx, value) {
|
|
56289
|
-
const backEdges = ctx[
|
|
56947
|
+
const backEdges = ctx[STATE2]?.backEdges;
|
|
56290
56948
|
return backEdges !== undefined && isRef(value) && backEdges.has(value);
|
|
56291
56949
|
}
|
|
56292
56950
|
// node_modules/zod/v4/locales/index.js
|
|
@@ -67966,7 +68624,7 @@ var ZodRealError = /* @__PURE__ */ $constructor("ZodError", initializer2, undefi
|
|
|
67966
68624
|
// node_modules/zod/v4/classic/parse.js
|
|
67967
68625
|
var parse3 = /* @__PURE__ */ _parse(ZodRealError);
|
|
67968
68626
|
var parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
|
|
67969
|
-
var
|
|
68627
|
+
var safeParse3 = /* @__PURE__ */ _safeParse(ZodRealError);
|
|
67970
68628
|
var safeParseAsync2 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
|
|
67971
68629
|
var encode2 = /* @__PURE__ */ _encode(ZodRealError);
|
|
67972
68630
|
var decode2 = /* @__PURE__ */ _decode(ZodRealError);
|
|
@@ -68106,7 +68764,7 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
|
|
|
68106
68764
|
return await parseAsync2(this, data, params, { callee: _parseAsync2 });
|
|
68107
68765
|
},
|
|
68108
68766
|
safeParse(data, params) {
|
|
68109
|
-
return
|
|
68767
|
+
return safeParse3(this, data, params);
|
|
68110
68768
|
},
|
|
68111
68769
|
async safeParseAsync(data, params) {
|
|
68112
68770
|
return safeParseAsync2(this, data, params);
|
|
@@ -70970,27 +71628,16 @@ var zCreateElicitationRequest = preserveCustomPayload(intersection(union([
|
|
|
70970
71628
|
})
|
|
70971
71629
|
})), "mode", ["form", "url"]);
|
|
70972
71630
|
var zMcpServerAcpId = string2();
|
|
70973
|
-
var
|
|
70974
|
-
serverId: zMcpServerAcpId,
|
|
70975
|
-
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
70976
|
-
return;
|
|
70977
|
-
})
|
|
70978
|
-
});
|
|
70979
|
-
var zMcpConnectionId = string2();
|
|
71631
|
+
var zMcpRequestId = string2();
|
|
70980
71632
|
var zMessageMcpRequest = object({
|
|
70981
|
-
|
|
71633
|
+
serverId: zMcpServerAcpId,
|
|
71634
|
+
requestId: zMcpRequestId,
|
|
70982
71635
|
method: string2(),
|
|
70983
71636
|
params: record(string2(), unknown()).nullish(),
|
|
70984
71637
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
70985
71638
|
return;
|
|
70986
71639
|
})
|
|
70987
71640
|
});
|
|
70988
|
-
var zDisconnectMcpRequest = object({
|
|
70989
|
-
connectionId: zMcpConnectionId,
|
|
70990
|
-
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
70991
|
-
return;
|
|
70992
|
-
})
|
|
70993
|
-
});
|
|
70994
71641
|
var zExtRequest = unknown();
|
|
70995
71642
|
var zAgentRequest = object({
|
|
70996
71643
|
id: zRequestId,
|
|
@@ -71005,9 +71652,7 @@ var zAgentRequest = object({
|
|
|
71005
71652
|
zWaitForTerminalExitRequest,
|
|
71006
71653
|
zKillTerminalRequest,
|
|
71007
71654
|
zCreateElicitationRequest,
|
|
71008
|
-
zConnectMcpRequest,
|
|
71009
71655
|
zMessageMcpRequest,
|
|
71010
|
-
zDisconnectMcpRequest,
|
|
71011
71656
|
zExtRequest
|
|
71012
71657
|
]).nullish()
|
|
71013
71658
|
});
|
|
@@ -71703,7 +72348,6 @@ var zCloseNesResponse = object({
|
|
|
71703
72348
|
})
|
|
71704
72349
|
});
|
|
71705
72350
|
var zExtResponse = unknown();
|
|
71706
|
-
var zMessageMcpResponse = unknown();
|
|
71707
72351
|
var zErrorCode = union([
|
|
71708
72352
|
literal(-32700),
|
|
71709
72353
|
literal(-32600),
|
|
@@ -71749,8 +72393,7 @@ var zAgentResponse = union([
|
|
|
71749
72393
|
zStartNesResponse,
|
|
71750
72394
|
zSuggestNesResponse,
|
|
71751
72395
|
zCloseNesResponse,
|
|
71752
|
-
zExtResponse
|
|
71753
|
-
zMessageMcpResponse
|
|
72396
|
+
zExtResponse
|
|
71754
72397
|
])
|
|
71755
72398
|
}),
|
|
71756
72399
|
object({
|
|
@@ -71968,6 +72611,108 @@ var zCompactionSummaryChunk = object({
|
|
|
71968
72611
|
return;
|
|
71969
72612
|
})
|
|
71970
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
|
+
});
|
|
71971
72716
|
var zSessionUpdate = union([
|
|
71972
72717
|
zContentChunk.and(object({
|
|
71973
72718
|
sessionUpdate: literal("user_message_chunk")
|
|
@@ -72016,6 +72761,15 @@ var zSessionUpdate = union([
|
|
|
72016
72761
|
})),
|
|
72017
72762
|
zCompactionSummaryChunk.and(object({
|
|
72018
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")
|
|
72019
72773
|
}))
|
|
72020
72774
|
]);
|
|
72021
72775
|
var zSessionNotification = object({
|
|
@@ -72031,23 +72785,12 @@ var zCompleteElicitationNotification = object({
|
|
|
72031
72785
|
return;
|
|
72032
72786
|
})
|
|
72033
72787
|
});
|
|
72034
|
-
var zMessageMcpNotification = object({
|
|
72035
|
-
connectionId: zMcpConnectionId,
|
|
72036
|
-
method: string2(),
|
|
72037
|
-
params: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
72038
|
-
return;
|
|
72039
|
-
}),
|
|
72040
|
-
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
72041
|
-
return;
|
|
72042
|
-
})
|
|
72043
|
-
});
|
|
72044
72788
|
var zExtNotification = unknown();
|
|
72045
72789
|
var zAgentNotification = object({
|
|
72046
72790
|
method: string2(),
|
|
72047
72791
|
params: union([
|
|
72048
72792
|
zSessionNotification,
|
|
72049
72793
|
zCompleteElicitationNotification,
|
|
72050
|
-
zMessageMcpNotification,
|
|
72051
72794
|
zExtNotification
|
|
72052
72795
|
]).nullish()
|
|
72053
72796
|
});
|
|
@@ -72087,6 +72830,11 @@ var zClientSessionCapabilities = object({
|
|
|
72087
72830
|
return;
|
|
72088
72831
|
})
|
|
72089
72832
|
});
|
|
72833
|
+
var zSubagentCapabilities = object({
|
|
72834
|
+
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
72835
|
+
return;
|
|
72836
|
+
})
|
|
72837
|
+
});
|
|
72090
72838
|
var zPlanCapabilities = object({
|
|
72091
72839
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
72092
72840
|
return;
|
|
@@ -72154,6 +72902,9 @@ var zClientCapabilities = object({
|
|
|
72154
72902
|
session: defaultOnError(zClientSessionCapabilities.nullish(), () => {
|
|
72155
72903
|
return;
|
|
72156
72904
|
}),
|
|
72905
|
+
subagents: defaultOnError(zSubagentCapabilities.nullish(), () => {
|
|
72906
|
+
return;
|
|
72907
|
+
}),
|
|
72157
72908
|
plan: defaultOnError(zPlanCapabilities.nullish(), () => {
|
|
72158
72909
|
return;
|
|
72159
72910
|
}),
|
|
@@ -72507,7 +73258,6 @@ var zClientRequest = object({
|
|
|
72507
73258
|
zStartNesRequest,
|
|
72508
73259
|
zSuggestNesRequest,
|
|
72509
73260
|
zCloseNesRequest,
|
|
72510
|
-
zMessageMcpRequest,
|
|
72511
73261
|
zExtRequest
|
|
72512
73262
|
]).nullish()
|
|
72513
73263
|
});
|
|
@@ -72622,17 +73372,29 @@ var zCreateElicitationResponse = preserveCustomPayload(intersection(union([
|
|
|
72622
73372
|
return;
|
|
72623
73373
|
})
|
|
72624
73374
|
})), "action", ["accept", "cancel", "decline"]);
|
|
72625
|
-
var
|
|
72626
|
-
|
|
72627
|
-
|
|
72628
|
-
|
|
72629
|
-
|
|
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()
|
|
72630
73383
|
});
|
|
72631
|
-
var
|
|
72632
|
-
|
|
72633
|
-
|
|
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
|
+
})
|
|
72634
73396
|
})
|
|
72635
|
-
|
|
73397
|
+
]);
|
|
72636
73398
|
var zClientResponse = union([
|
|
72637
73399
|
object({
|
|
72638
73400
|
id: zRequestId,
|
|
@@ -72646,8 +73408,6 @@ var zClientResponse = union([
|
|
|
72646
73408
|
zWaitForTerminalExitResponse,
|
|
72647
73409
|
zKillTerminalResponse,
|
|
72648
73410
|
zCreateElicitationResponse,
|
|
72649
|
-
zConnectMcpResponse,
|
|
72650
|
-
zDisconnectMcpResponse,
|
|
72651
73411
|
zMessageMcpResponse,
|
|
72652
73412
|
zExtResponse
|
|
72653
73413
|
])
|
|
@@ -72736,6 +73496,15 @@ var zRejectNesNotification = object({
|
|
|
72736
73496
|
return;
|
|
72737
73497
|
})
|
|
72738
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
|
+
});
|
|
72739
73508
|
var zClientNotification = object({
|
|
72740
73509
|
method: string2(),
|
|
72741
73510
|
params: union([
|
|
@@ -73103,11 +73872,11 @@ class Connection {
|
|
|
73103
73872
|
prepareRequest(method, params, mapResponse, options = {}) {
|
|
73104
73873
|
const id = this.nextRequestId++;
|
|
73105
73874
|
let cancel = () => {};
|
|
73106
|
-
const response = new Promise((
|
|
73875
|
+
const response = new Promise((resolve5, reject) => {
|
|
73107
73876
|
const pendingResponse = {
|
|
73108
73877
|
resolve: (value) => {
|
|
73109
73878
|
try {
|
|
73110
|
-
|
|
73879
|
+
resolve5(mapResponse ? mapResponse(value) : value);
|
|
73111
73880
|
} catch (error62) {
|
|
73112
73881
|
reject(error62);
|
|
73113
73882
|
}
|
|
@@ -73158,8 +73927,8 @@ class Connection {
|
|
|
73158
73927
|
this.stream = stream;
|
|
73159
73928
|
this.staticHandlers = handlers;
|
|
73160
73929
|
this.allowBatches = options?.allowBatches ?? true;
|
|
73161
|
-
this.closedPromise = new Promise((
|
|
73162
|
-
this.abortController.signal.addEventListener("abort", () =>
|
|
73930
|
+
this.closedPromise = new Promise((resolve5) => {
|
|
73931
|
+
this.abortController.signal.addEventListener("abort", () => resolve5());
|
|
73163
73932
|
});
|
|
73164
73933
|
this.receive();
|
|
73165
73934
|
}
|
|
@@ -73525,53 +74294,124 @@ function protocolErrorResponse(error62) {
|
|
|
73525
74294
|
};
|
|
73526
74295
|
}
|
|
73527
74296
|
|
|
74297
|
+
// node_modules/@agentclientprotocol/sdk/dist/stream-limits.js
|
|
74298
|
+
var DEFAULT_MAX_MESSAGE_BYTES = 32 * 1024 * 1024;
|
|
74299
|
+
|
|
74300
|
+
class MessageTooLargeError extends Error {
|
|
74301
|
+
maxMessageBytes;
|
|
74302
|
+
constructor(maxMessageBytes) {
|
|
74303
|
+
super(`Incoming ACP data exceeds the configured ${maxMessageBytes} byte limit`);
|
|
74304
|
+
this.maxMessageBytes = maxMessageBytes;
|
|
74305
|
+
this.name = "MessageTooLargeError";
|
|
74306
|
+
}
|
|
74307
|
+
}
|
|
74308
|
+
function resolveMaxMessageBytes(value) {
|
|
74309
|
+
const maxMessageBytes = value ?? DEFAULT_MAX_MESSAGE_BYTES;
|
|
74310
|
+
if (!Number.isSafeInteger(maxMessageBytes) || maxMessageBytes <= 0) {
|
|
74311
|
+
throw new RangeError("maxMessageBytes must be a positive safe integer");
|
|
74312
|
+
}
|
|
74313
|
+
return maxMessageBytes;
|
|
74314
|
+
}
|
|
74315
|
+
|
|
74316
|
+
class MessageBuffer {
|
|
74317
|
+
#buffer = new Uint8Array(0);
|
|
74318
|
+
#length = 0;
|
|
74319
|
+
#maxMessageBytes;
|
|
74320
|
+
constructor(maxMessageBytes) {
|
|
74321
|
+
this.#maxMessageBytes = resolveMaxMessageBytes(maxMessageBytes);
|
|
74322
|
+
}
|
|
74323
|
+
get byteLength() {
|
|
74324
|
+
return this.#length;
|
|
74325
|
+
}
|
|
74326
|
+
get lastByte() {
|
|
74327
|
+
return this.#buffer[this.#length - 1];
|
|
74328
|
+
}
|
|
74329
|
+
#checkAppend(byteLength) {
|
|
74330
|
+
if (byteLength > this.#maxMessageBytes - this.#length) {
|
|
74331
|
+
this.clear();
|
|
74332
|
+
throw new MessageTooLargeError(this.#maxMessageBytes);
|
|
74333
|
+
}
|
|
74334
|
+
}
|
|
74335
|
+
append(bytes) {
|
|
74336
|
+
this.#checkAppend(bytes.byteLength);
|
|
74337
|
+
const length = this.#length + bytes.byteLength;
|
|
74338
|
+
if (length > this.#buffer.byteLength) {
|
|
74339
|
+
const capacity = Math.min(this.#maxMessageBytes, Math.max(length, this.#buffer.byteLength * 2, 1024));
|
|
74340
|
+
const buffer = new Uint8Array(capacity);
|
|
74341
|
+
buffer.set(this.#buffer.subarray(0, this.#length));
|
|
74342
|
+
this.#buffer = buffer;
|
|
74343
|
+
}
|
|
74344
|
+
this.#buffer.set(bytes, this.#length);
|
|
74345
|
+
this.#length = length;
|
|
74346
|
+
}
|
|
74347
|
+
take() {
|
|
74348
|
+
const bytes = this.#buffer.subarray(0, this.#length);
|
|
74349
|
+
this.clear();
|
|
74350
|
+
return bytes;
|
|
74351
|
+
}
|
|
74352
|
+
clear() {
|
|
74353
|
+
this.#buffer = new Uint8Array(0);
|
|
74354
|
+
this.#length = 0;
|
|
74355
|
+
}
|
|
74356
|
+
}
|
|
74357
|
+
|
|
73528
74358
|
// node_modules/@agentclientprotocol/sdk/dist/line-buffer.js
|
|
73529
74359
|
var newline = 10;
|
|
73530
74360
|
|
|
73531
74361
|
class LineBuffer {
|
|
73532
|
-
#pending
|
|
73533
|
-
|
|
73534
|
-
|
|
74362
|
+
#pending;
|
|
74363
|
+
#maxMessageBytes;
|
|
74364
|
+
constructor(maxMessageBytes) {
|
|
74365
|
+
this.#maxMessageBytes = resolveMaxMessageBytes(maxMessageBytes);
|
|
74366
|
+
this.#pending = new MessageBuffer(Math.min(Number.MAX_SAFE_INTEGER, this.#maxMessageBytes + 1));
|
|
74367
|
+
}
|
|
74368
|
+
*push(chunk) {
|
|
73535
74369
|
let start = 0;
|
|
73536
74370
|
let newlineIndex = chunk.indexOf(newline, start);
|
|
73537
74371
|
while (newlineIndex !== -1) {
|
|
73538
|
-
|
|
74372
|
+
yield this.#takeLine(chunk.subarray(start, newlineIndex));
|
|
73539
74373
|
start = newlineIndex + 1;
|
|
73540
74374
|
newlineIndex = chunk.indexOf(newline, start);
|
|
73541
74375
|
}
|
|
73542
74376
|
if (start < chunk.byteLength) {
|
|
73543
|
-
|
|
74377
|
+
const tail = chunk.subarray(start);
|
|
74378
|
+
this.#checkLine(tail);
|
|
74379
|
+
this.#pending.append(tail);
|
|
73544
74380
|
}
|
|
73545
|
-
return lines;
|
|
73546
74381
|
}
|
|
73547
74382
|
flush() {
|
|
73548
|
-
if (this.#pending.
|
|
74383
|
+
if (this.#pending.byteLength === 0) {
|
|
73549
74384
|
return;
|
|
73550
74385
|
}
|
|
73551
|
-
return this.#
|
|
74386
|
+
return stripCarriageReturn(this.#pending.take());
|
|
74387
|
+
}
|
|
74388
|
+
clear() {
|
|
74389
|
+
this.#pending.clear();
|
|
73552
74390
|
}
|
|
73553
74391
|
#takeLine(tail) {
|
|
73554
|
-
|
|
73555
|
-
|
|
73556
|
-
|
|
73557
|
-
let total = tail.byteLength;
|
|
73558
|
-
for (const part of this.#pending) {
|
|
73559
|
-
total += part.byteLength;
|
|
74392
|
+
this.#checkLine(tail);
|
|
74393
|
+
if (this.#pending.byteLength === 0) {
|
|
74394
|
+
return stripCarriageReturn(tail);
|
|
73560
74395
|
}
|
|
73561
|
-
|
|
73562
|
-
|
|
73563
|
-
|
|
73564
|
-
|
|
73565
|
-
|
|
74396
|
+
this.#pending.append(tail);
|
|
74397
|
+
return stripCarriageReturn(this.#pending.take());
|
|
74398
|
+
}
|
|
74399
|
+
#checkLine(tail) {
|
|
74400
|
+
const lastByte = tail.byteLength > 0 ? tail[tail.byteLength - 1] : this.#pending.lastByte;
|
|
74401
|
+
const byteLength = this.#pending.byteLength + tail.byteLength - (lastByte === 13 ? 1 : 0);
|
|
74402
|
+
if (byteLength > this.#maxMessageBytes) {
|
|
74403
|
+
this.clear();
|
|
74404
|
+
throw new MessageTooLargeError(this.#maxMessageBytes);
|
|
73566
74405
|
}
|
|
73567
|
-
line.set(tail, offset);
|
|
73568
|
-
this.#pending = [];
|
|
73569
|
-
return line;
|
|
73570
74406
|
}
|
|
73571
74407
|
}
|
|
74408
|
+
function stripCarriageReturn(line) {
|
|
74409
|
+
return line[line.byteLength - 1] === 13 ? line.subarray(0, -1) : line;
|
|
74410
|
+
}
|
|
73572
74411
|
|
|
73573
74412
|
// node_modules/@agentclientprotocol/sdk/dist/stream.js
|
|
73574
|
-
function ndJsonStream(output2, input2) {
|
|
74413
|
+
function ndJsonStream(output2, input2, options = {}) {
|
|
74414
|
+
const maxMessageBytes = resolveMaxMessageBytes(options.maxMessageBytes);
|
|
73575
74415
|
const textEncoder = new TextEncoder;
|
|
73576
74416
|
const textDecoder = new TextDecoder;
|
|
73577
74417
|
let cancelled = false;
|
|
@@ -73593,7 +74433,7 @@ function ndJsonStream(output2, input2) {
|
|
|
73593
74433
|
};
|
|
73594
74434
|
const readable = new ReadableStream({
|
|
73595
74435
|
async start(controller) {
|
|
73596
|
-
const lines = new LineBuffer;
|
|
74436
|
+
const lines = new LineBuffer(maxMessageBytes);
|
|
73597
74437
|
const enqueueLine = async (lineBytes) => {
|
|
73598
74438
|
const trimmedLine = textDecoder.decode(lineBytes).trim();
|
|
73599
74439
|
if (!trimmedLine) {
|
|
@@ -73645,8 +74485,10 @@ function ndJsonStream(output2, input2) {
|
|
|
73645
74485
|
return;
|
|
73646
74486
|
}
|
|
73647
74487
|
controller.error(err);
|
|
74488
|
+
reader.cancel(err).catch(() => {});
|
|
73648
74489
|
return;
|
|
73649
74490
|
} finally {
|
|
74491
|
+
lines.clear();
|
|
73650
74492
|
if (inputReader === reader) {
|
|
73651
74493
|
inputReader = undefined;
|
|
73652
74494
|
}
|
|
@@ -73680,6 +74522,10 @@ var zGuardElicitationPropertySchemaInteger = zIntegerPropertySchema.and(object({
|
|
|
73680
74522
|
var zGuardElicitationPropertySchemaBoolean = zBooleanPropertySchema.and(object({ type: literal("boolean") }));
|
|
73681
74523
|
var zGuardElicitationPropertySchemaArray = zMultiSelectPropertySchema.and(object({ type: literal("array") }));
|
|
73682
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") }));
|
|
73683
74529
|
var zGuardCreateElicitationResponseAccept = zElicitationAcceptAction.and(object({ action: literal("accept") }));
|
|
73684
74530
|
var zGuardCreateElicitationResponseDecline = object({
|
|
73685
74531
|
action: literal("decline")
|
|
@@ -73688,8 +74534,8 @@ var zGuardCreateElicitationResponseCancel = object({
|
|
|
73688
74534
|
action: literal("cancel")
|
|
73689
74535
|
});
|
|
73690
74536
|
// node_modules/@agentclientprotocol/sdk/dist/acp.js
|
|
73691
|
-
function ndJsonStream2(output2, input2) {
|
|
73692
|
-
return ndJsonStream(output2, input2);
|
|
74537
|
+
function ndJsonStream2(output2, input2, options) {
|
|
74538
|
+
return ndJsonStream(output2, input2, options);
|
|
73693
74539
|
}
|
|
73694
74540
|
function emptyObjectResponse(response) {
|
|
73695
74541
|
return response ?? {};
|
|
@@ -73974,8 +74820,8 @@ class AsyncQueue {
|
|
|
73974
74820
|
if (this.failed) {
|
|
73975
74821
|
return Promise.reject(this.failure);
|
|
73976
74822
|
}
|
|
73977
|
-
return new Promise((
|
|
73978
|
-
this.waiters.push({ resolve:
|
|
74823
|
+
return new Promise((resolve5, reject) => {
|
|
74824
|
+
this.waiters.push({ resolve: resolve5, reject });
|
|
73979
74825
|
});
|
|
73980
74826
|
}
|
|
73981
74827
|
}
|
|
@@ -74703,7 +75549,7 @@ function classifyBlock2(info) {
|
|
|
74703
75549
|
}
|
|
74704
75550
|
|
|
74705
75551
|
// src/device-login.ts
|
|
74706
|
-
import { spawn as
|
|
75552
|
+
import { spawn as spawn6 } from "child_process";
|
|
74707
75553
|
class DeviceLoginError2 extends Error {
|
|
74708
75554
|
}
|
|
74709
75555
|
async function runDeviceLogin2(apiUrl) {
|
|
@@ -74721,7 +75567,7 @@ async function runDeviceLogin2(apiUrl) {
|
|
|
74721
75567
|
`);
|
|
74722
75568
|
try {
|
|
74723
75569
|
const [cmd, args] = process.platform === "win32" ? ["cmd", ["/c", "start", "", url2]] : [process.platform === "darwin" ? "open" : "xdg-open", [url2]];
|
|
74724
|
-
const child =
|
|
75570
|
+
const child = spawn6(cmd, args, { stdio: "ignore", detached: true });
|
|
74725
75571
|
child.on("error", () => {});
|
|
74726
75572
|
child.unref();
|
|
74727
75573
|
} catch {}
|
|
@@ -74751,7 +75597,7 @@ async function runDeviceLogin2(apiUrl) {
|
|
|
74751
75597
|
}
|
|
74752
75598
|
|
|
74753
75599
|
// src/acp.ts
|
|
74754
|
-
var
|
|
75600
|
+
var log3 = (...a) => process.stderr.write(`[acp] ${a.join(" ")}
|
|
74755
75601
|
`);
|
|
74756
75602
|
var ACP_KIND = { create: "edit", edit: "edit", read: "read", search: "search", shell: "execute" };
|
|
74757
75603
|
var toolTitle = (info) => {
|
|
@@ -74827,7 +75673,7 @@ class TodoforaiAgent {
|
|
|
74827
75673
|
}
|
|
74828
75674
|
this.api = new ApiClient(this.apiUrl, this.apiKey);
|
|
74829
75675
|
this.ws = ws;
|
|
74830
|
-
|
|
75676
|
+
log3(`ready (${this.apiUrl})`);
|
|
74831
75677
|
})();
|
|
74832
75678
|
}
|
|
74833
75679
|
async requireAuth() {
|
|
@@ -74872,7 +75718,7 @@ class TodoforaiAgent {
|
|
|
74872
75718
|
const agent2 = await this.resolveAgent(cwd);
|
|
74873
75719
|
const todoId = randomUUID2();
|
|
74874
75720
|
this.sessions.set(todoId, { todoId, projectId, agent: agent2 });
|
|
74875
|
-
|
|
75721
|
+
log3(`session ${todoId} agent=${agent2.name} cwd=${cwd}`);
|
|
74876
75722
|
return { sessionId: todoId, modes: await this.modes(agent2) };
|
|
74877
75723
|
}
|
|
74878
75724
|
async setSessionMode(p) {
|
|
@@ -74883,7 +75729,7 @@ class TodoforaiAgent {
|
|
|
74883
75729
|
if (!agent2)
|
|
74884
75730
|
throw RequestError.invalidParams(`unknown agent ${p.modeId}`);
|
|
74885
75731
|
s.agent = agent2;
|
|
74886
|
-
|
|
75732
|
+
log3(`session ${s.todoId} agent=${agent2.name}`);
|
|
74887
75733
|
this.conn.sessionUpdate({ sessionId: p.sessionId, update: { sessionUpdate: "current_mode_update", currentModeId: agent2.id } });
|
|
74888
75734
|
return {};
|
|
74889
75735
|
}
|
|
@@ -74893,7 +75739,7 @@ class TodoforaiAgent {
|
|
|
74893
75739
|
return;
|
|
74894
75740
|
s.turn.cancelled = true;
|
|
74895
75741
|
if (s.turn.started && !await this.ws.sendInterrupt(s.projectId, s.todoId))
|
|
74896
|
-
|
|
75742
|
+
log3("interrupt not delivered (socket down)");
|
|
74897
75743
|
}
|
|
74898
75744
|
async prompt(p) {
|
|
74899
75745
|
const s = this.sessions.get(p.sessionId);
|
|
@@ -74908,7 +75754,7 @@ ${b.resource.text}
|
|
|
74908
75754
|
</file>
|
|
74909
75755
|
` : "").join("");
|
|
74910
75756
|
const sessionId = p.sessionId;
|
|
74911
|
-
const update = (u) => this.conn.sessionUpdate({ sessionId, update: u }).catch((e) =>
|
|
75757
|
+
const update = (u) => this.conn.sessionUpdate({ sessionId, update: u }).catch((e) => log3("update failed", e?.message));
|
|
74912
75758
|
const blocks4 = new Map;
|
|
74913
75759
|
const view = (id) => blocks4.get(id) ?? blocks4.set(id, new BlockView).get(id);
|
|
74914
75760
|
const announce = (id, b) => {
|
|
@@ -74942,9 +75788,9 @@ ${b.resource.text}
|
|
|
74942
75788
|
return;
|
|
74943
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);
|
|
74944
75790
|
if (!ok)
|
|
74945
|
-
|
|
75791
|
+
log3(`approval for ${id} not delivered (socket down)`);
|
|
74946
75792
|
} catch (e) {
|
|
74947
|
-
|
|
75793
|
+
log3("permission request failed", e?.message);
|
|
74948
75794
|
}
|
|
74949
75795
|
};
|
|
74950
75796
|
const onEvent = (type, payload) => {
|
|
@@ -75020,18 +75866,18 @@ ${b.resource.text}
|
|
|
75020
75866
|
async function runAcp(apiUrl, apiKey, opts) {
|
|
75021
75867
|
console.log = (...a) => process.stderr.write(a.map(String).join(" ") + `
|
|
75022
75868
|
`);
|
|
75023
|
-
const eof = new Promise((
|
|
75024
|
-
process.stdin.once("end",
|
|
75025
|
-
process.stdin.once("close",
|
|
75026
|
-
process.stdin.once("error",
|
|
75869
|
+
const eof = new Promise((resolve5) => {
|
|
75870
|
+
process.stdin.once("end", resolve5);
|
|
75871
|
+
process.stdin.once("close", resolve5);
|
|
75872
|
+
process.stdin.once("error", resolve5);
|
|
75027
75873
|
});
|
|
75028
75874
|
const stream = ndJsonStream2(Writable.toWeb(process.stdout), Readable.toWeb(process.stdin));
|
|
75029
75875
|
let agent2;
|
|
75030
75876
|
new AgentSideConnection((conn) => agent2 = new TodoforaiAgent(conn, apiUrl, apiKey, opts), stream);
|
|
75031
75877
|
if (apiKey)
|
|
75032
|
-
agent2.connect().catch((e) =>
|
|
75878
|
+
agent2.connect().catch((e) => log3("connect failed:", e?.message));
|
|
75033
75879
|
else
|
|
75034
|
-
|
|
75880
|
+
log3("not logged in — waiting for authenticate");
|
|
75035
75881
|
await eof;
|
|
75036
75882
|
await agent2.close();
|
|
75037
75883
|
}
|
|
@@ -75124,12 +75970,15 @@ function installSignalHandlers() {
|
|
|
75124
75970
|
}
|
|
75125
75971
|
|
|
75126
75972
|
// src/index.ts
|
|
75973
|
+
var ownPkg;
|
|
75127
75974
|
try {
|
|
75128
|
-
|
|
75129
|
-
|
|
75975
|
+
ownPkg = JSON.parse(readFileSync5(path4.resolve(fileURLToPath(import.meta.url), "../../package.json"), "utf-8"));
|
|
75976
|
+
if (process.argv[2] !== "update")
|
|
75977
|
+
backgroundUpdate(ownPkg);
|
|
75130
75978
|
} catch {}
|
|
75979
|
+
var aliasTodoId = (alias) => typeof alias === "string" && alias.includes(":") ? alias.slice(0, alias.indexOf(":")) : undefined;
|
|
75131
75980
|
function formatPathWithTilde(path5) {
|
|
75132
|
-
const home =
|
|
75981
|
+
const home = homedir5();
|
|
75133
75982
|
return path5.startsWith(home) ? path5.replace(home, "~") : path5;
|
|
75134
75983
|
}
|
|
75135
75984
|
function promptArg(words) {
|
|
@@ -75239,6 +76088,10 @@ async function main() {
|
|
|
75239
76088
|
console.log(VERSION);
|
|
75240
76089
|
process.exit(0);
|
|
75241
76090
|
}
|
|
76091
|
+
if (positionals[0] === "update") {
|
|
76092
|
+
const r = ownPkg ? await selfUpdate(ownPkg) : "unsupported";
|
|
76093
|
+
process.exit(r === "updated" || r === "current" ? 0 : 1);
|
|
76094
|
+
}
|
|
75242
76095
|
if (positionals[0] === "status" && args.help) {
|
|
75243
76096
|
printStatusHelp();
|
|
75244
76097
|
process.exit(0);
|
|
@@ -75275,11 +76128,19 @@ async function main() {
|
|
|
75275
76128
|
printNotifyHelp();
|
|
75276
76129
|
process.exit(0);
|
|
75277
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
|
+
}
|
|
75278
76139
|
if ((positionals[0] === "list" || positionals[0] === "ls") && args.help) {
|
|
75279
76140
|
printListTodosHelp();
|
|
75280
76141
|
process.exit(0);
|
|
75281
76142
|
}
|
|
75282
|
-
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])) {
|
|
75283
76144
|
printUsage();
|
|
75284
76145
|
process.exit(0);
|
|
75285
76146
|
}
|
|
@@ -75308,7 +76169,7 @@ async function main() {
|
|
|
75308
76169
|
}
|
|
75309
76170
|
if (args["reset-config"]) {
|
|
75310
76171
|
const { unlinkSync } = await import("fs");
|
|
75311
|
-
if (
|
|
76172
|
+
if (existsSync4(cfg.path)) {
|
|
75312
76173
|
unlinkSync(cfg.path);
|
|
75313
76174
|
console.log(`Configuration reset: ${formatPathWithTilde(cfg.path)}`);
|
|
75314
76175
|
} else
|
|
@@ -75418,6 +76279,10 @@ async function main() {
|
|
|
75418
76279
|
await notifyCommand(api2, positionals, args, scopedProject);
|
|
75419
76280
|
return;
|
|
75420
76281
|
}
|
|
76282
|
+
if (positionals[0] === "import") {
|
|
76283
|
+
await importCommand(api2, positionals, args, scopedProject, cfgScope.data.default_agent_settings?.id);
|
|
76284
|
+
return;
|
|
76285
|
+
}
|
|
75421
76286
|
if (positionals[0] === "delete") {
|
|
75422
76287
|
const todoId = positionals[1];
|
|
75423
76288
|
if (!todoId) {
|
|
@@ -75472,14 +76337,16 @@ async function main() {
|
|
|
75472
76337
|
const kind = it.url ? `url ${it.url}` : it.mime || "";
|
|
75473
76338
|
const card = it.cardRef ? ` card=${it.cardRef}` : "";
|
|
75474
76339
|
const link = it.display === "link" ? " link" : "";
|
|
75475
|
-
|
|
76340
|
+
const shared = it.shareUrl ? ` ${it.shareUrl}` : "";
|
|
76341
|
+
console.log(`${it.ref} ${it.title || it.filename || ""} ${kind}${card}${link}${shared}`);
|
|
75476
76342
|
}
|
|
75477
76343
|
return;
|
|
75478
76344
|
}
|
|
75479
|
-
|
|
76345
|
+
const showSub = positionals[1];
|
|
76346
|
+
if (positionals[0] === "show" && (showSub === "rm" || showSub === "share" || showSub === "unshare")) {
|
|
75480
76347
|
const arg = positionals[2];
|
|
75481
76348
|
if (!arg) {
|
|
75482
|
-
process.stderr.write(`${RED3}Usage: tfa-cli show
|
|
76349
|
+
process.stderr.write(`${RED3}Usage: tfa-cli show ${showSub} <ref|alias>${RESET2}
|
|
75483
76350
|
`);
|
|
75484
76351
|
process.exit(2);
|
|
75485
76352
|
}
|
|
@@ -75487,18 +76354,30 @@ async function main() {
|
|
|
75487
76354
|
const todoId = sep >= 0 ? arg.slice(0, sep) : getEnv("TODO_ID") || cfgScope.data.last_todo_id;
|
|
75488
76355
|
const key = sep >= 0 ? arg.slice(sep + 1) : arg;
|
|
75489
76356
|
if (!todoId || !key) {
|
|
75490
|
-
process.stderr.write(`${RED3}show
|
|
76357
|
+
process.stderr.write(`${RED3}show ${showSub}: need <todoId>:<alias> (no current todo)${RESET2}
|
|
75491
76358
|
`);
|
|
75492
76359
|
process.exit(2);
|
|
75493
76360
|
}
|
|
75494
|
-
|
|
75495
|
-
|
|
76361
|
+
if (showSub === "rm") {
|
|
76362
|
+
await api2.removeShow(todoId, key);
|
|
76363
|
+
process.stderr.write(`${GREEN2}\u2705 removed ${todoId}:${key}${RESET2}
|
|
75496
76364
|
`);
|
|
76365
|
+
} else if (showSub === "share") {
|
|
76366
|
+
const res = await api2.shareShow(todoId, key);
|
|
76367
|
+
if (args.json)
|
|
76368
|
+
console.log(JSON.stringify(res, null, 2));
|
|
76369
|
+
else
|
|
76370
|
+
console.log(res.url);
|
|
76371
|
+
} else {
|
|
76372
|
+
await api2.unshareShow(todoId, key);
|
|
76373
|
+
process.stderr.write(`${GREEN2}\u2705 ${todoId}:${key} is private again${RESET2}
|
|
76374
|
+
`);
|
|
76375
|
+
}
|
|
75497
76376
|
return;
|
|
75498
76377
|
}
|
|
75499
76378
|
if (positionals[0] === "show") {
|
|
75500
76379
|
const [, filePath, todoArg] = positionals;
|
|
75501
|
-
const todoId = todoArg || getEnv("TODO_ID") || cfgScope.data.last_todo_id;
|
|
76380
|
+
const todoId = todoArg || aliasTodoId(args.alias) || getEnv("TODO_ID") || cfgScope.data.last_todo_id;
|
|
75502
76381
|
if (!filePath || !todoId) {
|
|
75503
76382
|
process.stderr.write(`${RED3}Usage: tfa-cli show <file|-> [todo-id] [--title T] [--alias A] [--mime M] [--card <name>] [--link]${RESET2}
|
|
75504
76383
|
`);
|
|
@@ -75517,13 +76396,13 @@ async function main() {
|
|
|
75517
76396
|
}
|
|
75518
76397
|
name = "stdin";
|
|
75519
76398
|
} else {
|
|
75520
|
-
const abs =
|
|
75521
|
-
if (!
|
|
76399
|
+
const abs = resolve5(filePath);
|
|
76400
|
+
if (!existsSync4(abs)) {
|
|
75522
76401
|
process.stderr.write(`${RED3}File not found: ${filePath}${RESET2}
|
|
75523
76402
|
`);
|
|
75524
76403
|
process.exit(1);
|
|
75525
76404
|
}
|
|
75526
|
-
blob = new Blob([
|
|
76405
|
+
blob = new Blob([readFileSync5(abs)], { type: getMimeTypeFromFilename(abs) || undefined });
|
|
75527
76406
|
name = path4.basename(filePath);
|
|
75528
76407
|
}
|
|
75529
76408
|
const res = await api2.showFile(todoId, blob, name, {
|
|
@@ -75536,12 +76415,12 @@ async function main() {
|
|
|
75536
76415
|
if (args.json)
|
|
75537
76416
|
console.log(JSON.stringify(res, null, 2));
|
|
75538
76417
|
else
|
|
75539
|
-
console.log(res.
|
|
76418
|
+
console.log(res.shareUrl ? `${res.ref} ${res.shareUrl}` : res.ref);
|
|
75540
76419
|
return;
|
|
75541
76420
|
}
|
|
75542
76421
|
if (positionals[0] === "open") {
|
|
75543
76422
|
const [, url2, todoArg] = positionals;
|
|
75544
|
-
const todoId = todoArg || getEnv("TODO_ID") || cfgScope.data.last_todo_id;
|
|
76423
|
+
const todoId = todoArg || aliasTodoId(args.alias) || getEnv("TODO_ID") || cfgScope.data.last_todo_id;
|
|
75545
76424
|
if (!url2 || !todoId) {
|
|
75546
76425
|
process.stderr.write(`${RED3}Usage: tfa-cli open <url> [todo-id]${RESET2}
|
|
75547
76426
|
`);
|
|
@@ -75855,7 +76734,7 @@ Resumed: ${CYAN2}${getFrontendUrl(apiUrl, todoId)}${RESET2}
|
|
|
75855
76734
|
const wsReady = ws ? ws.connect() : null;
|
|
75856
76735
|
const bridgeReady = !args["no-bridge"] && !args["no-watch"] && !args.isolated ? ensureBridgeRunning2(apiUrl, apiKey) : null;
|
|
75857
76736
|
const isolatedTodoId = args.isolated ? randomUUID3() : undefined;
|
|
75858
|
-
const mayfly = isolatedTodoId ? await spawnMayflyBridge(apiUrl, isolatedTodoId, realpathSync2(
|
|
76737
|
+
const mayfly = isolatedTodoId ? await spawnMayflyBridge(apiUrl, isolatedTodoId, realpathSync2(resolve5(args.path || ".")), { debug: !!args.debug, apiKey }) : null;
|
|
75859
76738
|
if (mayfly) {
|
|
75860
76739
|
process.stderr.write(`${DIM2}Isolated bridge:${RESET2} ${CYAN2}mayfly-${isolatedTodoId}${RESET2}
|
|
75861
76740
|
`);
|
|
@@ -75887,7 +76766,7 @@ Resumed: ${CYAN2}${getFrontendUrl(apiUrl, todoId)}${RESET2}
|
|
|
75887
76766
|
cfgScope.setDefaultAgent(getDisplayName(preMatchedAgent), preMatchedAgent);
|
|
75888
76767
|
} else {
|
|
75889
76768
|
const pathArg = args.path || ".";
|
|
75890
|
-
const resolved = realpathSync2(
|
|
76769
|
+
const resolved = realpathSync2(resolve5(pathArg));
|
|
75891
76770
|
const matches = await api2.listAgentSettings({ workspacePath: resolved });
|
|
75892
76771
|
if (matches.length > 0) {
|
|
75893
76772
|
preMatchedAgent = matches[0];
|
|
@@ -75960,7 +76839,7 @@ Resumed: ${CYAN2}${getFrontendUrl(apiUrl, todoId)}${RESET2}
|
|
|
75960
76839
|
if (args.model)
|
|
75961
76840
|
agent2 = { ...agent2, model: args.model };
|
|
75962
76841
|
if (args["raw-sysmsg"]) {
|
|
75963
|
-
const sysmsg =
|
|
76842
|
+
const sysmsg = readFileSync5(resolve5(args["raw-sysmsg"]), "utf-8");
|
|
75964
76843
|
agent2 = { ...agent2, systemMessage: sysmsg, systemMessageMode: "raw" };
|
|
75965
76844
|
}
|
|
75966
76845
|
if (args["allow-all"]) {
|