@autumnai/cli 0.1.0 → 0.1.2
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/bin/autumn.mjs +97 -6
- package/package.json +1 -1
- package/skill.md +12 -0
package/bin/autumn.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import os from "node:os";
|
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
|
|
10
|
-
const VERSION = "0.1.
|
|
10
|
+
const VERSION = "0.1.2";
|
|
11
11
|
const DEFAULT_API_URL = "https://api.autumn.ai";
|
|
12
12
|
const USER_AGENT = `autumn-cli/${VERSION}`;
|
|
13
13
|
const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -214,8 +214,8 @@ async function request(config, route, options) {
|
|
|
214
214
|
function parseArgs(tokens) {
|
|
215
215
|
const flags = {};
|
|
216
216
|
const positionals = [];
|
|
217
|
-
const booleanFlags = new Set(["detach", "force", "json", "no-browser", "wait", "help", "h"]);
|
|
218
|
-
const valueFlags = new Set(["out", "timeout", "limit", "format"]);
|
|
217
|
+
const booleanFlags = new Set(["detach", "force", "json", "no-browser", "wait", "help", "h", "yes"]);
|
|
218
|
+
const valueFlags = new Set(["out", "timeout", "limit", "format", "days", "name", "website", "share-by-default", "owners-can-demote"]);
|
|
219
219
|
for (let index = 0; index < tokens.length; index += 1) {
|
|
220
220
|
const token = tokens[index];
|
|
221
221
|
if (token === "--") {
|
|
@@ -264,7 +264,9 @@ Commands:
|
|
|
264
264
|
status <id> [--json] Show current task status once
|
|
265
265
|
rows <id> [--out FILE] [--format csv|json]
|
|
266
266
|
stop <id> Stop a running task
|
|
267
|
-
list [--limit N] (default 20)
|
|
267
|
+
list [query] [--limit N] [--json] List or search recent tasks (default limit: 20)
|
|
268
|
+
team [invite|revoke|role|remove|set] Manage your team (writes are owner-only)
|
|
269
|
+
usage [--days N] [--json] Read usage for the last N days (1–90, default: 30)
|
|
268
270
|
setup [claude|codex|all] Install the Autumn Skill
|
|
269
271
|
mcp-config [claude|codex|cursor] Print MCP connection configuration
|
|
270
272
|
|
|
@@ -289,7 +291,9 @@ function commandHelp(command) {
|
|
|
289
291
|
status: "autumn status <id> [--json]",
|
|
290
292
|
rows: "autumn rows <id> [--out FILE] [--format csv|json]",
|
|
291
293
|
stop: "autumn stop <id>",
|
|
292
|
-
list: "autumn list [--limit N] [--json] (default limit: 20)",
|
|
294
|
+
list: "autumn list [query] [--limit N] [--json] (default limit: 20)",
|
|
295
|
+
team: "autumn team [invite <email>|revoke <invitation_id>|role <user_id> owner|member|remove <user_id> --yes|set [--name N] [--website W] [--share-by-default true|false] [--owners-can-demote true|false]]",
|
|
296
|
+
usage: "autumn usage [--days N] [--json] (1–90, default: 30)",
|
|
293
297
|
setup: "autumn setup [claude|codex|all]",
|
|
294
298
|
"mcp-config": "autumn mcp-config [claude|codex|cursor]",
|
|
295
299
|
};
|
|
@@ -300,6 +304,88 @@ function requirePositionals(positionals, count, usage) {
|
|
|
300
304
|
if (positionals.length < count) throw new CliError(`Usage: ${usage}`);
|
|
301
305
|
}
|
|
302
306
|
|
|
307
|
+
function teamBoolean(value, option) {
|
|
308
|
+
if (value !== "true" && value !== "false") {
|
|
309
|
+
throw new CliError(`--${option} must be true or false.`);
|
|
310
|
+
}
|
|
311
|
+
return value === "true";
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
async function teamCommand(config, positionals, options) {
|
|
315
|
+
const action = positionals[0] || "";
|
|
316
|
+
if (!action) {
|
|
317
|
+
const result = await request(config, "/team");
|
|
318
|
+
if (jsonMode) emit(result);
|
|
319
|
+
else {
|
|
320
|
+
const account = result.account || {};
|
|
321
|
+
writeOut(`account\t${account.type || ""}\t${account.name || ""}\t${account.role || ""}`);
|
|
322
|
+
writeOut("user_id\tname\temail\trole");
|
|
323
|
+
for (const member of result.members || []) {
|
|
324
|
+
writeOut([member.user_id, member.name, member.email, member.role].map((value) => String(value || "").replace(/[\t\r\n]/g, " ")).join("\t"));
|
|
325
|
+
}
|
|
326
|
+
if (account.type === "team" && account.role === "owner") {
|
|
327
|
+
writeOut("\nPending invitations");
|
|
328
|
+
writeOut("id\temail\tcreated_at");
|
|
329
|
+
for (const invitation of result.invitations || []) {
|
|
330
|
+
writeOut([invitation.id, invitation.email, invitation.created_at].map((value) => String(value || "").replace(/[\t\r\n]/g, " ")).join("\t"));
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return 0;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
let result;
|
|
338
|
+
if (action === "invite") {
|
|
339
|
+
requirePositionals(positionals, 2, commandHelp("team"));
|
|
340
|
+
result = await request(config, "/team/invitations", { method: "POST", body: { email: positionals[1] } });
|
|
341
|
+
} else if (action === "revoke") {
|
|
342
|
+
requirePositionals(positionals, 2, commandHelp("team"));
|
|
343
|
+
result = await request(config, `/team/invitations/${encodeURIComponent(positionals[1])}`, { method: "DELETE" });
|
|
344
|
+
} else if (action === "role") {
|
|
345
|
+
requirePositionals(positionals, 3, commandHelp("team"));
|
|
346
|
+
if (!["owner", "member"].includes(positionals[2])) throw new CliError("Role must be owner or member.");
|
|
347
|
+
result = await request(config, `/team/members/${encodeURIComponent(positionals[1])}`, { method: "PATCH", body: { role: positionals[2] } });
|
|
348
|
+
} else if (action === "remove") {
|
|
349
|
+
requirePositionals(positionals, 2, commandHelp("team"));
|
|
350
|
+
if (!options.yes) throw new CliError(`Rerun with --yes to remove ${positionals[1]}`);
|
|
351
|
+
result = await request(config, `/team/members/${encodeURIComponent(positionals[1])}`, { method: "DELETE" });
|
|
352
|
+
} else if (action === "set") {
|
|
353
|
+
if (positionals.length !== 1) throw new CliError(`Usage: ${commandHelp("team")}`);
|
|
354
|
+
const body = {};
|
|
355
|
+
if (options.name !== undefined || options.website !== undefined) {
|
|
356
|
+
if (options.name !== undefined) body.name = options.name;
|
|
357
|
+
if (options.website !== undefined) body.website = options.website;
|
|
358
|
+
}
|
|
359
|
+
const settings = {};
|
|
360
|
+
if (options["share-by-default"] !== undefined) settings.share_chats_by_default = teamBoolean(options["share-by-default"], "share-by-default");
|
|
361
|
+
if (options["owners-can-demote"] !== undefined) settings.owners_can_demote_owners = teamBoolean(options["owners-can-demote"], "owners-can-demote");
|
|
362
|
+
if (Object.keys(settings).length) {
|
|
363
|
+
const current = await request(config, "/team");
|
|
364
|
+
body.settings = settings;
|
|
365
|
+
body.version = current.settings?.version;
|
|
366
|
+
}
|
|
367
|
+
if (!Object.keys(body).length) throw new CliError(`Usage: ${commandHelp("team")}`);
|
|
368
|
+
result = await request(config, "/team", { method: "PATCH", body });
|
|
369
|
+
} else {
|
|
370
|
+
throw new CliError(`Unknown team command: ${action}\n${commandHelp("team")}`);
|
|
371
|
+
}
|
|
372
|
+
if (jsonMode) emit(result);
|
|
373
|
+
else writeOut(action === "invite" ? `Invitation sent to ${positionals[1]}.` : action === "revoke" ? "Invitation revoked." : action === "remove" ? `Removed ${positionals[1]} from the team.` : action === "role" ? `Set ${positionals[1]} to ${positionals[2]}.` : "Team updated.");
|
|
374
|
+
return 0;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
async function usageCommand(config, options) {
|
|
378
|
+
const days = Number(options.days || 30);
|
|
379
|
+
if (!Number.isInteger(days) || days < 1 || days > 90) throw new CliError("--days must be an integer from 1 to 90.");
|
|
380
|
+
const result = await request(config, `/team/usage?days=${days}`);
|
|
381
|
+
if (jsonMode) emit(result);
|
|
382
|
+
else {
|
|
383
|
+
writeOut(`${result.credits_used || 0} credits used across ${result.tasks || 0} tasks in the last ${result.days || days} days.`);
|
|
384
|
+
for (const member of result.members || []) writeOut(`${member.name || member.user_id}: ${member.credits_used || 0} credits, ${member.tasks || 0} tasks`);
|
|
385
|
+
}
|
|
386
|
+
return 0;
|
|
387
|
+
}
|
|
388
|
+
|
|
303
389
|
function taskRoute(taskId) {
|
|
304
390
|
return `/task/${encodeURIComponent(taskId)}`;
|
|
305
391
|
}
|
|
@@ -863,7 +949,10 @@ async function commandMain(command, options, positionals, config) {
|
|
|
863
949
|
if (!Number.isInteger(limit) || limit < 1 || limit > 200) {
|
|
864
950
|
throw new CliError("--limit must be an integer from 1 to 200.");
|
|
865
951
|
}
|
|
866
|
-
const
|
|
952
|
+
const query = positionals.join(" ").trim();
|
|
953
|
+
const params = new URLSearchParams({ limit: String(limit) });
|
|
954
|
+
if (query) params.set("q", query);
|
|
955
|
+
const result = await request(config, `/task?${params}`);
|
|
867
956
|
if (jsonMode) emit(result);
|
|
868
957
|
else {
|
|
869
958
|
const tasks = Array.isArray(result) ? result : result.tasks || [];
|
|
@@ -872,6 +961,8 @@ async function commandMain(command, options, positionals, config) {
|
|
|
872
961
|
}
|
|
873
962
|
return 0;
|
|
874
963
|
}
|
|
964
|
+
if (command === "team") return teamCommand(config, positionals, options);
|
|
965
|
+
if (command === "usage") return usageCommand(config, options);
|
|
875
966
|
throw new CliError(`Unknown command: ${command}\n\n${globalHelp()}`);
|
|
876
967
|
}
|
|
877
968
|
|
package/package.json
CHANGED
package/skill.md
CHANGED
|
@@ -10,6 +10,8 @@ verifies and saves rows with sources, and you read the rows. A task takes minute
|
|
|
10
10
|
seconds, and a task is a conversation: you can answer its questions and refine it on the
|
|
11
11
|
same `task_id`.
|
|
12
12
|
|
|
13
|
+
No task_id? Find it with `list_tasks` (MCP), `autumn list "<words>"` (CLI) or `GET /task?q=<words>`.
|
|
14
|
+
|
|
13
15
|
Don't use Autumn for a quick fact you can answer yourself.
|
|
14
16
|
|
|
15
17
|
## Fastest path: the CLI
|
|
@@ -46,6 +48,16 @@ working or approval pending, and `4` authentication required.
|
|
|
46
48
|
- Check it works: `curl -sS https://api.autumn.ai/credits -H "X-API-Key: $AUTUMN_API_KEY"`.
|
|
47
49
|
- To buy credits, use MCP `buy_credits` or `autumn buy 10000` to get a payment link for the user.
|
|
48
50
|
|
|
51
|
+
## Team and usage
|
|
52
|
+
|
|
53
|
+
- MCP: `get_team`, `get_usage`, `invite_member`, `revoke_invitation`,
|
|
54
|
+
`set_member_role`, `update_team`, `remove_member`.
|
|
55
|
+
- CLI: `autumn team`, `autumn team invite|revoke|role|remove|set`, `autumn usage`.
|
|
56
|
+
- REST: `GET /team`, `PATCH /team`, `POST /team/invitations`,
|
|
57
|
+
`DELETE /team/invitations/{invitation_id}`, `PATCH` / `DELETE /team/members/{user_id}`,
|
|
58
|
+
and `GET /team/usage?days=30`.
|
|
59
|
+
- Team writes are owner-only. Creating or leaving a team is done in the app.
|
|
60
|
+
|
|
49
61
|
## The loop
|
|
50
62
|
|
|
51
63
|
```bash
|