@krodak/clickup-cli 1.25.2 → 1.26.1

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "clickup-cli",
3
3
  "description": "ClickUp CLI skills for managing tasks, sprints, comments, checklists, custom fields, tags, and time tracking via the cup command",
4
- "version": "1.25.2",
4
+ "version": "1.26.1",
5
5
  "author": {
6
6
  "name": "Krzysztof Rodak"
7
7
  },
package/README.md CHANGED
@@ -51,17 +51,17 @@ Install the CLI, add the skill file to your agent, and it works with ClickUp. No
51
51
 
52
52
  The agent reads the skill file, picks the right `cup` commands, and handles everything. You don't need to learn the CLI - the agent does.
53
53
 
54
- ### Agent mode
54
+ ### Terminal mode (TTY)
55
55
 
56
- When piped (no TTY), output is Markdown optimized for AI context windows. Pass `--json` for structured data.
56
+ Task listing commands (`cup tasks`, `cup search`, `cup sprint`, etc.) present an interactive picker — navigate with arrow keys or j/k, Space to select tasks, Enter to confirm. Selected tasks show full details and offer to open in the browser. Other prompts (sprint disambiguation, delete confirmations) also use interactive selection.
57
57
 
58
- ![Agent Mode - markdown and JSON output](demos/agent-mode.gif)
58
+ ![TTY Mode - interactive tables and detail views](demos/tty-mode.gif)
59
59
 
60
- ### Terminal mode
60
+ ### Agent / piped mode
61
61
 
62
- In a terminal, you get interactive tables with colors. Most commands scope to your assigned tasks by default.
62
+ When piped (no TTY), the same commands output clean Markdown (or JSON with `--json`). No prompts, no colors designed for agents and pipelines.
63
63
 
64
- ![TTY Mode - interactive tables and detail views](demos/tty-mode.gif)
64
+ ![Agent Mode - markdown and JSON output](demos/agent-mode.gif)
65
65
 
66
66
  ## Why a CLI and not MCP?
67
67
 
package/dist/index.js CHANGED
@@ -1521,6 +1521,7 @@ function formatAssignConfirmation(taskId, opts) {
1521
1521
  import { execFileSync } from "child_process";
1522
1522
  import { checkbox, confirm, Separator } from "@inquirer/prompts";
1523
1523
  import chalk2 from "chalk";
1524
+ var vimTheme = { keybindings: ["vim"] };
1524
1525
  function openUrl(url) {
1525
1526
  switch (process.platform) {
1526
1527
  case "darwin":
@@ -1672,7 +1673,8 @@ async function interactiveTaskPicker(tasks) {
1672
1673
  name: formatChoiceName(t),
1673
1674
  value: t.id
1674
1675
  })),
1675
- pageSize: 20
1676
+ pageSize: 20,
1677
+ theme: vimTheme
1676
1678
  });
1677
1679
  return tasks.filter((t) => selected.includes(t.id));
1678
1680
  }
@@ -1691,7 +1693,8 @@ async function groupedTaskPicker(groups) {
1691
1693
  const selected = await checkbox({
1692
1694
  message: `${totalCount} task(s) found. Select to view details / open in browser:`,
1693
1695
  choices,
1694
- pageSize: 20
1696
+ pageSize: 20,
1697
+ theme: vimTheme
1695
1698
  });
1696
1699
  return allTasks.filter((t) => selected.includes(t.id));
1697
1700
  }
