@todoforai/cli 0.1.24 → 0.1.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/todoai.js +93 -118
- package/package.json +3 -5
package/dist/todoai.js
CHANGED
|
@@ -43465,6 +43465,7 @@ var SERVER_TO_FRONTENDS = {
|
|
|
43465
43465
|
block_update: (todoId) => `todo:${todoId}:block_update`,
|
|
43466
43466
|
context_summary_updated: (todoId) => `${"context:summary_updated" /* CONTEXT_SUMMARY_UPDATED */}:${todoId}`,
|
|
43467
43467
|
context_info_updated: (todoId) => `${"context:info_updated" /* CONTEXT_INFO_UPDATED */}:${todoId}`,
|
|
43468
|
+
predicted_reply_updated: (todoId) => `${"predict:reply_updated" /* PREDICTED_REPLY_UPDATED */}:${todoId}`,
|
|
43468
43469
|
error_result: (todoId) => `${"block:error_result" /* BLOCK_ERROR_RESULT */}:${todoId}`,
|
|
43469
43470
|
meta_result: (todoId) => `${"block:meta_result" /* BLOCK_META_RESULT */}:${todoId}`,
|
|
43470
43471
|
file_changed: (edgeId, path3) => `${"block:file_changed" /* BLOCK_FILE_CHANGED */}:${edgeId}:${path3}`,
|
|
@@ -43896,16 +43897,23 @@ When the user asks you to recommend how to grow (e.g. "recommend growth TODOs",
|
|
|
43896
43897
|
Recommending actionable TODOs from your recommendations:
|
|
43897
43898
|
To materialize growth recommendations, create recommendation cards in the project's Recommendations column. You NEVER create running todos \u2014 you only recommend templates by reference. Two tools, strict roles:
|
|
43898
43899
|
|
|
43899
|
-
1.
|
|
43900
|
-
-
|
|
43901
|
-
- If none fits, CREATE one right there (auth is inherited from your shell):
|
|
43900
|
+
1. GET A TEMPLATE (todoregistry-cli) \u2014 generate-first, reuse only on a close fit:
|
|
43901
|
+
- Default: CREATE a template tailored to THIS business, right there (auth is inherited from your shell):
|
|
43902
43902
|
\`todoregistry-cli create --name "<name>" --description "<one line>" --body @<prompt-file>\` (or \`--body -\` for stdin). It prints the new template id on stdout.
|
|
43903
|
+
- Before creating, you MAY \`todoregistry-cli search <query>\` / \`list -c <category>\` / \`get <id>\`; reuse an existing template ONLY when it already fits this business closely with no meaningful edits. If it needs tailoring, create a new one instead \u2014 do not recommend a generic playbook that ignores this company's specifics.
|
|
43904
|
+
|
|
43905
|
+
Write every generated body to be unmistakably about THIS company \u2014 bake the specifics from the business context into the task itself: the company name, its actual competitors, the target segment, the specific channel/platform, and the concrete metric to move. A reader should never mistake it for a generic template.
|
|
43906
|
+
|
|
43907
|
+
Body structure (REQUIRED \u2014 the body is split into the agent's system prompt and the first user turn by section headings, so follow this exactly):
|
|
43908
|
+
- Start with the persona/expertise and any Rules as plain prose/paragraphs at the top (no heading needed) \u2014 this becomes the agent's system prompt.
|
|
43909
|
+
- Then the request, using these exact standalone heading lines (letters only, each on its own line, ending with a colon): \`Your task:\`, \`Steps:\`, \`Data needed:\`. Everything under these headings becomes the first user turn.
|
|
43910
|
+
- Headings must match exactly (e.g. \`Your task:\`, not \`Your task (SEO):\`) or the split breaks. Put the business-specific detail in the body text under each heading, never in the heading itself.
|
|
43903
43911
|
|
|
43904
43912
|
2. RECOMMEND (todoforai-cli \u2014 references a template id onto the project; never creates a running todo):
|
|
43905
43913
|
\`todoforai-cli recommend --template <id> --project <projectId> --business-context <businessContextId> --note "<why>" --priority high|medium|low\`
|
|
43906
43914
|
Take <projectId> and <businessContextId> from your current session context and pass them explicitly. Put the one-line WHY for THIS business in --note (the card's tooltip). The card appears in the Recommendations column for the user to review before any credits are spent.
|
|
43907
43915
|
|
|
43908
|
-
3. Recommend 3-6 cards (highest priority first).
|
|
43916
|
+
3. Recommend 3-6 cards (highest priority first). Then reply with a one-line summary per card and tell the user they're waiting in the Recommendations column for review.`,
|
|
43909
43917
|
mcpConfigs: {},
|
|
43910
43918
|
edgesMcpConfigs: {},
|
|
43911
43919
|
permissions: {
|
|
@@ -43981,6 +43989,10 @@ var TOPICS = {
|
|
|
43981
43989
|
channel: (p) => SERVER_TO_FRONTENDS.todo.context_info_updated(p.todoId),
|
|
43982
43990
|
audience: "frontend"
|
|
43983
43991
|
},
|
|
43992
|
+
["predict:reply_updated" /* PREDICTED_REPLY_UPDATED */]: {
|
|
43993
|
+
channel: (p) => SERVER_TO_FRONTENDS.todo.predicted_reply_updated(p.todoId),
|
|
43994
|
+
audience: "frontend"
|
|
43995
|
+
},
|
|
43984
43996
|
["hexgrid:updated" /* HEXGRID_UPDATED */]: {
|
|
43985
43997
|
channel: (p) => SERVER_TO_FRONTENDS.hexGrid.updated(p.projectId),
|
|
43986
43998
|
audience: "frontend"
|
|
@@ -44113,12 +44125,13 @@ Usage:
|
|
|
44113
44125
|
todoforai-cli status <todo-id> <STATUS> # Update a todo's status (run 'status --help' for the full list)
|
|
44114
44126
|
todoforai-cli delete <todo-id> # Permanently delete a todo
|
|
44115
44127
|
todoforai-cli addmessage <todo-id> "text" # Add a message to an existing todo
|
|
44128
|
+
todoforai-cli show <file|-> [todo-id] # Show a file in the chat (rendered by mimetype; - reads stdin)
|
|
44129
|
+
# [--title T] [--alias A] [--mime M] [--json]
|
|
44130
|
+
todoforai-cli open <url> [todo-id] # Show a live http(s) url in the chat as a preview
|
|
44131
|
+
# [--title T] [--alias A] [--json]
|
|
44116
44132
|
todoforai-cli recommend --template <id> # Add a template as a recommendation card (see 'todoregistry-cli create')
|
|
44117
44133
|
todoforai-cli claim mint --seed <projectId> [--emails a@x,b@y] [--ttl <sec>] # Mint /claim/<token> ownership links for a project you own
|
|
44118
|
-
todoforai-cli
|
|
44119
|
-
todoforai-cli steering direction "<text>" # Set the direction the generator should follow
|
|
44120
|
-
todoforai-cli steering boost|mute <cat> # Favour / avoid a category
|
|
44121
|
-
todoforai-cli next # Generate steered recommendation cards
|
|
44134
|
+
todoforai-cli next [--direction "<text>"] # Ask the analyzer for growth recommendation cards (optional free-text steer)
|
|
44122
44135
|
|
|
44123
44136
|
Options:
|
|
44124
44137
|
--path <dir> Workspace path (default: cwd)
|
|
@@ -44192,6 +44205,9 @@ function parseCliArgs() {
|
|
|
44192
44205
|
note: { type: "string" },
|
|
44193
44206
|
priority: { type: "string" },
|
|
44194
44207
|
title: { type: "string" },
|
|
44208
|
+
alias: { type: "string" },
|
|
44209
|
+
mime: { type: "string" },
|
|
44210
|
+
direction: { type: "string" },
|
|
44195
44211
|
"business-context": { type: "string" },
|
|
44196
44212
|
seed: { type: "string" },
|
|
44197
44213
|
emails: { type: "string" },
|
|
@@ -46405,92 +46421,6 @@ async function listTodosCommand(api, defaultProjectId, argv) {
|
|
|
46405
46421
|
`);
|
|
46406
46422
|
}
|
|
46407
46423
|
|
|
46408
|
-
// src/steering-command.ts
|
|
46409
|
-
var RED2 = "\x1B[31m";
|
|
46410
|
-
var GREEN2 = "\x1B[32m";
|
|
46411
|
-
var DIM2 = "\x1B[2m";
|
|
46412
|
-
var RESET2 = "\x1B[0m";
|
|
46413
|
-
async function rest(ctx, method, path4, body) {
|
|
46414
|
-
const res = await fetch(`${ctx.apiUrl}${restBasePath(ctx.apiKey)}${path4}`, {
|
|
46415
|
-
method,
|
|
46416
|
-
headers: { "content-type": "application/json", "x-api-key": ctx.apiKey },
|
|
46417
|
-
...body ? { body: JSON.stringify(body) } : {},
|
|
46418
|
-
signal: AbortSignal.timeout(30000)
|
|
46419
|
-
});
|
|
46420
|
-
const text = await res.text();
|
|
46421
|
-
if (!res.ok)
|
|
46422
|
-
throw new Error(`${method} ${path4} failed: ${res.status} ${text}`);
|
|
46423
|
-
return text ? JSON.parse(text) : null;
|
|
46424
|
-
}
|
|
46425
|
-
function printSteering(s) {
|
|
46426
|
-
process.stderr.write(`${GREEN2}Direction:${RESET2} ${s.direction || DIM2 + "(none)" + RESET2}
|
|
46427
|
-
`);
|
|
46428
|
-
process.stderr.write(`${GREEN2}Boosted:${RESET2} ${s.boostedCategoryIds?.join(", ") || DIM2 + "(none)" + RESET2}
|
|
46429
|
-
`);
|
|
46430
|
-
process.stderr.write(`${GREEN2}Muted:${RESET2} ${s.mutedCategoryIds?.join(", ") || DIM2 + "(none)" + RESET2}
|
|
46431
|
-
`);
|
|
46432
|
-
}
|
|
46433
|
-
var USAGE = `${RED2}Usage:
|
|
46434
|
-
todoforai-cli steering get [--project <id>]
|
|
46435
|
-
todoforai-cli steering direction "<text>" [--project <id>] (empty text clears it)
|
|
46436
|
-
todoforai-cli steering boost <categoryId> [--project <id>]
|
|
46437
|
-
todoforai-cli steering mute <categoryId> [--project <id>]
|
|
46438
|
-
todoforai-cli steering clear [--project <id>] (clears all steering)${RESET2}`;
|
|
46439
|
-
async function steeringCommand(ctx, argv) {
|
|
46440
|
-
const sub = argv[0];
|
|
46441
|
-
const path4 = `/projects/${ctx.projectId}/recommendation-steering`;
|
|
46442
|
-
if (!sub || sub === "get") {
|
|
46443
|
-
const s = await rest(ctx, "GET", path4);
|
|
46444
|
-
if (ctx.json)
|
|
46445
|
-
console.log(JSON.stringify(s, null, 2));
|
|
46446
|
-
else
|
|
46447
|
-
printSteering(s);
|
|
46448
|
-
return;
|
|
46449
|
-
}
|
|
46450
|
-
if (sub === "direction") {
|
|
46451
|
-
const text = argv.slice(1).join(" ").trim();
|
|
46452
|
-
const s = await rest(ctx, "PATCH", path4, { projectId: ctx.projectId, direction: text || null });
|
|
46453
|
-
if (ctx.json)
|
|
46454
|
-
console.log(JSON.stringify(s, null, 2));
|
|
46455
|
-
else
|
|
46456
|
-
process.stderr.write(`${GREEN2}\u2705 ${text ? `Direction set: ${text}` : "Direction cleared"}${RESET2}
|
|
46457
|
-
`);
|
|
46458
|
-
return;
|
|
46459
|
-
}
|
|
46460
|
-
if (sub === "boost" || sub === "mute") {
|
|
46461
|
-
const categoryId = argv[1];
|
|
46462
|
-
if (!categoryId) {
|
|
46463
|
-
process.stderr.write(USAGE + `
|
|
46464
|
-
`);
|
|
46465
|
-
process.exit(2);
|
|
46466
|
-
}
|
|
46467
|
-
const current = await rest(ctx, "GET", path4);
|
|
46468
|
-
const key = sub === "boost" ? "boostedCategoryIds" : "mutedCategoryIds";
|
|
46469
|
-
const other = sub === "boost" ? "mutedCategoryIds" : "boostedCategoryIds";
|
|
46470
|
-
const next = Array.from(new Set([...current[key] ?? [], categoryId]));
|
|
46471
|
-
const nextOther = (current[other] ?? []).filter((c2) => c2 !== categoryId);
|
|
46472
|
-
const s = await rest(ctx, "PATCH", path4, { projectId: ctx.projectId, [key]: next, [other]: nextOther });
|
|
46473
|
-
if (ctx.json)
|
|
46474
|
-
console.log(JSON.stringify(s, null, 2));
|
|
46475
|
-
else
|
|
46476
|
-
process.stderr.write(`${GREEN2}\u2705 ${sub === "boost" ? "Boosted" : "Muted"} ${categoryId}${RESET2}
|
|
46477
|
-
`);
|
|
46478
|
-
return;
|
|
46479
|
-
}
|
|
46480
|
-
if (sub === "clear") {
|
|
46481
|
-
const s = await rest(ctx, "PATCH", path4, { projectId: ctx.projectId, direction: null, boostedCategoryIds: [], mutedCategoryIds: [] });
|
|
46482
|
-
if (ctx.json)
|
|
46483
|
-
console.log(JSON.stringify(s, null, 2));
|
|
46484
|
-
else
|
|
46485
|
-
process.stderr.write(`${GREEN2}\u2705 Steering cleared${RESET2}
|
|
46486
|
-
`);
|
|
46487
|
-
return;
|
|
46488
|
-
}
|
|
46489
|
-
process.stderr.write(USAGE + `
|
|
46490
|
-
`);
|
|
46491
|
-
process.exit(2);
|
|
46492
|
-
}
|
|
46493
|
-
|
|
46494
46424
|
// src/index.ts
|
|
46495
46425
|
try {
|
|
46496
46426
|
const pkgPath = path4.resolve(fileURLToPath(import.meta.url), "../../package.json");
|
|
@@ -46735,8 +46665,8 @@ Cancelled by user (Ctrl+C)
|
|
|
46735
46665
|
return;
|
|
46736
46666
|
}
|
|
46737
46667
|
if (positionals[0] === "addmessage") {
|
|
46738
|
-
const [, todoId, ...
|
|
46739
|
-
const content2 =
|
|
46668
|
+
const [, todoId, ...rest] = positionals;
|
|
46669
|
+
const content2 = rest.join(" ") || await readStdin();
|
|
46740
46670
|
if (!todoId || !content2) {
|
|
46741
46671
|
process.stderr.write(`${RED}Usage: todoforai-cli addmessage <todo-id> "content"${RESET}
|
|
46742
46672
|
`);
|
|
@@ -46751,6 +46681,55 @@ Cancelled by user (Ctrl+C)
|
|
|
46751
46681
|
`);
|
|
46752
46682
|
return;
|
|
46753
46683
|
}
|
|
46684
|
+
if (positionals[0] === "show") {
|
|
46685
|
+
const [, filePath, todoArg] = positionals;
|
|
46686
|
+
const todoId = todoArg || getEnv("TODO_ID") || cfgScope.data.last_todo_id;
|
|
46687
|
+
if (!filePath || !todoId) {
|
|
46688
|
+
process.stderr.write(`${RED}Usage: todoforai-cli show <file|-> [todo-id]${RESET}
|
|
46689
|
+
`);
|
|
46690
|
+
process.exit(2);
|
|
46691
|
+
}
|
|
46692
|
+
let blob, name;
|
|
46693
|
+
if (filePath === "-") {
|
|
46694
|
+
blob = new Blob([await Bun.readableStreamToArrayBuffer(Bun.stdin.stream())]);
|
|
46695
|
+
if (blob.size === 0) {
|
|
46696
|
+
process.stderr.write(`${RED}No data on stdin${RESET}
|
|
46697
|
+
`);
|
|
46698
|
+
process.exit(1);
|
|
46699
|
+
}
|
|
46700
|
+
name = "stdin";
|
|
46701
|
+
} else {
|
|
46702
|
+
const file = Bun.file(resolve3(filePath));
|
|
46703
|
+
if (!await file.exists()) {
|
|
46704
|
+
process.stderr.write(`${RED}File not found: ${filePath}${RESET}
|
|
46705
|
+
`);
|
|
46706
|
+
process.exit(1);
|
|
46707
|
+
}
|
|
46708
|
+
blob = file;
|
|
46709
|
+
name = path4.basename(filePath);
|
|
46710
|
+
}
|
|
46711
|
+
const res = await api.showFile(todoId, blob, name, { title: args.title, alias: args.alias, mime: args.mime });
|
|
46712
|
+
if (args.json)
|
|
46713
|
+
console.log(JSON.stringify(res, null, 2));
|
|
46714
|
+
else
|
|
46715
|
+
console.log(res.ref);
|
|
46716
|
+
return;
|
|
46717
|
+
}
|
|
46718
|
+
if (positionals[0] === "open") {
|
|
46719
|
+
const [, url, todoArg] = positionals;
|
|
46720
|
+
const todoId = todoArg || getEnv("TODO_ID") || cfgScope.data.last_todo_id;
|
|
46721
|
+
if (!url || !todoId) {
|
|
46722
|
+
process.stderr.write(`${RED}Usage: todoforai-cli open <url> [todo-id]${RESET}
|
|
46723
|
+
`);
|
|
46724
|
+
process.exit(2);
|
|
46725
|
+
}
|
|
46726
|
+
const res = await api.showUrl(todoId, url, { title: args.title, alias: args.alias });
|
|
46727
|
+
if (args.json)
|
|
46728
|
+
console.log(JSON.stringify(res, null, 2));
|
|
46729
|
+
else
|
|
46730
|
+
console.log(res.ref);
|
|
46731
|
+
return;
|
|
46732
|
+
}
|
|
46754
46733
|
if (positionals[0] === "recommend") {
|
|
46755
46734
|
const templateId = args.template || positionals[1];
|
|
46756
46735
|
if (!templateId) {
|
|
@@ -46833,7 +46812,7 @@ Cancelled by user (Ctrl+C)
|
|
|
46833
46812
|
`);
|
|
46834
46813
|
return;
|
|
46835
46814
|
}
|
|
46836
|
-
if (positionals[0] === "
|
|
46815
|
+
if (positionals[0] === "next") {
|
|
46837
46816
|
let projectId2 = args.project || cfgScope.data.default_project_id;
|
|
46838
46817
|
if (!projectId2) {
|
|
46839
46818
|
const projects2 = await api.listProjects();
|
|
@@ -46844,29 +46823,25 @@ Cancelled by user (Ctrl+C)
|
|
|
46844
46823
|
`);
|
|
46845
46824
|
process.exit(2);
|
|
46846
46825
|
}
|
|
46847
|
-
const
|
|
46848
|
-
|
|
46849
|
-
|
|
46850
|
-
|
|
46851
|
-
|
|
46852
|
-
|
|
46853
|
-
|
|
46854
|
-
|
|
46855
|
-
|
|
46856
|
-
|
|
46857
|
-
process.stderr.write(`${RED}Generate failed: ${res.status} ${text}${RESET}
|
|
46858
|
-
`);
|
|
46859
|
-
process.exit(1);
|
|
46860
|
-
}
|
|
46861
|
-
const out = JSON.parse(text);
|
|
46862
|
-
if (args.json)
|
|
46863
|
-
console.log(JSON.stringify(out, null, 2));
|
|
46864
|
-
else
|
|
46865
|
-
process.stderr.write(`${GREEN}\u2705 Generating recommendations \u2014 analyzer todo ${out.todoId}${RESET}
|
|
46826
|
+
const direction = args.direction || positionals.slice(1).join(" ").trim() || undefined;
|
|
46827
|
+
const res = await fetch(`${apiUrl}${restBasePath(apiKey)}/projects/${projectId2}/recommendations/generate`, {
|
|
46828
|
+
method: "POST",
|
|
46829
|
+
headers: { "content-type": "application/json", "x-api-key": apiKey },
|
|
46830
|
+
body: JSON.stringify({ projectId: projectId2, ...args["business-context"] ? { businessContextId: args["business-context"] } : {}, ...direction ? { direction } : {} }),
|
|
46831
|
+
signal: AbortSignal.timeout(30000)
|
|
46832
|
+
});
|
|
46833
|
+
const text = await res.text();
|
|
46834
|
+
if (!res.ok) {
|
|
46835
|
+
process.stderr.write(`${RED}Generate failed: ${res.status} ${text}${RESET}
|
|
46866
46836
|
`);
|
|
46867
|
-
|
|
46837
|
+
process.exit(1);
|
|
46868
46838
|
}
|
|
46869
|
-
|
|
46839
|
+
const out = JSON.parse(text);
|
|
46840
|
+
if (args.json)
|
|
46841
|
+
console.log(JSON.stringify(out, null, 2));
|
|
46842
|
+
else
|
|
46843
|
+
process.stderr.write(`${GREEN}\u2705 Generating recommendations \u2014 analyzer todo ${out.todoId}${RESET}
|
|
46844
|
+
`);
|
|
46870
46845
|
return;
|
|
46871
46846
|
}
|
|
46872
46847
|
if (args["list-agents"]) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@todoforai/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.25",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"todoforai-cli": "bin/todoforai-cli.js",
|
|
@@ -14,8 +14,7 @@
|
|
|
14
14
|
"build": "bun build src/index.ts --target=bun --outfile dist/todoai.js --external ws",
|
|
15
15
|
"prepublishOnly": "bun run build",
|
|
16
16
|
"start": "bun run src/index.ts",
|
|
17
|
-
"dev": "bun run src/index.ts"
|
|
18
|
-
"postinstall": "rm -rf node_modules/@todoforai/edge && ln -s ../../../edge/bun node_modules/@todoforai/edge"
|
|
17
|
+
"dev": "bun run src/index.ts"
|
|
19
18
|
},
|
|
20
19
|
"dependencies": {
|
|
21
20
|
"@shared/credentials": "file:../packages/shared-credentials",
|
|
@@ -25,7 +24,7 @@
|
|
|
25
24
|
"ws": "^8.18.0"
|
|
26
25
|
},
|
|
27
26
|
"peerDependencies": {
|
|
28
|
-
"@todoforai/edge": "
|
|
27
|
+
"@todoforai/edge": ">=0.12.0"
|
|
29
28
|
},
|
|
30
29
|
"peerDependenciesMeta": {
|
|
31
30
|
"@todoforai/edge": {
|
|
@@ -34,7 +33,6 @@
|
|
|
34
33
|
},
|
|
35
34
|
"devDependencies": {
|
|
36
35
|
"@types/ws": "^8.5.13",
|
|
37
|
-
"@todoforai/edge": "file:../edge/bun",
|
|
38
36
|
"typescript": "^5.7.0"
|
|
39
37
|
}
|
|
40
38
|
}
|