@todoforai/cli 0.1.72 → 0.1.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/todoforai-cli.js +337 -116
- package/package.json +1 -1
package/dist/todoforai-cli.js
CHANGED
|
@@ -43281,6 +43281,10 @@ class ApiClient {
|
|
|
43281
43281
|
const { projectId, ...body } = input;
|
|
43282
43282
|
return this.request("POST", `/api/v1/projects/${projectId}/recommendations`, body);
|
|
43283
43283
|
}
|
|
43284
|
+
async feedIgnore(input) {
|
|
43285
|
+
const { projectId, ...body } = input;
|
|
43286
|
+
return this.request("POST", `/api/v1/projects/${projectId}/feed/ignored`, body);
|
|
43287
|
+
}
|
|
43284
43288
|
async getRegistrySpec(specId) {
|
|
43285
43289
|
const base = this.apiUrl.replace(/\/api\/v1\/?$/, "").replace(/\/$/, "");
|
|
43286
43290
|
const res = await fetch(`${base}/cookie/v1/registry/templates/${specId}`);
|
|
@@ -43763,14 +43767,15 @@ var mimetypes_default = {
|
|
|
43763
43767
|
to_jpeg_90: { toMime: "image/jpeg", toExt: "jpg", quality: 0.9 }
|
|
43764
43768
|
},
|
|
43765
43769
|
types: {
|
|
43766
|
-
image: { icon: "
|
|
43767
|
-
audio: { icon: "mdi:file-music", color: "
|
|
43768
|
-
video: { icon: "
|
|
43770
|
+
image: { icon: "vscode-icons:file-type-image", color: "green", prefixRule: "image/", needsObjectUrl: true },
|
|
43771
|
+
audio: { icon: "mdi:file-music", color: "blue", prefixRule: "audio/", needsObjectUrl: true },
|
|
43772
|
+
video: { icon: "vscode-icons:file-type-video", color: "red", prefixRule: "video/", needsObjectUrl: true },
|
|
43769
43773
|
pdf: { icon: "vscode-icons:file-type-pdf2", color: "red", needsObjectUrl: true },
|
|
43770
43774
|
document: { icon: "vscode-icons:file-type-word", color: "lightblue" },
|
|
43771
43775
|
spreadsheet: { icon: "vscode-icons:file-type-excel", color: "green" },
|
|
43772
|
-
|
|
43773
|
-
|
|
43776
|
+
presentation: { icon: "vscode-icons:file-type-powerpoint", color: "red" },
|
|
43777
|
+
text: { icon: "vscode-icons:file-type-text", color: "white", prefixRule: "text/" },
|
|
43778
|
+
archive: { icon: "vscode-icons:file-type-zip", color: "yellow" },
|
|
43774
43779
|
unknown: { icon: "mdi:file", color: "grey" },
|
|
43775
43780
|
mcp_text: { icon: "mdi:robot", color: "purple" },
|
|
43776
43781
|
mcp_image: { icon: "mdi:robot", color: "purple", needsObjectUrl: true },
|
|
@@ -43821,8 +43826,8 @@ var mimetypes_default = {
|
|
|
43821
43826
|
pdf: { mime: "application/pdf", type: "pdf" },
|
|
43822
43827
|
doc: { mime: "application/msword", type: "document" },
|
|
43823
43828
|
docx: { mime: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", type: "document", tags: ["docx"] },
|
|
43824
|
-
ppt: { mime: "application/vnd.ms-powerpoint", type: "
|
|
43825
|
-
pptx: { mime: "application/vnd.openxmlformats-officedocument.presentationml.presentation", type: "
|
|
43829
|
+
ppt: { mime: "application/vnd.ms-powerpoint", type: "presentation" },
|
|
43830
|
+
pptx: { mime: "application/vnd.openxmlformats-officedocument.presentationml.presentation", type: "presentation", tags: ["pptx"] },
|
|
43826
43831
|
xls: { mime: "application/vnd.ms-excel", type: "spreadsheet", tags: ["xls"] },
|
|
43827
43832
|
xlsx: { mime: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", type: "spreadsheet", tags: ["xlsx"] },
|
|
43828
43833
|
zip: { mime: "application/zip", type: "archive" },
|
|
@@ -44070,7 +44075,7 @@ var FILE_TOOL_TYPES = new Set([
|
|
|
44070
44075
|
"modify_file" /* ModifyFile */
|
|
44071
44076
|
]);
|
|
44072
44077
|
// ../packages/shared-fbe/src/channels.ts
|
|
44073
|
-
var privateSuffix = (
|
|
44078
|
+
var privateSuffix = (userId) => userId ? `:private:${userId}` : "";
|
|
44074
44079
|
var SERVER_TO_FRONTENDS = {
|
|
44075
44080
|
task: {
|
|
44076
44081
|
actionUpdate: (userId) => `${"task_action:update" /* TASK_ACTION_UPDATE */}:${userId}`
|
|
@@ -44118,9 +44123,9 @@ var SERVER_TO_FRONTENDS = {
|
|
|
44118
44123
|
writeFileResult: (edgeId) => `${"edge:write_file_response" /* EDGE_WRITE_FILE_RESPONSE */}:${edgeId}`
|
|
44119
44124
|
},
|
|
44120
44125
|
project: {
|
|
44121
|
-
new_message: (projectId,
|
|
44122
|
-
new_todo: (projectId,
|
|
44123
|
-
status: (projectId,
|
|
44126
|
+
new_message: (projectId, memberId) => `${"task:new_update" /* TASK_NEW */}:${projectId}${privateSuffix(memberId)}`,
|
|
44127
|
+
new_todo: (projectId, memberId) => `${"todo:new" /* NEW_TODO */}:${projectId}${privateSuffix(memberId)}`,
|
|
44128
|
+
status: (projectId, memberId) => `${"project:status" /* PROJECT_STATUS */}:${projectId}${privateSuffix(memberId)}`
|
|
44124
44129
|
},
|
|
44125
44130
|
todo: {
|
|
44126
44131
|
msgStart: (todoId) => `${"todo:msg_start" /* TODO_MSG_START */}:${todoId}`,
|
|
@@ -44637,32 +44642,15 @@ To materialize growth recommendations, propose todos on the project board. A pro
|
|
|
44637
44642
|
|
|
44638
44643
|
Exactly ONE \`api_recommend_template\` call per proposal: it carries both what the todo is and where it lands on the board.
|
|
44639
44644
|
|
|
44640
|
-
1. WHAT IT IS. Pass \`name\`
|
|
44645
|
+
1. WHAT IT IS. Pass \`name\`, \`description\` and \`body\`, written for THIS business.
|
|
44641
44646
|
- Reuse an existing registry template instead ONLY when it already fits this business closely with no meaningful edits: pass its id as \`templateId\` and omit \`name\`/\`body\`. If it needs tailoring, write yours inline. Do not recommend a generic playbook that ignores this company's specifics.
|
|
44642
44647
|
|
|
44643
|
-
|
|
44644
|
-
|
|
44645
|
-
|
|
44646
|
-
|
|
44647
|
-
Hard limits: body ≤80 words total. One sentence of persona. One-sentence task. 2-4 steps, each a short fragment of at most 8 words naming WHAT, not how. Data needed is a comma-separated list. If a sentence wouldn't change what the agent does, delete it.
|
|
44648
|
+
A person reads it at a glance and decides whether to run it, so use as few words as possible. The executing agent is capable, reads the business context at run time and asks for anything it is missing, so give no steps, no list of inputs and no background.
|
|
44649
|
+
- \`name\`: 3-6 words, action-first like "Win Reddit comparison threads", with no company name prefix.
|
|
44650
|
+
- \`description\`: one plain sentence of at most 15 words saying what the user gets, such as "Three vs-Gmail pages, drafted and ready to publish." Never repeat the name.
|
|
44651
|
+
- \`body\`: one sentence naming the expert to act as, such as "You are an SEO writer for email products." Nothing else: no headings, no task, no steps.
|
|
44648
44652
|
|
|
44649
|
-
|
|
44650
|
-
|
|
44651
|
-
Example body at the right density (adapt specifics, keep the brevity):
|
|
44652
|
-
"You are a B2B outbound specialist for dev-tool companies.
|
|
44653
|
-
Your task:
|
|
44654
|
-
Land Acme in 10 agency partner conversations this month.
|
|
44655
|
-
Steps:
|
|
44656
|
-
- Shortlist 30 EU automation agencies
|
|
44657
|
-
- Draft one-line personalized openers
|
|
44658
|
-
- Send, track replies in a sheet
|
|
44659
|
-
Data needed:
|
|
44660
|
-
Acme pricing page, current partner list, founder's LinkedIn"
|
|
44661
|
-
|
|
44662
|
-
Body structure (REQUIRED). The body is split into the agent's system prompt and the first user turn by section headings, so follow this exactly:
|
|
44663
|
-
- Start with the persona, expertise and any Rules as plain prose at the top with no heading. This becomes the agent's system prompt.
|
|
44664
|
-
- Then write the request using these exact standalone heading lines, letters only, each on its own line and ending with a colon: \`Your task:\`, \`Steps:\`, \`Data needed:\`. Everything under these headings becomes the first user turn.
|
|
44665
|
-
- Headings must match exactly or the split breaks. Write \`Your task:\`, not \`Your task (SEO):\`. Put the business-specific detail in the body text under each heading, never in the heading itself.
|
|
44653
|
+
Language: write the name, description, body and note in the language the company itself communicates in. When the company is international or unclear, use English.
|
|
44666
44654
|
|
|
44667
44655
|
2. WHERE IT LANDS, in that same call. It becomes a PROPOSED todo on the project and never a running todo:
|
|
44668
44656
|
Give it a one-line \`note\` of roughly 15 words at most giving the WHY for THIS business, which becomes the proposal's tooltip, a \`priority\` of high, medium or low. Leave \`group\` empty: proposals land on the board without a group, and you never create, rename or archive groups. Project and business context default to the current session, so pass them only when targeting a different one. The proposal appears as a ✧ row on the board for the user to review before any credits are spent. Re-proposing the same \`templateId\` refreshes that open proposal instead of duplicating it. An inline proposal is always a new one, so check the board you just read before repeating a move that is already there. Dismissed proposals since your last run are fed back to you. Don't re-propose those, steer elsewhere.
|
|
@@ -44723,6 +44711,137 @@ var OUTPUT_POLICIES = {
|
|
|
44723
44711
|
full: { firstLimit: Infinity, lastLimit: 0, hardCap: RUN_OUTPUT_CAP, lineLimit: MAX_LINE_LEN },
|
|
44724
44712
|
raw: { firstLimit: Infinity, lastLimit: 0, hardCap: Infinity, lineLimit: Infinity }
|
|
44725
44713
|
};
|
|
44714
|
+
// ../packages/shared-fbe/src/agentRoles.ts
|
|
44715
|
+
var SAFE = "Prepare drafts and lists; never send, publish, pay or delete anything without my OK.";
|
|
44716
|
+
var AGENT_ROLES = [
|
|
44717
|
+
{
|
|
44718
|
+
key: "assistant",
|
|
44719
|
+
name: "Assistant",
|
|
44720
|
+
icon: "inbox",
|
|
44721
|
+
color: "#6366f1",
|
|
44722
|
+
tagline: "Inbox, calendar, meetings",
|
|
44723
|
+
outcomes: ["Inbox sorted, replies drafted", "A brief before every meeting", "Your week planned by Monday"],
|
|
44724
|
+
tools: ["zele", "zele-calendar", "outlook-api"],
|
|
44725
|
+
systemMessage: `You are my executive assistant. Keep my inbox and calendar under control. ${SAFE}
|
|
44726
|
+
|
|
44727
|
+
How you work:
|
|
44728
|
+
1. Read new emails and sort them: needs me / FYI / ignore.
|
|
44729
|
+
2. Draft replies for the ones that need me, in my voice.
|
|
44730
|
+
3. For meetings in the next 2 days, write a short brief from the related emails.
|
|
44731
|
+
4. Show me the drafts before anything is sent.`
|
|
44732
|
+
},
|
|
44733
|
+
{
|
|
44734
|
+
key: "bookkeeper",
|
|
44735
|
+
name: "Bookkeeping assistant",
|
|
44736
|
+
icon: "receipt",
|
|
44737
|
+
color: "#10b981",
|
|
44738
|
+
tagline: "Invoices, receipts, accountant",
|
|
44739
|
+
outcomes: ["Invoices from the inbox in one table", "Unpaid invoices reminded", "Month-end email to the accountant"],
|
|
44740
|
+
tools: ["zele", "stripe", "gdrive"],
|
|
44741
|
+
systemMessage: `You are my bookkeeping assistant. Keep invoices and receipts complete and organised. ${SAFE}
|
|
44742
|
+
|
|
44743
|
+
How you work:
|
|
44744
|
+
1. Find invoices and receipts from the last month (inbox, Stripe, Drive).
|
|
44745
|
+
2. Put them in a table: date, vendor, amount, VAT, attachment.
|
|
44746
|
+
3. List unpaid invoices and draft polite reminders.
|
|
44747
|
+
4. Draft the email to my accountant with the table; ask me before sending.`
|
|
44748
|
+
},
|
|
44749
|
+
{
|
|
44750
|
+
key: "sales",
|
|
44751
|
+
name: "Sales rep",
|
|
44752
|
+
icon: "target",
|
|
44753
|
+
color: "#f97316",
|
|
44754
|
+
tagline: "Leads, outreach, follow-ups",
|
|
44755
|
+
outcomes: ["Lead replies drafted in minutes", "Personal outreach at scale", "CRM always up to date"],
|
|
44756
|
+
tools: ["hubspot", "linkedin-api", "zele"],
|
|
44757
|
+
systemMessage: `You are my sales development rep. Research leads and write short, personal outreach. ${SAFE}
|
|
44758
|
+
|
|
44759
|
+
How you work:
|
|
44760
|
+
1. Research each lead: company, role, a relevant recent fact.
|
|
44761
|
+
2. Draft a short personal first message or reply.
|
|
44762
|
+
3. Update the CRM with the lead and a follow-up date.
|
|
44763
|
+
4. Ask me before sending any message.`
|
|
44764
|
+
},
|
|
44765
|
+
{
|
|
44766
|
+
key: "account-manager",
|
|
44767
|
+
name: "Account manager",
|
|
44768
|
+
icon: "briefcase",
|
|
44769
|
+
color: "#f59e0b",
|
|
44770
|
+
tagline: "Client updates, renewals",
|
|
44771
|
+
outcomes: ["Weekly status per client", "Recap after every call", "Silent clients flagged"],
|
|
44772
|
+
tools: ["zele", "slack-cli", "zele-calendar"],
|
|
44773
|
+
systemMessage: `You are my account manager. Keep every client relationship warm and on track. ${SAFE}
|
|
44774
|
+
|
|
44775
|
+
How you work:
|
|
44776
|
+
1. Find clients who have not replied to my last message for 5+ days.
|
|
44777
|
+
2. Draft a short, friendly follow-up for each.
|
|
44778
|
+
3. After calls, write a recap with decisions and next steps.
|
|
44779
|
+
4. Ask me before sending.`
|
|
44780
|
+
},
|
|
44781
|
+
{
|
|
44782
|
+
key: "social",
|
|
44783
|
+
name: "Social media manager",
|
|
44784
|
+
icon: "megaphone",
|
|
44785
|
+
color: "#ec4899",
|
|
44786
|
+
tagline: "Weekly posts in your voice",
|
|
44787
|
+
outcomes: ["Posts per channel in your style", "A full weekly calendar", "Reply drafts for comments"],
|
|
44788
|
+
tools: ["linkedin-api", "xurl", "facebook-pages-api"],
|
|
44789
|
+
systemMessage: `You are my social media manager. Write in my brand voice for each channel. ${SAFE}
|
|
44790
|
+
|
|
44791
|
+
How you work:
|
|
44792
|
+
1. Read my brand page and the voice for each channel.
|
|
44793
|
+
2. Draft 3 posts for this week, one idea each.
|
|
44794
|
+
3. Draft replies to new comments worth answering.
|
|
44795
|
+
4. Ask me before publishing anything.`
|
|
44796
|
+
},
|
|
44797
|
+
{
|
|
44798
|
+
key: "ads",
|
|
44799
|
+
name: "Ads manager",
|
|
44800
|
+
icon: "trending-up",
|
|
44801
|
+
color: "#3b82f6",
|
|
44802
|
+
tagline: "Meta and Google ads",
|
|
44803
|
+
outcomes: ["Wasted spend flagged daily", "Budget moved to the best ROAS", "Creative fatigue caught early"],
|
|
44804
|
+
tools: ["meta-ads", "google-ads"],
|
|
44805
|
+
systemMessage: `You are my ads manager. Watch performance and propose concrete changes. ${SAFE}
|
|
44806
|
+
|
|
44807
|
+
How you work:
|
|
44808
|
+
1. Pull yesterday's results per campaign and ad.
|
|
44809
|
+
2. Flag the worst cost per result and tired creatives.
|
|
44810
|
+
3. Propose budget moves with the numbers behind them.
|
|
44811
|
+
4. Ask me before changing any budget or pausing anything.`
|
|
44812
|
+
},
|
|
44813
|
+
{
|
|
44814
|
+
key: "developer",
|
|
44815
|
+
name: "Developer",
|
|
44816
|
+
icon: "code",
|
|
44817
|
+
color: "#0ea5e9",
|
|
44818
|
+
tagline: "Errors, PRs, deploys",
|
|
44819
|
+
outcomes: ["New errors grouped by cause each morning", "PR reviews with fixes", "Deploys after your OK"],
|
|
44820
|
+
tools: ["gh", "sentry-cli", "vercel"],
|
|
44821
|
+
systemMessage: `You are my senior developer. Keep the code healthy: small, tested, reviewed changes. Never deploy or merge without my OK.
|
|
44822
|
+
|
|
44823
|
+
How you work:
|
|
44824
|
+
1. Check new errors since yesterday and group them by cause.
|
|
44825
|
+
2. Fix the most important one on a branch, with a test.
|
|
44826
|
+
3. Open a pull request with a short explanation.
|
|
44827
|
+
4. Ask me before merging or deploying.`
|
|
44828
|
+
},
|
|
44829
|
+
{
|
|
44830
|
+
key: "researcher",
|
|
44831
|
+
name: "Market researcher",
|
|
44832
|
+
icon: "search",
|
|
44833
|
+
color: "#8b5cf6",
|
|
44834
|
+
tagline: "Competitors, markets, trends",
|
|
44835
|
+
outcomes: ["Weekly competitor watch", "Market brief before a pitch", "Brand mentions caught"],
|
|
44836
|
+
tools: ["perplexity-api", "agent-browser"],
|
|
44837
|
+
systemMessage: `You are my market researcher. Cite sources, separate facts from guesses, keep it short.
|
|
44838
|
+
|
|
44839
|
+
How you work:
|
|
44840
|
+
1. Check what my competitors shipped or announced this week.
|
|
44841
|
+
2. Search for new mentions of my brand.
|
|
44842
|
+
3. Write a one-page brief with sources.`
|
|
44843
|
+
}
|
|
44844
|
+
];
|
|
44726
44845
|
// ../packages/shared-fbe/src/tool_catalog.json
|
|
44727
44846
|
var tool_catalog_default = {
|
|
44728
44847
|
zele: {
|
|
@@ -44811,6 +44930,22 @@ var tool_catalog_default = {
|
|
|
44811
44930
|
description: "Figma REST API CLI. File commands take a file key or Figma URL. Canvas writes (frames/text/shapes) use `figma-api run` via the plugin bridge. Run `figma-api <cmd> --help` for params.",
|
|
44812
44931
|
versionCmd: "figma-api --version 2>/dev/null | sed -n 1p"
|
|
44813
44932
|
},
|
|
44933
|
+
"slack-api": {
|
|
44934
|
+
oauthBroker: true,
|
|
44935
|
+
category: "communication",
|
|
44936
|
+
pkg: "@todoforai/slack-api",
|
|
44937
|
+
installer: "npm",
|
|
44938
|
+
label: "Slack",
|
|
44939
|
+
summary: "Read and answer your Slack as yourself: DMs and mentions, search, history, threads.",
|
|
44940
|
+
loginCmd: "slack-api auth --token <user_token>",
|
|
44941
|
+
statusCmd: `slack-api whoami 2>/dev/null | sed -n 's/.*"user"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' | grep -m1 .`,
|
|
44942
|
+
logoutCmd: "slack-api logout",
|
|
44943
|
+
credentialPaths: [
|
|
44944
|
+
"~/.config/slack-api/credentials.json"
|
|
44945
|
+
],
|
|
44946
|
+
versionCmd: "slack-api --version 2>/dev/null | sed -n 1p",
|
|
44947
|
+
description: "Slack Web API as the signed-in user (user token xoxp-, sees exactly what the user sees), JSON out. Sign-in: Connect (TODOforAI Slack app, user scopes) or `slack-api auth --stdin` / env SLACK_USER_TOKEN. `slack-api inbox [--days 3]` = DMs to you + @mentions, newest first, one JSON line each {id, thread, from, chat, subject, text, url, date} — a ready Feed source: `tfa-wait slack --feed --draft --repeat --forever --watch 'slack-api inbox' --every 2m --name Slack \"{{payload.text}}\"` (send-ready reply drafts in the Feed). Also `search '<slack query>'`, `history <C…|D…>`, `thread <channel> <ts>`, `conversations`, `user <U…>`, `dm <U…>`, `send <channel> <text> [--thread ts] --yes` (posts AS the user; without --yes only previews), `api <method> --param k=v` for any Web API method. search.messages is Tier 2 (~20/min); on ratelimited the error has retry_after. For Slack app development use slack-cli instead."
|
|
44948
|
+
},
|
|
44814
44949
|
"slack-cli": {
|
|
44815
44950
|
preinstallCloud: true,
|
|
44816
44951
|
cloudInstallCmd: "curl -fsSL https://github.com/slackapi/slack-cli/releases/download/v4.2.0/slack_cli_4.2.0_linux_amd64.tar.gz | tar -xz -C /tmp bin/slack && install -m0755 /tmp/bin/slack /usr/local/bin/slack-cli && rm -rf /tmp/bin",
|
|
@@ -45244,7 +45379,7 @@ var tool_catalog_default = {
|
|
|
45244
45379
|
installer: "npm",
|
|
45245
45380
|
label: "TODOforAI",
|
|
45246
45381
|
summary: "Create and follow up on your TODOs, and show results in the chat.",
|
|
45247
|
-
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]` (your own todos; `--
|
|
45382
|
+
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]` (your own todos; `--contributor all` for every member's), `--inspect <id>`. Edit any todo without opening it: `status <id> DONE|READY|CANCELLED|ARCHIVED|DELETED` (close, reopen, stop, archive, 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=…` (also permissions=… and judgeSysmsg=…; 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, `show ref <alias|todoId:alias>` re-posts it live at the chat bottom, `--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>] [--url <link>: tap opens it on the phone, e.g. a Google Maps navigation link]` 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).",
|
|
45248
45383
|
installCmd: "npm install -g @todoforai/cli",
|
|
45249
45384
|
versionCmd: "tfa-cli --version 2>/dev/null | sed -n 1p",
|
|
45250
45385
|
preinstallCloud: true,
|
|
@@ -45448,12 +45583,9 @@ var tool_catalog_default = {
|
|
|
45448
45583
|
binName: "az",
|
|
45449
45584
|
statusCmd: "az account show --query user.name -o tsv 2>/dev/null | tr -d '\\r' | grep -m1 .",
|
|
45450
45585
|
logoutCmd: "az logout 2>&1; az account clear 2>&1",
|
|
45451
|
-
loginCmd: "az login --
|
|
45452
|
-
oauthUrlPattern: "(https://login\\.microsoft\\.com/device\\S*)",
|
|
45453
|
-
deviceCodePattern: "enter the code ([A-Z0-9]+)",
|
|
45454
|
-
canStreamLogin: true,
|
|
45586
|
+
loginCmd: "az login --allow-no-subscriptions",
|
|
45455
45587
|
credentialPaths: ["~/.azure"],
|
|
45456
|
-
description: 'Official Azure CLI.
|
|
45588
|
+
description: 'Official Azure CLI. Browser login with a localhost callback (device code is blocked by Entra Security Defaults on new tenants); `--allow-no-subscriptions` so tenants without a subscription still sign in. Azure SQL: `az sql server list -o json`, `az sql db list -s <server> -g <rg>`, `az sql server firewall-rule create …`; run queries with go-sqlcmd (github.com/microsoft/go-sqlcmd): `sqlcmd -S <server>.database.windows.net -d <db> --authentication-method ActiveDirectoryDefault -Q "SELECT …"` (reuses the az login) or `-U user -P pass` for SQL auth.',
|
|
45457
45589
|
versionCmd: "az version -o tsv 2>/dev/null | cut -f1 | sed -n 1p"
|
|
45458
45590
|
},
|
|
45459
45591
|
doctl: {
|
|
@@ -46145,11 +46277,12 @@ var tool_catalog_default = {
|
|
|
46145
46277
|
statusCmd: `outlook-api whoami 2>/dev/null | sed -n 's/.*"userPrincipalName"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' | grep -m10 .`,
|
|
46146
46278
|
logoutCmd: "outlook-api logout",
|
|
46147
46279
|
loginCmd: "outlook-api auth --tenant common",
|
|
46280
|
+
oauthBroker: true,
|
|
46148
46281
|
credentialPaths: ["~/.config/outlook-api/config.json"],
|
|
46149
|
-
description: "Outlook/Hotmail/M365 mail and calendar over Microsoft Graph (on-prem Exchange → ews-api). `auth` =
|
|
46282
|
+
description: "Outlook/Hotmail/M365 mail and calendar over Microsoft Graph (on-prem Exchange → ews-api). `auth --tenant common` = browser login, redirect to localhost:8644 (`--device` = device code for headless hosts). list/search/read/attachments are read-only; `draft`/`reply` stay in Drafts unless --send; `send <draftId>`. Calendar: `events [--days N|--start|--end] [--tz Europe/Budapest]` (calendarView, recurrences expanded), `event <id>`, `calendars`, `freebusy <emails…>`; writes: `event-create`, `event-respond <id> accept|tentativelyAccept|decline`, `event-delete`. `get <path>` = raw Graph GET. JSON out.",
|
|
46150
46283
|
versionCmd: "outlook-api --version 2>/dev/null | sed -n 1p",
|
|
46151
|
-
|
|
46152
|
-
|
|
46284
|
+
oauthUrlPattern: "(https://login\\.microsoftonline\\.com/\\S+/oauth2/v2\\.0/authorize\\S+)",
|
|
46285
|
+
oauthCallbackPort: 8644,
|
|
46153
46286
|
canStreamLogin: true
|
|
46154
46287
|
},
|
|
46155
46288
|
"outlook-calendar": {
|
|
@@ -46164,11 +46297,12 @@ var tool_catalog_default = {
|
|
|
46164
46297
|
statusCmd: `outlook-api whoami 2>/dev/null | sed -n 's/.*"userPrincipalName"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' | grep -m10 .`,
|
|
46165
46298
|
logoutCmd: "outlook-api logout",
|
|
46166
46299
|
loginCmd: "outlook-api auth --tenant common",
|
|
46300
|
+
oauthBroker: true,
|
|
46167
46301
|
credentialPaths: ["~/.config/outlook-api/config.json"],
|
|
46168
46302
|
description: "Outlook/M365 calendar via `outlook-api`: `events [--days N|--start|--end] [--tz Europe/Budapest]` (calendarView, recurrences expanded), `event <id>`, `calendars`, `freebusy <emails…>` (getSchedule; work/school accounts only); writes: `event-create --subject --start --end [--tz] [--attendee …] [--online]`, `event-respond <id> accept|tentativelyAccept|decline`, `event-delete <id>`. Same sign-in as Outlook mail (`auth`, device code).",
|
|
46169
46303
|
versionCmd: "outlook-api --version 2>/dev/null | sed -n 1p",
|
|
46170
|
-
|
|
46171
|
-
|
|
46304
|
+
oauthUrlPattern: "(https://login\\.microsoftonline\\.com/\\S+/oauth2/v2\\.0/authorize\\S+)",
|
|
46305
|
+
oauthCallbackPort: 8644,
|
|
46172
46306
|
canStreamLogin: true
|
|
46173
46307
|
},
|
|
46174
46308
|
neonctl: {
|
|
@@ -46196,11 +46330,9 @@ var tool_catalog_default = {
|
|
|
46196
46330
|
summary: "Work with Microsoft 365 mail, Teams, SharePoint and users.",
|
|
46197
46331
|
statusCmd: `m365 status --output text 2>/dev/null | tr -d '"' | grep -vi 'logged out' | grep -m1 .`,
|
|
46198
46332
|
logoutCmd: "m365 logout",
|
|
46199
|
-
loginCmd: "m365 login --authType
|
|
46200
|
-
deviceCodePattern: "enter the code ([A-Z0-9]{8,}) to authenticate",
|
|
46201
|
-
oauthUrlPattern: "open the page (https://\\S+) and enter",
|
|
46333
|
+
loginCmd: "m365 login --authType browser --appId 14d82eec-204b-4c2f-b7e8-296a70dab67e",
|
|
46202
46334
|
credentialPaths: ["~/.cli-m365-msal.json", "~/.cli-m365-connection.json"],
|
|
46203
|
-
description: "Microsoft 365 from the shell: `m365 outlook message list`, `m365 teams team list`, `m365 spo site list`.
|
|
46335
|
+
description: "Microsoft 365 from the shell: `m365 outlook message list`, `m365 teams team list`, `m365 spo site list`. Browser login with a localhost callback (device code is blocked by Entra Security Defaults); add `--output json` for parseable output.",
|
|
46204
46336
|
versionCmd: `m365 version 2>/dev/null | tr -d '"' | sed -n 1p`
|
|
46205
46337
|
},
|
|
46206
46338
|
gws: {
|
|
@@ -46374,7 +46506,7 @@ var tool_catalog_default = {
|
|
|
46374
46506
|
installer: "pip",
|
|
46375
46507
|
label: "Blender",
|
|
46376
46508
|
summary: "Model, texture and render 3D scenes in a running Blender.",
|
|
46377
|
-
statusCmd:
|
|
46509
|
+
statusCmd: "command -v blender-mcp >/dev/null && mcporter call blender.get_addon_status --output json 2>/dev/null | grep -o 'blender_version[^,}]*' | grep -m1 .",
|
|
46378
46510
|
loginNoBrowser: true,
|
|
46379
46511
|
loginTerminalHint: "Needs Blender (blender.org) open on this host: in Blender, Edit → Preferences → Add-ons, enable `Blender MCP`, then press N in the 3D view → BlenderMCP tab → Connect / Start MCP server. Then press Connect here.",
|
|
46380
46512
|
loginCmd: `blender-mcp install-addon >/dev/null 2>&1; command -v mcporter >/dev/null 2>&1 || npm install -g --prefix "$HOME/.local" mcporter; mcporter config add blender --command blender-mcp --env BLENDER_MCP_DISABLE_TELEMETRY=1 --description 'Blender 3D via ahujasid/blender-mcp addon' --scope home`,
|
|
@@ -50193,7 +50325,56 @@ var PUBLIC_EMAIL_DOMAINS = new Set([
|
|
|
50193
50325
|
"gmx.com",
|
|
50194
50326
|
"gmx.net",
|
|
50195
50327
|
"mail.com",
|
|
50196
|
-
"zoho.com"
|
|
50328
|
+
"zoho.com",
|
|
50329
|
+
"aol.com",
|
|
50330
|
+
"msn.com",
|
|
50331
|
+
"yahoo.co.uk",
|
|
50332
|
+
"yahoo.de",
|
|
50333
|
+
"yahoo.fr",
|
|
50334
|
+
"yahoo.co.jp",
|
|
50335
|
+
"ymail.com",
|
|
50336
|
+
"pm.me",
|
|
50337
|
+
"tutanota.com",
|
|
50338
|
+
"tuta.io",
|
|
50339
|
+
"gmx.de",
|
|
50340
|
+
"gmx.at",
|
|
50341
|
+
"web.de",
|
|
50342
|
+
"t-online.de",
|
|
50343
|
+
"freenet.de",
|
|
50344
|
+
"orange.fr",
|
|
50345
|
+
"free.fr",
|
|
50346
|
+
"laposte.net",
|
|
50347
|
+
"libero.it",
|
|
50348
|
+
"virgilio.it",
|
|
50349
|
+
"freemail.hu",
|
|
50350
|
+
"citromail.hu",
|
|
50351
|
+
"indamail.hu",
|
|
50352
|
+
"vipmail.hu",
|
|
50353
|
+
"t-email.hu",
|
|
50354
|
+
"seznam.cz",
|
|
50355
|
+
"centrum.cz",
|
|
50356
|
+
"wp.pl",
|
|
50357
|
+
"o2.pl",
|
|
50358
|
+
"onet.pl",
|
|
50359
|
+
"interia.pl",
|
|
50360
|
+
"yandex.ru",
|
|
50361
|
+
"yandex.com",
|
|
50362
|
+
"mail.ru",
|
|
50363
|
+
"rambler.ru",
|
|
50364
|
+
"bk.ru",
|
|
50365
|
+
"inbox.ru",
|
|
50366
|
+
"list.ru",
|
|
50367
|
+
"ukr.net",
|
|
50368
|
+
"qq.com",
|
|
50369
|
+
"foxmail.com",
|
|
50370
|
+
"163.com",
|
|
50371
|
+
"126.com",
|
|
50372
|
+
"yeah.net",
|
|
50373
|
+
"sina.com",
|
|
50374
|
+
"naver.com",
|
|
50375
|
+
"daum.net",
|
|
50376
|
+
"hanmail.net",
|
|
50377
|
+
"rediffmail.com"
|
|
50197
50378
|
]);
|
|
50198
50379
|
// ../packages/shared-fbe/src/toolInstallCommand.ts
|
|
50199
50380
|
var NPM_HOME = '"${TFA_NPM_HOME:-$HOME}"';
|
|
@@ -50210,38 +50391,52 @@ var model_promos_default = {
|
|
|
50210
50391
|
"`family` is a regex on the normalized model id (last path segment, lowercase, dots→dashes, '(level)' suffix stripped);",
|
|
50211
50392
|
"'(-\\\\d+)*' trailing point versions are appended by the consumer, so 'claude-opus-5' covers claude-opus-5.2 too.",
|
|
50212
50393
|
"`provider` matches the provider name instead (TODO GO / Ollama Cloud, subscription-wide).",
|
|
50213
|
-
"`rate` = fraction off. `boostable:false` = the Ultra/Team promo boost (remaining price × boost_remaining_price_factor: +50% usage,
|
|
50394
|
+
"`rate` = fraction off. `boostable:false` = the Ultra/Team promo boost (remaining price × boost_remaining_price_factor ≈ 2/3: +50% usage, 70%→80%, 55%→70%; 0.6666 not 0.667 so the floored display hits 80/70) is NOT applied.",
|
|
50214
50395
|
"`ends` is the last inclusive day (UTC).",
|
|
50215
|
-
"Overlapping rows are fine: the consumer takes the highest live rate. Launch pricing = 85% until 2026-09-13
|
|
50396
|
+
"Overlapping rows are fine: the consumer takes the highest live rate. Launch pricing = 85% until 2026-09-13, 80% until 2026-10-28; from 2026-10-29 to 2026-11-21: OpenAI 70%, Anthropic 55%, Astra 50%, Fable 30%; TODO GO/Ollama no promo (ended 2026-10-28). Astra/Fable/subscription providers are never boosted.",
|
|
50216
50397
|
"A change here goes live with a backend + frontend deploy; agent/src/assets/model_promos.json is only the agent's offline fallback, refresh it occasionally."
|
|
50217
50398
|
],
|
|
50218
|
-
boost_remaining_price_factor: 0.
|
|
50399
|
+
boost_remaining_price_factor: 0.6666,
|
|
50219
50400
|
promos: [
|
|
50220
|
-
{ family: "claude-fable-5", rate: 0.5, starts: "2026-06-29", ends: "2026-
|
|
50401
|
+
{ family: "claude-fable-5", rate: 0.5, starts: "2026-06-29", ends: "2026-10-28", boostable: false },
|
|
50221
50402
|
{ family: "claude-opus-5", rate: 0.85, starts: "2026-06-29", ends: "2026-09-13" },
|
|
50222
|
-
{ family: "claude-opus-5", rate: 0.8, starts: "2026-09-14", ends: "2026-
|
|
50403
|
+
{ family: "claude-opus-5", rate: 0.8, starts: "2026-09-14", ends: "2026-10-28" },
|
|
50223
50404
|
{ family: "claude-opus-4-[78]", rate: 0.85, starts: "2026-06-29", ends: "2026-09-13" },
|
|
50224
|
-
{ family: "claude-opus-4-[78]", rate: 0.8, starts: "2026-09-14", ends: "2026-
|
|
50405
|
+
{ family: "claude-opus-4-[78]", rate: 0.8, starts: "2026-09-14", ends: "2026-10-28" },
|
|
50225
50406
|
{ family: "claude-sonnet-5", rate: 0.85, starts: "2026-06-29", ends: "2026-09-13" },
|
|
50226
|
-
{ family: "claude-sonnet-5", rate: 0.8, starts: "2026-09-14", ends: "2026-
|
|
50407
|
+
{ family: "claude-sonnet-5", rate: 0.8, starts: "2026-09-14", ends: "2026-10-28" },
|
|
50227
50408
|
{ family: "claude-haiku-4-5", rate: 0.85, starts: "2026-06-29", ends: "2026-09-13" },
|
|
50228
|
-
{ family: "claude-haiku-4-5", rate: 0.8, starts: "2026-09-14", ends: "2026-
|
|
50409
|
+
{ family: "claude-haiku-4-5", rate: 0.8, starts: "2026-09-14", ends: "2026-10-28" },
|
|
50229
50410
|
{ family: "claude-haiku-5", rate: 0.85, starts: "2026-06-29", ends: "2026-09-13" },
|
|
50230
|
-
{ family: "claude-haiku-5", rate: 0.8, starts: "2026-09-14", ends: "2026-
|
|
50411
|
+
{ family: "claude-haiku-5", rate: 0.8, starts: "2026-09-14", ends: "2026-10-28" },
|
|
50231
50412
|
{ family: "gpt-5-5(-pro)?", rate: 0.85, starts: "2026-06-29", ends: "2026-09-13" },
|
|
50232
|
-
{ family: "gpt-5-5(-pro)?", rate: 0.8, starts: "2026-09-14", ends: "2026-
|
|
50413
|
+
{ family: "gpt-5-5(-pro)?", rate: 0.8, starts: "2026-09-14", ends: "2026-10-28" },
|
|
50233
50414
|
{ family: "gpt-5-6-sol", rate: 0.85, starts: "2026-08-26", ends: "2026-09-13" },
|
|
50234
|
-
{ family: "gpt-5-6-sol", rate: 0.8, starts: "2026-09-14", ends: "2026-
|
|
50235
|
-
{ family: "gpt-6-sol", rate: 0.8, starts: "2026-09-22", ends: "2026-
|
|
50236
|
-
{ family: "gpt-6-1-sol", rate: 0.8, starts: "2026-09-29", ends: "2026-
|
|
50237
|
-
{ family: "gpt-6-luna", rate: 0.8, starts: "2026-09-22", ends: "2026-
|
|
50415
|
+
{ family: "gpt-5-6-sol", rate: 0.8, starts: "2026-09-14", ends: "2026-10-28" },
|
|
50416
|
+
{ family: "gpt-6-sol", rate: 0.8, starts: "2026-09-22", ends: "2026-10-28" },
|
|
50417
|
+
{ family: "gpt-6-1-sol", rate: 0.8, starts: "2026-09-29", ends: "2026-10-28" },
|
|
50418
|
+
{ family: "gpt-6-luna", rate: 0.8, starts: "2026-09-22", ends: "2026-10-28" },
|
|
50238
50419
|
{ family: "gpt-6-astra", rate: 0.85, starts: "2026-09-05", ends: "2026-09-13", boostable: false },
|
|
50239
|
-
{ family: "gpt-6-astra", rate: 0.8, starts: "2026-09-14", ends: "2026-
|
|
50420
|
+
{ family: "gpt-6-astra", rate: 0.8, starts: "2026-09-14", ends: "2026-10-28", boostable: false },
|
|
50240
50421
|
{ family: "gpt-5-6-terra", rate: 0.85, starts: "2026-06-29", ends: "2026-09-13" },
|
|
50241
|
-
{ family: "gpt-5-6-terra", rate: 0.8, starts: "2026-09-14", ends: "2026-
|
|
50422
|
+
{ family: "gpt-5-6-terra", rate: 0.8, starts: "2026-09-14", ends: "2026-10-28" },
|
|
50242
50423
|
{ family: "gpt-5-6-luna", rate: 0.85, starts: "2026-06-29", ends: "2026-09-13" },
|
|
50243
|
-
{ family: "gpt-5-6-luna", rate: 0.8, starts: "2026-09-14", ends: "2026-
|
|
50244
|
-
{ provider: "opencode[_ -]?go|ollama[_ -]?cloud", rate: 0.5, starts: "2026-06-29", ends: "2026-
|
|
50424
|
+
{ family: "gpt-5-6-luna", rate: 0.8, starts: "2026-09-14", ends: "2026-10-28" },
|
|
50425
|
+
{ provider: "opencode[_ -]?go|ollama[_ -]?cloud", rate: 0.5, starts: "2026-06-29", ends: "2026-10-28", boostable: false },
|
|
50426
|
+
{ family: "claude-opus-5", rate: 0.55, starts: "2026-10-29", ends: "2026-11-21" },
|
|
50427
|
+
{ family: "claude-opus-4-[78]", rate: 0.55, starts: "2026-10-29", ends: "2026-11-21" },
|
|
50428
|
+
{ family: "claude-sonnet-5", rate: 0.55, starts: "2026-10-29", ends: "2026-11-21" },
|
|
50429
|
+
{ family: "claude-haiku-4-5", rate: 0.55, starts: "2026-10-29", ends: "2026-11-21" },
|
|
50430
|
+
{ family: "claude-haiku-5", rate: 0.55, starts: "2026-10-29", ends: "2026-11-21" },
|
|
50431
|
+
{ family: "claude-fable-5", rate: 0.3, starts: "2026-10-29", ends: "2026-11-21", boostable: false },
|
|
50432
|
+
{ family: "gpt-5-5(-pro)?", rate: 0.7, starts: "2026-10-29", ends: "2026-11-21" },
|
|
50433
|
+
{ family: "gpt-5-6-sol", rate: 0.7, starts: "2026-10-29", ends: "2026-11-21" },
|
|
50434
|
+
{ family: "gpt-6-sol", rate: 0.7, starts: "2026-10-29", ends: "2026-11-21" },
|
|
50435
|
+
{ family: "gpt-6-1-sol", rate: 0.7, starts: "2026-10-29", ends: "2026-11-21" },
|
|
50436
|
+
{ family: "gpt-6-luna", rate: 0.7, starts: "2026-10-29", ends: "2026-11-21" },
|
|
50437
|
+
{ family: "gpt-5-6-terra", rate: 0.7, starts: "2026-10-29", ends: "2026-11-21" },
|
|
50438
|
+
{ family: "gpt-5-6-luna", rate: 0.7, starts: "2026-10-29", ends: "2026-11-21" },
|
|
50439
|
+
{ family: "gpt-6-astra", rate: 0.5, starts: "2026-10-29", ends: "2026-11-21", boostable: false }
|
|
50245
50440
|
]
|
|
50246
50441
|
};
|
|
50247
50442
|
|
|
@@ -50251,11 +50446,11 @@ var MODEL_PROMOS = model_promos_default.promos;
|
|
|
50251
50446
|
// ../packages/shared-fbe/src/realtime/topics.ts
|
|
50252
50447
|
var TOPICS = {
|
|
50253
50448
|
["todo:new" /* NEW_TODO */]: {
|
|
50254
|
-
channel: (p) => SERVER_TO_FRONTENDS.project.new_todo(p.projectId, p.
|
|
50449
|
+
channel: (p) => SERVER_TO_FRONTENDS.project.new_todo(p.projectId, p.memberId),
|
|
50255
50450
|
audience: "frontend"
|
|
50256
50451
|
},
|
|
50257
50452
|
["todo:new_message" /* TODO_NEW_MESSAGE */]: {
|
|
50258
|
-
channel: (p) => SERVER_TO_FRONTENDS.project.new_message(p.projectId, p.
|
|
50453
|
+
channel: (p) => SERVER_TO_FRONTENDS.project.new_message(p.projectId, p.memberId),
|
|
50259
50454
|
audience: "frontend"
|
|
50260
50455
|
},
|
|
50261
50456
|
["todo:new_message_created" /* TODO_NEW_MESSAGE_CREATED */]: {
|
|
@@ -50403,7 +50598,7 @@ var TOPICS = {
|
|
|
50403
50598
|
audience: "frontend"
|
|
50404
50599
|
},
|
|
50405
50600
|
["project:status" /* PROJECT_STATUS */]: {
|
|
50406
|
-
channel: (p) => SERVER_TO_FRONTENDS.project.status(p.projectId, p.
|
|
50601
|
+
channel: (p) => SERVER_TO_FRONTENDS.project.status(p.projectId, p.memberId),
|
|
50407
50602
|
audience: "frontend"
|
|
50408
50603
|
},
|
|
50409
50604
|
["todo:status" /* TODO_STATUS */]: {
|
|
@@ -50445,7 +50640,7 @@ var package_default = {
|
|
|
50445
50640
|
type: "git",
|
|
50446
50641
|
url: "git+https://github.com/todoforai/cli.git"
|
|
50447
50642
|
},
|
|
50448
|
-
version: "0.1.
|
|
50643
|
+
version: "0.1.74",
|
|
50449
50644
|
type: "module",
|
|
50450
50645
|
bin: {
|
|
50451
50646
|
"todoforai-cli": "bin/todoforai-cli.js",
|
|
@@ -50515,6 +50710,7 @@ Examples:
|
|
|
50515
50710
|
tfa-cli open <url> [todo-id] # Live url preview in the chat
|
|
50516
50711
|
tfa-cli connect <key>… [--reason "why"] # Sign-in card for connectors on this machine (several keys = one choice)
|
|
50517
50712
|
tfa-cli recommend --template <id> | --title "…" [--info] [--source "label|ref|url"] # ✧ proposal card, or an ⓘ info row
|
|
50713
|
+
tfa-cli ignore --title "…" [--source "label|ref|url|from"] [--note "why"] # Log an inbound item as noise (folded under the Feed card)
|
|
50518
50714
|
tfa-cli inbox [needs-you|messages|activity] [--unread] # Read the notification feed (the bell)
|
|
50519
50715
|
tfa-cli inbox seen [tab] # Mark notifications read
|
|
50520
50716
|
tfa-cli notify [--to <email>] "Title" "message" [--href /t/<id>] [--url <link>] # Note to your own user, or --to a project member (Messages tab + phone push)
|
|
@@ -50599,7 +50795,7 @@ var STATUS_HELP = {
|
|
|
50599
50795
|
["READY_CHECKED" /* READY_CHECKED */]: "AI finished and the user reviewed it",
|
|
50600
50796
|
["DONE" /* DONE */]: "Completed and finalized",
|
|
50601
50797
|
["REVIEW_REQUESTED" /* REVIEW_REQUESTED */]: "Asks the user to review",
|
|
50602
|
-
["
|
|
50798
|
+
["CANCELLED" /* CANCELLED */]: "Stop a running TODO",
|
|
50603
50799
|
["ARCHIVED" /* ARCHIVED */]: "Archived (hidden from active list)",
|
|
50604
50800
|
["DELETED" /* DELETED */]: "Marked for deletion"
|
|
50605
50801
|
};
|
|
@@ -50612,7 +50808,7 @@ ${Object.entries(STATUS_HELP).map(([s, d]) => ` ${s.padEnd(18)}${d}`).join(`
|
|
|
50612
50808
|
`)}
|
|
50613
50809
|
|
|
50614
50810
|
All valid statuses:
|
|
50615
|
-
${Object.values(TodoStatus).join(", ")}
|
|
50811
|
+
${Object.values(TodoStatus).filter((s) => s !== "POSTPONED" /* POSTPONED */).join(", ")}
|
|
50616
50812
|
`);
|
|
50617
50813
|
}
|
|
50618
50814
|
var WORD_FLAGS = {
|
|
@@ -53478,8 +53674,9 @@ Examples:
|
|
|
53478
53674
|
tfa-cli agent update <agent> sysmsg="You are a terse video editor."
|
|
53479
53675
|
tfa-cli agent create name=Reviewer model=claude sysmsg="Review diffs only."
|
|
53480
53676
|
tfa-cli agent update <agent> judgeSysmsg="Ask before sending email." (approval checker; ""=off, null=inherit global)
|
|
53677
|
+
tfa-cli agent update <agent> permissions='{"allow":[…],"ask":[…],"deny":[…]}' (replaces all three lists; read them with get --json first)
|
|
53481
53678
|
|
|
53482
|
-
From an agent shell (dst_ token)
|
|
53679
|
+
From an agent shell (dst_ token) edgesMcpConfigs, devicesConfig, toolProfiles and delete are refused by the backend.
|
|
53483
53680
|
`);
|
|
53484
53681
|
}
|
|
53485
53682
|
var FIELD_ALIASES = {
|
|
@@ -53686,7 +53883,7 @@ var STATUS_HELP2 = {
|
|
|
53686
53883
|
["READY_CHECKED" /* READY_CHECKED */]: "AI finished and the user reviewed it",
|
|
53687
53884
|
["DONE" /* DONE */]: "Completed and finalized",
|
|
53688
53885
|
["REVIEW_REQUESTED" /* REVIEW_REQUESTED */]: "Asks the user to review",
|
|
53689
|
-
["
|
|
53886
|
+
["CANCELLED" /* CANCELLED */]: "Stop a running TODO",
|
|
53690
53887
|
["ARCHIVED" /* ARCHIVED */]: "Archived (hidden from active list)",
|
|
53691
53888
|
["DELETED" /* DELETED */]: "Marked for deletion"
|
|
53692
53889
|
};
|
|
@@ -53903,7 +54100,7 @@ tfa-cli project — edit the current project
|
|
|
53903
54100
|
Usage:
|
|
53904
54101
|
tfa-cli project list Projects you can access (* = default)
|
|
53905
54102
|
tfa-cli project members Who is on it (notify --to <email> reaches them)
|
|
53906
|
-
tfa-cli project set <field=value>… name=… description=…
|
|
54103
|
+
tfa-cli project set <field=value>… name=… description=… logo=<https image url|"">
|
|
53907
54104
|
(isPublic refused from an agent shell)
|
|
53908
54105
|
tfa-cli project default Make it the project you land on at /
|
|
53909
54106
|
tfa-cli project agent <agent> Default agent for new todos in this project
|
|
@@ -53913,11 +54110,15 @@ Usage:
|
|
|
53913
54110
|
tfa-cli project groups intake <slug> [on|off|regenerate] [field=value]…
|
|
53914
54111
|
Public intake: autoStart maxSubmissions postIpLimit placeholder agentSettingsId
|
|
53915
54112
|
tfa-cli project groups reorder <slug>… Set wall order
|
|
53916
|
-
tfa-cli project surfaces List the board's
|
|
53917
|
-
tfa-cli project surfaces set <id> ref=<ref> [title=…] [group=<slug>] [order=N]
|
|
54113
|
+
tfa-cli project surfaces List the board's cards you can see: id, title, ref|note, group, color
|
|
54114
|
+
tfa-cli project surfaces set <id> ref=<ref> [title=…] [group=<slug>] [color=#hex] [order=N]
|
|
53918
54115
|
Show a ref on the board: a todo id, <todoId>:<alias>
|
|
53919
54116
|
(shown artifact) or an http(s) url. group= puts it
|
|
53920
54117
|
inside that group's card; group="" makes it standalone.
|
|
54118
|
+
tfa-cli project surfaces set <id> body="…" [group=<slug>] [color=#hex]
|
|
54119
|
+
A note (markdown text). Seen by
|
|
54120
|
+
whoever sees where it sits: standalone = the project,
|
|
54121
|
+
group = its members, your My Private group = only you.
|
|
53921
54122
|
tfa-cli project surfaces rm <id> Take it off the board
|
|
53922
54123
|
|
|
53923
54124
|
Examples:
|
|
@@ -53925,6 +54126,7 @@ Examples:
|
|
|
53925
54126
|
tfa-cli project groups set marketing name=Marketing description="Top-of-funnel work"
|
|
53926
54127
|
tfa-cli project groups reorder marketing sales ops
|
|
53927
54128
|
tfa-cli project surfaces set weekly-kpis ref=$TODOFORAI_TODO_ID:kpi title="Weekly KPIs" group=marketing
|
|
54129
|
+
tfa-cli project surfaces set sales-rules body="Quote prices in EUR, net of VAT." group=sales
|
|
53928
54130
|
`);
|
|
53929
54131
|
}
|
|
53930
54132
|
var TODO_ALIASES = {
|
|
@@ -54113,21 +54315,23 @@ async function projectCommand(api, positionals, args, projectId) {
|
|
|
54113
54315
|
console.log(JSON.stringify(surfaces, null, 2));
|
|
54114
54316
|
return;
|
|
54115
54317
|
}
|
|
54318
|
+
const titleOf = (s) => s.title || (s.body ?? "").split(`
|
|
54319
|
+
`).find((l) => l.trim())?.trim().slice(0, 60) || "";
|
|
54116
54320
|
for (const s of surfaces)
|
|
54117
|
-
process.stderr.write(`${s.id} ${s
|
|
54321
|
+
process.stderr.write(`${s.id} ${titleOf(s)} ${DIM}${[s.ref ?? "note", s.group && `in ${s.group}`, s.color].filter(Boolean).join(" ")}${RESET}
|
|
54118
54322
|
`);
|
|
54119
54323
|
return;
|
|
54120
54324
|
}
|
|
54121
54325
|
if (verb === "set") {
|
|
54122
54326
|
const [id, ...fields] = sargs;
|
|
54123
54327
|
if (!id)
|
|
54124
|
-
fail("Usage: tfa-cli project surfaces set <id> ref=<ref
|
|
54328
|
+
fail("Usage: tfa-cli project surfaces set <id> [ref=<ref>|body=…] [title=…] [group=<slug>] [color=#hex] [order=N]");
|
|
54125
54329
|
const surface = await api.upsertProjectSurface(projectId, id, parseAssignments2(fields));
|
|
54126
54330
|
if (args.json) {
|
|
54127
54331
|
console.log(JSON.stringify(surface, null, 2));
|
|
54128
54332
|
return;
|
|
54129
54333
|
}
|
|
54130
|
-
process.stderr.write(`${GREEN}✅ surface ${id} shows ${surface.ref}${surface.group ? ` in ${surface.group}` : ""}${RESET}
|
|
54334
|
+
process.stderr.write(`${GREEN}✅ surface ${id} ${surface.ref ? `shows ${surface.ref}` : "is a note"}${surface.group ? ` in ${surface.group}` : ""}${RESET}
|
|
54131
54335
|
`);
|
|
54132
54336
|
return;
|
|
54133
54337
|
}
|
|
@@ -54499,40 +54703,26 @@ var VALID_STATUS = new Set(Object.values(TodoStatus));
|
|
|
54499
54703
|
var isOpen = (s) => !CLOSED.has(s);
|
|
54500
54704
|
function printListTodosHelp() {
|
|
54501
54705
|
process.stderr.write(`
|
|
54502
|
-
todoforai-cli list —
|
|
54706
|
+
todoforai-cli list [flags] — todos of a project, newest first (lastActivityAt)
|
|
54503
54707
|
|
|
54504
|
-
|
|
54708
|
+
Scope: yours only (todos you opened or wrote in) → --contributor all = every member's
|
|
54709
|
+
open only (hides DONE, ARCHIVED, DELETED) → -A / --all = closed too
|
|
54710
|
+
Output: STATUS YYYY-MM-DD HH:MM <todoId> <first line of content>
|
|
54711
|
+
--json → { items: [{ id, status, content, lastActivityAt, createdAt, contributorIds, … }], nextCursor }
|
|
54505
54712
|
|
|
54506
|
-
|
|
54507
|
-
|
|
54713
|
+
Filters (all combinable):
|
|
54714
|
+
-s, --status <S,S2> exact statuses, union (closed ones included); OPEN = any non-closed
|
|
54715
|
+
--search <text> content/status substring (backend)
|
|
54716
|
+
--contributor <u> id or email, comma = any; "all" = no filter (default: you)
|
|
54717
|
+
--since/--until <t> window on the sort field: epoch ms | YYYY-MM-DD | ISO | 12h / 3d (ago)
|
|
54718
|
+
--sort created by createdAt instead of activity
|
|
54719
|
+
--project <id> other project (default: the current one)
|
|
54508
54720
|
|
|
54509
|
-
|
|
54510
|
-
--project-wide Every member's todos, not just yours
|
|
54511
|
-
-n, --limit <n> Max rows to show (default: 30)
|
|
54512
|
-
--cursor <n> Fetch todos older than this cursor (sort field, epoch ms)
|
|
54513
|
-
--since <t> Only todos with sort field >= t (inclusive)
|
|
54514
|
-
--until <t> Only todos with sort field < t (exclusive)
|
|
54515
|
-
t = epoch ms | YYYY-MM-DD (local midnight) | ISO datetime | 12h / 3d ago
|
|
54516
|
-
--sort <key> activity (lastActivityAt, default) | created (createdAt)
|
|
54517
|
-
--contributor <u> Only todos a member opened/wrote in (id or email; comma = any; replaces the "mine" default)
|
|
54518
|
-
--page-size <n> Backend page size per request (default: min(limit, 400), max: 400)
|
|
54519
|
-
--search <text> Search content/status on the backend
|
|
54520
|
-
-s, --status <S[,S2]> Filter by status (comma-separated, union).
|
|
54521
|
-
-A, --all Include closed (DONE, ARCHIVED, DELETED)
|
|
54522
|
-
--project <id> Project ID (default: current default project)
|
|
54523
|
-
--json Output { items, nextCursor } as JSON
|
|
54524
|
-
-h, --help Show this help
|
|
54721
|
+
Paging: -n <limit> (default 30). "Next cursor: N" on stderr / nextCursor in JSON → re-run with --cursor N.
|
|
54525
54722
|
|
|
54526
54723
|
Examples:
|
|
54527
|
-
todoforai-cli list # 30 most recent open todos of yours
|
|
54528
|
-
todoforai-cli list --project-wide # … of everyone in the project
|
|
54529
|
-
todoforai-cli list -n 50 # last 50 open
|
|
54530
|
-
todoforai-cli list --cursor 1719234567890 # next page
|
|
54531
|
-
todoforai-cli list --all # include DONE
|
|
54532
54724
|
todoforai-cli list -s RUNNING,REVIEW_REQUESTED
|
|
54533
|
-
todoforai-cli list -A --since
|
|
54534
|
-
todoforai-cli list -A --sort created --since 7d --contributor a@b.com
|
|
54535
|
-
todoforai-cli list --search bug --json | jq '.items[].id'
|
|
54725
|
+
todoforai-cli list --contributor all -A --since 7d --json | jq -r '.items[] | [.id, .status] | @tsv'
|
|
54536
54726
|
`);
|
|
54537
54727
|
}
|
|
54538
54728
|
function positiveInt(value, name) {
|
|
@@ -54629,7 +54819,6 @@ async function listTodosCommand(api, defaultProjectId, argv, resolveUserId) {
|
|
|
54629
54819
|
until: { type: "string" },
|
|
54630
54820
|
sort: { type: "string" },
|
|
54631
54821
|
contributor: { type: "string" },
|
|
54632
|
-
"project-wide": { type: "boolean", default: false },
|
|
54633
54822
|
status: { type: "string", short: "s" },
|
|
54634
54823
|
all: { type: "boolean", short: "A", default: false },
|
|
54635
54824
|
project: { type: "string" },
|
|
@@ -54662,9 +54851,11 @@ async function listTodosCommand(api, defaultProjectId, argv, resolveUserId) {
|
|
|
54662
54851
|
if (until !== undefined)
|
|
54663
54852
|
cursor = cursor === undefined ? until : Math.min(cursor, until);
|
|
54664
54853
|
const search = values.search ? String(values.search) : undefined;
|
|
54665
|
-
|
|
54854
|
+
const contributorArg = values.contributor === undefined ? undefined : String(values.contributor);
|
|
54855
|
+
const everyone = contributorArg?.trim().toLowerCase() === "all";
|
|
54856
|
+
let contributorIds = contributorArg && !everyone ? await resolveContributors(api, projectId, contributorArg) : undefined;
|
|
54666
54857
|
let mineOnly = false;
|
|
54667
|
-
if (!contributorIds && !
|
|
54858
|
+
if (!contributorIds && !everyone && resolveUserId) {
|
|
54668
54859
|
const me = await resolveUserId();
|
|
54669
54860
|
if (me) {
|
|
54670
54861
|
contributorIds = [me];
|
|
@@ -54726,7 +54917,7 @@ async function listTodosCommand(api, defaultProjectId, argv, resolveUserId) {
|
|
|
54726
54917
|
`);
|
|
54727
54918
|
return;
|
|
54728
54919
|
}
|
|
54729
|
-
const scopeHint = mineOnly ? " of yours (--
|
|
54920
|
+
const scopeHint = mineOnly ? " of yours (--contributor all for everyone's)" : "";
|
|
54730
54921
|
if (!visible.length) {
|
|
54731
54922
|
process.stderr.write(`${DIM}(no todos${scopeHint})${RESET}
|
|
54732
54923
|
`);
|
|
@@ -80418,6 +80609,28 @@ async function main() {
|
|
|
80418
80609
|
console.log(res.ref);
|
|
80419
80610
|
return;
|
|
80420
80611
|
}
|
|
80612
|
+
if (positionals[0] === "ignore") {
|
|
80613
|
+
const title = args.title?.trim();
|
|
80614
|
+
if (!title) {
|
|
80615
|
+
process.stderr.write(`${RED3}Usage: tfa-cli ignore --title "..." [--source "label|ref|url|from"] [--note "why"] [--project <id>]${RESET2}
|
|
80616
|
+
`);
|
|
80617
|
+
process.exit(2);
|
|
80618
|
+
}
|
|
80619
|
+
const source = args.source ? (() => {
|
|
80620
|
+
const [label, ref, url2, from] = String(args.source).split("|");
|
|
80621
|
+
return label && ref ? { label, ref, ...url2 ? { url: url2 } : {}, ...from ? { from } : {} } : undefined;
|
|
80622
|
+
})() : undefined;
|
|
80623
|
+
const projectId2 = args.project || getEnv("PROJECT_ID") || cfgScope.data.default_project_id;
|
|
80624
|
+
if (!projectId2) {
|
|
80625
|
+
process.stderr.write(`${RED3}No project found \u2014 pass --project <id>${RESET2}
|
|
80626
|
+
`);
|
|
80627
|
+
process.exit(2);
|
|
80628
|
+
}
|
|
80629
|
+
await api2.feedIgnore({ projectId: projectId2, title, ...source ? { source } : {}, ...args.note ? { why: args.note } : {} });
|
|
80630
|
+
process.stderr.write(`${DIM2}ignored: ${title}${RESET2}
|
|
80631
|
+
`);
|
|
80632
|
+
return;
|
|
80633
|
+
}
|
|
80421
80634
|
if (positionals[0] === "recommend") {
|
|
80422
80635
|
const templateId = args.template || positionals[1];
|
|
80423
80636
|
const inlineTitle = !templateId && args.title?.trim();
|
|
@@ -80457,7 +80670,15 @@ async function main() {
|
|
|
80457
80670
|
}
|
|
80458
80671
|
const rec = await api2.recommend({
|
|
80459
80672
|
projectId: projectId2,
|
|
80460
|
-
...templateId ? { specId: templateId } : { template: {
|
|
80673
|
+
...templateId ? { specId: templateId } : { template: {
|
|
80674
|
+
name: inlineTitle,
|
|
80675
|
+
description: args.note || (source ? `From ${source.label}` : inlineTitle),
|
|
80676
|
+
body: `Handle this item: ${inlineTitle}${args.note ? `
|
|
80677
|
+
|
|
80678
|
+
${args.note}` : ""}${source?.url ? `
|
|
80679
|
+
|
|
80680
|
+
Original: ${source.url}` : ""}`
|
|
80681
|
+
} },
|
|
80461
80682
|
...args.info ? { todoKind: "info" } : {},
|
|
80462
80683
|
...source ? { source } : {},
|
|
80463
80684
|
...args.title ? { title: args.title } : {},
|