@@ -2171,7 +2174,8 @@ ${NEXT_STEPS}`);
2171
2174
  } else {
2172
2175
  teamId = await select({
2173
2176
  message: "Select workspace:",
2174
- choices: teams.map((t) => ({ name: t.name, value: t.id }))
2177
+ choices: teams.map((t) => ({ name: t.name, value: t.id })),
2178
+ theme: { keybindings: ["vim"] }
2175
2179
  });
2176
2180
  }
2177
2181
  writeConfig({ apiToken, teamId });
@@ -2363,7 +2367,8 @@ async function runSprintCommand(config, opts) {
2363
2367
  choices: sprintLists.map((l) => ({
2364
2368
  name: `${l.name} (${l.id})`,
2365
2369
  value: l
2366
- }))
2370
+ })),
2371
+ theme: { keybindings: ["vim"] }
2367
2372
  });
2368
2373
  activeList = choice;
2369
2374
  }
@@ -3373,7 +3378,7 @@ var commandMetadata = [
3373
3378
  },
3374
3379
  {
3375
3380
  name: "tasks",
3376
- description: "List tasks assigned to me (use --all for all tasks)",
3381
+ description: "List tasks assigned to you by default. Use --all to search across all assignees.",
3377
3382
  flags: [
3378
3383
  "--status",
3379
3384
  "--list",
@@ -3392,7 +3397,7 @@ var commandMetadata = [
3392
3397
  "--json"
3393
3398
  ],
3394
3399
  quickReference: [
3395
- { section: "read", usage: "tasks", description: "List tasks assigned to me (--all for all)" }
3400
+ { section: "read", usage: "tasks", description: "My tasks (--all for all assignees)" }
3396
3401
  ]
3397
3402
  },
3398
3403
  {
@@ -3594,7 +3599,7 @@ var commandMetadata = [
3594
3599
  },
3595
3600
  {
3596
3601
  name: "search",
3597
- description: "Search my tasks by name (use --all for all tasks)",
3602
+ description: "Search tasks assigned to you by default. Use --all to search across all assignees.",
3598
3603
  flags: [
3599
3604
  "--status",
3600
3605
  "--list",
@@ -3611,7 +3616,11 @@ var commandMetadata = [
3611
3616
  "--json"
3612
3617
  ],
3613
3618
  quickReference: [
3614
- { section: "read", usage: "search <query>", description: "Search my tasks by name" }
3619
+ {
3620
+ section: "read",
3621
+ usage: "search <query>",
3622
+ description: "Search your tasks by name (--all for all assignees)"
3623
+ }
3615
3624
  ]
3616
3625
  },
3617
3626
  {
@@ -5382,7 +5391,8 @@ async function installSkillInteractive() {
5382
5391
  name: `${t.name}${t.detected ? chalk8.dim(" (detected)") : ""}`,
5383
5392
  value: t.name,
5384
5393
  checked: t.detected
5385
- }))
5394
+ })),
5395
+ theme: { keybindings: ["vim"] }
5386
5396
  });
5387
5397
  if (selected.length === 0) {
5388
5398
  throw new Error("No agents selected");
@@ -5432,6 +5442,29 @@ async function checkAuth(config) {
5432
5442
  }
5433
5443
 
5434
5444
  // src/commands/search.ts
5445
+ async function resolveSpaceNameToId(config, value) {
5446
+ if (/^\d+$/.test(value)) {
5447
+ return value;
5448
+ }
5449
+ const client = new ClickUpClient(config);
5450
+ const spaces = await client.getSpaces(config.teamId);
5451
+ const lower = value.toLowerCase();
5452
+ const matches = spaces.filter((s) => s.name.toLowerCase().includes(lower));
5453
+ if (matches.length === 1) {
5454
+ process.stderr.write(`Space matched: "${value}" -> "${matches[0].name}" (${matches[0].id})
5455
+ `);
5456
+ return matches[0].id;
5457
+ }
5458
+ if (matches.length > 1) {
5459
+ const list = matches.map((s) => ` - "${s.name}" (${s.id})`).join("\n");
5460
+ throw new Error(`Multiple spaces match "${value}":
5461
+ ${list}
5462
+ Specify the space ID directly.`);
5463
+ }
5464
+ const available = spaces.map((s) => ` - "${s.name}" (${s.id})`).join("\n");
5465
+ throw new Error(`No space matching "${value}" found. Available spaces:
5466
+ ${available}`);
5467
+ }
5435
5468
  async function searchTasks(config, query, opts = {}) {
5436
5469
  const trimmed = query.trim();
5437
5470
  if (!trimmed) {
@@ -6966,7 +6999,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
6966
6999
  }
6967
7000
  })
6968
7001
  );
6969
- program.command("tasks").description("List tasks assigned to me (use --all for all tasks)").option("--status <status>", 'Filter by status (e.g. "in progress")').option("--list <listId>", "Filter by list ID").option("--space <spaceId>", "Filter by space ID").option("--name <partial>", "Filter by name (case-insensitive contains)").option(
7002
+ program.command("tasks").description("List tasks assigned to you by default. Use --all to search across all assignees.").option("--status <status>", 'Filter by status (e.g. "in progress")').option("--list <listId>", "Filter by list ID").option("--space <spaceId|name>", "Filter by space ID or name (partial match)").option("--name <partial>", "Filter by name (case-insensitive contains)").option(
6970
7003
  "--type <type>",
6971
7004
  'Filter by task type (e.g. "task", "initiative", or custom type name/ID)'
6972
7005
  ).option("--all", "Include all tasks, not just mine").option("--include-closed", "Include done/closed tasks").option("--assignee <userId>", 'Filter by assignee (user ID or "me")').option("--tag <tag>", "Filter by tag name").option("--due-before <date>", "Tasks due before date (YYYY-MM-DD)").option("--due-after <date>", "Tasks due after date (YYYY-MM-DD)").option("--created-after <date>", "Tasks created after date (YYYY-MM-DD)").option("--created-before <date>", "Tasks created before date (YYYY-MM-DD)").option("--field <nameAndValue...>", 'Filter by custom field: --field "Name" value').option("--json", "Force JSON output even in terminal").action(
@@ -6982,6 +7015,10 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
6982
7015
  assigneeIds = [Number(opts.assignee)];
6983
7016
  }
6984
7017
  }
7018
+ let resolvedSpaceId;
7019
+ if (opts.space) {
7020
+ resolvedSpaceId = await resolveSpaceNameToId(config, opts.space);
7021
+ }
6985
7022
  const parseDateFilter = (d) => {
6986
7023
  const parts = d.split("-");
6987
7024
  return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2])).getTime();
@@ -7016,7 +7053,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
7016
7053
  typeFilter: opts.type,
7017
7054
  statuses: opts.status ? [opts.status] : void 0,
7018
7055
  listIds: opts.list ? [opts.list] : void 0,
7019
- spaceIds: opts.space ? [opts.space] : void 0,
7056
+ spaceIds: resolvedSpaceId ? [resolvedSpaceId] : void 0,
7020
7057
  name: opts.name,
7021
7058
  all: opts.all,
7022
7059
  assignees: assigneeIds,
@@ -7328,7 +7365,9 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
7328
7365
  await openTask(config, query, opts);
7329
7366
  })
7330
7367
  );
7331
- program.command("search <query>").description("Search my tasks by name (use --all for all tasks)").option("--status <status>", "Filter by status").option("--list <listId>", "Filter by list ID").option("--space <spaceId>", "Filter by space ID").option("--all", "Search all tasks, not just mine").option("--include-closed", "Include done/closed tasks in search").option("--assignee <userId>", 'Filter by assignee (user ID or "me")').option("--tag <tag>", "Filter by tag name").option("--due-before <date>", "Tasks due before date (YYYY-MM-DD)").option("--due-after <date>", "Tasks due after date (YYYY-MM-DD)").option("--created-after <date>", "Tasks created after date (YYYY-MM-DD)").option("--created-before <date>", "Tasks created before date (YYYY-MM-DD)").option("--field <nameAndValue...>", 'Filter by custom field: --field "Name" value').option("--json", "Force JSON output even in terminal").action(
7368
+ program.command("search <query>").description(
7369
+ "Search tasks assigned to you by default. Use --all to search across all assignees."
7370
+ ).option("--status <status>", "Filter by status").option("--list <listId>", "Filter by list ID").option("--space <spaceId|name>", "Filter by space ID or name (partial match)").option("--all", "Search all tasks, not just mine").option("--include-closed", "Include done/closed tasks in search").option("--assignee <userId>", 'Filter by assignee (user ID or "me")').option("--tag <tag>", "Filter by tag name").option("--due-before <date>", "Tasks due before date (YYYY-MM-DD)").option("--due-after <date>", "Tasks due after date (YYYY-MM-DD)").option("--created-after <date>", "Tasks created after date (YYYY-MM-DD)").option("--created-before <date>", "Tasks created before date (YYYY-MM-DD)").option("--field <nameAndValue...>", 'Filter by custom field: --field "Name" value').option("--json", "Force JSON output even in terminal").action(
7332
7371
  wrapAction(
7333
7372
  async (query, opts) => {
7334
7373
  const config = loadConfig(getProfileName());
@@ -7342,6 +7381,10 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
7342
7381
  assigneeIds = [Number(opts.assignee)];
7343
7382
  }
7344
7383
  }
7384
+ let resolvedSpaceId;
7385
+ if (opts.space) {
7386
+ resolvedSpaceId = await resolveSpaceNameToId(config, opts.space);
7387
+ }
7345
7388
  const parseDateFilter = (d) => {
7346
7389
  const parts = d.split("-");
7347
7390
  return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2])).getTime();
@@ -7377,7 +7420,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
7377
7420
  all: opts.all,
7378
7421
  includeClosed: opts.includeClosed,
7379
7422
  listIds: opts.list ? [opts.list] : void 0,
7380
- spaceIds: opts.space ? [opts.space] : void 0,
7423
+ spaceIds: resolvedSpaceId ? [resolvedSpaceId] : void 0,
7381
7424
  assignees: assigneeIds,
7382
7425
  tags: opts.tag ? [opts.tag] : void 0,
7383
7426
  dueDateLt: opts.dueBefore ? parseDateFilter(opts.dueBefore) : void 0,
@@ -8592,7 +8635,8 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
8592
8635
  } else {
8593
8636
  teamId = await select3({
8594
8637
  message: "Select workspace:",
8595
- choices: teams.map((t) => ({ name: t.name, value: t.id }))
8638
+ choices: teams.map((t) => ({ name: t.name, value: t.id })),
8639
+ theme: { keybindings: ["vim"] }
8596
8640
  });
8597
8641
  }
8598
8642
  addProfile(name, { apiToken, teamId });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krodak/clickup-cli",
3
- "version": "1.25.2",
3
+ "version": "1.26.1",
4
4
  "description": "ClickUp CLI for AI agents and humans",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -3,11 +3,11 @@ name: clickup
3
3
  description: 'Use when managing ClickUp tasks, sprints, or comments via the `cup` CLI tool. Triggers: task queries, status updates, sprint tracking, creating subtasks, posting comments, threaded replies, standup summaries, searching tasks, checking overdue items, assigning tasks, listing spaces and lists, opening tasks in browser, checking auth or config, setting custom fields, deleting tasks, managing tags, managing checklists, editing comments, task links, time tracking, attachments, file uploads, listing members, listing fields, duplicating tasks, bulk operations, goals, key results, saved filters, favorites.'
4
4
  ---
5
5
 
6
- # ClickUp CLI (`cup`) - skill version 1.25.2
6
+ # ClickUp CLI (`cup`) - skill version 1.26.1
7
7
 
8
8
  Reference for AI agents using the `cup` CLI tool. Covers task management, sprint tracking, comments, time tracking, custom fields, goals, docs, and project workflows.
9
9
 
10
- > **Version check:** Run `cup --version`. If your installed version is older than 1.25.2, update with `npm install -g @krodak/clickup-cli` and refresh this skill with `cup skill`.
10
+ > **Version check:** Run `cup --version`. If your installed version is older than 1.26.1, update with `npm install -g @krodak/clickup-cli` and refresh this skill with `cup skill`.
11
11
 
12
12
  ## Install & Configure
13
13
 
@@ -107,40 +107,40 @@ All commands support `--help` for full flag details. All commands support `--jso
107
107
 
