@todoforai/cli 0.1.66 → 0.1.67
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 +2 -0
- package/dist/todoforai-cli.js +412 -114
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,6 +39,8 @@ echo "content" | tfa-cli # pipe from stdin
|
|
|
39
39
|
tfa-cli --path /my/project "Fix bug" # explicit workspace
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
Ctrl+C (or closing the terminal) only exits the CLI — the todo keeps running; `tfa-cli --resume <id>` reattaches. Exception: `--isolated` runs are stopped, since they can't outlive their bridge.
|
|
43
|
+
|
|
42
44
|
### Start from a registry template
|
|
43
45
|
|
|
44
46
|
```bash
|
package/dist/todoforai-cli.js
CHANGED
|
@@ -42969,6 +42969,9 @@ class ApiClient {
|
|
|
42969
42969
|
unshareDevice(id, email) {
|
|
42970
42970
|
return this.request("POST", `/api/v1/devices/${id}/unshare`, { id, email });
|
|
42971
42971
|
}
|
|
42972
|
+
leaveDevice(id) {
|
|
42973
|
+
return this.request("POST", `/api/v1/devices/${id}/leave`, { id });
|
|
42974
|
+
}
|
|
42972
42975
|
setDeviceWallpaperMode(id, mode) {
|
|
42973
42976
|
return this.request("POST", `/api/v1/devices/${id}/wallpaper-mode`, { id, mode });
|
|
42974
42977
|
}
|
|
@@ -43008,6 +43011,15 @@ class ApiClient {
|
|
|
43008
43011
|
listProjectGroups(projectId) {
|
|
43009
43012
|
return this.request("GET", `/api/v1/projects/${projectId}/groups`);
|
|
43010
43013
|
}
|
|
43014
|
+
getProjectGroupIntake(projectId, groupTag) {
|
|
43015
|
+
return this.request("GET", `/api/v1/projects/${projectId}/groups/${encodeURIComponent(groupTag)}/intake`);
|
|
43016
|
+
}
|
|
43017
|
+
updateProjectGroupIntake(projectId, groupTag, fields) {
|
|
43018
|
+
return this.request("PUT", `/api/v1/projects/${projectId}/groups/${encodeURIComponent(groupTag)}/intake`, { projectId, groupTag, ...fields });
|
|
43019
|
+
}
|
|
43020
|
+
regenerateProjectGroupIntake(projectId, groupTag) {
|
|
43021
|
+
return this.request("POST", `/api/v1/projects/${projectId}/groups/${encodeURIComponent(groupTag)}/intake/regenerate`, { projectId, groupTag });
|
|
43022
|
+
}
|
|
43011
43023
|
upsertProjectGroup(projectId, slug, fields) {
|
|
43012
43024
|
return this.request("PUT", `/api/v1/projects/${projectId}/groups/${encodeURIComponent(slug)}`, { projectId, slug, ...fields });
|
|
43013
43025
|
}
|
|
@@ -43609,6 +43621,7 @@ var TodoStatus;
|
|
|
43609
43621
|
TodoStatus2["PAUSED"] = "PAUSED";
|
|
43610
43622
|
TodoStatus2["POSTPONED"] = "POSTPONED";
|
|
43611
43623
|
TodoStatus2["REVIEW_REQUESTED"] = "REVIEW_REQUESTED";
|
|
43624
|
+
TodoStatus2["WAITING_AGENT"] = "WAITING_AGENT";
|
|
43612
43625
|
TodoStatus2["RUNNING"] = "RUNNING";
|
|
43613
43626
|
TodoStatus2["WAITING_FOR_USER"] = "WAITING_FOR_USER";
|
|
43614
43627
|
TodoStatus2["COMPACTING"] = "COMPACTING";
|
|
@@ -43623,6 +43636,11 @@ var TodoStatus;
|
|
|
43623
43636
|
TodoStatus2["ARCHIVED"] = "ARCHIVED";
|
|
43624
43637
|
TodoStatus2["DELETED"] = "DELETED";
|
|
43625
43638
|
})(TodoStatus ||= {});
|
|
43639
|
+
var CLOSED_STATUSES = [
|
|
43640
|
+
"DONE" /* DONE */,
|
|
43641
|
+
"ARCHIVED" /* ARCHIVED */,
|
|
43642
|
+
"DELETED" /* DELETED */
|
|
43643
|
+
];
|
|
43626
43644
|
// ../packages/shared-fbe/src/constants.ts
|
|
43627
43645
|
var APPEAL_EMAIL = "support@todofor.ai";
|
|
43628
43646
|
var ACCOUNT_SUSPENDED_MESSAGE = `Account suspended for suspected abuse. If you think this is a mistake, email ${APPEAL_EMAIL}.`;
|
|
@@ -43639,22 +43657,28 @@ var PROVIDER_BY_AUTHOR = {
|
|
|
43639
43657
|
"x-ai": "xai",
|
|
43640
43658
|
"z-ai": "z.ai",
|
|
43641
43659
|
google: "google-ai-studio",
|
|
43642
|
-
moonshotai: "opencode_go"
|
|
43660
|
+
moonshotai: "opencode_go",
|
|
43661
|
+
meta: "meta"
|
|
43643
43662
|
};
|
|
43644
43663
|
var MODEL_PROVIDER_OVERRIDES = {
|
|
43645
43664
|
"openai/gpt-5.5-pro": "openrouter"
|
|
43646
43665
|
};
|
|
43666
|
+
var MODEL_ENDPOINT_OVERRIDES = {
|
|
43667
|
+
"google/gemini-4-argon": { "google-ai-studio": "vertex" }
|
|
43668
|
+
};
|
|
43647
43669
|
function resolveDispatchProvider(modelId, endpointProvider) {
|
|
43648
|
-
|
|
43670
|
+
const id = modelId.toLowerCase();
|
|
43671
|
+
return MODEL_PROVIDER_OVERRIDES[id] ?? MODEL_ENDPOINT_OVERRIDES[id]?.[endpointProvider.toLowerCase()] ?? endpointProvider;
|
|
43649
43672
|
}
|
|
43650
43673
|
var SUBSCRIPTION_PROVIDERS = new Set(["opencode_go"]);
|
|
43651
43674
|
function applyProviderOverride(qualified) {
|
|
43652
43675
|
const colon = qualified.indexOf(":");
|
|
43676
|
+
const provider = qualified.slice(0, colon);
|
|
43653
43677
|
const rest = qualified.slice(colon + 1);
|
|
43654
43678
|
const suffix = rest.match(/\([^)]+\)$/)?.[0] ?? "";
|
|
43655
43679
|
const bare = (suffix ? rest.slice(0, -suffix.length) : rest).toLowerCase();
|
|
43656
|
-
const
|
|
43657
|
-
return
|
|
43680
|
+
const resolved = resolveDispatchProvider(bare, provider);
|
|
43681
|
+
return resolved === provider ? qualified : `${resolved}:${bare}${suffix}`;
|
|
43658
43682
|
}
|
|
43659
43683
|
function isQualifiedModel(model) {
|
|
43660
43684
|
const id = model.trim();
|
|
@@ -43677,9 +43701,9 @@ function qualifyModel(model) {
|
|
|
43677
43701
|
const override = MODEL_PROVIDER_OVERRIDES[lower];
|
|
43678
43702
|
if (override)
|
|
43679
43703
|
return { model: `${override}:${lower}${suffix}` };
|
|
43680
|
-
const
|
|
43681
|
-
if (
|
|
43682
|
-
return { model: `${
|
|
43704
|
+
const author = PROVIDER_BY_AUTHOR[lower.split("/")[0]];
|
|
43705
|
+
if (author && lower.includes("/"))
|
|
43706
|
+
return { model: `${resolveDispatchProvider(lower, author)}:${lower}${suffix}` };
|
|
43683
43707
|
return { model: id };
|
|
43684
43708
|
}
|
|
43685
43709
|
function qualifiedModelIds(listing, filter) {
|
|
@@ -43738,6 +43762,7 @@ var mimetypes_default = {
|
|
|
43738
43762
|
js: { mime: "text/javascript", type: "text" },
|
|
43739
43763
|
ts: { mime: "text/typescript", type: "text" },
|
|
43740
43764
|
html: { mime: "text/html", type: "text" },
|
|
43765
|
+
htm: { mime: "text/html", type: "text" },
|
|
43741
43766
|
css: { mime: "text/css", type: "text" },
|
|
43742
43767
|
xml: { mime: "text/xml", type: "text" },
|
|
43743
43768
|
py: { mime: "text/x-python", type: "text" },
|
|
@@ -43776,7 +43801,7 @@ var mimetypes_default = {
|
|
|
43776
43801
|
docx: { mime: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", type: "document", tags: ["docx"] },
|
|
43777
43802
|
ppt: { mime: "application/vnd.ms-powerpoint", type: "document" },
|
|
43778
43803
|
pptx: { mime: "application/vnd.openxmlformats-officedocument.presentationml.presentation", type: "document", tags: ["pptx"] },
|
|
43779
|
-
xls: { mime: "application/vnd.ms-excel", type: "spreadsheet" },
|
|
43804
|
+
xls: { mime: "application/vnd.ms-excel", type: "spreadsheet", tags: ["xls"] },
|
|
43780
43805
|
xlsx: { mime: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", type: "spreadsheet", tags: ["xlsx"] },
|
|
43781
43806
|
zip: { mime: "application/zip", type: "archive" },
|
|
43782
43807
|
rar: { mime: "application/vnd.rar", type: "archive" },
|
|
@@ -44169,6 +44194,8 @@ var USER_HEADINGS = new Set([
|
|
|
44169
44194
|
"steps",
|
|
44170
44195
|
"data needed"
|
|
44171
44196
|
]);
|
|
44197
|
+
// ../packages/shared-fbe/src/bridgeProtocol.ts
|
|
44198
|
+
var ADB_DATA_CHUNK = 40 * 1024;
|
|
44172
44199
|
// ../packages/shared-fbe/src/bashPatterns.ts
|
|
44173
44200
|
function splitShellCommands(input) {
|
|
44174
44201
|
const parts = [];
|
|
@@ -44410,7 +44437,6 @@ function getBlockServerId(block) {
|
|
|
44410
44437
|
const prefix = getBlockServerPrefix(block);
|
|
44411
44438
|
return prefix ? prefix.slice(0, -1) : "*";
|
|
44412
44439
|
}
|
|
44413
|
-
|
|
44414
44440
|
// ../packages/shared-fbe/src/permissionUtils.ts
|
|
44415
44441
|
function parsePattern(pattern) {
|
|
44416
44442
|
const colonIndex = pattern.indexOf(":");
|
|
@@ -44640,7 +44666,7 @@ Exactly ONE \`api_recommend_template\` call per proposal: it carries both what t
|
|
|
44640
44666
|
};
|
|
44641
44667
|
var JARVIS_AGENT = {
|
|
44642
44668
|
id: "00000000-0000-0000-0000-202601013152",
|
|
44643
|
-
name: "
|
|
44669
|
+
name: "Tod",
|
|
44644
44670
|
ownerId: "SYSTEM",
|
|
44645
44671
|
systemMessage: "",
|
|
44646
44672
|
model: "",
|
|
@@ -45173,7 +45199,7 @@ var tool_catalog_default = {
|
|
|
45173
45199
|
installer: "npm",
|
|
45174
45200
|
label: "TODOforAI",
|
|
45175
45201
|
summary: "Create and follow up on your TODOs, and show results in the chat.",
|
|
45176
|
-
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.',
|
|
45202
|
+
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. Show viewer chrome: `--title` appears in the header; a kebab menu holds file actions, versions and sharing when available. Desktop floating previews add minimize (park in a tab), maximize/restore and close (X); inline blocks have no window controls. For authored HTML, do not duplicate the header/controls or add a rounded, bordered root card: the floating viewer owns the rounded frame. Keep content edge-to-edge; internal layout padding is fine. 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. Project files: `memory sync|path [--project <id>]` requires a project and checks out only projects/<id>/{memory,context} and projects/<id>/me/{memory,context}; legacy global files are read-only recovery. Voice commands use `--scope mine|project` (default mine, private within this project; project is shared).',
|
|
45177
45203
|
installCmd: "npm install -g @todoforai/cli",
|
|
45178
45204
|
versionCmd: "tfa-cli --version 2>/dev/null | sed -n 1p",
|
|
45179
45205
|
preinstallCloud: true,
|
|
@@ -49944,21 +49970,67 @@ var tool_catalog_default = {
|
|
|
49944
49970
|
},
|
|
49945
49971
|
statusCmd: `zoo user view --format json 2>/dev/null | sed -n 's/.*"email": *"\\([^"]*\\)".*/\\1/p' | grep -m1 .`,
|
|
49946
49972
|
loginCmd: "zoo auth login --web",
|
|
49973
|
+
logoutCmd: "printf 'y\\n' | zoo --host api.zoo.dev auth logout",
|
|
49947
49974
|
loginNeedsPty: true,
|
|
49948
49975
|
deviceCodePattern: "user code: ([A-Z0-9]{4}-[A-Z0-9]{4})",
|
|
49949
|
-
oauthUrlPattern: "(https://api\\.zoo\\.dev/oauth2/device/verify
|
|
49976
|
+
oauthUrlPattern: "(https://api\\.zoo\\.dev/oauth2/device/verify\\?[^\\s']+)",
|
|
49950
49977
|
canStreamLogin: true,
|
|
49951
49978
|
credentialPaths: [
|
|
49952
49979
|
"~/.config/zoo/hosts.toml"
|
|
49953
49980
|
],
|
|
49954
49981
|
description: 'Official Zoo (KittyCAD) CLI. Text-to-CAD: `zoo ml text-to-cad export --output-format step "a 40mm gear"`; convert: `zoo file convert in.obj out/ --output-format step`; mass/volume: `zoo file mass|volume <file>`; KCL: `zoo kcl export|snapshot`; raw: `zoo api /user`. Token alternative: `echo <token> | zoo auth login --with-token`.',
|
|
49955
49982
|
versionCmd: "zoo --version 2>/dev/null | sed -n 1p"
|
|
49983
|
+
},
|
|
49984
|
+
"python-docx": {
|
|
49985
|
+
category: "documents",
|
|
49986
|
+
pkg: "python-docx",
|
|
49987
|
+
pipModules: ["docx"],
|
|
49988
|
+
installer: "pip",
|
|
49989
|
+
label: "Word documents",
|
|
49990
|
+
summary: "Create, read and edit Word documents.",
|
|
49991
|
+
versionCmd: `{ "$HOME/.todoforai/tools/venv/bin/python" -c 'import docx; print(docx.__version__)' || python -c 'import docx; print(docx.__version__)' || python3 -c 'import docx; print(docx.__version__)' || py -c 'import docx; print(docx.__version__)'; } 2>/dev/null`,
|
|
49992
|
+
description: "Python python-docx library. Use python3 to create, save, reopen and edit Office files; no Microsoft account required."
|
|
49993
|
+
},
|
|
49994
|
+
openpyxl: {
|
|
49995
|
+
category: "documents",
|
|
49996
|
+
pkg: "openpyxl",
|
|
49997
|
+
pipModules: ["openpyxl"],
|
|
49998
|
+
installer: "pip",
|
|
49999
|
+
label: "Excel workbooks",
|
|
50000
|
+
summary: "Create, read and edit Excel workbooks.",
|
|
50001
|
+
versionCmd: `{ "$HOME/.todoforai/tools/venv/bin/python" -c 'import openpyxl; print(openpyxl.__version__)' || python -c 'import openpyxl; print(openpyxl.__version__)' || python3 -c 'import openpyxl; print(openpyxl.__version__)' || py -c 'import openpyxl; print(openpyxl.__version__)'; } 2>/dev/null`,
|
|
50002
|
+
description: "Python openpyxl library. Use python3 to create, save, reopen and edit Office files; no Microsoft account required."
|
|
50003
|
+
},
|
|
50004
|
+
"python-pptx": {
|
|
50005
|
+
category: "documents",
|
|
50006
|
+
pkg: "python-pptx",
|
|
50007
|
+
pipModules: ["pptx"],
|
|
50008
|
+
installer: "pip",
|
|
50009
|
+
label: "PowerPoint decks",
|
|
50010
|
+
summary: "Create, read and edit PowerPoint decks.",
|
|
50011
|
+
versionCmd: `{ "$HOME/.todoforai/tools/venv/bin/python" -c 'import pptx; print(pptx.__version__)' || python -c 'import pptx; print(pptx.__version__)' || python3 -c 'import pptx; print(pptx.__version__)' || py -c 'import pptx; print(pptx.__version__)'; } 2>/dev/null`,
|
|
50012
|
+
description: "Python python-pptx library. Use python3 to create, save, reopen and edit Office files; no Microsoft account required."
|
|
50013
|
+
},
|
|
50014
|
+
"modal-h3": {
|
|
50015
|
+
category: "creative",
|
|
50016
|
+
pkg: "@todoforai/modal-h3",
|
|
50017
|
+
installer: "npm",
|
|
50018
|
+
label: "MiniMax-H3 on Modal",
|
|
50019
|
+
summary: "Generate videos with sound using MiniMax-H3 on your own Modal GPUs.",
|
|
50020
|
+
versionCmd: "modal-h3 --version 2>/dev/null | sed -n 1p",
|
|
50021
|
+
statusCmd: `modal-h3 whoami 2>/dev/null | grep '"authenticated": true' >/dev/null && echo authenticated`,
|
|
50022
|
+
loginCmd: "printf '%s' <proxy_token> | modal-h3 auth --token-stdin --fl2va-url <fl2va_url> --ref2va-url <ref2va_url>",
|
|
50023
|
+
credentialPaths: ["~/.config/modal-h3/credentials.json"],
|
|
50024
|
+
description: "MiniMax-H3 text/image/reference-to-video+audio on a self-deployed Modal app (SGLang, 4x H200, scale-to-zero). `modal-h3 generate -p '…' [--first @a.png] [--last …] [--ref-image|--ref-video|--ref-audio <url|@file>] [--duration 4-15] [--ratio 16:9|auto] [--quality high] -o out.mp4` (task inferred, retries 503 during cold start, polls, downloads), `warmup`, `status|download|delete <id>`, `list`, `api <METHOD> <path>`. Deploy once with `modal run modal/serve.py::download` + `modal deploy modal/serve.py`. Costs ~$18/h of 4x H200 while a container is up (cold start minutes, ~75 s per 5 s 768p clip warm); every request wakes a container, `whoami` is offline. Jobs live in container memory. 2K needs `minimax-api regenerate`."
|
|
49956
50025
|
}
|
|
49957
50026
|
};
|
|
49958
50027
|
|
|
49959
50028
|
// ../packages/shared-fbe/src/toolCatalog.ts
|
|
49960
50029
|
var TOOL_CATALOG = tool_catalog_default;
|
|
49961
50030
|
// ../packages/shared-fbe/src/toolInstallCommand.ts
|
|
50031
|
+
var NPM_HOME = '"${TFA_NPM_HOME:-$HOME}"';
|
|
50032
|
+
var NPM_TOOLS = NPM_HOME.replace('}"', '}/.todoforai/tools"');
|
|
50033
|
+
var NPM_LOCAL = NPM_HOME.replace('}"', '}/.local"');
|
|
49962
50034
|
var KEY_OF = new Map(Object.entries(TOOL_CATALOG).map(([k, e]) => [e, k]));
|
|
49963
50035
|
var NODE_MIN_MAJOR = 24;
|
|
49964
50036
|
var NODE_OK = `command -v npm >/dev/null 2>&1 && node -e 'process.exit(+process.versions.node.split(".")[0]>=${NODE_MIN_MAJOR}?0:1)' >/dev/null 2>&1`;
|
|
@@ -50200,7 +50272,7 @@ var package_default = {
|
|
|
50200
50272
|
type: "git",
|
|
50201
50273
|
url: "git+https://github.com/todoforai/cli.git"
|
|
50202
50274
|
},
|
|
50203
|
-
version: "0.1.
|
|
50275
|
+
version: "0.1.67",
|
|
50204
50276
|
type: "module",
|
|
50205
50277
|
bin: {
|
|
50206
50278
|
"todoforai-cli": "bin/todoforai-cli.js",
|
|
@@ -50330,6 +50402,13 @@ Usage:
|
|
|
50330
50402
|
|
|
50331
50403
|
todo-id defaults to $TODOFORAI_TODO_ID (agent shell) or the last todo this CLI touched.
|
|
50332
50404
|
|
|
50405
|
+
Viewer chrome:
|
|
50406
|
+
--title appears in the header; a kebab menu holds file actions, versions and sharing when available.
|
|
50407
|
+
Desktop floating previews add minimize (park in a tab), maximize/restore and close (X).
|
|
50408
|
+
Inline blocks have no window controls. Do not draw these controls or a duplicate title bar in authored HTML.
|
|
50409
|
+
The floating viewer owns the rounded frame. Keep the HTML root flat, without a border, radius, shadow or outer margin;
|
|
50410
|
+
internal content padding and spacing are fine. Existing files and websites keep their own styling.
|
|
50411
|
+
|
|
50333
50412
|
When to use what:
|
|
50334
50413
|
read once, move on → plain chat reply
|
|
50335
50414
|
interactive, this chat only → html_snippet (can exec/connect/chat back)
|
|
@@ -51404,15 +51483,20 @@ function blockToAnthropic(block, mode, format) {
|
|
|
51404
51483
|
const msg = block.error_message || block.content || "(unknown error)";
|
|
51405
51484
|
return [{ type: "text", text: `[error] ${msg}` }];
|
|
51406
51485
|
}
|
|
51486
|
+
const name = t === "named_tool" ? block.tool_name === "run_shell" ? "bash" : block.tool_name : t;
|
|
51407
51487
|
const inputFields = [];
|
|
51408
51488
|
for (const [k, v] of Object.entries(block)) {
|
|
51409
|
-
if (BLOCK_META_KEYS.has(k))
|
|
51489
|
+
if (BLOCK_META_KEYS.has(k) || k === "args" || t === "named_tool" && k === "tool_name")
|
|
51410
51490
|
continue;
|
|
51411
51491
|
if (v === undefined || v === null || v === "")
|
|
51412
51492
|
continue;
|
|
51413
51493
|
inputFields.push([k, v]);
|
|
51414
51494
|
}
|
|
51415
|
-
const
|
|
51495
|
+
for (const [k, v] of Object.entries(block.args ?? {})) {
|
|
51496
|
+
if (!inputFields.some(([key]) => key === k))
|
|
51497
|
+
inputFields.push([k, v]);
|
|
51498
|
+
}
|
|
51499
|
+
const use = format === "anthropic" ? { type: "tool_use", id: block.id, name, input: Object.fromEntries(inputFields) } : { type: "tool_use", content: `<${name}${inputFields.map(([k, v]) => ` ${k}=${xmlAttr(v)}`).join("")}/>` };
|
|
51416
51500
|
if (format === "compact" && mode !== "default")
|
|
51417
51501
|
use.id = block.id;
|
|
51418
51502
|
const items = [use];
|
|
@@ -51428,8 +51512,9 @@ function blockToAnthropic(block, mode, format) {
|
|
|
51428
51512
|
source.name = att.originalName;
|
|
51429
51513
|
parts.push({ type: isImage ? "image" : "document", source });
|
|
51430
51514
|
}
|
|
51431
|
-
|
|
51432
|
-
|
|
51515
|
+
const text = r.content || r.meta?.text;
|
|
51516
|
+
if (typeof text === "string" && text)
|
|
51517
|
+
parts.push({ type: "text", text });
|
|
51433
51518
|
return parts;
|
|
51434
51519
|
});
|
|
51435
51520
|
const result = { type: "tool_result", tool_use_id: block.id };
|
|
@@ -51446,8 +51531,9 @@ function blockToAnthropic(block, mode, format) {
|
|
|
51446
51531
|
const nameAttr = att.originalName && !isAutoName ? ` name=${xmlAttr(att.originalName)}` : "";
|
|
51447
51532
|
parts.push(`<attachment uri=${xmlAttr(att.uri)}${nameAttr} size=${att.fileSize}/>`);
|
|
51448
51533
|
}
|
|
51449
|
-
|
|
51450
|
-
|
|
51534
|
+
const text = r.content || r.meta?.text;
|
|
51535
|
+
if (typeof text === "string" && text)
|
|
51536
|
+
parts.push(text);
|
|
51451
51537
|
}
|
|
51452
51538
|
const result = { type: "tool_result", content: parts.join(`
|
|
51453
51539
|
`) };
|
|
@@ -52673,6 +52759,7 @@ function renderDiff(originalContent, modifiedContent, filePath) {
|
|
|
52673
52759
|
|
|
52674
52760
|
// src/shutdown.ts
|
|
52675
52761
|
var activeRun = null;
|
|
52762
|
+
var stopOnExit = false;
|
|
52676
52763
|
var cleanups = [];
|
|
52677
52764
|
var exiting = null;
|
|
52678
52765
|
var cancelling = null;
|
|
@@ -52680,6 +52767,9 @@ var CANCEL_TIMEOUT_MS = 5000;
|
|
|
52680
52767
|
function setActiveRun(run) {
|
|
52681
52768
|
activeRun = run;
|
|
52682
52769
|
}
|
|
52770
|
+
var stopsRunOnExit = () => stopOnExit;
|
|
52771
|
+
var detachNotice = (todoId) => `Todo keeps running — reattach: tfa-cli --resume ${todoId}
|
|
52772
|
+
`;
|
|
52683
52773
|
function withTimeout(p, ms, fallback) {
|
|
52684
52774
|
let timer;
|
|
52685
52775
|
const timeout = new Promise((r) => {
|
|
@@ -52691,7 +52781,7 @@ function cancelActiveRun(timeoutMs = CANCEL_TIMEOUT_MS) {
|
|
|
52691
52781
|
if (cancelling)
|
|
52692
52782
|
return cancelling;
|
|
52693
52783
|
const pending = activeRun;
|
|
52694
|
-
if (!pending)
|
|
52784
|
+
if (!pending || !stopOnExit)
|
|
52695
52785
|
return Promise.resolve({ ok: false, todoId: null });
|
|
52696
52786
|
const res = { ok: false };
|
|
52697
52787
|
const attempt = (async () => {
|
|
@@ -52717,7 +52807,11 @@ function shutdown(code, reason) {
|
|
|
52717
52807
|
process.stderr.write(`
|
|
52718
52808
|
${reason}
|
|
52719
52809
|
`);
|
|
52720
|
-
if (activeRun) {
|
|
52810
|
+
if (activeRun && !stopOnExit) {
|
|
52811
|
+
const run = await withTimeout(Promise.resolve(activeRun), CANCEL_TIMEOUT_MS, null);
|
|
52812
|
+
if (run)
|
|
52813
|
+
process.stderr.write(detachNotice(run.todoId));
|
|
52814
|
+
} else if (activeRun) {
|
|
52721
52815
|
const { ok, todoId } = await cancelActiveRun();
|
|
52722
52816
|
if (ok)
|
|
52723
52817
|
process.stderr.write(`Stopped todo ${todoId}
|
|
@@ -52829,20 +52923,6 @@ async function watchTodo(ws, todoId, projectId, opts = {}) {
|
|
|
52829
52923
|
diffStoreByWs.set(ws, diffStore);
|
|
52830
52924
|
const diffRendered = new Set;
|
|
52831
52925
|
let approveAll = !!opts.autoApprove;
|
|
52832
|
-
let interruptCount = 0;
|
|
52833
|
-
const origHandler = process.listeners("SIGINT").slice();
|
|
52834
|
-
process.removeAllListeners("SIGINT");
|
|
52835
|
-
process.on("SIGINT", () => {
|
|
52836
|
-
interruptCount++;
|
|
52837
|
-
if (opts.exitOnInterrupt || interruptCount >= 2)
|
|
52838
|
-
return void shutdown(130, "Cancelled by user (Ctrl+C)");
|
|
52839
|
-
process.stderr.write(`
|
|
52840
|
-
${YELLOW}Interrupting... (Ctrl+C again to force exit)${RESET}
|
|
52841
|
-
`);
|
|
52842
|
-
if (opts.interruptOnCancel !== false) {
|
|
52843
|
-
ws.sendInterrupt(projectId, todoId);
|
|
52844
|
-
}
|
|
52845
|
-
});
|
|
52846
52926
|
const pendingBlocks = [];
|
|
52847
52927
|
let approvalPromptActive = false;
|
|
52848
52928
|
let activeApprovalBlocks = [];
|
|
@@ -53065,14 +53145,10 @@ ${YELLOW}Connection lost — reconnecting...${RESET}
|
|
|
53065
53145
|
await cancelActiveRun();
|
|
53066
53146
|
process.exitCode = 1;
|
|
53067
53147
|
if (!opts.suppressCancelNotice) {
|
|
53068
|
-
process.stderr.write(`${YELLOW}Interrupted${RESET}
|
|
53069
|
-
`);
|
|
53148
|
+
process.stderr.write(stopsRunOnExit() ? `${YELLOW}Interrupted${RESET}
|
|
53149
|
+
` : detachNotice(todoId));
|
|
53070
53150
|
}
|
|
53071
53151
|
return false;
|
|
53072
|
-
} finally {
|
|
53073
|
-
process.removeAllListeners("SIGINT");
|
|
53074
|
-
for (const fn of origHandler)
|
|
53075
|
-
process.on("SIGINT", fn);
|
|
53076
53152
|
}
|
|
53077
53153
|
}
|
|
53078
53154
|
|
|
@@ -53641,6 +53717,8 @@ Usage:
|
|
|
53641
53717
|
tfa-cli project settings <field=value>… Project settings (PUT /settings/projects/{id})
|
|
53642
53718
|
tfa-cli project groups List todo groups
|
|
53643
53719
|
tfa-cli project groups set <slug> <field=value>… Create/update a group: name description pinned archived order
|
|
53720
|
+
tfa-cli project groups intake <slug> [on|off|regenerate] [field=value]…
|
|
53721
|
+
Public intake: autoStart maxSubmissions postIpLimit placeholder agentSettingsId
|
|
53644
53722
|
tfa-cli project groups reorder <slug>… Set wall order
|
|
53645
53723
|
tfa-cli project surfaces List the board's card surfaces (live refs shown as cards)
|
|
53646
53724
|
tfa-cli project surfaces set <id> ref=<ref> [title=…] [group=<slug>] [order=N]
|
|
@@ -53805,6 +53883,25 @@ async function projectCommand(api, positionals, args, projectId) {
|
|
|
53805
53883
|
`);
|
|
53806
53884
|
return;
|
|
53807
53885
|
}
|
|
53886
|
+
if (verb === "intake") {
|
|
53887
|
+
const [slug, ...options] = gargs;
|
|
53888
|
+
if (!slug)
|
|
53889
|
+
fail("Usage: tfa-cli project groups intake <slug> [on|off|regenerate] [field=value]…");
|
|
53890
|
+
const action = ["on", "off", "regenerate"].includes(options[0]) ? options.shift() : undefined;
|
|
53891
|
+
if (options.length && action === "regenerate")
|
|
53892
|
+
fail("regenerate does not accept settings");
|
|
53893
|
+
const fields = parseAssignments2(options);
|
|
53894
|
+
const intake = action === "regenerate" ? await api.regenerateProjectGroupIntake(projectId, slug) : action || options.length ? await api.updateProjectGroupIntake(projectId, slug, { ...fields, ...action && { enabled: action === "on" } }) : await api.getProjectGroupIntake(projectId, slug);
|
|
53895
|
+
if (args.json) {
|
|
53896
|
+
console.log(JSON.stringify(intake, null, 2));
|
|
53897
|
+
return;
|
|
53898
|
+
}
|
|
53899
|
+
process.stderr.write(`${slug}: public ${intake.enabled ? "on" : "off"}, ${intake.submissionCount}/${intake.maxSubmissions}, autoStart=${intake.autoStart}
|
|
53900
|
+
`);
|
|
53901
|
+
if (intake.url)
|
|
53902
|
+
console.log(intake.url);
|
|
53903
|
+
return;
|
|
53904
|
+
}
|
|
53808
53905
|
if (verb === "reorder") {
|
|
53809
53906
|
if (!gargs.length)
|
|
53810
53907
|
fail("Usage: tfa-cli project groups reorder <slug>…");
|
|
@@ -53880,11 +53977,10 @@ Usage:
|
|
|
53880
53977
|
tfa-cli brand voice correct "<what is off>" Tell the learner what it got wrong; profile is updated
|
|
53881
53978
|
in one pass and the correction is kept for every re-learn
|
|
53882
53979
|
|
|
53883
|
-
Every voice verb takes --scope
|
|
53884
|
-
|
|
53885
|
-
|
|
53886
|
-
|
|
53887
|
-
Agents read all three; on the same voice name the narrower wins: mine > project > personal.
|
|
53980
|
+
Every voice verb takes --scope mine|project — which voice to teach:
|
|
53981
|
+
mine yours, only in this project (default)
|
|
53982
|
+
project the project's, shared with its members (needs write access)
|
|
53983
|
+
On the same voice name the narrower wins: mine > project.
|
|
53888
53984
|
|
|
53889
53985
|
|
|
53890
53986
|
Questions the UI asks (keys for 'answers'):
|
|
@@ -53984,9 +54080,9 @@ async function voiceDeviceCommand(rest, args) {
|
|
|
53984
54080
|
}
|
|
53985
54081
|
async function voiceCommand(api, projectId, rest, args) {
|
|
53986
54082
|
const [verb, ...vargs] = rest;
|
|
53987
|
-
const scope = args.scope;
|
|
53988
|
-
if (
|
|
53989
|
-
fail(`--scope must be
|
|
54083
|
+
const scope = args.scope ?? "mine";
|
|
54084
|
+
if (!["project", "mine"].includes(scope))
|
|
54085
|
+
fail(`--scope must be mine or project, got '${scope}'`);
|
|
53990
54086
|
if (verb === "collect" && !vargs[0])
|
|
53991
54087
|
fail("Usage: tfa-cli brand voice collect <channel> [--url U | --account <page-id> | --max N] [--dry-run]");
|
|
53992
54088
|
if (verb === "answers") {
|
|
@@ -54113,6 +54209,7 @@ Usage:
|
|
|
54113
54209
|
tfa-cli device access <device> who you shared the device with
|
|
54114
54210
|
tfa-cli device share <device> <email> let a teammate use it (their runs act as THEM)
|
|
54115
54211
|
tfa-cli device unshare <device> <email>
|
|
54212
|
+
tfa-cli device leave <device> remove your own access to a shared device
|
|
54116
54213
|
|
|
54117
54214
|
<device> is an id, name or hostname (unique partial works).
|
|
54118
54215
|
Devices shared with you are marked "shared"; only the owner can rename/share them.
|
|
@@ -54149,6 +54246,12 @@ async function deviceCommand(api, positionals, args) {
|
|
|
54149
54246
|
fail("Usage: tfa-cli device rename <device> <name>");
|
|
54150
54247
|
await api.renameDevice(found.id, value);
|
|
54151
54248
|
process.stderr.write(`${GREEN}✅ ${found.name} → ${value}${RESET}
|
|
54249
|
+
`);
|
|
54250
|
+
return;
|
|
54251
|
+
}
|
|
54252
|
+
if (sub === "leave") {
|
|
54253
|
+
await api.leaveDevice(found.id);
|
|
54254
|
+
process.stderr.write(`${GREEN}✅ Removed ${found.name} from your devices${RESET}
|
|
54152
54255
|
`);
|
|
54153
54256
|
return;
|
|
54154
54257
|
}
|
|
@@ -54198,15 +54301,7 @@ var STATUS_COLOR = {
|
|
|
54198
54301
|
POSTPONED: CYAN,
|
|
54199
54302
|
PAUSED: CYAN
|
|
54200
54303
|
};
|
|
54201
|
-
var CLOSED = new Set(
|
|
54202
|
-
"DONE",
|
|
54203
|
-
"READY_CHECKED",
|
|
54204
|
-
"CANCELLED",
|
|
54205
|
-
"CANCELLED_CHECKED",
|
|
54206
|
-
"ERROR_CHECKED",
|
|
54207
|
-
"ARCHIVED",
|
|
54208
|
-
"DELETED"
|
|
54209
|
-
]);
|
|
54304
|
+
var CLOSED = new Set(CLOSED_STATUSES);
|
|
54210
54305
|
var VALID_STATUS = new Set(Object.values(TodoStatus));
|
|
54211
54306
|
var isOpen = (s) => !CLOSED.has(s);
|
|
54212
54307
|
function printListTodosHelp() {
|
|
@@ -54218,11 +54313,16 @@ Usage:
|
|
|
54218
54313
|
|
|
54219
54314
|
Flags:
|
|
54220
54315
|
-n, --limit <n> Max rows to show (default: 30)
|
|
54221
|
-
--cursor <n> Fetch todos older than this cursor (
|
|
54222
|
-
--
|
|
54316
|
+
--cursor <n> Fetch todos older than this cursor (sort field, epoch ms)
|
|
54317
|
+
--since <t> Only todos with sort field >= t (inclusive)
|
|
54318
|
+
--until <t> Only todos with sort field < t (exclusive)
|
|
54319
|
+
t = epoch ms | YYYY-MM-DD (local midnight) | ISO datetime | 12h / 3d ago
|
|
54320
|
+
--sort <key> activity (lastActivityAt, default) | created (createdAt)
|
|
54321
|
+
--contributor <u> Only todos a member opened/wrote in (id or email; comma = any)
|
|
54322
|
+
--page-size <n> Backend page size per request (default: min(limit, 400), max: 400)
|
|
54223
54323
|
--search <text> Search content/status on the backend
|
|
54224
54324
|
-s, --status <S[,S2]> Filter by status (comma-separated, union).
|
|
54225
|
-
-A, --all Include
|
|
54325
|
+
-A, --all Include closed (DONE, ARCHIVED, DELETED)
|
|
54226
54326
|
--project <id> Project ID (default: current default project)
|
|
54227
54327
|
--json Output { items, nextCursor } as JSON
|
|
54228
54328
|
-h, --help Show this help
|
|
@@ -54233,6 +54333,8 @@ Examples:
|
|
|
54233
54333
|
todoforai-cli list --cursor 1719234567890 # next page
|
|
54234
54334
|
todoforai-cli list --all # include DONE
|
|
54235
54335
|
todoforai-cli list -s RUNNING,REVIEW_REQUESTED
|
|
54336
|
+
todoforai-cli list -A --since 2026-10-11 --until 2026-10-12 # touched that day
|
|
54337
|
+
todoforai-cli list -A --sort created --since 7d --contributor a@b.com
|
|
54236
54338
|
todoforai-cli list --search bug --json | jq '.items[].id'
|
|
54237
54339
|
`);
|
|
54238
54340
|
}
|
|
@@ -54258,6 +54360,25 @@ function cursorValue(value) {
|
|
|
54258
54360
|
}
|
|
54259
54361
|
return n;
|
|
54260
54362
|
}
|
|
54363
|
+
function parseTime(value, name, now = Date.now()) {
|
|
54364
|
+
if (value === undefined)
|
|
54365
|
+
return;
|
|
54366
|
+
const s = String(value).trim();
|
|
54367
|
+
const rel = s.match(/^(\d+)([mhd])$/);
|
|
54368
|
+
let n;
|
|
54369
|
+
if (/^\d+$/.test(s))
|
|
54370
|
+
n = Number(s);
|
|
54371
|
+
else if (rel)
|
|
54372
|
+
n = now - Number(rel[1]) * { m: 60000, h: 3600000, d: 86400000 }[rel[2]];
|
|
54373
|
+
else
|
|
54374
|
+
n = Date.parse(/^\d{4}-\d{2}-\d{2}$/.test(s) ? `${s}T00:00` : s);
|
|
54375
|
+
if (!Number.isFinite(n) || n < 0) {
|
|
54376
|
+
process.stderr.write(`${RED}Error: ${name} must be epoch ms, YYYY-MM-DD, ISO datetime or e.g. 12h / 3d${RESET}
|
|
54377
|
+
`);
|
|
54378
|
+
process.exit(2);
|
|
54379
|
+
}
|
|
54380
|
+
return n;
|
|
54381
|
+
}
|
|
54261
54382
|
function toItemsPage(response) {
|
|
54262
54383
|
if (Array.isArray(response))
|
|
54263
54384
|
return { items: response };
|
|
@@ -54266,8 +54387,25 @@ function toItemsPage(response) {
|
|
|
54266
54387
|
nextCursor: typeof response?.nextCursor === "number" ? response.nextCursor : undefined
|
|
54267
54388
|
};
|
|
54268
54389
|
}
|
|
54269
|
-
function rowTime(t) {
|
|
54270
|
-
return Number(t.lastActivityAt ?? t.createdAt ?? 0);
|
|
54390
|
+
function rowTime(t, sort = "activity") {
|
|
54391
|
+
return Number((sort === "created" ? t.createdAt : t.lastActivityAt ?? t.createdAt) ?? 0);
|
|
54392
|
+
}
|
|
54393
|
+
async function resolveContributors(api, projectId, raw) {
|
|
54394
|
+
const wanted = raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
54395
|
+
if (!wanted.some((w) => w.includes("@")))
|
|
54396
|
+
return wanted;
|
|
54397
|
+
const members = await api.getProjectMembers(projectId);
|
|
54398
|
+
return wanted.map((w) => {
|
|
54399
|
+
if (!w.includes("@"))
|
|
54400
|
+
return w;
|
|
54401
|
+
const m = members.find((m2) => m2.email?.toLowerCase() === w.toLowerCase());
|
|
54402
|
+
if (!m) {
|
|
54403
|
+
process.stderr.write(`${RED}Error: no project member with email ${w}${RESET}
|
|
54404
|
+
`);
|
|
54405
|
+
process.exit(2);
|
|
54406
|
+
}
|
|
54407
|
+
return m.id;
|
|
54408
|
+
});
|
|
54271
54409
|
}
|
|
54272
54410
|
function printStatusError(unknown) {
|
|
54273
54411
|
process.stderr.write(`${RED}Error: unknown status ${unknown.map((s) => `'${s}'`).join(", ")}${RESET}
|
|
@@ -54290,6 +54428,10 @@ async function listTodosCommand(api, defaultProjectId, argv) {
|
|
|
54290
54428
|
cursor: { type: "string" },
|
|
54291
54429
|
"page-size": { type: "string" },
|
|
54292
54430
|
search: { type: "string" },
|
|
54431
|
+
since: { type: "string" },
|
|
54432
|
+
until: { type: "string" },
|
|
54433
|
+
sort: { type: "string" },
|
|
54434
|
+
contributor: { type: "string" },
|
|
54293
54435
|
status: { type: "string", short: "s" },
|
|
54294
54436
|
all: { type: "boolean", short: "A", default: false },
|
|
54295
54437
|
project: { type: "string" },
|
|
@@ -54309,9 +54451,20 @@ async function listTodosCommand(api, defaultProjectId, argv) {
|
|
|
54309
54451
|
process.exit(1);
|
|
54310
54452
|
}
|
|
54311
54453
|
const limit = positiveInt(values.limit, "--limit") ?? 30;
|
|
54312
|
-
const pageSize = Math.min(positiveInt(values["page-size"], "--page-size") ?? Math.min(Math.max(limit, 1),
|
|
54454
|
+
const pageSize = Math.min(positiveInt(values["page-size"], "--page-size") ?? Math.min(Math.max(limit, 1), 400), 400);
|
|
54455
|
+
const sort = values.sort === undefined ? "activity" : String(values.sort);
|
|
54456
|
+
if (sort !== "activity" && sort !== "created") {
|
|
54457
|
+
process.stderr.write(`${RED}Error: --sort must be activity or created${RESET}
|
|
54458
|
+
`);
|
|
54459
|
+
process.exit(2);
|
|
54460
|
+
}
|
|
54461
|
+
const since = parseTime(values.since, "--since");
|
|
54462
|
+
const until = parseTime(values.until, "--until");
|
|
54313
54463
|
let cursor = cursorValue(values.cursor);
|
|
54464
|
+
if (until !== undefined)
|
|
54465
|
+
cursor = cursor === undefined ? until : Math.min(cursor, until);
|
|
54314
54466
|
const search = values.search ? String(values.search) : undefined;
|
|
54467
|
+
const contributorIds = values.contributor ? await resolveContributors(api, projectId, String(values.contributor)) : undefined;
|
|
54315
54468
|
const requested = values.status ? String(values.status).split(",").map((s) => s.trim().toUpperCase()).filter(Boolean) : null;
|
|
54316
54469
|
const unknown = requested?.filter((s) => s !== "OPEN" && !VALID_STATUS.has(s)) ?? [];
|
|
54317
54470
|
if (unknown.length)
|
|
@@ -54323,9 +54476,24 @@ async function listTodosCommand(api, defaultProjectId, argv) {
|
|
|
54323
54476
|
let backendNextCursor;
|
|
54324
54477
|
while (rows.length < limit) {
|
|
54325
54478
|
const requestLimit = Math.min(pageSize, limit - rows.length);
|
|
54326
|
-
const page = toItemsPage(await api.listTodos(projectId, {
|
|
54479
|
+
const page = toItemsPage(await api.listTodos(projectId, {
|
|
54480
|
+
limit: requestLimit,
|
|
54481
|
+
cursor,
|
|
54482
|
+
search,
|
|
54483
|
+
since,
|
|
54484
|
+
contributorIds,
|
|
54485
|
+
...!includeClosed && { excludeClosed: true },
|
|
54486
|
+
...sort !== "activity" && { sort }
|
|
54487
|
+
}));
|
|
54327
54488
|
backendNextCursor = page.nextCursor;
|
|
54489
|
+
let exhausted = false;
|
|
54328
54490
|
for (const t of page.items) {
|
|
54491
|
+
if (since !== undefined && rowTime(t) < since) {
|
|
54492
|
+
exhausted = true;
|
|
54493
|
+
break;
|
|
54494
|
+
}
|
|
54495
|
+
if (since !== undefined && rowTime(t, sort) < since)
|
|
54496
|
+
continue;
|
|
54329
54497
|
const status = String(t.status).toUpperCase();
|
|
54330
54498
|
if (!includeClosed && CLOSED.has(status))
|
|
54331
54499
|
continue;
|
|
@@ -54335,14 +54503,18 @@ async function listTodosCommand(api, defaultProjectId, argv) {
|
|
|
54335
54503
|
if (rows.length >= limit)
|
|
54336
54504
|
break;
|
|
54337
54505
|
}
|
|
54506
|
+
if (exhausted) {
|
|
54507
|
+
backendNextCursor = undefined;
|
|
54508
|
+
break;
|
|
54509
|
+
}
|
|
54338
54510
|
if (!backendNextCursor || page.items.length === 0)
|
|
54339
54511
|
break;
|
|
54340
54512
|
cursor = backendNextCursor;
|
|
54341
54513
|
}
|
|
54342
|
-
rows.sort((a, b) => rowTime(b) - rowTime(a));
|
|
54514
|
+
rows.sort((a, b) => rowTime(b, sort) - rowTime(a, sort));
|
|
54343
54515
|
const visible = rows.slice(0, limit);
|
|
54344
54516
|
const hasBufferedRows = rows.length > visible.length;
|
|
54345
|
-
const nextCursor = visible.length && (backendNextCursor !== undefined || hasBufferedRows) ? rowTime(visible[visible.length - 1]) : undefined;
|
|
54517
|
+
const nextCursor = visible.length && (backendNextCursor !== undefined || hasBufferedRows) ? rowTime(visible[visible.length - 1], sort) : undefined;
|
|
54346
54518
|
if (values.json) {
|
|
54347
54519
|
process.stdout.write(JSON.stringify({ items: visible, nextCursor }, null, 2) + `
|
|
54348
54520
|
`);
|
|
@@ -54360,7 +54532,7 @@ async function listTodosCommand(api, defaultProjectId, argv) {
|
|
|
54360
54532
|
for (const t of visible) {
|
|
54361
54533
|
const status = String(t.status).toUpperCase();
|
|
54362
54534
|
const sc = STATUS_COLOR[status] || DIM;
|
|
54363
|
-
const ts = new Date(rowTime(t)).toISOString().slice(0, 16).replace("T", " ");
|
|
54535
|
+
const ts = new Date(rowTime(t, sort)).toISOString().slice(0, 16).replace("T", " ");
|
|
54364
54536
|
const title = String(t.content ?? "").split(`
|
|
54365
54537
|
`)[0].slice(0, 100);
|
|
54366
54538
|
process.stdout.write(`${sc}${status.padEnd(statusW)}${RESET} ${DIM}${ts}${RESET} ${t.id} ${title}
|
|
@@ -55248,7 +55420,6 @@ tfa-cli memory — memory and context folders as git checkouts
|
|
|
55248
55420
|
|
|
55249
55421
|
Usage:
|
|
55250
55422
|
tfa-cli memory sync [--project <id>] Clone, or pull, into:
|
|
55251
|
-
~/.todoforai/{memory,context} yours (todoforai:memory, todoforai:context)
|
|
55252
55423
|
~/.todoforai/projects/<id>/{memory,context} the project's (todoforai:projects/<id>/…)
|
|
55253
55424
|
~/.todoforai/projects/<id>/me/{memory,context} yours in it (todoforai:projects/<id>/me/…)
|
|
55254
55425
|
tfa-cli memory path [--project <id>] Print the checkout paths
|
|
@@ -55258,14 +55429,17 @@ use plain git: log, diff, show, revert, commit, then \`git push\` — the push u
|
|
|
55258
55429
|
folder. A push behind the server is refused: \`git pull\` first. Files over 5 MB live outside
|
|
55259
55430
|
history (upload them instead). Project folders: members with write access push; your own in
|
|
55260
55431
|
a project (me/) is private to you. The project
|
|
55261
|
-
defaults to $TODOFORAI_PROJECT_ID.
|
|
55432
|
+
defaults to $TODOFORAI_PROJECT_ID and is required. Legacy global folders are read-only
|
|
55433
|
+
recovery, not synced.
|
|
55262
55434
|
`);
|
|
55263
55435
|
}
|
|
55264
55436
|
var FOLDERS = ["memory", "context"];
|
|
55265
55437
|
function checkouts(projectId) {
|
|
55266
55438
|
const root = join5(homedir5(), ".todoforai");
|
|
55267
|
-
|
|
55268
|
-
|
|
55439
|
+
if (!projectId)
|
|
55440
|
+
throw new Error("Select a project with --project <id> or $TODOFORAI_PROJECT_ID.");
|
|
55441
|
+
const project = join5(root, "projects", projectId);
|
|
55442
|
+
const scopes = [[project, `projects/${projectId}/`], [join5(project, "me"), `projects/${projectId}/me/`]];
|
|
55269
55443
|
return scopes.flatMap(([dir, remote]) => FOLDERS.map((f) => [join5(dir, f), `${remote}${f}.git`]));
|
|
55270
55444
|
}
|
|
55271
55445
|
function git(args, cwd) {
|
|
@@ -56226,6 +56400,7 @@ __export(exports_util, {
|
|
|
56226
56400
|
toZod: () => toZod,
|
|
56227
56401
|
stringifyPrimitive: () => stringifyPrimitive,
|
|
56228
56402
|
slugify: () => slugify,
|
|
56403
|
+
sizeCaps: () => sizeCaps,
|
|
56229
56404
|
shallowClone: () => shallowClone,
|
|
56230
56405
|
safeExtend: () => safeExtend,
|
|
56231
56406
|
required: () => required,
|
|
@@ -56800,6 +56975,18 @@ function prefixIssues(path4, issues) {
|
|
|
56800
56975
|
function unwrapMessage(message) {
|
|
56801
56976
|
return typeof message === "string" ? message : message?.message;
|
|
56802
56977
|
}
|
|
56978
|
+
function sizeCaps(defChecks) {
|
|
56979
|
+
const caps = [];
|
|
56980
|
+
for (const ch of defChecks ?? []) {
|
|
56981
|
+
const d = ch._zod.def;
|
|
56982
|
+
if (!/_(length|size)$|_equals$/.test(d.check))
|
|
56983
|
+
break;
|
|
56984
|
+
const max = d.maximum ?? d.length ?? d.size;
|
|
56985
|
+
if (max >= 0)
|
|
56986
|
+
caps.push([max, ch]);
|
|
56987
|
+
}
|
|
56988
|
+
return caps;
|
|
56989
|
+
}
|
|
56803
56990
|
function attachSchema(issues, start, inst) {
|
|
56804
56991
|
var _a;
|
|
56805
56992
|
for (let i = start;i < issues.length; i++) {
|
|
@@ -58219,7 +58406,7 @@ ${content.join(`
|
|
|
58219
58406
|
var version = {
|
|
58220
58407
|
major: 4,
|
|
58221
58408
|
minor: 6,
|
|
58222
|
-
patch:
|
|
58409
|
+
patch: 7
|
|
58223
58410
|
};
|
|
58224
58411
|
|
|
58225
58412
|
// node_modules/zod/v4/core/schemas.js
|
|
@@ -58968,6 +59155,31 @@ var $ZodDate = /* @__PURE__ */ $constructor("$ZodDate", (inst, def) => {
|
|
|
58968
59155
|
return payload;
|
|
58969
59156
|
};
|
|
58970
59157
|
});
|
|
59158
|
+
function capSize(inst, size) {
|
|
59159
|
+
const caps = sizeCaps(inst._zod.def.checks);
|
|
59160
|
+
if (!caps.length)
|
|
59161
|
+
return;
|
|
59162
|
+
const cap = Math.min(...caps.map((c3) => c3[0]));
|
|
59163
|
+
const parse2 = inst._zod.parse;
|
|
59164
|
+
inst._zod.parse = (payload, ctx) => {
|
|
59165
|
+
const n = size(payload.value);
|
|
59166
|
+
if (n > cap && !ctx?.skipChecks && ctx?.direction !== "backward") {
|
|
59167
|
+
for (const [max, ch] of sizeCaps(inst._zod.def.checks)) {
|
|
59168
|
+
if (n > max && ch._zod.def.when(payload)) {
|
|
59169
|
+
const start = payload.issues.length;
|
|
59170
|
+
ch._zod.check(payload);
|
|
59171
|
+
payload.issues[start].continue = false;
|
|
59172
|
+
attachSchema(payload.issues, start, inst);
|
|
59173
|
+
return payload;
|
|
59174
|
+
}
|
|
59175
|
+
}
|
|
59176
|
+
}
|
|
59177
|
+
return parse2(payload, ctx);
|
|
59178
|
+
};
|
|
59179
|
+
}
|
|
59180
|
+
var arraySize = (input) => Array.isArray(input) ? input.length : -1;
|
|
59181
|
+
var mapSize = (input) => input instanceof Map ? input.size : -1;
|
|
59182
|
+
var setSize = (input) => input instanceof Set ? input.size : -1;
|
|
58971
59183
|
function handleArrayResult(result, final, index) {
|
|
58972
59184
|
if (result.issues.length) {
|
|
58973
59185
|
final.issues.push(...prefixIssues(index, result.issues));
|
|
@@ -59011,6 +59223,7 @@ var $ZodArray = /* @__PURE__ */ $constructor("$ZodArray", (inst, def) => {
|
|
|
59011
59223
|
}
|
|
59012
59224
|
return payload;
|
|
59013
59225
|
};
|
|
59226
|
+
capSize(inst, arraySize);
|
|
59014
59227
|
});
|
|
59015
59228
|
function handlePropertyResult(result, final, key, input, optin, optout) {
|
|
59016
59229
|
const isPresent = key in input;
|
|
@@ -59965,6 +60178,7 @@ var $ZodMap = /* @__PURE__ */ $constructor("$ZodMap", (inst, def) => {
|
|
|
59965
60178
|
return Promise.all(proms).then(() => payload);
|
|
59966
60179
|
return payload;
|
|
59967
60180
|
};
|
|
60181
|
+
capSize(inst, mapSize);
|
|
59968
60182
|
});
|
|
59969
60183
|
function handleMapResult(keyResult, valueResult, final, key, input, inst, ctx) {
|
|
59970
60184
|
if (keyResult.issues.length) {
|
|
@@ -60031,6 +60245,7 @@ var $ZodSet = /* @__PURE__ */ $constructor("$ZodSet", (inst, def) => {
|
|
|
60031
60245
|
return Promise.all(proms).then(() => payload);
|
|
60032
60246
|
return payload;
|
|
60033
60247
|
};
|
|
60248
|
+
capSize(inst, setSize);
|
|
60034
60249
|
});
|
|
60035
60250
|
function handleSetResult(result, final) {
|
|
60036
60251
|
if (result.issues.length) {
|
|
@@ -69480,9 +69695,15 @@ function generateNullableCheck(doc, ctx, schema, accessor, buildsValue = true) {
|
|
|
69480
69695
|
doc.write(`}`);
|
|
69481
69696
|
return outputVar;
|
|
69482
69697
|
}
|
|
69698
|
+
function generateSizeGate(doc, schema, size) {
|
|
69699
|
+
for (const [max, check] of sizeCaps(schema._zod.def.checks)) {
|
|
69700
|
+
doc.write(`if (${size} > ${numericOperand(max, check._zod.def.check)}) return INVALID;`);
|
|
69701
|
+
}
|
|
69702
|
+
}
|
|
69483
69703
|
function generateArrayCheck(doc, ctx, schema, accessor, buildsValue = true) {
|
|
69484
69704
|
const def = schema._zod.def;
|
|
69485
69705
|
doc.write(`if (!Array.isArray(${accessor})) return INVALID;`);
|
|
69706
|
+
generateSizeGate(doc, schema, `${accessor}.length`);
|
|
69486
69707
|
const outputVar = buildsValue ? newVar(ctx) : null;
|
|
69487
69708
|
const iVar = newVar(ctx);
|
|
69488
69709
|
const elemVar = newVar(ctx);
|
|
@@ -69882,6 +70103,7 @@ function literalPropertyKey(ctx, key) {
|
|
|
69882
70103
|
function generateMapCheck(doc, ctx, schema, accessor) {
|
|
69883
70104
|
const def = schema._zod.def;
|
|
69884
70105
|
doc.write(`if (!(${accessor} instanceof Map)) return INVALID;`);
|
|
70106
|
+
generateSizeGate(doc, schema, `${accessor}.size`);
|
|
69885
70107
|
const outputVar = newVar(ctx);
|
|
69886
70108
|
const kVar = newVar(ctx);
|
|
69887
70109
|
const valVar = newVar(ctx);
|
|
@@ -69898,6 +70120,7 @@ function generateMapCheck(doc, ctx, schema, accessor) {
|
|
|
69898
70120
|
function generateSetCheck(doc, ctx, schema, accessor) {
|
|
69899
70121
|
const def = schema._zod.def;
|
|
69900
70122
|
doc.write(`if (!(${accessor} instanceof Set)) return INVALID;`);
|
|
70123
|
+
generateSizeGate(doc, schema, `${accessor}.size`);
|
|
69901
70124
|
const outputVar = newVar(ctx);
|
|
69902
70125
|
const valVar = newVar(ctx);
|
|
69903
70126
|
doc.write(`const ${outputVar} = new Set();`);
|
|
@@ -75065,6 +75288,21 @@ function preserveCustomPayload(schema, key, knownTags) {
|
|
|
75065
75288
|
return output2;
|
|
75066
75289
|
});
|
|
75067
75290
|
}
|
|
75291
|
+
function defaultOnErrorOptionalStringTag(schema, key) {
|
|
75292
|
+
return exports_external.preprocess((value) => {
|
|
75293
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
75294
|
+
return value;
|
|
75295
|
+
}
|
|
75296
|
+
const record2 = value;
|
|
75297
|
+
const tag = record2[key];
|
|
75298
|
+
if (tag === undefined || tag === null || typeof tag === "string") {
|
|
75299
|
+
return value;
|
|
75300
|
+
}
|
|
75301
|
+
const normalized = { ...record2 };
|
|
75302
|
+
delete normalized[key];
|
|
75303
|
+
return normalized;
|
|
75304
|
+
}, schema);
|
|
75305
|
+
}
|
|
75068
75306
|
function vecSkipError(itemSchema) {
|
|
75069
75307
|
return exports_external.array(itemSchema.catch(skippedItem)).transform((items) => items.filter((item) => item !== skippedItem));
|
|
75070
75308
|
}
|
|
@@ -75083,16 +75321,12 @@ var zWriteTextFileRequest = object({
|
|
|
75083
75321
|
var zReadTextFileRequest = object({
|
|
75084
75322
|
sessionId: zSessionId,
|
|
75085
75323
|
path: string2(),
|
|
75086
|
-
line:
|
|
75324
|
+
line: int().gte(0).max(4294967295, {
|
|
75087
75325
|
error: "Invalid value: Expected uint32 to be <= 4294967295"
|
|
75088
|
-
}).nullish(),
|
|
75089
|
-
|
|
75090
|
-
}),
|
|
75091
|
-
limit: defaultOnError(int().gte(0).max(4294967295, {
|
|
75326
|
+
}).nullish(),
|
|
75327
|
+
limit: int().gte(0).max(4294967295, {
|
|
75092
75328
|
error: "Invalid value: Expected uint32 to be <= 4294967295"
|
|
75093
|
-
}).nullish(),
|
|
75094
|
-
return;
|
|
75095
|
-
}),
|
|
75329
|
+
}).nullish(),
|
|
75096
75330
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
75097
75331
|
return;
|
|
75098
75332
|
})
|
|
@@ -75343,14 +75577,10 @@ var zEnvVariable = object({
|
|
|
75343
75577
|
var zCreateTerminalRequest = object({
|
|
75344
75578
|
sessionId: zSessionId,
|
|
75345
75579
|
command: string2(),
|
|
75346
|
-
args:
|
|
75347
|
-
env:
|
|
75348
|
-
cwd:
|
|
75349
|
-
|
|
75350
|
-
}),
|
|
75351
|
-
outputByteLimit: defaultOnError(number2().nullish(), () => {
|
|
75352
|
-
return;
|
|
75353
|
-
}),
|
|
75580
|
+
args: array(string2()).optional(),
|
|
75581
|
+
env: array(zEnvVariable).optional(),
|
|
75582
|
+
cwd: string2().nullish(),
|
|
75583
|
+
outputByteLimit: number2().nullish(),
|
|
75354
75584
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
75355
75585
|
return;
|
|
75356
75586
|
})
|
|
@@ -75876,10 +76106,8 @@ var zAuthMethodTerminal = object({
|
|
|
75876
76106
|
description: defaultOnError(string2().nullish(), () => {
|
|
75877
76107
|
return;
|
|
75878
76108
|
}),
|
|
75879
|
-
args:
|
|
75880
|
-
env:
|
|
75881
|
-
return;
|
|
75882
|
-
}),
|
|
76109
|
+
args: array(string2()).optional(),
|
|
76110
|
+
env: record(string2(), string2()).optional(),
|
|
75883
76111
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
75884
76112
|
return;
|
|
75885
76113
|
})
|
|
@@ -76577,17 +76805,61 @@ var zRunningStateUpdate = object({
|
|
|
76577
76805
|
return;
|
|
76578
76806
|
})
|
|
76579
76807
|
});
|
|
76580
|
-
var
|
|
76581
|
-
|
|
76808
|
+
var zErrorStopReason = object({
|
|
76809
|
+
error: defaultOnError(zError.nullish(), () => {
|
|
76582
76810
|
return;
|
|
76811
|
+
})
|
|
76812
|
+
});
|
|
76813
|
+
var zIdleStateUpdate = defaultOnErrorOptionalStringTag(preserveCustomPayload(intersection(union([
|
|
76814
|
+
object({
|
|
76815
|
+
stopReason: literal("end_turn")
|
|
76816
|
+
}),
|
|
76817
|
+
object({
|
|
76818
|
+
stopReason: literal("max_tokens")
|
|
76819
|
+
}),
|
|
76820
|
+
object({
|
|
76821
|
+
stopReason: literal("max_turn_requests")
|
|
76822
|
+
}),
|
|
76823
|
+
object({
|
|
76824
|
+
stopReason: literal("refusal")
|
|
76825
|
+
}),
|
|
76826
|
+
object({
|
|
76827
|
+
stopReason: literal("cancelled")
|
|
76583
76828
|
}),
|
|
76829
|
+
zErrorStopReason.and(object({
|
|
76830
|
+
stopReason: literal("error")
|
|
76831
|
+
})),
|
|
76832
|
+
excludeKnownTags(object({
|
|
76833
|
+
stopReason: string2()
|
|
76834
|
+
}), "stopReason", [
|
|
76835
|
+
"cancelled",
|
|
76836
|
+
"end_turn",
|
|
76837
|
+
"error",
|
|
76838
|
+
"max_tokens",
|
|
76839
|
+
"max_turn_requests",
|
|
76840
|
+
"refusal"
|
|
76841
|
+
]),
|
|
76842
|
+
object({
|
|
76843
|
+
stopReason: _null3().optional()
|
|
76844
|
+
})
|
|
76845
|
+
]), object({
|
|
76584
76846
|
usage: defaultOnError(zUsage.nullish(), () => {
|
|
76585
76847
|
return;
|
|
76586
76848
|
}),
|
|
76587
76849
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
76588
76850
|
return;
|
|
76851
|
+
}),
|
|
76852
|
+
stopReason: defaultOnError(string2().nullish(), () => {
|
|
76853
|
+
return;
|
|
76589
76854
|
})
|
|
76590
|
-
})
|
|
76855
|
+
})), "stopReason", [
|
|
76856
|
+
"cancelled",
|
|
76857
|
+
"end_turn",
|
|
76858
|
+
"error",
|
|
76859
|
+
"max_tokens",
|
|
76860
|
+
"max_turn_requests",
|
|
76861
|
+
"refusal"
|
|
76862
|
+
]), "stopReason");
|
|
76591
76863
|
var zRequiresActionStateUpdate = object({
|
|
76592
76864
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
76593
76865
|
return;
|
|
@@ -76970,16 +77242,16 @@ var zMcpServer = union([
|
|
|
76970
77242
|
]);
|
|
76971
77243
|
var zNewSessionRequest = object({
|
|
76972
77244
|
cwd: string2(),
|
|
76973
|
-
additionalDirectories:
|
|
76974
|
-
mcpServers:
|
|
77245
|
+
additionalDirectories: array(string2()).optional(),
|
|
77246
|
+
mcpServers: array(zMcpServer),
|
|
76975
77247
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
76976
77248
|
return;
|
|
76977
77249
|
})
|
|
76978
77250
|
});
|
|
76979
77251
|
var zLoadSessionRequest = object({
|
|
76980
|
-
mcpServers:
|
|
77252
|
+
mcpServers: array(zMcpServer),
|
|
76981
77253
|
cwd: string2(),
|
|
76982
|
-
additionalDirectories:
|
|
77254
|
+
additionalDirectories: array(string2()).optional(),
|
|
76983
77255
|
sessionId: zSessionId,
|
|
76984
77256
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
76985
77257
|
return;
|
|
@@ -77001,8 +77273,8 @@ var zDeleteSessionRequest = object({
|
|
|
77001
77273
|
var zForkSessionRequest = object({
|
|
77002
77274
|
sessionId: zSessionId,
|
|
77003
77275
|
cwd: string2(),
|
|
77004
|
-
additionalDirectories:
|
|
77005
|
-
mcpServers:
|
|
77276
|
+
additionalDirectories: array(string2()).optional(),
|
|
77277
|
+
mcpServers: array(zMcpServer).optional(),
|
|
77006
77278
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
77007
77279
|
return;
|
|
77008
77280
|
})
|
|
@@ -77010,8 +77282,8 @@ var zForkSessionRequest = object({
|
|
|
77010
77282
|
var zResumeSessionRequest = object({
|
|
77011
77283
|
sessionId: zSessionId,
|
|
77012
77284
|
cwd: string2(),
|
|
77013
|
-
additionalDirectories:
|
|
77014
|
-
mcpServers:
|
|
77285
|
+
additionalDirectories: array(string2()).optional(),
|
|
77286
|
+
mcpServers: array(zMcpServer).optional(),
|
|
77015
77287
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
77016
77288
|
return;
|
|
77017
77289
|
})
|
|
@@ -77392,7 +77664,7 @@ var zDidChangeDocumentNotification = object({
|
|
|
77392
77664
|
sessionId: zSessionId,
|
|
77393
77665
|
uri: string2(),
|
|
77394
77666
|
version: number2(),
|
|
77395
|
-
contentChanges:
|
|
77667
|
+
contentChanges: array(zTextDocumentContentChangeEvent),
|
|
77396
77668
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
77397
77669
|
return;
|
|
77398
77670
|
})
|
|
@@ -78471,9 +78743,26 @@ var zGuardElicitationPropertySchemaBoolean = zBooleanPropertySchema.and(object({
|
|
|
78471
78743
|
var zGuardElicitationPropertySchemaArray = zMultiSelectPropertySchema.and(object({ type: literal("array") }));
|
|
78472
78744
|
var zGuardMultiSelectItemsString = zStringMultiSelectItems.and(object({ type: literal("string") }));
|
|
78473
78745
|
var zGuardStateUpdateRunning = zRunningStateUpdate.and(object({ state: literal("running") }));
|
|
78474
|
-
var zGuardStateUpdateIdle = zIdleStateUpdate.and(object({ state: literal("idle") }));
|
|
78746
|
+
var zGuardStateUpdateIdle = zIdleStateUpdate.and(object({ usage: zUsage.nullish() })).and(object({ state: literal("idle") }));
|
|
78475
78747
|
var zGuardStateUpdateRequiresAction = zRequiresActionStateUpdate.and(object({ state: literal("requires_action") }));
|
|
78476
78748
|
var zGuardStateUpdateUnknown = zUnknownStateUpdate.and(object({ state: literal("unknown") }));
|
|
78749
|
+
var zGuardIdleStateUpdateEndTurn = object({
|
|
78750
|
+
stopReason: literal("end_turn")
|
|
78751
|
+
});
|
|
78752
|
+
var zGuardIdleStateUpdateMaxTokens = object({
|
|
78753
|
+
stopReason: literal("max_tokens")
|
|
78754
|
+
});
|
|
78755
|
+
var zGuardIdleStateUpdateMaxTurnRequests = object({
|
|
78756
|
+
stopReason: literal("max_turn_requests")
|
|
78757
|
+
});
|
|
78758
|
+
var zGuardIdleStateUpdateRefusal = object({
|
|
78759
|
+
stopReason: literal("refusal")
|
|
78760
|
+
});
|
|
78761
|
+
var zGuardIdleStateUpdateCancelled = object({
|
|
78762
|
+
stopReason: literal("cancelled")
|
|
78763
|
+
});
|
|
78764
|
+
var zGuardIdleStateUpdateError = zErrorStopReason.and(object({ error: zError.nullish() })).and(object({ stopReason: literal("error") }));
|
|
78765
|
+
var zGuardIdleStateUpdateNone = object({ stopReason: _null3().optional() });
|
|
78477
78766
|
var zGuardCreateElicitationResponseAccept = zElicitationAcceptAction.and(object({ action: literal("accept") }));
|
|
78478
78767
|
var zGuardCreateElicitationResponseDecline = object({
|
|
78479
78768
|
action: literal("decline")
|
|
@@ -79832,6 +80121,7 @@ async function runAcp(apiUrl, apiKey, opts) {
|
|
|
79832
80121
|
|
|
79833
80122
|
// src/shutdown.ts
|
|
79834
80123
|
var activeRun2 = null;
|
|
80124
|
+
var stopOnExit2 = false;
|
|
79835
80125
|
var cleanups2 = [];
|
|
79836
80126
|
var exiting2 = null;
|
|
79837
80127
|
var cancelling2 = null;
|
|
@@ -79839,6 +80129,11 @@ var CANCEL_TIMEOUT_MS2 = 5000;
|
|
|
79839
80129
|
function setActiveRun2(run2) {
|
|
79840
80130
|
activeRun2 = run2;
|
|
79841
80131
|
}
|
|
80132
|
+
function stopRunOnExit() {
|
|
80133
|
+
stopOnExit2 = true;
|
|
80134
|
+
}
|
|
80135
|
+
var detachNotice2 = (todoId) => `Todo keeps running — reattach: tfa-cli --resume ${todoId}
|
|
80136
|
+
`;
|
|
79842
80137
|
function trackStart(ws, projectId, started) {
|
|
79843
80138
|
setActiveRun2(started.then((todoId) => ({ ws, projectId, todoId }), () => null));
|
|
79844
80139
|
}
|
|
@@ -79856,7 +80151,7 @@ function cancelActiveRun2(timeoutMs = CANCEL_TIMEOUT_MS2) {
|
|
|
79856
80151
|
if (cancelling2)
|
|
79857
80152
|
return cancelling2;
|
|
79858
80153
|
const pending = activeRun2;
|
|
79859
|
-
if (!pending)
|
|
80154
|
+
if (!pending || !stopOnExit2)
|
|
79860
80155
|
return Promise.resolve({ ok: false, todoId: null });
|
|
79861
80156
|
const res = { ok: false };
|
|
79862
80157
|
const attempt = (async () => {
|
|
@@ -79882,7 +80177,11 @@ function shutdown2(code, reason) {
|
|
|
79882
80177
|
process.stderr.write(`
|
|
79883
80178
|
${reason}
|
|
79884
80179
|
`);
|
|
79885
|
-
if (activeRun2) {
|
|
80180
|
+
if (activeRun2 && !stopOnExit2) {
|
|
80181
|
+
const run2 = await withTimeout2(Promise.resolve(activeRun2), CANCEL_TIMEOUT_MS2, null);
|
|
80182
|
+
if (run2)
|
|
80183
|
+
process.stderr.write(detachNotice2(run2.todoId));
|
|
80184
|
+
} else if (activeRun2) {
|
|
79886
80185
|
const { ok, todoId } = await cancelActiveRun2();
|
|
79887
80186
|
if (ok)
|
|
79888
80187
|
process.stderr.write(`Stopped todo ${todoId}
|
|
@@ -79912,7 +80211,7 @@ function finish(code) {
|
|
|
79912
80211
|
});
|
|
79913
80212
|
}
|
|
79914
80213
|
function installSignalHandlers() {
|
|
79915
|
-
process.on("SIGINT", () => void shutdown2(130, "
|
|
80214
|
+
process.on("SIGINT", () => void shutdown2(130, "Exited (Ctrl+C)"));
|
|
79916
80215
|
process.on("SIGTERM", () => void shutdown2(143, "Terminated (SIGTERM)"));
|
|
79917
80216
|
process.on("SIGHUP", () => void shutdown2(129, "Hangup (SIGHUP)"));
|
|
79918
80217
|
}
|
|
@@ -80632,8 +80931,7 @@ async function main() {
|
|
|
80632
80931
|
await watchTodo(ws2, todoId, projectId2, {
|
|
80633
80932
|
json: !!args.json,
|
|
80634
80933
|
autoApprove,
|
|
80635
|
-
agentSettings: agent3
|
|
80636
|
-
exitOnInterrupt: !!args["non-interactive"]
|
|
80934
|
+
agentSettings: agent3
|
|
80637
80935
|
});
|
|
80638
80936
|
if (!args["non-interactive"]) {
|
|
80639
80937
|
process.stderr.write(`
|
|
@@ -80684,7 +80982,7 @@ Resumed: ${CYAN2}${getFrontendUrl(apiUrl, todoId)}${RESET2}
|
|
|
80684
80982
|
cfg.addToHistory(followUp);
|
|
80685
80983
|
await appendTracked(api2, ws2, projectId2, followUp, agent3, todoId);
|
|
80686
80984
|
await linkToSpawningBlock(api2, todoId);
|
|
80687
|
-
await watchTodo(ws2, todoId, projectId2, { json: !!args.json, autoApprove, agentSettings: agent3
|
|
80985
|
+
await watchTodo(ws2, todoId, projectId2, { json: !!args.json, autoApprove, agentSettings: agent3 });
|
|
80688
80986
|
}
|
|
80689
80987
|
if (!args["non-interactive"]) {
|
|
80690
80988
|
await interactiveLoop(ws2, api2, todoId, projectId2, agent3, !!args.json, autoApprove, cfg);
|
|
@@ -80706,6 +81004,7 @@ Resumed: ${CYAN2}${getFrontendUrl(apiUrl, todoId)}${RESET2}
|
|
|
80706
81004
|
if (mayfly) {
|
|
80707
81005
|
process.stderr.write(`${DIM2}Isolated bridge:${RESET2} ${CYAN2}mayfly-${isolatedTodoId}${RESET2}
|
|
80708
81006
|
`);
|
|
81007
|
+
stopRunOnExit();
|
|
80709
81008
|
onShutdown(mayfly.stop);
|
|
80710
81009
|
mayfly.child.on("exit", (code, sig) => {
|
|
80711
81010
|
if (!mayfly.stopped())
|
|
@@ -80845,8 +81144,7 @@ Resumed: ${CYAN2}${getFrontendUrl(apiUrl, todoId)}${RESET2}
|
|
|
80845
81144
|
await watchTodo(ws, actualTodoId, projectId, {
|
|
80846
81145
|
json: !!args.json,
|
|
80847
81146
|
autoApprove,
|
|
80848
|
-
agentSettings: agent2
|
|
80849
|
-
exitOnInterrupt: !!args["non-interactive"]
|
|
81147
|
+
agentSettings: agent2
|
|
80850
81148
|
});
|
|
80851
81149
|
if (!args["non-interactive"]) {
|
|
80852
81150
|
process.stderr.write(`
|