@krodak/clickup-cli 1.1.0 → 1.3.0
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/plugin.json +1 -1
- package/README.md +12 -11
- package/dist/index.js +286 -12
- package/package.json +1 -1
- package/skills/clickup-cli/SKILL.md +17 -3
|
@@ -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.
|
|
4
|
+
"version": "1.3.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Krzysztof Rodak"
|
|
7
7
|
},
|
package/README.md
CHANGED
|
@@ -210,7 +210,7 @@ Status: :white_check_mark: implemented | :construction: planned | :no_entry_sign
|
|
|
210
210
|
| Feature | Command | Status |
|
|
211
211
|
| ----------------------- | -------------------- | ------------------ |
|
|
212
212
|
| Add/remove tag on task | `cup tag <id>` | :white_check_mark: |
|
|
213
|
-
| List space tags | `cup tags <spaceId>` | :
|
|
213
|
+
| List space tags | `cup tags <spaceId>` | :white_check_mark: |
|
|
214
214
|
| Create/delete space tag | | :construction: |
|
|
215
215
|
|
|
216
216
|
### Time Tracking
|
|
@@ -222,8 +222,8 @@ Status: :white_check_mark: implemented | :construction: planned | :no_entry_sign
|
|
|
222
222
|
| Timer status | `cup time status` | :white_check_mark: |
|
|
223
223
|
| Log time entry | `cup time log <id> <duration>` | :white_check_mark: |
|
|
224
224
|
| List entries | `cup time list` | :white_check_mark: |
|
|
225
|
-
| Update entry | `cup time update <id>` | :
|
|
226
|
-
| Delete entry | `cup time delete <id>` | :
|
|
225
|
+
| Update entry | `cup time update <id>` | :white_check_mark: |
|
|
226
|
+
| Delete entry | `cup time delete <id>` | :white_check_mark: |
|
|
227
227
|
|
|
228
228
|
### Workspace
|
|
229
229
|
|
|
@@ -232,7 +232,7 @@ Status: :white_check_mark: implemented | :construction: planned | :no_entry_sign
|
|
|
232
232
|
| List spaces | `cup spaces` | :white_check_mark: |
|
|
233
233
|
| List lists | `cup lists <spaceId>` | :white_check_mark: |
|
|
234
234
|
| Check auth | `cup auth` | :white_check_mark: |
|
|
235
|
-
| List folders | `cup folders <spaceId>` | :
|
|
235
|
+
| List folders | `cup folders <spaceId>` | :white_check_mark: |
|
|
236
236
|
| List members | `cup members` | :construction: |
|
|
237
237
|
|
|
238
238
|
### Goals & Key Results
|
|
@@ -245,13 +245,14 @@ Status: :white_check_mark: implemented | :construction: planned | :no_entry_sign
|
|
|
245
245
|
|
|
246
246
|
### Docs
|
|
247
247
|
|
|
248
|
-
| Feature
|
|
249
|
-
|
|
|
250
|
-
| Search docs
|
|
251
|
-
| View
|
|
252
|
-
|
|
|
253
|
-
| Create
|
|
254
|
-
|
|
|
248
|
+
| Feature | Command | Status |
|
|
249
|
+
| ---------------- | ------------------------------------ | ------------------ |
|
|
250
|
+
| Search docs | `cup docs [query]` | :white_check_mark: |
|
|
251
|
+
| View doc / page | `cup doc <docId> [pageId]` | :white_check_mark: |
|
|
252
|
+
| All page content | `cup doc-pages <docId>` | :white_check_mark: |
|
|
253
|
+
| Create doc | `cup doc-create <title>` | :white_check_mark: |
|
|
254
|
+
| Create page | `cup doc-page-create <docId> <name>` | :white_check_mark: |
|
|
255
|
+
| Edit page | `cup doc-page-edit <docId> <pageId>` | :white_check_mark: |
|
|
255
256
|
|
|
256
257
|
### Attachments
|
|
257
258
|
|
package/dist/index.js
CHANGED
|
@@ -371,6 +371,17 @@ var ClickUpClient = class {
|
|
|
371
371
|
}
|
|
372
372
|
return entries;
|
|
373
373
|
}
|
|
374
|
+
async updateTimeEntry(teamId, timeEntryId, updates) {
|
|
375
|
+
const data = await this.request(
|
|
376
|
+
`/team/${teamId}/time_entries/${timeEntryId}`,
|
|
377
|
+
{ method: "PUT", body: JSON.stringify(updates) }
|
|
378
|
+
);
|
|
379
|
+
return data.data;
|
|
380
|
+
}
|
|
381
|
+
async getSpaceTags(spaceId) {
|
|
382
|
+
const data = await this.request(`/space/${spaceId}/tag`);
|
|
383
|
+
return data.tags ?? [];
|
|
384
|
+
}
|
|
374
385
|
async deleteTimeEntry(teamId, timeEntryId) {
|
|
375
386
|
await this.request(`/team/${teamId}/time_entries/${timeEntryId}`, {
|
|
376
387
|
method: "DELETE"
|
|
@@ -443,6 +454,21 @@ var ClickUpClient = class {
|
|
|
443
454
|
body: JSON.stringify(updates)
|
|
444
455
|
});
|
|
445
456
|
}
|
|
457
|
+
async getDoc(workspaceId, docId) {
|
|
458
|
+
return this.requestV3(`/workspaces/${workspaceId}/docs/${docId}`);
|
|
459
|
+
}
|
|
460
|
+
async getDocPageListing(workspaceId, docId) {
|
|
461
|
+
const data = await this.requestV3(
|
|
462
|
+
`/workspaces/${workspaceId}/docs/${docId}/pagelisting`
|
|
463
|
+
);
|
|
464
|
+
return data.pages ?? [];
|
|
465
|
+
}
|
|
466
|
+
async getDocPages(workspaceId, docId) {
|
|
467
|
+
const data = await this.requestV3(
|
|
468
|
+
`/workspaces/${workspaceId}/docs/${docId}/pages?content_format=text/md`
|
|
469
|
+
);
|
|
470
|
+
return data.pages ?? [];
|
|
471
|
+
}
|
|
446
472
|
};
|
|
447
473
|
|
|
448
474
|
// src/config.ts
|
|
@@ -2091,7 +2117,7 @@ function bashCompletion(name) {
|
|
|
2091
2117
|
cword=$COMP_CWORD
|
|
2092
2118
|
fi
|
|
2093
2119
|
|
|
2094
|
-
local commands="init auth tasks task update create sprint sprints subtasks comment comment-edit comment-delete comments replies reply activity lists spaces inbox assigned open search summary overdue assign depend link attach move field delete tag checklist time docs doc doc-create doc-page-create doc-page-edit config completion"
|
|
2120
|
+
local commands="init auth tasks task update create sprint sprints subtasks comment comment-edit comment-delete comments replies reply activity lists spaces inbox assigned open search summary overdue assign depend link attach move field delete tag tags checklist time docs doc doc-create doc-pages doc-page-create doc-page-edit folders config completion"
|
|
2095
2121
|
|
|
2096
2122
|
if [[ $cword -eq 1 ]]; then
|
|
2097
2123
|
COMPREPLY=($(compgen -W "$commands --help --version" -- "$cur"))
|
|
@@ -2221,6 +2247,15 @@ function bashCompletion(name) {
|
|
|
2221
2247
|
doc)
|
|
2222
2248
|
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2223
2249
|
;;
|
|
2250
|
+
doc-pages)
|
|
2251
|
+
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2252
|
+
;;
|
|
2253
|
+
tags)
|
|
2254
|
+
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2255
|
+
;;
|
|
2256
|
+
folders)
|
|
2257
|
+
COMPREPLY=($(compgen -W "--name --json" -- "$cur"))
|
|
2258
|
+
;;
|
|
2224
2259
|
doc-create)
|
|
2225
2260
|
COMPREPLY=($(compgen -W "-c --content --json" -- "$cur"))
|
|
2226
2261
|
;;
|
|
@@ -2291,10 +2326,13 @@ _${name}() {
|
|
|
2291
2326
|
'link:Add or remove a link between two tasks'
|
|
2292
2327
|
'attach:Upload a file attachment to a task'
|
|
2293
2328
|
'docs:List workspace docs'
|
|
2294
|
-
'doc:View a doc page'
|
|
2329
|
+
'doc:View a doc or doc page'
|
|
2295
2330
|
'doc-create:Create a new doc'
|
|
2331
|
+
'doc-pages:List all pages in a doc with content'
|
|
2296
2332
|
'doc-page-create:Create a page in a doc'
|
|
2297
2333
|
'doc-page-edit:Edit a doc page'
|
|
2334
|
+
'tags:List tags in a space'
|
|
2335
|
+
'folders:List folders in a space'
|
|
2298
2336
|
'config:Manage CLI configuration'
|
|
2299
2337
|
'completion:Output shell completion script'
|
|
2300
2338
|
)
|
|
@@ -2628,6 +2666,22 @@ _${name}() {
|
|
|
2628
2666
|
'2:page_id:' \\
|
|
2629
2667
|
'--json[Force JSON output]'
|
|
2630
2668
|
;;
|
|
2669
|
+
doc-pages)
|
|
2670
|
+
_arguments \\
|
|
2671
|
+
'1:doc_id:' \\
|
|
2672
|
+
'--json[Force JSON output]'
|
|
2673
|
+
;;
|
|
2674
|
+
tags)
|
|
2675
|
+
_arguments \\
|
|
2676
|
+
'1:space_id:' \\
|
|
2677
|
+
'--json[Force JSON output]'
|
|
2678
|
+
;;
|
|
2679
|
+
folders)
|
|
2680
|
+
_arguments \\
|
|
2681
|
+
'1:space_id:' \\
|
|
2682
|
+
'--name[Filter by folder name]:text:' \\
|
|
2683
|
+
'--json[Force JSON output]'
|
|
2684
|
+
;;
|
|
2631
2685
|
doc-create)
|
|
2632
2686
|
_arguments \\
|
|
2633
2687
|
'1:title:' \\
|
|
@@ -2725,10 +2779,13 @@ complete -c ${name} -n __fish_use_subcommand -a reply -d 'Reply to a comment'
|
|
|
2725
2779
|
complete -c ${name} -n __fish_use_subcommand -a link -d 'Add or remove a link between two tasks'
|
|
2726
2780
|
complete -c ${name} -n __fish_use_subcommand -a attach -d 'Upload a file attachment to a task'
|
|
2727
2781
|
complete -c ${name} -n __fish_use_subcommand -a docs -d 'List workspace docs'
|
|
2728
|
-
complete -c ${name} -n __fish_use_subcommand -a doc -d 'View a doc page'
|
|
2782
|
+
complete -c ${name} -n __fish_use_subcommand -a doc -d 'View a doc or doc page'
|
|
2729
2783
|
complete -c ${name} -n __fish_use_subcommand -a doc-create -d 'Create a new doc'
|
|
2784
|
+
complete -c ${name} -n __fish_use_subcommand -a doc-pages -d 'List all pages in a doc with content'
|
|
2730
2785
|
complete -c ${name} -n __fish_use_subcommand -a doc-page-create -d 'Create a page in a doc'
|
|
2731
2786
|
complete -c ${name} -n __fish_use_subcommand -a doc-page-edit -d 'Edit a doc page'
|
|
2787
|
+
complete -c ${name} -n __fish_use_subcommand -a tags -d 'List tags in a space'
|
|
2788
|
+
complete -c ${name} -n __fish_use_subcommand -a folders -d 'List folders in a space'
|
|
2732
2789
|
complete -c ${name} -n __fish_use_subcommand -a config -d 'Manage CLI configuration'
|
|
2733
2790
|
complete -c ${name} -n __fish_use_subcommand -a completion -d 'Output shell completion script'
|
|
2734
2791
|
|
|
@@ -2886,6 +2943,13 @@ complete -c ${name} -n '__fish_seen_subcommand_from docs' -l json -d 'Force JSON
|
|
|
2886
2943
|
|
|
2887
2944
|
complete -c ${name} -n '__fish_seen_subcommand_from doc' -l json -d 'Force JSON output'
|
|
2888
2945
|
|
|
2946
|
+
complete -c ${name} -n '__fish_seen_subcommand_from doc-pages' -l json -d 'Force JSON output'
|
|
2947
|
+
|
|
2948
|
+
complete -c ${name} -n '__fish_seen_subcommand_from tags' -l json -d 'Force JSON output'
|
|
2949
|
+
|
|
2950
|
+
complete -c ${name} -n '__fish_seen_subcommand_from folders' -l name -d 'Filter by folder name'
|
|
2951
|
+
complete -c ${name} -n '__fish_seen_subcommand_from folders' -l json -d 'Force JSON output'
|
|
2952
|
+
|
|
2889
2953
|
complete -c ${name} -n '__fish_seen_subcommand_from doc-create' -s c -l content -d 'Initial content'
|
|
2890
2954
|
complete -c ${name} -n '__fish_seen_subcommand_from doc-create' -l json -d 'Force JSON output'
|
|
2891
2955
|
|
|
@@ -3296,10 +3360,76 @@ function formatDocsMarkdown(docs) {
|
|
|
3296
3360
|
}
|
|
3297
3361
|
|
|
3298
3362
|
// src/commands/doc.ts
|
|
3363
|
+
import chalk8 from "chalk";
|
|
3364
|
+
async function getDocInfo(config, docId) {
|
|
3365
|
+
const client = new ClickUpClient(config);
|
|
3366
|
+
const [doc, pages] = await Promise.all([
|
|
3367
|
+
client.getDoc(config.teamId, docId),
|
|
3368
|
+
client.getDocPageListing(config.teamId, docId)
|
|
3369
|
+
]);
|
|
3370
|
+
return { doc, pages };
|
|
3371
|
+
}
|
|
3372
|
+
function formatDocInfo(doc, pages, indent = 0) {
|
|
3373
|
+
const lines = [];
|
|
3374
|
+
if (indent === 0) {
|
|
3375
|
+
lines.push(`${chalk8.bold(doc.name)} ${chalk8.dim(doc.id)}`);
|
|
3376
|
+
if (pages.length === 0) {
|
|
3377
|
+
lines.push(" (no pages)");
|
|
3378
|
+
}
|
|
3379
|
+
}
|
|
3380
|
+
for (const page of pages) {
|
|
3381
|
+
const prefix = " ".repeat(indent + 1);
|
|
3382
|
+
lines.push(`${prefix}${page.name} ${chalk8.dim(page.id)}`);
|
|
3383
|
+
if (page.pages && page.pages.length > 0) {
|
|
3384
|
+
lines.push(formatDocInfo(doc, page.pages, indent + 1));
|
|
3385
|
+
}
|
|
3386
|
+
}
|
|
3387
|
+
return lines.join("\n");
|
|
3388
|
+
}
|
|
3389
|
+
function formatDocInfoMarkdown(doc, pages, indent = 0) {
|
|
3390
|
+
const lines = [];
|
|
3391
|
+
if (indent === 0) {
|
|
3392
|
+
lines.push(`# ${doc.name}`);
|
|
3393
|
+
lines.push(`ID: ${doc.id}`);
|
|
3394
|
+
lines.push("");
|
|
3395
|
+
if (pages.length === 0) {
|
|
3396
|
+
lines.push("No pages.");
|
|
3397
|
+
return lines.join("\n");
|
|
3398
|
+
}
|
|
3399
|
+
lines.push("## Pages");
|
|
3400
|
+
}
|
|
3401
|
+
for (const page of pages) {
|
|
3402
|
+
const prefix = " ".repeat(indent);
|
|
3403
|
+
lines.push(`${prefix}- **${page.name}** (${page.id})`);
|
|
3404
|
+
if (page.pages && page.pages.length > 0) {
|
|
3405
|
+
lines.push(formatDocInfoMarkdown(doc, page.pages, indent + 1));
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
return lines.join("\n");
|
|
3409
|
+
}
|
|
3299
3410
|
async function getDocPage(config, docId, pageId) {
|
|
3300
3411
|
const client = new ClickUpClient(config);
|
|
3301
3412
|
return client.getDocPage(config.teamId, docId, pageId);
|
|
3302
3413
|
}
|
|
3414
|
+
async function getAllDocPages(config, docId) {
|
|
3415
|
+
const client = new ClickUpClient(config);
|
|
3416
|
+
return client.getDocPages(config.teamId, docId);
|
|
3417
|
+
}
|
|
3418
|
+
function formatDocPages(pages) {
|
|
3419
|
+
if (pages.length === 0) return "No pages found";
|
|
3420
|
+
return pages.map((p) => {
|
|
3421
|
+
const header = `# ${p.name}
|
|
3422
|
+
`;
|
|
3423
|
+
return header + (p.content ?? "");
|
|
3424
|
+
}).join("\n\n---\n\n");
|
|
3425
|
+
}
|
|
3426
|
+
function formatDocPagesMarkdown(pages) {
|
|
3427
|
+
if (pages.length === 0) return "No pages found";
|
|
3428
|
+
return pages.map((p) => {
|
|
3429
|
+
const header = `# ${p.name}`;
|
|
3430
|
+
return header + "\n\n" + (p.content ?? "");
|
|
3431
|
+
}).join("\n\n---\n\n");
|
|
3432
|
+
}
|
|
3303
3433
|
async function createDoc(config, title, content) {
|
|
3304
3434
|
if (!title.trim()) throw new Error("Doc title cannot be empty");
|
|
3305
3435
|
const client = new ClickUpClient(config);
|
|
@@ -3319,8 +3449,44 @@ async function editDocPage(config, docId, pageId, updates) {
|
|
|
3319
3449
|
return client.editDocPage(config.teamId, docId, pageId, updates);
|
|
3320
3450
|
}
|
|
3321
3451
|
|
|
3452
|
+
// src/commands/folders.ts
|
|
3453
|
+
import chalk9 from "chalk";
|
|
3454
|
+
async function listFolders(config, spaceId, nameFilter) {
|
|
3455
|
+
const client = new ClickUpClient(config);
|
|
3456
|
+
const folders = await client.getFolders(spaceId);
|
|
3457
|
+
let filtered = folders;
|
|
3458
|
+
if (nameFilter) {
|
|
3459
|
+
const lower = nameFilter.toLowerCase();
|
|
3460
|
+
filtered = folders.filter((f) => f.name.toLowerCase().includes(lower));
|
|
3461
|
+
}
|
|
3462
|
+
const results = [];
|
|
3463
|
+
for (const folder of filtered) {
|
|
3464
|
+
const lists = await client.getFolderLists(folder.id);
|
|
3465
|
+
results.push({ id: folder.id, name: folder.name, lists });
|
|
3466
|
+
}
|
|
3467
|
+
return results;
|
|
3468
|
+
}
|
|
3469
|
+
function formatFolders(folders) {
|
|
3470
|
+
if (folders.length === 0) return "No folders found";
|
|
3471
|
+
return folders.map((f) => {
|
|
3472
|
+
const header = `${chalk9.bold(f.name)} ${chalk9.dim(f.id)}`;
|
|
3473
|
+
if (f.lists.length === 0) return header;
|
|
3474
|
+
const listLines = f.lists.map((l) => ` ${l.name} ${chalk9.dim(l.id)}`);
|
|
3475
|
+
return [header, ...listLines].join("\n");
|
|
3476
|
+
}).join("\n\n");
|
|
3477
|
+
}
|
|
3478
|
+
function formatFoldersMarkdown(folders) {
|
|
3479
|
+
if (folders.length === 0) return "No folders found";
|
|
3480
|
+
return folders.map((f) => {
|
|
3481
|
+
const header = `- **${f.name}** (${f.id})`;
|
|
3482
|
+
if (f.lists.length === 0) return header;
|
|
3483
|
+
const listLines = f.lists.map((l) => ` - ${l.name} (${l.id})`);
|
|
3484
|
+
return [header, ...listLines].join("\n");
|
|
3485
|
+
}).join("\n");
|
|
3486
|
+
}
|
|
3487
|
+
|
|
3322
3488
|
// src/commands/time.ts
|
|
3323
|
-
import
|
|
3489
|
+
import chalk10 from "chalk";
|
|
3324
3490
|
async function startTimer(config, taskId, description) {
|
|
3325
3491
|
const client = new ClickUpClient(config);
|
|
3326
3492
|
return client.startTimeEntry(config.teamId, taskId, description);
|
|
@@ -3349,6 +3515,20 @@ async function listTimeEntries(config, opts) {
|
|
|
3349
3515
|
taskId: opts?.taskId
|
|
3350
3516
|
});
|
|
3351
3517
|
}
|
|
3518
|
+
async function updateTimeEntry(config, timeEntryId, opts) {
|
|
3519
|
+
if (!opts.description && !opts.duration) {
|
|
3520
|
+
throw new Error("Provide --description or --duration to update");
|
|
3521
|
+
}
|
|
3522
|
+
const client = new ClickUpClient(config);
|
|
3523
|
+
const updates = {};
|
|
3524
|
+
if (opts.description) updates.description = opts.description;
|
|
3525
|
+
if (opts.duration) updates.duration = parseTimeEstimate(opts.duration);
|
|
3526
|
+
return client.updateTimeEntry(config.teamId, timeEntryId, updates);
|
|
3527
|
+
}
|
|
3528
|
+
async function deleteTimeEntry(config, timeEntryId) {
|
|
3529
|
+
const client = new ClickUpClient(config);
|
|
3530
|
+
await client.deleteTimeEntry(config.teamId, timeEntryId);
|
|
3531
|
+
}
|
|
3352
3532
|
function formatTimeEntry(entry) {
|
|
3353
3533
|
const lines = [];
|
|
3354
3534
|
const taskName = entry.task?.name ?? "No task";
|
|
@@ -3356,8 +3536,8 @@ function formatTimeEntry(entry) {
|
|
|
3356
3536
|
const isRunning = entry.duration < 0;
|
|
3357
3537
|
const elapsed = isRunning ? Date.now() - Number(entry.start) : entry.duration;
|
|
3358
3538
|
const durationStr = formatDuration(elapsed);
|
|
3359
|
-
const status = isRunning ?
|
|
3360
|
-
lines.push(`${
|
|
3539
|
+
const status = isRunning ? chalk10.green("RUNNING") : "";
|
|
3540
|
+
lines.push(`${chalk10.bold(taskName)} ${chalk10.dim(taskId)} ${status}`);
|
|
3361
3541
|
lines.push(
|
|
3362
3542
|
` ${durationStr} - ${formatTimestamp(entry.start)}${entry.description ? ` - ${entry.description}` : ""}`
|
|
3363
3543
|
);
|
|
@@ -3381,6 +3561,21 @@ function formatTimeEntriesMarkdown(entries) {
|
|
|
3381
3561
|
return entries.map(formatTimeEntryMarkdown).join("\n");
|
|
3382
3562
|
}
|
|
3383
3563
|
|
|
3564
|
+
// src/commands/tags.ts
|
|
3565
|
+
import chalk11 from "chalk";
|
|
3566
|
+
async function listSpaceTags(config, spaceId) {
|
|
3567
|
+
const client = new ClickUpClient(config);
|
|
3568
|
+
return client.getSpaceTags(spaceId);
|
|
3569
|
+
}
|
|
3570
|
+
function formatTags(tags) {
|
|
3571
|
+
if (tags.length === 0) return "No tags found";
|
|
3572
|
+
return tags.map((t) => chalk11.bold(t.name)).join(", ");
|
|
3573
|
+
}
|
|
3574
|
+
function formatTagsMarkdown(tags) {
|
|
3575
|
+
if (tags.length === 0) return "No tags found";
|
|
3576
|
+
return tags.map((t) => `- ${t.name}`).join("\n");
|
|
3577
|
+
}
|
|
3578
|
+
|
|
3384
3579
|
// src/index.ts
|
|
3385
3580
|
var require2 = createRequire(import.meta.url);
|
|
3386
3581
|
var { version } = require2("../package.json");
|
|
@@ -3923,6 +4118,48 @@ timeCmd.command("list").description("List recent time entries (default: last 7 d
|
|
|
3923
4118
|
}
|
|
3924
4119
|
})
|
|
3925
4120
|
);
|
|
4121
|
+
timeCmd.command("update <timeEntryId>").description("Update a time entry").option("-d, --description <text>", "New description").option("--duration <duration>", 'New duration (e.g. "2h", "30m")').option("--json", "Force JSON output even in terminal").action(
|
|
4122
|
+
wrapAction(
|
|
4123
|
+
async (timeEntryId, opts) => {
|
|
4124
|
+
const config = loadConfig();
|
|
4125
|
+
const entry = await updateTimeEntry(config, timeEntryId, {
|
|
4126
|
+
description: opts.description,
|
|
4127
|
+
duration: opts.duration
|
|
4128
|
+
});
|
|
4129
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4130
|
+
console.log(JSON.stringify(entry, null, 2));
|
|
4131
|
+
} else if (isTTY()) {
|
|
4132
|
+
console.log(formatTimeEntry(entry));
|
|
4133
|
+
} else {
|
|
4134
|
+
console.log(formatTimeEntryMarkdown(entry));
|
|
4135
|
+
}
|
|
4136
|
+
}
|
|
4137
|
+
)
|
|
4138
|
+
);
|
|
4139
|
+
timeCmd.command("delete <timeEntryId>").description("Delete a time entry").option("--json", "Force JSON output even in terminal").action(
|
|
4140
|
+
wrapAction(async (timeEntryId, opts) => {
|
|
4141
|
+
const config = loadConfig();
|
|
4142
|
+
await deleteTimeEntry(config, timeEntryId);
|
|
4143
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4144
|
+
console.log(JSON.stringify({ deleted: timeEntryId }));
|
|
4145
|
+
} else {
|
|
4146
|
+
console.log(`Deleted time entry ${timeEntryId}`);
|
|
4147
|
+
}
|
|
4148
|
+
})
|
|
4149
|
+
);
|
|
4150
|
+
program.command("tags <spaceId>").description("List tags in a space").option("--json", "Force JSON output even in terminal").action(
|
|
4151
|
+
wrapAction(async (spaceId, opts) => {
|
|
4152
|
+
const config = loadConfig();
|
|
4153
|
+
const tags = await listSpaceTags(config, spaceId);
|
|
4154
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4155
|
+
console.log(JSON.stringify(tags, null, 2));
|
|
4156
|
+
} else if (isTTY()) {
|
|
4157
|
+
console.log(formatTags(tags));
|
|
4158
|
+
} else {
|
|
4159
|
+
console.log(formatTagsMarkdown(tags));
|
|
4160
|
+
}
|
|
4161
|
+
})
|
|
4162
|
+
);
|
|
3926
4163
|
program.command("docs [query]").description("List workspace docs (optionally filter by name)").option("--json", "Force JSON output even in terminal").action(
|
|
3927
4164
|
wrapAction(async (query, opts) => {
|
|
3928
4165
|
const config = loadConfig();
|
|
@@ -3936,16 +4173,53 @@ program.command("docs [query]").description("List workspace docs (optionally fil
|
|
|
3936
4173
|
}
|
|
3937
4174
|
})
|
|
3938
4175
|
);
|
|
3939
|
-
program.command("doc <docId>
|
|
4176
|
+
program.command("doc <docId> [pageId]").description("View a doc (metadata + page tree) or a specific page").option("--json", "Force JSON output even in terminal").action(
|
|
3940
4177
|
wrapAction(async (docId, pageId, opts) => {
|
|
3941
4178
|
const config = loadConfig();
|
|
3942
|
-
|
|
4179
|
+
if (pageId) {
|
|
4180
|
+
const page = await getDocPage(config, docId, pageId);
|
|
4181
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4182
|
+
console.log(JSON.stringify(page, null, 2));
|
|
4183
|
+
} else {
|
|
4184
|
+
if (page.name) console.log(`# ${page.name}
|
|
4185
|
+
`);
|
|
4186
|
+
console.log(page.content ?? "");
|
|
4187
|
+
}
|
|
4188
|
+
} else {
|
|
4189
|
+
const { doc, pages } = await getDocInfo(config, docId);
|
|
4190
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4191
|
+
console.log(JSON.stringify({ ...doc, pages }, null, 2));
|
|
4192
|
+
} else if (isTTY()) {
|
|
4193
|
+
console.log(formatDocInfo(doc, pages));
|
|
4194
|
+
} else {
|
|
4195
|
+
console.log(formatDocInfoMarkdown(doc, pages));
|
|
4196
|
+
}
|
|
4197
|
+
}
|
|
4198
|
+
})
|
|
4199
|
+
);
|
|
4200
|
+
program.command("doc-pages <docId>").description("List all pages in a doc with content").option("--json", "Force JSON output even in terminal").action(
|
|
4201
|
+
wrapAction(async (docId, opts) => {
|
|
4202
|
+
const config = loadConfig();
|
|
4203
|
+
const pages = await getAllDocPages(config, docId);
|
|
3943
4204
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
3944
|
-
console.log(JSON.stringify(
|
|
4205
|
+
console.log(JSON.stringify(pages, null, 2));
|
|
4206
|
+
} else if (isTTY()) {
|
|
4207
|
+
console.log(formatDocPages(pages));
|
|
3945
4208
|
} else {
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
4209
|
+
console.log(formatDocPagesMarkdown(pages));
|
|
4210
|
+
}
|
|
4211
|
+
})
|
|
4212
|
+
);
|
|
4213
|
+
program.command("folders <spaceId>").description("List folders in a space (with their lists)").option("--name <partial>", "Filter folders by partial name match").option("--json", "Force JSON output even in terminal").action(
|
|
4214
|
+
wrapAction(async (spaceId, opts) => {
|
|
4215
|
+
const config = loadConfig();
|
|
4216
|
+
const folders = await listFolders(config, spaceId, opts.name);
|
|
4217
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4218
|
+
console.log(JSON.stringify(folders, null, 2));
|
|
4219
|
+
} else if (isTTY()) {
|
|
4220
|
+
console.log(formatFolders(folders));
|
|
4221
|
+
} else {
|
|
4222
|
+
console.log(formatFoldersMarkdown(folders));
|
|
3949
4223
|
}
|
|
3950
4224
|
})
|
|
3951
4225
|
);
|
package/package.json
CHANGED
|
@@ -52,8 +52,11 @@ All commands support `--help` for full flag details.
|
|
|
52
52
|
| `cup lists <spaceId> [--name partial] [--json]` | Lists in a space (including folder lists) |
|
|
53
53
|
| `cup open <query> [--json]` | Open task in browser by ID or name |
|
|
54
54
|
| `cup auth [--json]` | Check authentication status |
|
|
55
|
+
| `cup folders <spaceId> [--name partial] [--json]` | Folders in a space (with their lists) |
|
|
56
|
+
| `cup tags <spaceId> [--json]` | List tags available in a space |
|
|
55
57
|
| `cup docs [query] [--json]` | List workspace docs (optionally filter by name) |
|
|
56
|
-
| `cup doc <docId>
|
|
58
|
+
| `cup doc <docId> [pageId] [--json]` | View doc metadata + page tree, or a specific page |
|
|
59
|
+
| `cup doc-pages <docId> [--json]` | All pages in a doc with content |
|
|
57
60
|
|
|
58
61
|
### Write
|
|
59
62
|
|
|
@@ -85,6 +88,8 @@ All commands support `--help` for full flag details.
|
|
|
85
88
|
| `cup time status [--json]` | Show currently running timer |
|
|
86
89
|
| `cup time log <taskId> <duration> [-d desc] [--json]` | Log manual time entry (e.g. "2h", "30m") |
|
|
87
90
|
| `cup time list [--days n] [--task id] [--json]` | List recent time entries |
|
|
91
|
+
| `cup time update <timeEntryId> [-d desc] [--duration dur] [--json]` | Update a time entry |
|
|
92
|
+
| `cup time delete <timeEntryId> [--json]` | Delete a time entry |
|
|
88
93
|
| `cup doc-create <title> [-c content] [--json]` | Create a new doc |
|
|
89
94
|
| `cup doc-page-create <docId> <name> [-c content] [--parent-page pageId] [--json]` | Create a page in a doc |
|
|
90
95
|
| `cup doc-page-edit <docId> <pageId> [--name text] [-c content] [--json]` | Edit a doc page |
|
|
@@ -121,7 +126,10 @@ All commands support `--help` for full flag details.
|
|
|
121
126
|
| `cup overdue` | Excludes closed tasks, sorted most overdue first |
|
|
122
127
|
| `cup open` | Tries task ID first, falls back to name search |
|
|
123
128
|
| `cup checklist` | Full CRUD for task checklists: view, create, delete, add-item, edit-item, delete-item |
|
|
124
|
-
| `cup
|
|
129
|
+
| `cup tags` | List available tags in a space. Useful for discovering valid tag names before using `cup tag` |
|
|
130
|
+
| `cup time` | Track time: start/stop timer, log entries, list history, update/delete entries. Duration format: "2h", "30m", "1h30m" |
|
|
131
|
+
| `cup time update` | Update a time entry description or duration |
|
|
132
|
+
| `cup time delete` | Delete a time entry |
|
|
125
133
|
| `cup comment-edit` | Edit comment text and resolution status |
|
|
126
134
|
| `cup comment-delete` | Delete a comment |
|
|
127
135
|
| `cup replies` / `cup reply` | View and post threaded comment replies |
|
|
@@ -129,8 +137,10 @@ All commands support `--help` for full flag details.
|
|
|
129
137
|
| `cup link` + custom IDs | Both IDs must be the same type (both custom or both native). Mixing may not work |
|
|
130
138
|
| `cup link` | Link/unlink tasks (different from dependencies) |
|
|
131
139
|
| `cup attach` | Upload files to tasks. Attachments shown in `cup task` detail view |
|
|
140
|
+
| `cup folders` | List folders in a space with their contained lists |
|
|
132
141
|
| `cup docs` | List and search workspace docs by name |
|
|
133
|
-
| `cup doc` | View
|
|
142
|
+
| `cup doc` | View doc metadata + page tree (no pageId), or a specific page (with pageId) |
|
|
143
|
+
| `cup doc-pages` | Dump all pages in a doc with full content |
|
|
134
144
|
| `cup doc-create` | Create a new doc with optional initial content |
|
|
135
145
|
| `cup doc-page-create` | Create a page in a doc, optionally nested under a parent page |
|
|
136
146
|
| `cup doc-page-edit` | Edit a doc page name or content |
|
|
@@ -210,7 +220,9 @@ cup delete abc123def --confirm # irreversible!
|
|
|
210
220
|
```bash
|
|
211
221
|
cup docs # list all docs
|
|
212
222
|
cup docs "design" # search docs by name
|
|
223
|
+
cup doc <docId> # doc metadata + page tree
|
|
213
224
|
cup doc <docId> <pageId> # view page content
|
|
225
|
+
cup doc-pages <docId> # all pages with content
|
|
214
226
|
cup doc-create "Architecture Notes" # create a doc
|
|
215
227
|
cup doc-create "Notes" -c "# Draft" # create with content
|
|
216
228
|
cup doc-page-create <docId> "New Section" # add page to doc
|
|
@@ -224,6 +236,8 @@ cup doc-page-edit <docId> <pageId> -c "# Updated content" # edit content
|
|
|
224
236
|
```bash
|
|
225
237
|
cup spaces # all spaces
|
|
226
238
|
cup spaces --name "Engineering" # find space ID by name
|
|
239
|
+
cup folders <spaceId> # folders with their lists
|
|
240
|
+
cup folders <spaceId> --name "sprint" # filter folders by name
|
|
227
241
|
cup lists <spaceId> # lists in a space (needs ID from cup spaces)
|
|
228
242
|
cup sprints # all sprints across folders
|
|
229
243
|
cup auth # verify token works
|