108
108
  ### Read
109
109
 
110
- | Command | What it returns |
111
- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
112
- | `cup tasks [--status s] [--name q] [--type t] [--list id] [--space id] [--all] [--include-closed] [--assignee id\|me] [--tag t] [--due-before d] [--due-after d] [--created-after d] [--created-before d] [--field "Name" val]` | My tasks (filter by status, name, type, list, space, assignee, tag, dates, custom fields). `--all` for all tasks in workspace |
113
- | `cup assigned [--status s] [--include-closed]` | All my tasks grouped by status |
114
- | `cup sprint [--status s] [--space nameOrId] [--folder id] [--include-closed]` | Tasks in active sprint (auto-detected) |
115
- | `cup sprints [--space nameOrId]` | List all sprints (marks active with \*) |
116
- | `cup search <query> [--status s] [--list id] [--space id] [--all] [--include-closed] [--assignee id\|me] [--tag t] [--due-before d] [--due-after d] [--created-after d] [--created-before d] [--field "Name" val]` | Search my tasks by name. `--all` for all tasks |
117
- | `cup task <id>` | Single task details (custom fields, checklists, attachments, deps, links) |
118
- | `cup subtasks <id> [--status s] [--name q] [--include-closed]` | Subtasks of a task |
119
- | `cup comments <id>` | Comments on a task |
120
- | `cup activity <id>` | Task details + comment history combined |
121
- | `cup inbox [--days n] [--include-closed]` | Tasks updated in last n days (default 30) |
122
- | `cup summary [--hours n]` | Standup: completed, in-progress, overdue |
123
- | `cup overdue [--all] [--include-closed]` | Tasks past due date (most overdue first) |
124
- | `cup spaces [--name partial] [--my] [--archived]` | List/filter workspace spaces |
125
- | `cup lists <spaceId> [--name partial] [--archived]` | Lists in a space (including folder lists) |
126
- | `cup folders <spaceId> [--name partial] [--archived]` | Folders in a space (with their lists) |
127
- | `cup time-in-status <id>` | Show how long a task has been in each status |
128
- | `cup members` | Workspace members (username, ID, email) |
129
- | `cup fields <listId>` | Custom fields on a list (type, required, options) |
130
- | `cup tags <spaceId>` | Tags available in a space |
131
- | `cup goals` | Workspace goals with progress |
132
- | `cup key-results <goalId>` | Key results for a goal |
133
- | `cup docs [query]` | Workspace docs (optionally filter by name) |
134
- | `cup doc <docId> [pageId]` | Doc metadata + page tree, or a specific page |
135
- | `cup doc-pages <docId>` | All pages in a doc with content |
136
- | `cup task-types` | Custom task types (for `--custom-item-id`) |
137
- | `cup templates` | Task templates (for `--template`) |
138
- | `cup list-templates` | List templates (for `list-from-template`) |
139
- | `cup folder-templates` | Folder templates |
140
- | `cup views <listId>` | List views on a list |
141
- | `cup view <viewId>` | Get view details |
142
- | `cup open <query>` | Open task in browser by ID or name |
143
- | `cup auth` | Check authentication status |
110
+ | Command | What it returns |
111
+ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
112
+ | `cup tasks [--status s] [--name q] [--type t] [--list id] [--space id] [--all] [--include-closed] [--assignee id\|me] [--tag t] [--due-before d] [--due-after d] [--created-after d] [--created-before d] [--field "Name" val]` | Tasks assigned to you (filter by status, name, type, list, space, assignee, tag, dates, custom fields). `--all` for all assignees |
113
+ | `cup assigned [--status s] [--include-closed]` | All my tasks grouped by status |
114
+ | `cup sprint [--status s] [--space nameOrId] [--folder id] [--include-closed]` | Tasks in active sprint (auto-detected) |
115
+ | `cup sprints [--space nameOrId]` | List all sprints (marks active with \*) |
116
+ | `cup search <query> [--status s] [--list id] [--space id] [--all] [--include-closed] [--assignee id\|me] [--tag t] [--due-before d] [--due-after d] [--created-after d] [--created-before d] [--field "Name" val]` | Search your tasks by name. `--all` for all assignees |
117
+ | `cup task <id>` | Single task details (custom fields, checklists, attachments, deps, links) |
118
+ | `cup subtasks <id> [--status s] [--name q] [--include-closed]` | Subtasks of a task |
119
+ | `cup comments <id>` | Comments on a task |
120
+ | `cup activity <id>` | Task details + comment history combined |
121
+ | `cup inbox [--days n] [--include-closed]` | Tasks updated in last n days (default 30) |
122
+ | `cup summary [--hours n]` | Standup: completed, in-progress, overdue |
123
+ | `cup overdue [--all] [--include-closed]` | Tasks past due date (most overdue first) |
124
+ | `cup spaces [--name partial] [--my] [--archived]` | List/filter workspace spaces |
125
+ | `cup lists <spaceId> [--name partial] [--archived]` | Lists in a space (including folder lists) |
126
+ | `cup folders <spaceId> [--name partial] [--archived]` | Folders in a space (with their lists) |
127
+ | `cup time-in-status <id>` | Show how long a task has been in each status |
128
+ | `cup members` | Workspace members (username, ID, email) |
129
+ | `cup fields <listId>` | Custom fields on a list (type, required, options) |
130
+ | `cup tags <spaceId>` | Tags available in a space |
131
+ | `cup goals` | Workspace goals with progress |
132
+ | `cup key-results <goalId>` | Key results for a goal |
133
+ | `cup docs [query]` | Workspace docs (optionally filter by name) |
134
+ | `cup doc <docId> [pageId]` | Doc metadata + page tree, or a specific page |
135
+ | `cup doc-pages <docId>` | All pages in a doc with content |
136
+ | `cup task-types` | Custom task types (for `--custom-item-id`) |
137
+ | `cup templates` | Task templates (for `--template`) |
138
+ | `cup list-templates` | List templates (for `list-from-template`) |
139
+ | `cup folder-templates` | Folder templates |
140
+ | `cup views <listId>` | List views on a list |
141
+ | `cup view <viewId>` | Get view details |
142
+ | `cup open <query>` | Open task in browser by ID or name |
143
+ | `cup auth` | Check authentication status |
144
144
 
