clickup-agent-cli 0.5.0 → 0.5.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/AGENTS.md +61 -0
- package/LICENSE +21 -0
- package/README.md +7 -1
- package/dist/clickup.js +1 -1
- package/package.json +4 -3
- package/skills/clickup/SKILL.md +2 -0
- package/skills/clickup-blocker-report/SKILL.md +3 -1
- package/skills/clickup-blocker-report/assets/report-template.md +16 -0
- package/skills/clickup-capacity-check/SKILL.md +3 -1
- package/skills/clickup-capacity-check/assets/report-template.md +14 -0
- package/skills/clickup-goal-progress/SKILL.md +3 -1
- package/skills/clickup-goal-progress/assets/report-template.md +13 -0
- package/skills/clickup-my-day/SKILL.md +2 -14
- package/skills/clickup-my-day/assets/report-template.md +12 -0
- package/skills/clickup-release-notes/SKILL.md +2 -13
- package/skills/clickup-release-notes/assets/report-template.md +12 -0
- package/skills/clickup-standup/SKILL.md +2 -14
- package/skills/clickup-standup/assets/report-template.md +9 -0
- package/skills/clickup-team-report/SKILL.md +3 -1
- package/skills/clickup-team-report/assets/report-template.md +24 -0
- package/skills/clickup-time-audit/SKILL.md +5 -1
- package/skills/clickup-time-audit/assets/report-template.md +19 -0
- package/skills/clickup-timesheet-export/SKILL.md +18 -19
- package/skills/clickup-timesheet-export/assets/report-template.md +9 -0
- package/skills/clickup-timesheet-export/scripts/aggregate.mjs +73 -0
- package/skills/clickup-weekly-review/SKILL.md +3 -1
- package/skills/clickup-weekly-review/assets/report-template.md +26 -0
- package/skills/clickup-workspace-audit/SKILL.md +12 -20
- package/skills/clickup-workspace-audit/assets/report-template.md +21 -0
- package/skills/clickup-workspace-audit/scripts/classify.mjs +72 -0
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"name": "clickup",
|
|
12
12
|
"source": "./",
|
|
13
13
|
"description": "ClickUp CLI with 31 agent skills covering the full API -- token-efficient alternative to MCP with chat, time tracking, docs, and project management workflows",
|
|
14
|
-
"version": "0.5.
|
|
14
|
+
"version": "0.5.2",
|
|
15
15
|
"homepage": "https://github.com/henryreith/clickup-cli",
|
|
16
16
|
"keywords": ["clickup", "project-management", "tasks", "time-tracking"],
|
|
17
17
|
"category": "productivity"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clickup",
|
|
3
3
|
"description": "ClickUp CLI with 31 agent skills covering the full API -- token-efficient alternative to MCP with chat, time tracking, docs, and project management workflows",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.2",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Henry Reith"
|
|
7
7
|
},
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# ClickUp CLI: Agent Operating Manual
|
|
2
|
+
|
|
3
|
+
You have (or can install) `clickup`, a command-line tool covering the full ClickUp API v2. This file is the fastest path from zero to productive for any agent on any platform. Everything here works headless.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g clickup-agent-cli
|
|
9
|
+
|
|
10
|
+
# Authenticate: env var (preferred for agents), --token-file, or --token per call
|
|
11
|
+
export CLICKUP_API_TOKEN=pk_your_token
|
|
12
|
+
|
|
13
|
+
# Verify auth and workspace resolution
|
|
14
|
+
clickup config validate
|
|
15
|
+
|
|
16
|
+
# One-time workspace binding (auto-selects when the account has one workspace)
|
|
17
|
+
clickup workspace setup
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Discover, never guess
|
|
21
|
+
|
|
22
|
+
Do not guess command syntax. The CLI is self-describing:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
clickup skill show clickup # Root skill: index of all capabilities (~150 tokens)
|
|
26
|
+
clickup skill list # All 31 skills (12 resource references, 18 workflows)
|
|
27
|
+
clickup skill show <name> # Full skill content (JSON with a "content" field when piped)
|
|
28
|
+
clickup skill path <name> # Skill directory: bundled references/, assets/, scripts/
|
|
29
|
+
clickup schema <resource> # Actions for a resource (task, list, doc, time, ...)
|
|
30
|
+
clickup schema <resource>.<action> # Required and optional flags for one action
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Skills bundle supporting files per the Agent Skills standard: `assets/report-template.md` (copy the structure for report output), `scripts/*.mjs` (deterministic helpers; pipe JSON in via node), and `references/` (deep detail such as `clickup skill path clickup`/references/gotchas.md).
|
|
34
|
+
|
|
35
|
+
## Conventions that matter
|
|
36
|
+
|
|
37
|
+
- **Output**: JSON by default when piped; force with `--format json|table|csv|tsv|quiet|id|md`. `--format id` prints just the first result's ID for capture: `ID=$(clickup task create ... --format id)`.
|
|
38
|
+
- **Exit codes**: 0 ok, 1 general, 2 bad arguments, 3 auth, 4 not found, 5 permission, 6 rate limited, 7 network. Branch on these.
|
|
39
|
+
- **Destructive commands** (`* delete`, `field remove`, `time delete`) require `--confirm` when non-interactive. Pass it deliberately; never bypass a confirmation you were not asked to give.
|
|
40
|
+
- **Dates**: Unix ms/seconds, ISO 8601 (`2026-07-10`), or relative (`today`, `tomorrow`, `3d`, `-1w`, `friday`). Filter flags ending `-gt`/`-lt` take Unix ms only.
|
|
41
|
+
- **Rate limits**: ~100 requests/min; 429s retry automatically. Prefer `task bulk-update`/`task bulk-delete` for batches.
|
|
42
|
+
- **Dry runs**: add `--dry-run` to print the exact request without sending it.
|
|
43
|
+
- Errors and spinners go to stderr; stdout is data only. Safe to pipe.
|
|
44
|
+
|
|
45
|
+
## Quick example
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Find the list, create a task, comment on it
|
|
49
|
+
LIST_ID=$(clickup list list --space-id 123 --filter name="Sprint 12" --format id)
|
|
50
|
+
TASK_ID=$(clickup task create --list-id "$LIST_ID" --name "Fix login redirect" \
|
|
51
|
+
--priority high --due-date friday --format id)
|
|
52
|
+
clickup comment create --task-id "$TASK_ID" --text "Repro steps in thread"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## For Claude Code specifically
|
|
56
|
+
|
|
57
|
+
Install as a plugin instead: `/plugin marketplace add henryreith/clickup-cli` then `/plugin install clickup@clickup-agent-cli`. Skills load natively (`/clickup:weekly-review`, etc.).
|
|
58
|
+
|
|
59
|
+
## Developing this repo
|
|
60
|
+
|
|
61
|
+
Build/test conventions live in [CLAUDE.md](./CLAUDE.md): `npm run typecheck && npm test && npm run build && npm run lint:skills` must pass. The full command reference is [COMMANDS.md](./COMMANDS.md); architecture is [SPEC.md](./SPEC.md).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Henry Reith
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# ClickUp CLI
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/clickup-agent-cli)
|
|
4
|
+
[](https://nodejs.org)
|
|
5
|
+
[](https://github.com/henryreith/clickup-cli/actions/workflows/ci.yml)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
[](./skills)
|
|
8
|
+
|
|
3
9
|
Zero-overhead CLI for the ClickUp API v2 -- for AI agents, scripts, and automation. Covers the entire API surface with all MCP capabilities and more.
|
|
4
10
|
|
|
5
11
|
## Why This Exists
|
|
@@ -187,7 +193,7 @@ This creates `/marketing-weekly` alongside the built-in `/clickup:*` skills.
|
|
|
187
193
|
|
|
188
194
|
### Bootstrap From Any Agent
|
|
189
195
|
|
|
190
|
-
Any agent that can run shell commands can set up and use the CLI in five steps, no plugin system required:
|
|
196
|
+
The repo and npm package ship an [AGENTS.md](./AGENTS.md) operating manual that agent platforms (Codex, Cursor, Gemini CLI, custom agents) pick up automatically. Any agent that can run shell commands can set up and use the CLI in five steps, no plugin system required:
|
|
191
197
|
|
|
192
198
|
```bash
|
|
193
199
|
# 1. Install
|
package/dist/clickup.js
CHANGED
|
@@ -4629,7 +4629,7 @@ function registerChatCommands(program, getClient) {
|
|
|
4629
4629
|
}
|
|
4630
4630
|
|
|
4631
4631
|
// src/cli.ts
|
|
4632
|
-
var VERSION = "0.5.
|
|
4632
|
+
var VERSION = "0.5.2";
|
|
4633
4633
|
function createProgram() {
|
|
4634
4634
|
const program = new Command();
|
|
4635
4635
|
program.name("clickup").description("ClickUp CLI - Manage ClickUp workspaces from the terminal").version(VERSION).option("--token <token>", "API token").option("--token-file <path>", "Read API token from this file path").option("--profile <name>", "Profile to use (key, workspace name, or nickname)").option("--workspace-id <id>", "Workspace ID").addOption(
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clickup-agent-cli",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "CLI
|
|
3
|
+
"version": "0.5.2",
|
|
4
|
+
"description": "Zero-overhead ClickUp CLI for AI agents, shell scripts, and automation. Full ClickUp API v2 coverage with 31 bundled agent skills.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"clickup": "dist/clickup.js"
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
11
|
"skills",
|
|
12
|
-
".claude-plugin"
|
|
12
|
+
".claude-plugin",
|
|
13
|
+
"AGENTS.md"
|
|
13
14
|
],
|
|
14
15
|
"engines": {
|
|
15
16
|
"node": ">=22.0.0"
|
package/skills/clickup/SKILL.md
CHANGED
|
@@ -37,6 +37,8 @@ clickup skill show <name> # Print a skill's full contents (e.g. cli
|
|
|
37
37
|
|
|
38
38
|
Known pitfalls (rate limits, error codes, exit codes, destructive-command rules) live in `references/gotchas.md` next to this file; read it before debugging a failing command (`clickup skill path clickup` prints this skill's directory).
|
|
39
39
|
|
|
40
|
+
Skills bundle supporting files per the Agent Skills standard: `references/` (deep detail), `assets/` (output templates to copy), and `scripts/` (deterministic helpers to run with node). `clickup skill path <name>` prints any skill's directory so these files can be read or executed directly.
|
|
41
|
+
|
|
40
42
|
## Sub-Skills (load when needed)
|
|
41
43
|
|
|
42
44
|
| Skill | What it covers |
|
|
@@ -6,7 +6,7 @@ disable-model-invocation: true
|
|
|
6
6
|
context: fork
|
|
7
7
|
agent: general-purpose
|
|
8
8
|
argument-hint: "[workspace-id]"
|
|
9
|
-
allowed-tools: Bash(clickup *)
|
|
9
|
+
allowed-tools: Bash(clickup *), Read
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Blocker Report
|
|
@@ -71,6 +71,8 @@ clickup task bulk-time-in-status --task-id <id1> --task-id <id2> --format json
|
|
|
71
71
|
|
|
72
72
|
### Step 6: Compile the report
|
|
73
73
|
|
|
74
|
+
Copy the exact structure from `assets/report-template.md` in this skill's directory (`clickup skill path clickup-blocker-report` prints it). Fill every placeholder; drop sections with no content.
|
|
75
|
+
|
|
74
76
|
- **Blocked tasks**: What, who, and what is blocking them
|
|
75
77
|
- **Stale tasks**: In progress but not updated recently
|
|
76
78
|
- **Overdue + unassigned**: Nobody owns these
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
## Blocker Report: <scope> (<date>)
|
|
2
|
+
|
|
3
|
+
### Blocked tasks
|
|
4
|
+
- <task> - <assignee>, blocked <n> days, waiting on: <blocker>
|
|
5
|
+
|
|
6
|
+
### Dependency chains
|
|
7
|
+
- <task A> blocks <task B> blocks <task C> (chain head is <status>)
|
|
8
|
+
|
|
9
|
+
### Stale (in progress, no updates)
|
|
10
|
+
- <task> - <assignee>, last touched <date>
|
|
11
|
+
|
|
12
|
+
### Overdue and unassigned (nobody owns these)
|
|
13
|
+
- <task> - due <date> (<list>)
|
|
14
|
+
|
|
15
|
+
### Escalations needed
|
|
16
|
+
1. <task>: blocked <n> days - <suggested action>
|
|
@@ -6,7 +6,7 @@ disable-model-invocation: true
|
|
|
6
6
|
context: fork
|
|
7
7
|
agent: general-purpose
|
|
8
8
|
argument-hint: "[workspace-id]"
|
|
9
|
-
allowed-tools: Bash(clickup *)
|
|
9
|
+
allowed-tools: Bash(clickup *), Read
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Capacity Check
|
|
@@ -57,6 +57,8 @@ clickup task search --workspace-id <id> --assignee <user-id> \
|
|
|
57
57
|
|
|
58
58
|
### Step 5: Compile capacity report
|
|
59
59
|
|
|
60
|
+
Copy the exact structure from `assets/report-template.md` in this skill's directory (`clickup skill path clickup-capacity-check` prints it). Fill every placeholder; drop sections with no content.
|
|
61
|
+
|
|
60
62
|
For each team member:
|
|
61
63
|
- **Active tasks**: Count and total estimated hours
|
|
62
64
|
- **Time logged this week**: Hours
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
## Capacity Check: <team/scope> (<date>)
|
|
2
|
+
|
|
3
|
+
| Person | Active tasks | Est. hours | Logged this week | Overdue | Status |
|
|
4
|
+
|--------|--------------|-----------|------------------|---------|--------|
|
|
5
|
+
| <name> | <n> | <n>h | <n>h | <n> | Under / At / Over |
|
|
6
|
+
|
|
7
|
+
### Overloaded
|
|
8
|
+
- <name>: <what to move and to whom>
|
|
9
|
+
|
|
10
|
+
### Available bandwidth
|
|
11
|
+
- <name>: <n> open tasks, can take on more
|
|
12
|
+
|
|
13
|
+
### Suggested rebalance
|
|
14
|
+
1. Move "<task>" from <overloaded> to <available>
|
|
@@ -6,7 +6,7 @@ disable-model-invocation: true
|
|
|
6
6
|
context: fork
|
|
7
7
|
agent: general-purpose
|
|
8
8
|
argument-hint: "[workspace-id]"
|
|
9
|
-
allowed-tools: Bash(clickup *)
|
|
9
|
+
allowed-tools: Bash(clickup *), Read
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Goal Progress Report
|
|
@@ -56,6 +56,8 @@ clickup task list --list-id <linked-list-id> --include-closed --format json
|
|
|
56
56
|
|
|
57
57
|
### Step 5: Compile the report
|
|
58
58
|
|
|
59
|
+
Copy the exact structure from `assets/report-template.md` in this skill's directory (`clickup skill path clickup-goal-progress` prints it). Fill every placeholder; drop sections with no content.
|
|
60
|
+
|
|
59
61
|
For each goal:
|
|
60
62
|
- **Goal name** and due date
|
|
61
63
|
- **Key results**: Current vs. target, % complete
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
## Goal Progress: <scope> (<date>)
|
|
2
|
+
|
|
3
|
+
| Goal | Due | Progress | Expected | Status |
|
|
4
|
+
|------|-----|----------|----------|--------|
|
|
5
|
+
| <goal> | <date> | <current>/<target> (<x>%) | <y>% | On track / At risk / Behind |
|
|
6
|
+
|
|
7
|
+
### <goal name>
|
|
8
|
+
- <key result>: <current> of <target> (<x>%)
|
|
9
|
+
- Latest: <most recent note or update>
|
|
10
|
+
- <status rationale in one line>
|
|
11
|
+
|
|
12
|
+
### Stale goals (no recent key result updates)
|
|
13
|
+
- <goal> - last update <date>
|
|
@@ -6,7 +6,7 @@ disable-model-invocation: true
|
|
|
6
6
|
context: fork
|
|
7
7
|
agent: general-purpose
|
|
8
8
|
argument-hint: "[optional: a different person, or 'this week' for a wider window]"
|
|
9
|
-
allowed-tools: Bash(clickup *)
|
|
9
|
+
allowed-tools: Bash(clickup *), Read
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# My Day
|
|
@@ -45,19 +45,7 @@ Priority (urgent=1 to low=4) breaks ties inside each bucket.
|
|
|
45
45
|
|
|
46
46
|
### Step 4: Present the agenda
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
## Your day - <date>
|
|
50
|
-
|
|
51
|
-
Now: <running timer task, if any>
|
|
52
|
-
|
|
53
|
-
1. [OVERDUE] <task> - was due <date> (<list>)
|
|
54
|
-
2. [TODAY] <task> - <priority>
|
|
55
|
-
3. ...
|
|
56
|
-
|
|
57
|
-
Blocked (not actionable): <task> - waiting on <dependency>
|
|
58
|
-
|
|
59
|
-
Suggestion: <one sentence - e.g. "Clear the two overdue items before starting new work.">
|
|
60
|
-
```
|
|
48
|
+
Copy the exact structure from `assets/report-template.md` in this skill's directory (`clickup skill path clickup-my-day` prints it). Fill every placeholder; drop sections with no content.
|
|
61
49
|
|
|
62
50
|
Keep it under ~10 items; summarize the rest as "and N more in the backlog".
|
|
63
51
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
## Your day - <date>
|
|
2
|
+
|
|
3
|
+
Now: <running timer task, if any>
|
|
4
|
+
|
|
5
|
+
1. [OVERDUE] <task> - was due <date> (<list>)
|
|
6
|
+
2. [TODAY] <task> - <priority>
|
|
7
|
+
3. [IN PROGRESS] <task> - untouched <n> days
|
|
8
|
+
4. [UP NEXT] <task> - <priority>
|
|
9
|
+
|
|
10
|
+
Blocked (not actionable): <task> - waiting on <dependency>
|
|
11
|
+
|
|
12
|
+
Suggestion: <one sentence on what to tackle first>
|
|
@@ -6,7 +6,7 @@ disable-model-invocation: true
|
|
|
6
6
|
context: fork
|
|
7
7
|
agent: general-purpose
|
|
8
8
|
argument-hint: "[period and scope - e.g. 'last sprint for the mobile space', 'June, customer-facing']"
|
|
9
|
-
allowed-tools: Bash(clickup *), Write
|
|
9
|
+
allowed-tools: Bash(clickup *), Write, Read
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Release Notes
|
|
@@ -39,18 +39,7 @@ Group by tags and task names into: **Features**, **Improvements**, **Fixes**, an
|
|
|
39
39
|
|
|
40
40
|
Rewrite task names for the audience - "Fix login redirect on Safari" becomes "Fixed an issue where Safari users could be redirected to the wrong page after logging in." Never paste raw task IDs into customer-facing notes.
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
# Release Notes - <period>
|
|
44
|
-
|
|
45
|
-
## New
|
|
46
|
-
- ...
|
|
47
|
-
|
|
48
|
-
## Improved
|
|
49
|
-
- ...
|
|
50
|
-
|
|
51
|
-
## Fixed
|
|
52
|
-
- ...
|
|
53
|
-
```
|
|
42
|
+
Copy the exact structure from `assets/report-template.md` in this skill's directory (`clickup skill path clickup-release-notes` prints it). Fill every placeholder; drop sections with no content.
|
|
54
43
|
|
|
55
44
|
For internal notes append task IDs and assignees for traceability.
|
|
56
45
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Release Notes - <period>
|
|
2
|
+
|
|
3
|
+
## New
|
|
4
|
+
- <benefit-focused line for each shipped feature>
|
|
5
|
+
|
|
6
|
+
## Improved
|
|
7
|
+
- <what got better and for whom>
|
|
8
|
+
|
|
9
|
+
## Fixed
|
|
10
|
+
- <user-visible bug fixes, written as outcomes>
|
|
11
|
+
|
|
12
|
+
<!-- Internal variant: append task IDs and assignees per line -->
|
|
@@ -6,7 +6,7 @@ disable-model-invocation: true
|
|
|
6
6
|
context: fork
|
|
7
7
|
agent: general-purpose
|
|
8
8
|
argument-hint: "[scope - e.g. 'my tasks', 'engineering team', user-id]"
|
|
9
|
-
allowed-tools: Bash(clickup *)
|
|
9
|
+
allowed-tools: Bash(clickup *), Read
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Daily Standup
|
|
@@ -74,19 +74,7 @@ clickup time running --workspace-id <id> --assignee <user-id> --format json
|
|
|
74
74
|
|
|
75
75
|
### Step 6: Compile standup
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
```
|
|
80
|
-
**Yesterday:**
|
|
81
|
-
- Completed: [list of finished tasks with names]
|
|
82
|
-
|
|
83
|
-
**Today:**
|
|
84
|
-
- Working on: [list of in-progress tasks]
|
|
85
|
-
- Due today: [list of tasks due today]
|
|
86
|
-
|
|
87
|
-
**Blockers:**
|
|
88
|
-
- [list of blocked tasks, if any]
|
|
89
|
-
```
|
|
77
|
+
Copy the exact structure from `assets/report-template.md` in this skill's directory (`clickup skill path clickup-standup` prints it). Fill every placeholder; drop sections with no content.
|
|
90
78
|
|
|
91
79
|
## Tips
|
|
92
80
|
|
|
@@ -6,7 +6,7 @@ disable-model-invocation: true
|
|
|
6
6
|
context: fork
|
|
7
7
|
agent: general-purpose
|
|
8
8
|
argument-hint: "[team or department name, e.g. 'marketing', 'engineering', 'operations']"
|
|
9
|
-
allowed-tools: Bash(clickup *)
|
|
9
|
+
allowed-tools: Bash(clickup *), Read
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Team / Department Report
|
|
@@ -102,6 +102,8 @@ Filter time entries to those related to the team's tasks.
|
|
|
102
102
|
|
|
103
103
|
### Step 7: Compile the report
|
|
104
104
|
|
|
105
|
+
Copy the exact structure from `assets/report-template.md` in this skill's directory (`clickup skill path clickup-team-report` prints it). Fill every placeholder; drop sections with no content.
|
|
106
|
+
|
|
105
107
|
Structure the report as:
|
|
106
108
|
|
|
107
109
|
- **Team/Department**: Name and scope of what is covered
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# <Team> Status Report (<date>)
|
|
2
|
+
|
|
3
|
+
**Scope:** <spaces/folders/lists covered>
|
|
4
|
+
**Summary:** <2-3 sentences on where things stand>
|
|
5
|
+
|
|
6
|
+
## By the numbers
|
|
7
|
+
| To do | In progress | Done this week | Overdue |
|
|
8
|
+
|-------|-------------|----------------|---------|
|
|
9
|
+
| <n> | <n> | <n> | <n> |
|
|
10
|
+
|
|
11
|
+
## Key accomplishments
|
|
12
|
+
- <completed task worth naming> (<assignee>)
|
|
13
|
+
|
|
14
|
+
## Currently working on
|
|
15
|
+
- <task> - <assignee>, due <date>
|
|
16
|
+
|
|
17
|
+
## Upcoming deadlines (next 7 days)
|
|
18
|
+
- <task> - due <date>, <assignee>
|
|
19
|
+
|
|
20
|
+
## Risks and blockers
|
|
21
|
+
- <overdue or blocked item> - <what unblocks it>
|
|
22
|
+
|
|
23
|
+
## Time invested
|
|
24
|
+
<n> hours logged this period (<top contributors>)
|
|
@@ -6,7 +6,7 @@ disable-model-invocation: true
|
|
|
6
6
|
context: fork
|
|
7
7
|
agent: general-purpose
|
|
8
8
|
argument-hint: "[workspace-id] [start-date] [end-date]"
|
|
9
|
-
allowed-tools: Bash(clickup *)
|
|
9
|
+
allowed-tools: Bash(clickup *), Read
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Time Audit
|
|
@@ -81,6 +81,10 @@ Look for:
|
|
|
81
81
|
clickup time running --workspace-id <id> --format json
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
+
### Compile the report
|
|
85
|
+
|
|
86
|
+
Copy the exact structure from `assets/report-template.md` in this skill's directory (`clickup skill path clickup-time-audit` prints it). Fill every placeholder; drop sections with no content.
|
|
87
|
+
|
|
84
88
|
## Tips
|
|
85
89
|
|
|
86
90
|
- Duration is in milliseconds. Divide by 3600000 for hours.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
## Time Audit: <scope> (<period>)
|
|
2
|
+
|
|
3
|
+
Total logged: <n>h (<m>h billable / <k>h non-billable)
|
|
4
|
+
|
|
5
|
+
### By person
|
|
6
|
+
| Person | Hours | Billable | Entries |
|
|
7
|
+
|--------|-------|----------|---------|
|
|
8
|
+
| <name> | <n>h | <n>h | <n> |
|
|
9
|
+
|
|
10
|
+
### Estimate accuracy (actual / estimated)
|
|
11
|
+
- <task>: <actual>h vs <estimated>h (<ratio>)
|
|
12
|
+
|
|
13
|
+
### Anomalies
|
|
14
|
+
- <entry over 8h - forgot to stop timer?>
|
|
15
|
+
- <entries with no description>
|
|
16
|
+
- <running timers active for days>
|
|
17
|
+
|
|
18
|
+
### Missing time
|
|
19
|
+
- <tasks that changed status with zero time logged>
|
|
@@ -6,7 +6,7 @@ disable-model-invocation: true
|
|
|
6
6
|
context: fork
|
|
7
7
|
agent: general-purpose
|
|
8
8
|
argument-hint: "[period and scope - e.g. 'last week', 'June for Sarah', 'this month billable only']"
|
|
9
|
-
allowed-tools: Bash(clickup *), Write
|
|
9
|
+
allowed-tools: Bash(clickup *), Bash(node *), Write, Read
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Timesheet Export
|
|
@@ -29,38 +29,37 @@ clickup time list --workspace-id <id> \
|
|
|
29
29
|
|
|
30
30
|
`--start`/`--end` accept ISO dates (`2026-06-01`), relative forms (`-30d`), or Unix timestamps. Entry durations are milliseconds.
|
|
31
31
|
|
|
32
|
-
### Step 2: Aggregate
|
|
32
|
+
### Step 2: Aggregate deterministically
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
Never sum hours yourself. Pipe the entries through the bundled script; the math comes out exact:
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
```bash
|
|
37
|
+
SKILL_DIR=$(clickup skill path clickup-timesheet-export)
|
|
38
|
+
|
|
39
|
+
# JSON summary: totals, byPerson, byTask, flagged entries
|
|
40
|
+
clickup time list --workspace-id <id> --start <start> --end <end> --format json \
|
|
41
|
+
| node "$SKILL_DIR/scripts/aggregate.mjs"
|
|
42
|
+
|
|
43
|
+
# CSV rows for the export file
|
|
44
|
+
clickup time list --workspace-id <id> --start <start> --end <end> --format json \
|
|
45
|
+
| node "$SKILL_DIR/scripts/aggregate.mjs" --csv
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The summary's `flags` field lists running timers (excluded from totals), entries with no task, and entries over 12h.
|
|
40
49
|
|
|
41
50
|
### Step 3: Write the export
|
|
42
51
|
|
|
43
52
|
CSV for spreadsheets (default when the user says export/invoice):
|
|
44
53
|
|
|
45
|
-
|
|
46
|
-
date,person,task,description,hours,billable
|
|
47
|
-
2026-06-30,Sarah,Login bug fix,Safari redirect,2.50,true
|
|
48
|
-
```
|
|
54
|
+
Copy the exact structure from `assets/report-template.md` in this skill's directory (`clickup skill path clickup-timesheet-export` prints it). Fill every placeholder; drop sections with no content.
|
|
49
55
|
|
|
50
56
|
Save with the Write tool as `timesheet-<start>-<end>.csv` and tell the user the path. For a chat answer, use a markdown table plus totals instead.
|
|
51
57
|
|
|
52
58
|
### Step 4: Summarize
|
|
53
59
|
|
|
54
|
-
|
|
55
|
-
Timesheet <start> to <end>
|
|
56
|
-
- Total: N hours (M billable / K non-billable)
|
|
57
|
-
- By person: Sarah 32.5h, Tom 28.0h, ...
|
|
58
|
-
- Top tasks: <task> 12.5h, ...
|
|
59
|
-
Flagged: entries with no task attached, running timers still open
|
|
60
|
-
```
|
|
60
|
+
Use the summary block from the same template.
|
|
61
61
|
|
|
62
62
|
## Tips
|
|
63
63
|
|
|
64
|
-
- Entries with a null `end` are running timers; exclude them from totals and flag them.
|
|
65
64
|
- Cross-check suspicious days (over 12h per person) rather than silently exporting them.
|
|
66
65
|
- For a recurring client invoice, filter to the client's space via the task IDs' locations.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
date,person,task,description,hours,billable
|
|
2
|
+
2026-06-30,Sarah,Login bug fix,Safari redirect,2.50,true
|
|
3
|
+
|
|
4
|
+
<!-- Summary block to accompany the CSV: -->
|
|
5
|
+
Timesheet <start> to <end>
|
|
6
|
+
- Total: <n> hours (<m> billable / <k> non-billable)
|
|
7
|
+
- By person: <name> <n>h, ...
|
|
8
|
+
- Top tasks: <task> <n>h, ...
|
|
9
|
+
Flagged: <entries with no task, running timers still open>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Deterministic timesheet aggregation. Pipe `clickup time list ... --format json`
|
|
3
|
+
// into this script; totals come out exact so no arithmetic is done by the agent.
|
|
4
|
+
//
|
|
5
|
+
// clickup time list --workspace-id X --start -7d --end today --format json \
|
|
6
|
+
// | node scripts/aggregate.mjs [--csv]
|
|
7
|
+
//
|
|
8
|
+
// Default output: JSON summary (totals, byPerson, byTask, flags).
|
|
9
|
+
// --csv: timesheet rows (date,person,task,description,hours,billable) on stdout.
|
|
10
|
+
|
|
11
|
+
import { readFileSync } from 'node:fs'
|
|
12
|
+
|
|
13
|
+
const wantCsv = process.argv.includes('--csv')
|
|
14
|
+
const raw = readFileSync(0, 'utf-8')
|
|
15
|
+
let entries = JSON.parse(raw)
|
|
16
|
+
if (!Array.isArray(entries)) entries = entries.data ?? [entries]
|
|
17
|
+
|
|
18
|
+
const MS_PER_HOUR = 3_600_000
|
|
19
|
+
const hours = (ms) => Math.round((ms / MS_PER_HOUR) * 100) / 100
|
|
20
|
+
const rows = []
|
|
21
|
+
const flags = { runningTimers: [], noTask: [], over12h: [] }
|
|
22
|
+
const byPerson = {}
|
|
23
|
+
const byTask = {}
|
|
24
|
+
let totalMs = 0
|
|
25
|
+
let billableMs = 0
|
|
26
|
+
|
|
27
|
+
for (const e of entries) {
|
|
28
|
+
const duration = Number(e.duration)
|
|
29
|
+
const person = e.user_name || e.user?.username || 'unknown'
|
|
30
|
+
const task = e.task?.name || e.task_id || e.task?.id || ''
|
|
31
|
+
const desc = e.description || ''
|
|
32
|
+
const billable = e.billable === true || e.billable === 'true'
|
|
33
|
+
|
|
34
|
+
if (!e.end || duration < 0) {
|
|
35
|
+
flags.runningTimers.push({ id: e.id, person, task })
|
|
36
|
+
continue
|
|
37
|
+
}
|
|
38
|
+
if (!task) flags.noTask.push({ id: e.id, person, hours: hours(duration) })
|
|
39
|
+
if (duration > 12 * MS_PER_HOUR) flags.over12h.push({ id: e.id, person, task, hours: hours(duration) })
|
|
40
|
+
|
|
41
|
+
totalMs += duration
|
|
42
|
+
if (billable) billableMs += duration
|
|
43
|
+
byPerson[person] = (byPerson[person] ?? 0) + duration
|
|
44
|
+
byTask[task || '(no task)'] = (byTask[task || '(no task)'] ?? 0) + duration
|
|
45
|
+
|
|
46
|
+
const date = new Date(Number(e.start)).toISOString().slice(0, 10)
|
|
47
|
+
rows.push({ date, person, task, desc, hours: hours(duration), billable })
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (wantCsv) {
|
|
51
|
+
const esc = (v) => (/[",\n]/.test(String(v)) ? `"${String(v).replace(/"/g, '""')}"` : String(v))
|
|
52
|
+
process.stdout.write('date,person,task,description,hours,billable\n')
|
|
53
|
+
for (const r of rows.sort((a, b) => a.date.localeCompare(b.date) || a.person.localeCompare(b.person))) {
|
|
54
|
+
process.stdout.write([r.date, r.person, r.task, r.desc, r.hours.toFixed(2), r.billable].map(esc).join(',') + '\n')
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
const toHours = (o) => Object.fromEntries(Object.entries(o).sort((a, b) => b[1] - a[1]).map(([k, v]) => [k, hours(v)]))
|
|
58
|
+
process.stdout.write(
|
|
59
|
+
JSON.stringify(
|
|
60
|
+
{
|
|
61
|
+
entries: rows.length,
|
|
62
|
+
totalHours: hours(totalMs),
|
|
63
|
+
billableHours: hours(billableMs),
|
|
64
|
+
nonBillableHours: hours(totalMs - billableMs),
|
|
65
|
+
byPerson: toHours(byPerson),
|
|
66
|
+
byTask: toHours(byTask),
|
|
67
|
+
flags,
|
|
68
|
+
},
|
|
69
|
+
null,
|
|
70
|
+
2,
|
|
71
|
+
) + '\n',
|
|
72
|
+
)
|
|
73
|
+
}
|
|
@@ -6,7 +6,7 @@ disable-model-invocation: true
|
|
|
6
6
|
context: fork
|
|
7
7
|
agent: general-purpose
|
|
8
8
|
argument-hint: "[scope - e.g. 'marketing team', space-id, or workspace-id]"
|
|
9
|
-
allowed-tools: Bash(clickup *)
|
|
9
|
+
allowed-tools: Bash(clickup *), Read
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Weekly Review
|
|
@@ -82,6 +82,8 @@ clickup goal list --workspace-id <id> --format json
|
|
|
82
82
|
|
|
83
83
|
### Step 7: Compile the report
|
|
84
84
|
|
|
85
|
+
Copy the exact structure from `assets/report-template.md` in this skill's directory (`clickup skill path clickup-weekly-review` prints it). Fill every placeholder; drop sections with no content.
|
|
86
|
+
|
|
85
87
|
Summarize the data into a clear report with sections:
|
|
86
88
|
- **Completed this week**: Count and highlights of finished tasks
|
|
87
89
|
- **In progress**: Tasks actively being worked on
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Weekly Review: <scope> (<week-start> to <week-end>)
|
|
2
|
+
|
|
3
|
+
**Summary:** <2-3 sentences: overall trajectory, the one thing to know>
|
|
4
|
+
|
|
5
|
+
## By the numbers
|
|
6
|
+
| Metric | This week |
|
|
7
|
+
|--------|-----------|
|
|
8
|
+
| Completed | <n> |
|
|
9
|
+
| In progress | <n> |
|
|
10
|
+
| Overdue | <n> |
|
|
11
|
+
| Hours logged | <n> |
|
|
12
|
+
|
|
13
|
+
## Completed this week
|
|
14
|
+
- <task name> (<assignee>)
|
|
15
|
+
|
|
16
|
+
## In progress
|
|
17
|
+
- <task name> - <assignee>, due <date>
|
|
18
|
+
|
|
19
|
+
## Overdue / Blocked
|
|
20
|
+
- <task name> - due <date>, <why it matters>
|
|
21
|
+
|
|
22
|
+
## Goal progress
|
|
23
|
+
- <goal>: <current>/<target> (<status>)
|
|
24
|
+
|
|
25
|
+
## Next week
|
|
26
|
+
- <what is due or planned>
|
|
@@ -6,7 +6,7 @@ disable-model-invocation: true
|
|
|
6
6
|
context: fork
|
|
7
7
|
agent: general-purpose
|
|
8
8
|
argument-hint: "[scope - workspace, space name, or list name; optionally 'and fix']"
|
|
9
|
-
allowed-tools: Bash(clickup *)
|
|
9
|
+
allowed-tools: Bash(clickup *), Bash(node *), Read
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Workspace Audit
|
|
@@ -27,9 +27,17 @@ clickup task search --workspace-id <id> --format json
|
|
|
27
27
|
|
|
28
28
|
Server-side filters cannot express "no assignee" or "no due date", so fetch active tasks and inspect the JSON client-side. For large workspaces sweep one space at a time (`--space-id`).
|
|
29
29
|
|
|
30
|
-
### Step 2:
|
|
30
|
+
### Step 2: Classify deterministically
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Pipe the tasks through the bundled script so every task is bucketed by rule, not judgment:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
SKILL_DIR=$(clickup skill path clickup-workspace-audit)
|
|
36
|
+
clickup task search --workspace-id <id> --format json \
|
|
37
|
+
| node "$SKILL_DIR/scripts/classify.mjs" [--stale-days 14]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The output contains `activeTasks`, `flaggedTasks`, per-bucket lists, and per-person `load`. The buckets:
|
|
33
41
|
|
|
34
42
|
| Check | Condition |
|
|
35
43
|
|-------|-----------|
|
|
@@ -45,23 +53,7 @@ Tasks with `blocked` or `waiting` status whose blockers are themselves overdue d
|
|
|
45
53
|
|
|
46
54
|
### Step 4: Report
|
|
47
55
|
|
|
48
|
-
|
|
49
|
-
## Workspace Audit: <scope> (<date>)
|
|
50
|
-
|
|
51
|
-
Overall: N active tasks, M flagged (X%)
|
|
52
|
-
|
|
53
|
-
### Overdue (worst first)
|
|
54
|
-
- <task> - due <date>, assignee <name> (<id>)
|
|
55
|
-
|
|
56
|
-
### Unassigned / No due date / Stale
|
|
57
|
-
- ...
|
|
58
|
-
|
|
59
|
-
### Load
|
|
60
|
-
- <name>: N open tasks (team median: M)
|
|
61
|
-
|
|
62
|
-
### Recommended fixes
|
|
63
|
-
1. ...
|
|
64
|
-
```
|
|
56
|
+
Copy the exact structure from `assets/report-template.md` in this skill's directory (`clickup skill path clickup-workspace-audit` prints it). Fill every placeholder; drop sections with no content.
|
|
65
57
|
|
|
66
58
|
### Step 5: Apply fixes (only when asked)
|
|
67
59
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
## Workspace Audit: <scope> (<date>)
|
|
2
|
+
|
|
3
|
+
Overall: <n> active tasks, <m> flagged (<x>%)
|
|
4
|
+
|
|
5
|
+
### Overdue (worst first)
|
|
6
|
+
- <task> - due <date>, assignee <name> (<id>)
|
|
7
|
+
|
|
8
|
+
### Unassigned
|
|
9
|
+
- <task> (<list>)
|
|
10
|
+
|
|
11
|
+
### No due date
|
|
12
|
+
- <task> (<list>)
|
|
13
|
+
|
|
14
|
+
### Stale (in progress, untouched 14+ days)
|
|
15
|
+
- <task> - last touched <date>
|
|
16
|
+
|
|
17
|
+
### Load
|
|
18
|
+
- <name>: <n> open tasks (team median: <m>)
|
|
19
|
+
|
|
20
|
+
### Recommended fixes
|
|
21
|
+
1. <specific action with the command to run>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Deterministic hygiene classification. Pipe `clickup task search ... --format json`
|
|
3
|
+
// into this script; every task is bucketed by rule, not judgment.
|
|
4
|
+
//
|
|
5
|
+
// clickup task search --workspace-id X --format json | node scripts/classify.mjs
|
|
6
|
+
//
|
|
7
|
+
// Output: JSON buckets (overdue, unassigned, noDueDate, stale, load) plus counts.
|
|
8
|
+
// --stale-days <n> overrides the 14-day staleness window.
|
|
9
|
+
|
|
10
|
+
import { readFileSync } from 'node:fs'
|
|
11
|
+
|
|
12
|
+
const staleIdx = process.argv.indexOf('--stale-days')
|
|
13
|
+
const STALE_DAYS = staleIdx !== -1 ? Number(process.argv[staleIdx + 1]) : 14
|
|
14
|
+
const now = Date.now()
|
|
15
|
+
const staleCutoff = now - STALE_DAYS * 24 * 3_600_000
|
|
16
|
+
|
|
17
|
+
const raw = readFileSync(0, 'utf-8')
|
|
18
|
+
let tasks = JSON.parse(raw)
|
|
19
|
+
if (!Array.isArray(tasks)) tasks = tasks.tasks ?? [tasks]
|
|
20
|
+
|
|
21
|
+
const summarize = (t) => ({
|
|
22
|
+
id: t.id,
|
|
23
|
+
name: t.name,
|
|
24
|
+
status: typeof t.status === 'object' ? t.status?.status : t.status,
|
|
25
|
+
assignees: (t.assignees ?? []).map((a) => a.username ?? a.id),
|
|
26
|
+
due_date: t.due_date ? new Date(Number(t.due_date)).toISOString().slice(0, 10) : null,
|
|
27
|
+
list: t.list?.name ?? null,
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const buckets = { overdue: [], unassigned: [], noDueDate: [], stale: [] }
|
|
31
|
+
const load = {}
|
|
32
|
+
const isClosed = (t) => {
|
|
33
|
+
const type = typeof t.status === 'object' ? t.status?.type : undefined
|
|
34
|
+
const s = (typeof t.status === 'object' ? t.status?.status : t.status ?? '').toLowerCase()
|
|
35
|
+
return type === 'closed' || type === 'done' || ['closed', 'complete', 'done'].includes(s)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let active = 0
|
|
39
|
+
for (const t of tasks) {
|
|
40
|
+
if (isClosed(t)) continue
|
|
41
|
+
active++
|
|
42
|
+
const s = summarize(t)
|
|
43
|
+
for (const a of s.assignees) load[a] = (load[a] ?? 0) + 1
|
|
44
|
+
|
|
45
|
+
if (s.assignees.length === 0) buckets.unassigned.push(s)
|
|
46
|
+
if (!t.due_date) buckets.noDueDate.push(s)
|
|
47
|
+
else if (Number(t.due_date) < now) buckets.overdue.push(s)
|
|
48
|
+
|
|
49
|
+
const statusType = typeof t.status === 'object' ? t.status?.type : undefined
|
|
50
|
+
const updated = Number(t.date_updated)
|
|
51
|
+
if (statusType === 'custom' || /progress|review|doing/.test((s.status ?? '').toLowerCase())) {
|
|
52
|
+
if (updated && updated < staleCutoff) buckets.stale.push({ ...s, last_updated: new Date(updated).toISOString().slice(0, 10) })
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
buckets.overdue.sort((a, b) => (a.due_date ?? '').localeCompare(b.due_date ?? ''))
|
|
57
|
+
const flagged = new Set([...buckets.overdue, ...buckets.unassigned, ...buckets.noDueDate, ...buckets.stale].map((t) => t.id))
|
|
58
|
+
|
|
59
|
+
process.stdout.write(
|
|
60
|
+
JSON.stringify(
|
|
61
|
+
{
|
|
62
|
+
activeTasks: active,
|
|
63
|
+
flaggedTasks: flagged.size,
|
|
64
|
+
staleDays: STALE_DAYS,
|
|
65
|
+
counts: Object.fromEntries(Object.entries(buckets).map(([k, v]) => [k, v.length])),
|
|
66
|
+
load: Object.fromEntries(Object.entries(load).sort((a, b) => b[1] - a[1])),
|
|
67
|
+
...buckets,
|
|
68
|
+
},
|
|
69
|
+
null,
|
|
70
|
+
2,
|
|
71
|
+
) + '\n',
|
|
72
|
+
)
|