145
145
  ### Write
146
146
 
@@ -253,6 +253,21 @@ All commands support `--help` for full flag details. All commands support `--jso
253
253
  | `cup delete` | DESTRUCTIVE. Requires `--confirm` in non-interactive mode. Cannot be undone |
254
254
  | Errors | stderr with exit code 1. Strict parsing - excess/unknown arguments rejected |
255
255
 
256
+ > **Note:** `cup search`, `cup tasks`, `cup overdue`, and `cup assigned` default to tasks assigned to the current user. Use `--all` to include tasks assigned to others. This matters when searching for parent initiatives or team-wide items.
257
+
258
+ ## Interactive Mode (TTY)
259
+
260
+ When running in a terminal (not piped), task-listing commands (`cup tasks`, `cup search`, `cup sprint`, `cup overdue`, `cup assigned`, `cup inbox`, `cup summary`) present an interactive task picker:
261
+
262
+ - **↑/↓** or **j/k** to navigate the list
263
+ - **Space** to toggle task selection
264
+ - **Enter** to confirm and view details of selected tasks
265
+ - After viewing details, prompted to open tasks in browser
266
+
267
+ Other interactive prompts: sprint selection (when multiple match), workspace selection (`cup init`), agent selection (`cup skill`), destructive action confirmations (`cup delete`, `cup archive`, `cup view-delete`).
268
+
269
+ When piped or called with `--json`, all commands output non-interactive markdown or JSON. Agents should always use `--json` for structured data or pipe for markdown.
270
+
256
271
  ## Agent Workflow Examples
257
272
 
258
273
  ### Investigate a task