@krodak/clickup-cli 1.4.0 → 1.5.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.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +27 -172
- package/dist/index.js +2014 -1325
- package/package.json +2 -1
- package/skills/clickup-cli/SKILL.md +126 -198
package/dist/index.js
CHANGED
|
@@ -1,14 +1,69 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { basename } from "path";
|
|
4
|
+
import { basename, resolve } from "path";
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
import { createRequire } from "module";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
7
8
|
|
|
8
9
|
// src/api.ts
|
|
9
10
|
var BASE_URL = "https://api.clickup.com/api/v2";
|
|
10
11
|
var BASE_URL_V3 = "https://api.clickup.com/api/v3";
|
|
11
12
|
var MAX_PAGES = 100;
|
|
13
|
+
function isRecord(value) {
|
|
14
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15
|
+
}
|
|
16
|
+
function expectRecord(value, context) {
|
|
17
|
+
if (!isRecord(value)) {
|
|
18
|
+
throw new Error(`Unexpected API response: expected ${context} object`);
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
function expectRecordField(data, key, context) {
|
|
23
|
+
return expectRecord(data[key], context);
|
|
24
|
+
}
|
|
25
|
+
function expectNumericField(data, key, context) {
|
|
26
|
+
const value = Number(data[key]);
|
|
27
|
+
if (!Number.isInteger(value)) {
|
|
28
|
+
throw new Error(`Unexpected API response: expected ${context}.${key} to be numeric`);
|
|
29
|
+
}
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
function expectStringField(data, key, context) {
|
|
33
|
+
const value = data[key];
|
|
34
|
+
if (typeof value !== "string") {
|
|
35
|
+
throw new Error(`Unexpected API response: expected ${context}.${key} to be a string`);
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
function expectArrayField(data, key, context) {
|
|
40
|
+
const value = data[key];
|
|
41
|
+
if (!Array.isArray(value)) {
|
|
42
|
+
throw new Error(`Unexpected API response: expected ${context}.${key} to be an array`);
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
function readCollectionField(data, key, context) {
|
|
47
|
+
if (data[key] === void 0) return [];
|
|
48
|
+
return expectArrayField(data, key, context);
|
|
49
|
+
}
|
|
50
|
+
function expectBooleanField(data, key, context) {
|
|
51
|
+
const value = data[key];
|
|
52
|
+
if (typeof value !== "boolean") {
|
|
53
|
+
throw new Error(`Unexpected API response: expected ${context}.${key} to be a boolean`);
|
|
54
|
+
}
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
function expectPaginatedCollectionField(data, key, context) {
|
|
58
|
+
const items = data[key];
|
|
59
|
+
if (!Array.isArray(items)) {
|
|
60
|
+
throw new Error(`Unexpected API response: expected ${key} array`);
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
items,
|
|
64
|
+
lastPage: expectBooleanField(data, "last_page", context)
|
|
65
|
+
};
|
|
66
|
+
}
|
|
12
67
|
function isCustomTaskId(id) {
|
|
13
68
|
return /^[A-Z]+-\d+$/i.test(id);
|
|
14
69
|
}
|
|
@@ -34,8 +89,8 @@ var ClickUpClient = class {
|
|
|
34
89
|
}
|
|
35
90
|
return "";
|
|
36
91
|
}
|
|
37
|
-
async
|
|
38
|
-
const res = await fetch(`${
|
|
92
|
+
async _fetch(baseUrl, path, options = {}) {
|
|
93
|
+
const res = await fetch(`${baseUrl}${path}`, {
|
|
39
94
|
...options,
|
|
40
95
|
signal: AbortSignal.timeout(3e4),
|
|
41
96
|
headers: {
|
|
@@ -44,12 +99,13 @@ var ClickUpClient = class {
|
|
|
44
99
|
...options.headers
|
|
45
100
|
}
|
|
46
101
|
});
|
|
47
|
-
let
|
|
102
|
+
let parsed;
|
|
48
103
|
try {
|
|
49
|
-
|
|
104
|
+
parsed = await res.json();
|
|
50
105
|
} catch {
|
|
51
106
|
throw new Error(`ClickUp API error ${res.status}: response was not valid JSON`);
|
|
52
107
|
}
|
|
108
|
+
const data = expectRecord(parsed, "JSON");
|
|
53
109
|
if (!res.ok) {
|
|
54
110
|
const raw = data.err ?? data.error ?? data.ECODE ?? res.statusText;
|
|
55
111
|
const errMsg = typeof raw === "string" ? raw : JSON.stringify(raw);
|
|
@@ -57,34 +113,21 @@ var ClickUpClient = class {
|
|
|
57
113
|
}
|
|
58
114
|
return data;
|
|
59
115
|
}
|
|
116
|
+
async request(path, options = {}) {
|
|
117
|
+
return this._fetch(BASE_URL, path, options);
|
|
118
|
+
}
|
|
60
119
|
async requestV3(path, options = {}) {
|
|
61
|
-
|
|
62
|
-
...options,
|
|
63
|
-
signal: AbortSignal.timeout(3e4),
|
|
64
|
-
headers: {
|
|
65
|
-
Authorization: this.apiToken,
|
|
66
|
-
...options.body ? { "Content-Type": "application/json" } : {},
|
|
67
|
-
...options.headers
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
let data;
|
|
71
|
-
try {
|
|
72
|
-
data = await res.json();
|
|
73
|
-
} catch {
|
|
74
|
-
throw new Error(`ClickUp API error ${res.status}: response was not valid JSON`);
|
|
75
|
-
}
|
|
76
|
-
if (!res.ok) {
|
|
77
|
-
const raw = data.err ?? data.error ?? data.ECODE ?? res.statusText;
|
|
78
|
-
const msg = typeof raw === "string" ? raw : JSON.stringify(raw);
|
|
79
|
-
throw new Error(`ClickUp API error ${res.status}: ${msg}`);
|
|
80
|
-
}
|
|
81
|
-
return data;
|
|
120
|
+
return this._fetch(BASE_URL_V3, path, options);
|
|
82
121
|
}
|
|
83
122
|
async getMe() {
|
|
84
123
|
if (this.meCache) return this.meCache;
|
|
85
124
|
const data = await this.request("/user");
|
|
86
|
-
|
|
87
|
-
|
|
125
|
+
const user = expectRecordField(data, "user", "user");
|
|
126
|
+
this.meCache = {
|
|
127
|
+
id: expectNumericField(user, "id", "user"),
|
|
128
|
+
username: expectStringField(user, "username", "user")
|
|
129
|
+
};
|
|
130
|
+
return this.meCache;
|
|
88
131
|
}
|
|
89
132
|
async paginate(buildPath) {
|
|
90
133
|
const allTasks = [];
|
|
@@ -92,12 +135,13 @@ var ClickUpClient = class {
|
|
|
92
135
|
let lastPage = false;
|
|
93
136
|
while (!lastPage && page < MAX_PAGES) {
|
|
94
137
|
const data = await this.request(buildPath(page));
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
138
|
+
const taskPage = expectPaginatedCollectionField(
|
|
139
|
+
data,
|
|
140
|
+
"tasks",
|
|
141
|
+
"task page"
|
|
142
|
+
);
|
|
143
|
+
allTasks.push(...taskPage.items);
|
|
144
|
+
lastPage = taskPage.lastPage;
|
|
101
145
|
page++;
|
|
102
146
|
}
|
|
103
147
|
if (page >= MAX_PAGES && !lastPage) {
|
|
@@ -140,7 +184,11 @@ var ClickUpClient = class {
|
|
|
140
184
|
}
|
|
141
185
|
async getTaskComments(taskId) {
|
|
142
186
|
const data = await this.request(this.taskPath(taskId, "/comment"));
|
|
143
|
-
return
|
|
187
|
+
return readCollectionField(
|
|
188
|
+
data,
|
|
189
|
+
"comments",
|
|
190
|
+
"task comments"
|
|
191
|
+
);
|
|
144
192
|
}
|
|
145
193
|
async getTasksFromList(listId, params = {}, options = {}) {
|
|
146
194
|
return this.paginate((page) => {
|
|
@@ -161,7 +209,7 @@ var ClickUpClient = class {
|
|
|
161
209
|
}
|
|
162
210
|
async getTeams() {
|
|
163
211
|
const data = await this.request("/team");
|
|
164
|
-
return data
|
|
212
|
+
return readCollectionField(data, "teams", "teams");
|
|
165
213
|
}
|
|
166
214
|
async getSpaceWithStatuses(spaceId) {
|
|
167
215
|
return this.request(`/space/${spaceId}`);
|
|
@@ -171,27 +219,31 @@ var ClickUpClient = class {
|
|
|
171
219
|
}
|
|
172
220
|
async getSpaces(teamId) {
|
|
173
221
|
const data = await this.request(`/team/${teamId}/space?archived=false`);
|
|
174
|
-
return data
|
|
222
|
+
return readCollectionField(data, "spaces", "spaces");
|
|
175
223
|
}
|
|
176
224
|
async getCustomTaskTypes(teamId) {
|
|
177
225
|
const data = await this.request(
|
|
178
226
|
`/team/${teamId}/custom_item`
|
|
179
227
|
);
|
|
180
|
-
return
|
|
228
|
+
return readCollectionField(
|
|
229
|
+
data,
|
|
230
|
+
"custom_items",
|
|
231
|
+
"custom task types"
|
|
232
|
+
);
|
|
181
233
|
}
|
|
182
234
|
async getLists(spaceId) {
|
|
183
235
|
const data = await this.request(`/space/${spaceId}/list?archived=false`);
|
|
184
|
-
return data
|
|
236
|
+
return readCollectionField(data, "lists", "space lists");
|
|
185
237
|
}
|
|
186
238
|
async getFolders(spaceId) {
|
|
187
239
|
const data = await this.request(
|
|
188
240
|
`/space/${spaceId}/folder?archived=false`
|
|
189
241
|
);
|
|
190
|
-
return data
|
|
242
|
+
return readCollectionField(data, "folders", "space folders");
|
|
191
243
|
}
|
|
192
244
|
async getFolderLists(folderId) {
|
|
193
245
|
const data = await this.request(`/folder/${folderId}/list?archived=false`);
|
|
194
|
-
return data
|
|
246
|
+
return readCollectionField(data, "lists", "folder lists");
|
|
195
247
|
}
|
|
196
248
|
async getListViews(listId) {
|
|
197
249
|
return this.request(
|
|
@@ -259,7 +311,11 @@ var ClickUpClient = class {
|
|
|
259
311
|
}
|
|
260
312
|
async getThreadedComments(commentId) {
|
|
261
313
|
const data = await this.request(`/comment/${commentId}/reply`);
|
|
262
|
-
return
|
|
314
|
+
return readCollectionField(
|
|
315
|
+
data,
|
|
316
|
+
"comments",
|
|
317
|
+
"threaded comments"
|
|
318
|
+
);
|
|
263
319
|
}
|
|
264
320
|
async createThreadedComment(commentId, text, notifyAll) {
|
|
265
321
|
const body = { comment_text: text };
|
|
@@ -281,14 +337,22 @@ var ClickUpClient = class {
|
|
|
281
337
|
}
|
|
282
338
|
async getListCustomFields(listId) {
|
|
283
339
|
const data = await this.request(`/list/${listId}/field`);
|
|
284
|
-
return
|
|
340
|
+
return readCollectionField(
|
|
341
|
+
data,
|
|
342
|
+
"fields",
|
|
343
|
+
"list custom fields"
|
|
344
|
+
);
|
|
285
345
|
}
|
|
286
346
|
async createChecklist(taskId, name) {
|
|
287
347
|
const data = await this.request(this.taskPath(taskId, "/checklist"), {
|
|
288
348
|
method: "POST",
|
|
289
349
|
body: JSON.stringify({ name })
|
|
290
350
|
});
|
|
291
|
-
return
|
|
351
|
+
return expectRecordField(
|
|
352
|
+
data,
|
|
353
|
+
"checklist",
|
|
354
|
+
"checklist"
|
|
355
|
+
);
|
|
292
356
|
}
|
|
293
357
|
async deleteChecklist(checklistId) {
|
|
294
358
|
await this.request(`/checklist/${checklistId}`, { method: "DELETE" });
|
|
@@ -298,14 +362,22 @@ var ClickUpClient = class {
|
|
|
298
362
|
`/checklist/${checklistId}/checklist_item`,
|
|
299
363
|
{ method: "POST", body: JSON.stringify({ name }) }
|
|
300
364
|
);
|
|
301
|
-
return
|
|
365
|
+
return expectRecordField(
|
|
366
|
+
data,
|
|
367
|
+
"checklist",
|
|
368
|
+
"checklist"
|
|
369
|
+
);
|
|
302
370
|
}
|
|
303
371
|
async editChecklistItem(checklistId, checklistItemId, updates) {
|
|
304
372
|
const data = await this.request(
|
|
305
373
|
`/checklist/${checklistId}/checklist_item/${checklistItemId}`,
|
|
306
374
|
{ method: "PUT", body: JSON.stringify(updates) }
|
|
307
375
|
);
|
|
308
|
-
return
|
|
376
|
+
return expectRecordField(
|
|
377
|
+
data,
|
|
378
|
+
"checklist",
|
|
379
|
+
"checklist"
|
|
380
|
+
);
|
|
309
381
|
}
|
|
310
382
|
async deleteChecklistItem(checklistId, checklistItemId) {
|
|
311
383
|
await this.request(
|
|
@@ -365,7 +437,11 @@ var ClickUpClient = class {
|
|
|
365
437
|
const query = params.toString();
|
|
366
438
|
const url = `/team/${teamId}/time_entries${query ? `?${query}` : ""}`;
|
|
367
439
|
const data = await this.request(url);
|
|
368
|
-
const entries =
|
|
440
|
+
const entries = readCollectionField(
|
|
441
|
+
data,
|
|
442
|
+
"data",
|
|
443
|
+
"time entries"
|
|
444
|
+
);
|
|
369
445
|
if (opts?.taskId) {
|
|
370
446
|
return entries.filter((e) => e.task?.id === opts.taskId);
|
|
371
447
|
}
|
|
@@ -380,7 +456,7 @@ var ClickUpClient = class {
|
|
|
380
456
|
}
|
|
381
457
|
async getSpaceTags(spaceId) {
|
|
382
458
|
const data = await this.request(`/space/${spaceId}/tag`);
|
|
383
|
-
return data
|
|
459
|
+
return readCollectionField(data, "tags", "space tags");
|
|
384
460
|
}
|
|
385
461
|
async createSpaceTag(spaceId, name, fg, bg) {
|
|
386
462
|
await this.request(`/space/${spaceId}/tag`, {
|
|
@@ -398,7 +474,11 @@ var ClickUpClient = class {
|
|
|
398
474
|
}
|
|
399
475
|
async getWorkspaceMembers(teamId) {
|
|
400
476
|
const data = await this.request("/team");
|
|
401
|
-
const team =
|
|
477
|
+
const team = readCollectionField(
|
|
478
|
+
data,
|
|
479
|
+
"teams",
|
|
480
|
+
"workspace members"
|
|
481
|
+
).find((t) => t.id === teamId);
|
|
402
482
|
return team?.members?.map((m) => m.user) ?? [];
|
|
403
483
|
}
|
|
404
484
|
async deleteTimeEntry(teamId, timeEntryId) {
|
|
@@ -439,7 +519,7 @@ var ClickUpClient = class {
|
|
|
439
519
|
}
|
|
440
520
|
async getDocs(workspaceId) {
|
|
441
521
|
const data = await this.requestV3(`/workspaces/${workspaceId}/docs`);
|
|
442
|
-
return data
|
|
522
|
+
return readCollectionField(data, "docs", "docs");
|
|
443
523
|
}
|
|
444
524
|
async getDocPage(workspaceId, docId, pageId) {
|
|
445
525
|
return this.requestV3(
|
|
@@ -480,17 +560,21 @@ var ClickUpClient = class {
|
|
|
480
560
|
const data = await this.requestV3(
|
|
481
561
|
`/workspaces/${workspaceId}/docs/${docId}/pagelisting`
|
|
482
562
|
);
|
|
483
|
-
return
|
|
563
|
+
return readCollectionField(
|
|
564
|
+
data,
|
|
565
|
+
"pages",
|
|
566
|
+
"doc page listing"
|
|
567
|
+
);
|
|
484
568
|
}
|
|
485
569
|
async getDocPages(workspaceId, docId) {
|
|
486
570
|
const data = await this.requestV3(
|
|
487
571
|
`/workspaces/${workspaceId}/docs/${docId}/pages?content_format=text/md`
|
|
488
572
|
);
|
|
489
|
-
return data
|
|
573
|
+
return readCollectionField(data, "pages", "doc pages");
|
|
490
574
|
}
|
|
491
575
|
async getGoals(teamId) {
|
|
492
576
|
const data = await this.request(`/team/${teamId}/goal`);
|
|
493
|
-
return data
|
|
577
|
+
return readCollectionField(data, "goals", "goals");
|
|
494
578
|
}
|
|
495
579
|
async createGoal(teamId, name, opts) {
|
|
496
580
|
const body = { name, multiple_owners: true };
|
|
@@ -534,12 +618,104 @@ var ClickUpClient = class {
|
|
|
534
618
|
});
|
|
535
619
|
return data.key_result;
|
|
536
620
|
}
|
|
621
|
+
async deleteGoal(goalId) {
|
|
622
|
+
await this.request(`/goal/${goalId}`, { method: "DELETE" });
|
|
623
|
+
}
|
|
624
|
+
async deleteKeyResult(keyResultId) {
|
|
625
|
+
await this.request(`/key_result/${keyResultId}`, { method: "DELETE" });
|
|
626
|
+
}
|
|
627
|
+
async deleteDoc(workspaceId, docId) {
|
|
628
|
+
await this.requestV3(`/workspaces/${workspaceId}/docs/${docId}`, {
|
|
629
|
+
method: "DELETE"
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
async deleteDocPage(workspaceId, docId, pageId) {
|
|
633
|
+
await this.requestV3(
|
|
634
|
+
`/workspaces/${workspaceId}/docs/${docId}/pages/${pageId}`,
|
|
635
|
+
{ method: "DELETE" }
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
async updateSpaceTag(spaceId, tagName, updates) {
|
|
639
|
+
await this.request(
|
|
640
|
+
`/space/${spaceId}/tag/${encodeURIComponent(tagName)}`,
|
|
641
|
+
{
|
|
642
|
+
method: "PUT",
|
|
643
|
+
body: JSON.stringify({
|
|
644
|
+
tag: {
|
|
645
|
+
name: updates.name,
|
|
646
|
+
tag_fg: updates.tag_fg ?? "#000000",
|
|
647
|
+
tag_bg: updates.tag_bg ?? "#04A9F4"
|
|
648
|
+
}
|
|
649
|
+
})
|
|
650
|
+
}
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
async getTaskTemplates(teamId) {
|
|
654
|
+
const data = await this.request(
|
|
655
|
+
`/team/${teamId}/taskTemplate?page=0`
|
|
656
|
+
);
|
|
657
|
+
return readCollectionField(
|
|
658
|
+
data,
|
|
659
|
+
"templates",
|
|
660
|
+
"task templates"
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
async createTaskFromTemplate(listId, templateId, name) {
|
|
664
|
+
return this.request(`/list/${listId}/taskTemplate/${templateId}`, {
|
|
665
|
+
method: "POST",
|
|
666
|
+
body: JSON.stringify({ name })
|
|
667
|
+
});
|
|
668
|
+
}
|
|
537
669
|
};
|
|
538
670
|
|
|
539
671
|
// src/config.ts
|
|
540
672
|
import fs from "fs";
|
|
541
673
|
import { homedir } from "os";
|
|
542
674
|
import { join } from "path";
|
|
675
|
+
function isRecord2(value) {
|
|
676
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
677
|
+
}
|
|
678
|
+
function readConfigString(parsed, key, path, strict) {
|
|
679
|
+
const value = parsed[key];
|
|
680
|
+
if (value === void 0) return void 0;
|
|
681
|
+
if (typeof value !== "string") {
|
|
682
|
+
if (strict) {
|
|
683
|
+
throw new Error(`Config field ${key} must be a string in ${path}.`);
|
|
684
|
+
}
|
|
685
|
+
return void 0;
|
|
686
|
+
}
|
|
687
|
+
const trimmed = value.trim();
|
|
688
|
+
return trimmed || void 0;
|
|
689
|
+
}
|
|
690
|
+
function parseConfigFile(raw, path, strictFields, strictRoot = strictFields) {
|
|
691
|
+
let parsed;
|
|
692
|
+
try {
|
|
693
|
+
parsed = JSON.parse(raw);
|
|
694
|
+
} catch {
|
|
695
|
+
if (strictRoot) {
|
|
696
|
+
throw new Error(`Config file at ${path} contains invalid JSON. Please check the file syntax.`);
|
|
697
|
+
}
|
|
698
|
+
return {};
|
|
699
|
+
}
|
|
700
|
+
if (!isRecord2(parsed)) {
|
|
701
|
+
if (strictRoot) {
|
|
702
|
+
throw new Error(`Config file at ${path} must contain a JSON object.`);
|
|
703
|
+
}
|
|
704
|
+
return {};
|
|
705
|
+
}
|
|
706
|
+
const apiToken = readConfigString(parsed, "apiToken", path, strictFields);
|
|
707
|
+
const teamId = readConfigString(parsed, "teamId", path, strictFields);
|
|
708
|
+
const sprintFolderId = readConfigString(parsed, "sprintFolderId", path, strictFields);
|
|
709
|
+
return {
|
|
710
|
+
...apiToken ? { apiToken } : {},
|
|
711
|
+
...teamId ? { teamId } : {},
|
|
712
|
+
...sprintFolderId ? { sprintFolderId } : {}
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
function trimConfigValue(value) {
|
|
716
|
+
const trimmed = value?.trim();
|
|
717
|
+
return trimmed || void 0;
|
|
718
|
+
}
|
|
543
719
|
function configDir() {
|
|
544
720
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
545
721
|
if (xdg) return join(xdg, "cup");
|
|
@@ -574,15 +750,10 @@ function loadConfig() {
|
|
|
574
750
|
const path = configPath();
|
|
575
751
|
if (fs.existsSync(path)) {
|
|
576
752
|
const raw = fs.readFileSync(path, "utf-8");
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
throw new Error(`Config file at ${path} contains invalid JSON. Please check the file syntax.`);
|
|
582
|
-
}
|
|
583
|
-
fileToken = parsed.apiToken?.trim();
|
|
584
|
-
fileTeamId = parsed.teamId?.trim();
|
|
585
|
-
fileSprintFolderId = parsed.sprintFolderId?.trim() || void 0;
|
|
753
|
+
const parsed = parseConfigFile(raw, path, true);
|
|
754
|
+
fileToken = parsed.apiToken;
|
|
755
|
+
fileTeamId = parsed.teamId;
|
|
756
|
+
fileSprintFolderId = parsed.sprintFolderId;
|
|
586
757
|
}
|
|
587
758
|
const apiToken = envToken || fileToken;
|
|
588
759
|
if (!apiToken) {
|
|
@@ -601,11 +772,7 @@ function loadRawConfig() {
|
|
|
601
772
|
migrateFromLegacy();
|
|
602
773
|
const path = configPath();
|
|
603
774
|
if (!fs.existsSync(path)) return {};
|
|
604
|
-
|
|
605
|
-
return JSON.parse(fs.readFileSync(path, "utf-8"));
|
|
606
|
-
} catch {
|
|
607
|
-
return {};
|
|
608
|
-
}
|
|
775
|
+
return parseConfigFile(fs.readFileSync(path, "utf-8"), path, false, true);
|
|
609
776
|
}
|
|
610
777
|
function getConfigPath() {
|
|
611
778
|
migrateFromLegacy();
|
|
@@ -617,7 +784,15 @@ function writeConfig(config) {
|
|
|
617
784
|
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
618
785
|
}
|
|
619
786
|
const filePath = join(dir, "config.json");
|
|
620
|
-
|
|
787
|
+
const apiToken = trimConfigValue(config.apiToken) ?? "";
|
|
788
|
+
const teamId = trimConfigValue(config.teamId) ?? "";
|
|
789
|
+
const sprintFolderId = trimConfigValue(config.sprintFolderId);
|
|
790
|
+
const normalizedConfig = {
|
|
791
|
+
...apiToken ? { apiToken } : {},
|
|
792
|
+
...teamId ? { teamId } : {},
|
|
793
|
+
...sprintFolderId ? { sprintFolderId } : {}
|
|
794
|
+
};
|
|
795
|
+
fs.writeFileSync(filePath, JSON.stringify(normalizedConfig, null, 2) + "\n", {
|
|
621
796
|
encoding: "utf-8",
|
|
622
797
|
mode: 384
|
|
623
798
|
});
|
|
@@ -1268,6 +1443,10 @@ async function createTask(config, options) {
|
|
|
1268
1443
|
if (!listId) {
|
|
1269
1444
|
throw new Error("Provide --list or --parent (list is auto-detected from parent task)");
|
|
1270
1445
|
}
|
|
1446
|
+
if (options.template) {
|
|
1447
|
+
const task2 = await client.createTaskFromTemplate(listId, options.template, options.name);
|
|
1448
|
+
return { id: task2.id, name: task2.name, url: task2.url };
|
|
1449
|
+
}
|
|
1271
1450
|
const payload = {
|
|
1272
1451
|
name: options.name,
|
|
1273
1452
|
...options.description !== void 0 ? { markdown_content: options.description } : {},
|
|
@@ -2065,6 +2244,11 @@ async function fetchOverdueTasks(config, opts = {}) {
|
|
|
2065
2244
|
|
|
2066
2245
|
// src/commands/config.ts
|
|
2067
2246
|
var VALID_KEYS = /* @__PURE__ */ new Set(["apiToken", "teamId", "sprintFolderId"]);
|
|
2247
|
+
function readStoredString(value) {
|
|
2248
|
+
if (typeof value !== "string") return void 0;
|
|
2249
|
+
const trimmed = value.trim();
|
|
2250
|
+
return trimmed || void 0;
|
|
2251
|
+
}
|
|
2068
2252
|
function assertValidKey(key) {
|
|
2069
2253
|
if (!VALID_KEYS.has(key)) {
|
|
2070
2254
|
throw new Error(`Unknown config key: ${key}. Valid keys: ${[...VALID_KEYS].join(", ")}`);
|
|
@@ -2073,23 +2257,33 @@ function assertValidKey(key) {
|
|
|
2073
2257
|
function getConfigValue(key) {
|
|
2074
2258
|
assertValidKey(key);
|
|
2075
2259
|
const raw = loadRawConfig();
|
|
2076
|
-
|
|
2077
|
-
return value || void 0;
|
|
2260
|
+
return readStoredString(raw[key]);
|
|
2078
2261
|
}
|
|
2079
2262
|
function setConfigValue(key, value) {
|
|
2080
2263
|
assertValidKey(key);
|
|
2081
|
-
|
|
2264
|
+
const normalizedValue = readStoredString(value);
|
|
2265
|
+
if (key === "apiToken" && (!normalizedValue || !normalizedValue.startsWith("pk_"))) {
|
|
2082
2266
|
throw new Error("apiToken must start with pk_");
|
|
2083
2267
|
}
|
|
2084
|
-
if (key === "teamId" &&
|
|
2268
|
+
if (key === "teamId" && !normalizedValue) {
|
|
2085
2269
|
throw new Error("teamId must be non-empty");
|
|
2086
2270
|
}
|
|
2087
2271
|
const raw = loadRawConfig();
|
|
2272
|
+
const sprintFolderId = readStoredString(raw.sprintFolderId);
|
|
2088
2273
|
const merged = {
|
|
2089
|
-
apiToken: raw.apiToken
|
|
2090
|
-
teamId: raw.teamId
|
|
2091
|
-
...{
|
|
2274
|
+
...readStoredString(raw.apiToken) ? { apiToken: readStoredString(raw.apiToken) } : {},
|
|
2275
|
+
...readStoredString(raw.teamId) ? { teamId: readStoredString(raw.teamId) } : {},
|
|
2276
|
+
...sprintFolderId ? { sprintFolderId } : {}
|
|
2092
2277
|
};
|
|
2278
|
+
if (key === "sprintFolderId") {
|
|
2279
|
+
if (normalizedValue) {
|
|
2280
|
+
merged.sprintFolderId = normalizedValue;
|
|
2281
|
+
} else {
|
|
2282
|
+
delete merged.sprintFolderId;
|
|
2283
|
+
}
|
|
2284
|
+
} else {
|
|
2285
|
+
merged[key] = normalizedValue;
|
|
2286
|
+
}
|
|
2093
2287
|
writeConfig(merged);
|
|
2094
2288
|
}
|
|
2095
2289
|
function configPath2() {
|
|
@@ -2168,7 +2362,702 @@ ${commentsMd}`);
|
|
|
2168
2362
|
}
|
|
2169
2363
|
}
|
|
2170
2364
|
|
|
2365
|
+
// src/commands/metadata.ts
|
|
2366
|
+
var commandMetadata = [
|
|
2367
|
+
{
|
|
2368
|
+
name: "init",
|
|
2369
|
+
description: "Set up cup for the first time",
|
|
2370
|
+
quickReference: [{ section: "setup", usage: "init", description: "First-time setup wizard" }]
|
|
2371
|
+
},
|
|
2372
|
+
{
|
|
2373
|
+
name: "auth",
|
|
2374
|
+
description: "Validate API token and show current user",
|
|
2375
|
+
flags: ["--json"],
|
|
2376
|
+
quickReference: [
|
|
2377
|
+
{ section: "read", usage: "auth", description: "Check authentication status" }
|
|
2378
|
+
]
|
|
2379
|
+
},
|
|
2380
|
+
{
|
|
2381
|
+
name: "tasks",
|
|
2382
|
+
description: "List tasks assigned to me",
|
|
2383
|
+
flags: ["--status", "--list", "--space", "--name", "--type", "--include-closed", "--json"],
|
|
2384
|
+
quickReference: [{ section: "read", usage: "tasks", description: "List tasks assigned to me" }]
|
|
2385
|
+
},
|
|
2386
|
+
{
|
|
2387
|
+
name: "task",
|
|
2388
|
+
description: "Get task details",
|
|
2389
|
+
flags: ["--json"],
|
|
2390
|
+
quickReference: [{ section: "read", usage: "task <taskId>", description: "Get task details" }]
|
|
2391
|
+
},
|
|
2392
|
+
{
|
|
2393
|
+
name: "update",
|
|
2394
|
+
description: "Update a task",
|
|
2395
|
+
flags: [
|
|
2396
|
+
"-n",
|
|
2397
|
+
"--name",
|
|
2398
|
+
"-d",
|
|
2399
|
+
"--description",
|
|
2400
|
+
"-s",
|
|
2401
|
+
"--status",
|
|
2402
|
+
"--priority",
|
|
2403
|
+
"--due-date",
|
|
2404
|
+
"--time-estimate",
|
|
2405
|
+
"--assignee",
|
|
2406
|
+
"--parent",
|
|
2407
|
+
"--json"
|
|
2408
|
+
],
|
|
2409
|
+
quickReference: [{ section: "write", usage: "update <taskId>", description: "Update a task" }]
|
|
2410
|
+
},
|
|
2411
|
+
{
|
|
2412
|
+
name: "create",
|
|
2413
|
+
description: "Create a new task",
|
|
2414
|
+
flags: [
|
|
2415
|
+
"-l",
|
|
2416
|
+
"--list",
|
|
2417
|
+
"-n",
|
|
2418
|
+
"--name",
|
|
2419
|
+
"-d",
|
|
2420
|
+
"--description",
|
|
2421
|
+
"-p",
|
|
2422
|
+
"--parent",
|
|
2423
|
+
"-s",
|
|
2424
|
+
"--status",
|
|
2425
|
+
"--priority",
|
|
2426
|
+
"--due-date",
|
|
2427
|
+
"--assignee",
|
|
2428
|
+
"--tags",
|
|
2429
|
+
"--custom-item-id",
|
|
2430
|
+
"--time-estimate",
|
|
2431
|
+
"--template",
|
|
2432
|
+
"--json"
|
|
2433
|
+
],
|
|
2434
|
+
quickReference: [{ section: "write", usage: "create", description: "Create a new task" }]
|
|
2435
|
+
},
|
|
2436
|
+
{
|
|
2437
|
+
name: "sprint",
|
|
2438
|
+
description: "List my tasks in the current active sprint (auto-detected)",
|
|
2439
|
+
flags: ["--status", "--space", "--folder", "--include-closed", "--json"],
|
|
2440
|
+
quickReference: [
|
|
2441
|
+
{ section: "read", usage: "sprint", description: "My tasks in the active sprint" }
|
|
2442
|
+
]
|
|
2443
|
+
},
|
|
2444
|
+
{
|
|
2445
|
+
name: "sprints",
|
|
2446
|
+
description: "List all sprints in sprint folders",
|
|
2447
|
+
flags: ["--space", "--json"],
|
|
2448
|
+
quickReference: [
|
|
2449
|
+
{ section: "read", usage: "sprints", description: "List all sprints across folders" }
|
|
2450
|
+
]
|
|
2451
|
+
},
|
|
2452
|
+
{
|
|
2453
|
+
name: "subtasks",
|
|
2454
|
+
description: "List subtasks of a task or initiative",
|
|
2455
|
+
flags: ["--status", "--name", "--include-closed", "--json"],
|
|
2456
|
+
quickReference: [
|
|
2457
|
+
{ section: "read", usage: "subtasks <taskId>", description: "List subtasks of a task" }
|
|
2458
|
+
]
|
|
2459
|
+
},
|
|
2460
|
+
{
|
|
2461
|
+
name: "comment",
|
|
2462
|
+
description: "Post a comment on a task",
|
|
2463
|
+
flags: ["-m", "--message", "--notify-all", "--json"],
|
|
2464
|
+
quickReference: [
|
|
2465
|
+
{ section: "write", usage: "comment <taskId>", description: "Post a comment on a task" }
|
|
2466
|
+
]
|
|
2467
|
+
},
|
|
2468
|
+
{
|
|
2469
|
+
name: "comment-edit",
|
|
2470
|
+
description: "Edit an existing comment",
|
|
2471
|
+
flags: ["-m", "--message", "--resolved", "--unresolved", "--json"],
|
|
2472
|
+
quickReference: [
|
|
2473
|
+
{
|
|
2474
|
+
section: "write",
|
|
2475
|
+
usage: "comment-edit <commentId>",
|
|
2476
|
+
description: "Edit an existing comment"
|
|
2477
|
+
}
|
|
2478
|
+
]
|
|
2479
|
+
},
|
|
2480
|
+
{
|
|
2481
|
+
name: "comment-delete",
|
|
2482
|
+
description: "Delete a comment",
|
|
2483
|
+
flags: ["--json"],
|
|
2484
|
+
quickReference: [
|
|
2485
|
+
{
|
|
2486
|
+
section: "write",
|
|
2487
|
+
usage: "comment-delete <commentId>",
|
|
2488
|
+
description: "Delete a comment"
|
|
2489
|
+
}
|
|
2490
|
+
]
|
|
2491
|
+
},
|
|
2492
|
+
{
|
|
2493
|
+
name: "comments",
|
|
2494
|
+
description: "List comments on a task",
|
|
2495
|
+
flags: ["--json"],
|
|
2496
|
+
quickReference: [
|
|
2497
|
+
{ section: "read", usage: "comments <taskId>", description: "List comments on a task" }
|
|
2498
|
+
]
|
|
2499
|
+
},
|
|
2500
|
+
{
|
|
2501
|
+
name: "replies",
|
|
2502
|
+
description: "List threaded replies on a comment",
|
|
2503
|
+
flags: ["--json"],
|
|
2504
|
+
quickReference: [
|
|
2505
|
+
{
|
|
2506
|
+
section: "read",
|
|
2507
|
+
usage: "replies <commentId>",
|
|
2508
|
+
description: "List threaded replies on a comment"
|
|
2509
|
+
}
|
|
2510
|
+
]
|
|
2511
|
+
},
|
|
2512
|
+
{
|
|
2513
|
+
name: "reply",
|
|
2514
|
+
description: "Reply to a comment",
|
|
2515
|
+
flags: ["-m", "--message", "--notify-all", "--json"],
|
|
2516
|
+
quickReference: [
|
|
2517
|
+
{ section: "write", usage: "reply <commentId>", description: "Reply to a comment" }
|
|
2518
|
+
]
|
|
2519
|
+
},
|
|
2520
|
+
{
|
|
2521
|
+
name: "activity",
|
|
2522
|
+
description: "Show task details and comments combined",
|
|
2523
|
+
flags: ["--json"],
|
|
2524
|
+
quickReference: [
|
|
2525
|
+
{
|
|
2526
|
+
section: "read",
|
|
2527
|
+
usage: "activity <taskId>",
|
|
2528
|
+
description: "Task details + comment history"
|
|
2529
|
+
}
|
|
2530
|
+
]
|
|
2531
|
+
},
|
|
2532
|
+
{
|
|
2533
|
+
name: "lists",
|
|
2534
|
+
description: "List all lists in a space (including lists inside folders)",
|
|
2535
|
+
flags: ["--name", "--json"],
|
|
2536
|
+
quickReference: [
|
|
2537
|
+
{ section: "read", usage: "lists <spaceId>", description: "List all lists in a space" }
|
|
2538
|
+
]
|
|
2539
|
+
},
|
|
2540
|
+
{
|
|
2541
|
+
name: "spaces",
|
|
2542
|
+
description: "List spaces in your workspace",
|
|
2543
|
+
flags: ["--name", "--my", "--json"],
|
|
2544
|
+
quickReference: [{ section: "read", usage: "spaces", description: "List spaces in workspace" }]
|
|
2545
|
+
},
|
|
2546
|
+
{
|
|
2547
|
+
name: "inbox",
|
|
2548
|
+
description: "Recently updated tasks grouped by time period",
|
|
2549
|
+
flags: ["--include-closed", "--json", "--days"],
|
|
2550
|
+
quickReference: [
|
|
2551
|
+
{
|
|
2552
|
+
section: "read",
|
|
2553
|
+
usage: "inbox",
|
|
2554
|
+
description: "Recently updated tasks assigned to me"
|
|
2555
|
+
}
|
|
2556
|
+
]
|
|
2557
|
+
},
|
|
2558
|
+
{
|
|
2559
|
+
name: "assigned",
|
|
2560
|
+
description: "Show all tasks assigned to me, grouped by status",
|
|
2561
|
+
flags: ["--status", "--include-closed", "--json"],
|
|
2562
|
+
quickReference: [
|
|
2563
|
+
{ section: "read", usage: "assigned", description: "My tasks grouped by pipeline stage" }
|
|
2564
|
+
]
|
|
2565
|
+
},
|
|
2566
|
+
{
|
|
2567
|
+
name: "open",
|
|
2568
|
+
description: "Open a task in the browser by ID or name",
|
|
2569
|
+
flags: ["--json"],
|
|
2570
|
+
quickReference: [
|
|
2571
|
+
{ section: "read", usage: "open <query>", description: "Open a task in the browser" }
|
|
2572
|
+
]
|
|
2573
|
+
},
|
|
2574
|
+
{
|
|
2575
|
+
name: "search",
|
|
2576
|
+
description: "Search my tasks by name",
|
|
2577
|
+
flags: ["--status", "--include-closed", "--json"],
|
|
2578
|
+
quickReference: [
|
|
2579
|
+
{ section: "read", usage: "search <query>", description: "Search my tasks by name" }
|
|
2580
|
+
]
|
|
2581
|
+
},
|
|
2582
|
+
{
|
|
2583
|
+
name: "summary",
|
|
2584
|
+
description: "Daily standup summary: completed, in-progress, overdue",
|
|
2585
|
+
flags: ["--hours", "--json"],
|
|
2586
|
+
quickReference: [{ section: "read", usage: "summary", description: "Daily standup helper" }]
|
|
2587
|
+
},
|
|
2588
|
+
{
|
|
2589
|
+
name: "overdue",
|
|
2590
|
+
description: "List tasks that are past their due date",
|
|
2591
|
+
flags: ["--include-closed", "--json"],
|
|
2592
|
+
quickReference: [
|
|
2593
|
+
{ section: "read", usage: "overdue", description: "Tasks past their due date" }
|
|
2594
|
+
]
|
|
2595
|
+
},
|
|
2596
|
+
{
|
|
2597
|
+
name: "assign",
|
|
2598
|
+
description: "Assign or unassign users from a task",
|
|
2599
|
+
flags: ["--to", "--remove", "--json"],
|
|
2600
|
+
quickReference: [
|
|
2601
|
+
{ section: "write", usage: "assign <taskId>", description: "Assign or unassign users" }
|
|
2602
|
+
]
|
|
2603
|
+
},
|
|
2604
|
+
{
|
|
2605
|
+
name: "depend",
|
|
2606
|
+
description: "Add or remove task dependencies",
|
|
2607
|
+
flags: ["--on", "--blocks", "--remove", "--json"],
|
|
2608
|
+
quickReference: [
|
|
2609
|
+
{
|
|
2610
|
+
section: "write",
|
|
2611
|
+
usage: "depend <taskId>",
|
|
2612
|
+
description: "Add or remove task dependencies"
|
|
2613
|
+
}
|
|
2614
|
+
]
|
|
2615
|
+
},
|
|
2616
|
+
{
|
|
2617
|
+
name: "link",
|
|
2618
|
+
description: "Add or remove a link between two tasks",
|
|
2619
|
+
flags: ["--remove", "--json"],
|
|
2620
|
+
quickReference: [
|
|
2621
|
+
{
|
|
2622
|
+
section: "write",
|
|
2623
|
+
usage: "link <taskId> <linksTo>",
|
|
2624
|
+
description: "Add or remove a link between tasks"
|
|
2625
|
+
}
|
|
2626
|
+
]
|
|
2627
|
+
},
|
|
2628
|
+
{
|
|
2629
|
+
name: "attach",
|
|
2630
|
+
description: "Upload a file attachment to a task",
|
|
2631
|
+
flags: ["--json"],
|
|
2632
|
+
bashFileCompletion: true,
|
|
2633
|
+
quickReference: [
|
|
2634
|
+
{
|
|
2635
|
+
section: "write",
|
|
2636
|
+
usage: "attach <taskId> <filePath>",
|
|
2637
|
+
description: "Upload a file attachment to a task"
|
|
2638
|
+
}
|
|
2639
|
+
]
|
|
2640
|
+
},
|
|
2641
|
+
{
|
|
2642
|
+
name: "move",
|
|
2643
|
+
description: "Add or remove a task from a list",
|
|
2644
|
+
flags: ["--to", "--remove", "--json"],
|
|
2645
|
+
quickReference: [
|
|
2646
|
+
{ section: "write", usage: "move <taskId>", description: "Add or remove a task from a list" }
|
|
2647
|
+
]
|
|
2648
|
+
},
|
|
2649
|
+
{
|
|
2650
|
+
name: "field",
|
|
2651
|
+
description: "Set or remove a custom field value on a task",
|
|
2652
|
+
flags: ["--set", "--remove", "--json"],
|
|
2653
|
+
quickReference: [
|
|
2654
|
+
{
|
|
2655
|
+
section: "write",
|
|
2656
|
+
usage: "field <taskId>",
|
|
2657
|
+
description: "Set or remove custom field values"
|
|
2658
|
+
}
|
|
2659
|
+
]
|
|
2660
|
+
},
|
|
2661
|
+
{
|
|
2662
|
+
name: "delete",
|
|
2663
|
+
description: "Delete a task (requires confirmation)",
|
|
2664
|
+
flags: ["--confirm", "--json"],
|
|
2665
|
+
quickReference: [{ section: "write", usage: "delete <taskId>", description: "Delete a task" }]
|
|
2666
|
+
},
|
|
2667
|
+
{
|
|
2668
|
+
name: "tag",
|
|
2669
|
+
description: "Add or remove tags from a task",
|
|
2670
|
+
flags: ["--add", "--remove", "--json"],
|
|
2671
|
+
quickReference: [
|
|
2672
|
+
{ section: "write", usage: "tag <taskId>", description: "Add or remove tags on a task" }
|
|
2673
|
+
]
|
|
2674
|
+
},
|
|
2675
|
+
{
|
|
2676
|
+
name: "tags",
|
|
2677
|
+
description: "List tags in a space",
|
|
2678
|
+
flags: ["--json"],
|
|
2679
|
+
quickReference: [
|
|
2680
|
+
{ section: "read", usage: "tags <spaceId>", description: "List tags in a space" }
|
|
2681
|
+
]
|
|
2682
|
+
},
|
|
2683
|
+
{
|
|
2684
|
+
name: "tag-create",
|
|
2685
|
+
description: "Create a tag in a space",
|
|
2686
|
+
flags: ["--fg", "--bg", "--json"],
|
|
2687
|
+
quickReference: [
|
|
2688
|
+
{
|
|
2689
|
+
section: "write",
|
|
2690
|
+
usage: "tag-create <spaceId> <name>",
|
|
2691
|
+
description: "Create a tag in a space"
|
|
2692
|
+
}
|
|
2693
|
+
]
|
|
2694
|
+
},
|
|
2695
|
+
{
|
|
2696
|
+
name: "tag-delete",
|
|
2697
|
+
description: "Delete a tag from a space",
|
|
2698
|
+
flags: ["--json"],
|
|
2699
|
+
quickReference: [
|
|
2700
|
+
{
|
|
2701
|
+
section: "write",
|
|
2702
|
+
usage: "tag-delete <spaceId> <name>",
|
|
2703
|
+
description: "Delete a tag from a space"
|
|
2704
|
+
}
|
|
2705
|
+
]
|
|
2706
|
+
},
|
|
2707
|
+
{
|
|
2708
|
+
name: "tag-update",
|
|
2709
|
+
description: "Update a tag in a space",
|
|
2710
|
+
flags: ["--name", "--fg", "--bg", "--json"],
|
|
2711
|
+
quickReference: [
|
|
2712
|
+
{
|
|
2713
|
+
section: "write",
|
|
2714
|
+
usage: "tag-update <spaceId> <tagName>",
|
|
2715
|
+
description: "Update a tag in a space"
|
|
2716
|
+
}
|
|
2717
|
+
]
|
|
2718
|
+
},
|
|
2719
|
+
{
|
|
2720
|
+
name: "checklist",
|
|
2721
|
+
description: "Manage checklists on a task",
|
|
2722
|
+
quickReference: [
|
|
2723
|
+
{ section: "write", usage: "checklist", description: "Manage checklists on tasks" }
|
|
2724
|
+
]
|
|
2725
|
+
},
|
|
2726
|
+
{
|
|
2727
|
+
name: "time",
|
|
2728
|
+
description: "Track time on tasks",
|
|
2729
|
+
quickReference: [
|
|
2730
|
+
{
|
|
2731
|
+
section: "write",
|
|
2732
|
+
usage: "time start <taskId>",
|
|
2733
|
+
description: "Start tracking time on a task"
|
|
2734
|
+
},
|
|
2735
|
+
{ section: "write", usage: "time stop", description: "Stop the running timer" },
|
|
2736
|
+
{ section: "write", usage: "time status", description: "Show the currently running timer" },
|
|
2737
|
+
{
|
|
2738
|
+
section: "write",
|
|
2739
|
+
usage: "time log <taskId> <duration>",
|
|
2740
|
+
description: "Log a manual time entry"
|
|
2741
|
+
},
|
|
2742
|
+
{ section: "write", usage: "time list", description: "List recent time entries" },
|
|
2743
|
+
{ section: "write", usage: "time update <timeEntryId>", description: "Update a time entry" },
|
|
2744
|
+
{ section: "write", usage: "time delete <timeEntryId>", description: "Delete a time entry" }
|
|
2745
|
+
]
|
|
2746
|
+
},
|
|
2747
|
+
{
|
|
2748
|
+
name: "docs",
|
|
2749
|
+
description: "List workspace docs (optionally filter by name)",
|
|
2750
|
+
flags: ["--json"],
|
|
2751
|
+
quickReference: [
|
|
2752
|
+
{ section: "read", usage: "docs [query]", description: "List workspace docs" }
|
|
2753
|
+
]
|
|
2754
|
+
},
|
|
2755
|
+
{
|
|
2756
|
+
name: "doc",
|
|
2757
|
+
description: "View a doc (metadata + page tree) or a specific page",
|
|
2758
|
+
flags: ["--json"],
|
|
2759
|
+
quickReference: [
|
|
2760
|
+
{ section: "read", usage: "doc <docId> [pageId]", description: "View a doc or doc page" }
|
|
2761
|
+
]
|
|
2762
|
+
},
|
|
2763
|
+
{
|
|
2764
|
+
name: "doc-create",
|
|
2765
|
+
description: "Create a new doc",
|
|
2766
|
+
flags: ["-c", "--content", "--json"],
|
|
2767
|
+
quickReference: [
|
|
2768
|
+
{ section: "write", usage: "doc-create <title>", description: "Create a new doc" }
|
|
2769
|
+
]
|
|
2770
|
+
},
|
|
2771
|
+
{
|
|
2772
|
+
name: "doc-pages",
|
|
2773
|
+
description: "List all pages in a doc with content",
|
|
2774
|
+
flags: ["--json"],
|
|
2775
|
+
quickReference: [
|
|
2776
|
+
{
|
|
2777
|
+
section: "read",
|
|
2778
|
+
usage: "doc-pages <docId>",
|
|
2779
|
+
description: "All pages in a doc with content"
|
|
2780
|
+
}
|
|
2781
|
+
]
|
|
2782
|
+
},
|
|
2783
|
+
{
|
|
2784
|
+
name: "doc-page-create",
|
|
2785
|
+
description: "Create a page in a doc",
|
|
2786
|
+
flags: ["-c", "--content", "--parent-page", "--json"],
|
|
2787
|
+
quickReference: [
|
|
2788
|
+
{
|
|
2789
|
+
section: "write",
|
|
2790
|
+
usage: "doc-page-create <docId> <name>",
|
|
2791
|
+
description: "Create a page in a doc"
|
|
2792
|
+
}
|
|
2793
|
+
]
|
|
2794
|
+
},
|
|
2795
|
+
{
|
|
2796
|
+
name: "doc-page-edit",
|
|
2797
|
+
description: "Edit a doc page",
|
|
2798
|
+
flags: ["--name", "-c", "--content", "--json"],
|
|
2799
|
+
quickReference: [
|
|
2800
|
+
{
|
|
2801
|
+
section: "write",
|
|
2802
|
+
usage: "doc-page-edit <docId> <pageId>",
|
|
2803
|
+
description: "Edit a doc page"
|
|
2804
|
+
}
|
|
2805
|
+
]
|
|
2806
|
+
},
|
|
2807
|
+
{
|
|
2808
|
+
name: "doc-delete",
|
|
2809
|
+
description: "Delete a doc",
|
|
2810
|
+
flags: ["--json"],
|
|
2811
|
+
quickReference: [
|
|
2812
|
+
{ section: "write", usage: "doc-delete <docId>", description: "Delete a doc" }
|
|
2813
|
+
]
|
|
2814
|
+
},
|
|
2815
|
+
{
|
|
2816
|
+
name: "doc-page-delete",
|
|
2817
|
+
description: "Delete a doc page",
|
|
2818
|
+
flags: ["--json"],
|
|
2819
|
+
quickReference: [
|
|
2820
|
+
{
|
|
2821
|
+
section: "write",
|
|
2822
|
+
usage: "doc-page-delete <docId> <pageId>",
|
|
2823
|
+
description: "Delete a doc page"
|
|
2824
|
+
}
|
|
2825
|
+
]
|
|
2826
|
+
},
|
|
2827
|
+
{
|
|
2828
|
+
name: "folders",
|
|
2829
|
+
description: "List folders in a space (with their lists)",
|
|
2830
|
+
flags: ["--name", "--json"],
|
|
2831
|
+
quickReference: [
|
|
2832
|
+
{ section: "read", usage: "folders <spaceId>", description: "List folders in a space" }
|
|
2833
|
+
]
|
|
2834
|
+
},
|
|
2835
|
+
{
|
|
2836
|
+
name: "members",
|
|
2837
|
+
description: "List workspace members",
|
|
2838
|
+
flags: ["--json"],
|
|
2839
|
+
quickReference: [{ section: "read", usage: "members", description: "List workspace members" }]
|
|
2840
|
+
},
|
|
2841
|
+
{
|
|
2842
|
+
name: "fields",
|
|
2843
|
+
description: "List custom fields for a list",
|
|
2844
|
+
flags: ["--json"],
|
|
2845
|
+
quickReference: [
|
|
2846
|
+
{ section: "read", usage: "fields <listId>", description: "List custom fields for a list" }
|
|
2847
|
+
]
|
|
2848
|
+
},
|
|
2849
|
+
{
|
|
2850
|
+
name: "duplicate",
|
|
2851
|
+
description: "Duplicate a task",
|
|
2852
|
+
flags: ["--json"],
|
|
2853
|
+
quickReference: [
|
|
2854
|
+
{ section: "write", usage: "duplicate <taskId>", description: "Duplicate a task" }
|
|
2855
|
+
]
|
|
2856
|
+
},
|
|
2857
|
+
{
|
|
2858
|
+
name: "bulk",
|
|
2859
|
+
description: "Bulk task operations",
|
|
2860
|
+
quickReference: [
|
|
2861
|
+
{
|
|
2862
|
+
section: "write",
|
|
2863
|
+
usage: "bulk status <status> <taskIds...>",
|
|
2864
|
+
description: "Bulk update task status"
|
|
2865
|
+
}
|
|
2866
|
+
]
|
|
2867
|
+
},
|
|
2868
|
+
{
|
|
2869
|
+
name: "goals",
|
|
2870
|
+
description: "List goals in your workspace",
|
|
2871
|
+
flags: ["--json"],
|
|
2872
|
+
quickReference: [
|
|
2873
|
+
{ section: "read", usage: "goals", description: "List goals in your workspace" }
|
|
2874
|
+
]
|
|
2875
|
+
},
|
|
2876
|
+
{
|
|
2877
|
+
name: "goal-create",
|
|
2878
|
+
description: "Create a goal",
|
|
2879
|
+
flags: ["-d", "--description", "--color", "--json"],
|
|
2880
|
+
quickReference: [
|
|
2881
|
+
{ section: "write", usage: "goal-create <name>", description: "Create a goal" }
|
|
2882
|
+
]
|
|
2883
|
+
},
|
|
2884
|
+
{
|
|
2885
|
+
name: "goal-update",
|
|
2886
|
+
description: "Update a goal",
|
|
2887
|
+
flags: ["-n", "--name", "-d", "--description", "--color", "--json"],
|
|
2888
|
+
quickReference: [
|
|
2889
|
+
{ section: "write", usage: "goal-update <goalId>", description: "Update a goal" }
|
|
2890
|
+
]
|
|
2891
|
+
},
|
|
2892
|
+
{
|
|
2893
|
+
name: "goal-delete",
|
|
2894
|
+
description: "Delete a goal",
|
|
2895
|
+
flags: ["--json"],
|
|
2896
|
+
quickReference: [
|
|
2897
|
+
{ section: "write", usage: "goal-delete <goalId>", description: "Delete a goal" }
|
|
2898
|
+
]
|
|
2899
|
+
},
|
|
2900
|
+
{
|
|
2901
|
+
name: "key-results",
|
|
2902
|
+
description: "List key results for a goal",
|
|
2903
|
+
flags: ["--json"],
|
|
2904
|
+
quickReference: [
|
|
2905
|
+
{
|
|
2906
|
+
section: "read",
|
|
2907
|
+
usage: "key-results <goalId>",
|
|
2908
|
+
description: "List key results for a goal"
|
|
2909
|
+
}
|
|
2910
|
+
]
|
|
2911
|
+
},
|
|
2912
|
+
{
|
|
2913
|
+
name: "key-result-create",
|
|
2914
|
+
description: "Create a key result on a goal",
|
|
2915
|
+
flags: ["--type", "--target", "--json"],
|
|
2916
|
+
quickReference: [
|
|
2917
|
+
{
|
|
2918
|
+
section: "write",
|
|
2919
|
+
usage: "key-result-create <goalId> <name>",
|
|
2920
|
+
description: "Create a key result on a goal"
|
|
2921
|
+
}
|
|
2922
|
+
]
|
|
2923
|
+
},
|
|
2924
|
+
{
|
|
2925
|
+
name: "key-result-update",
|
|
2926
|
+
description: "Update a key result",
|
|
2927
|
+
flags: ["--progress", "--note", "--json"],
|
|
2928
|
+
quickReference: [
|
|
2929
|
+
{
|
|
2930
|
+
section: "write",
|
|
2931
|
+
usage: "key-result-update <keyResultId>",
|
|
2932
|
+
description: "Update a key result"
|
|
2933
|
+
}
|
|
2934
|
+
]
|
|
2935
|
+
},
|
|
2936
|
+
{
|
|
2937
|
+
name: "key-result-delete",
|
|
2938
|
+
description: "Delete a key result",
|
|
2939
|
+
flags: ["--json"],
|
|
2940
|
+
quickReference: [
|
|
2941
|
+
{
|
|
2942
|
+
section: "write",
|
|
2943
|
+
usage: "key-result-delete <keyResultId>",
|
|
2944
|
+
description: "Delete a key result"
|
|
2945
|
+
}
|
|
2946
|
+
]
|
|
2947
|
+
},
|
|
2948
|
+
{
|
|
2949
|
+
name: "task-types",
|
|
2950
|
+
description: "List custom task types in your workspace",
|
|
2951
|
+
flags: ["--json"],
|
|
2952
|
+
quickReference: [
|
|
2953
|
+
{ section: "read", usage: "task-types", description: "List custom task types" }
|
|
2954
|
+
]
|
|
2955
|
+
},
|
|
2956
|
+
{
|
|
2957
|
+
name: "templates",
|
|
2958
|
+
description: "List task templates in your workspace",
|
|
2959
|
+
flags: ["--json"],
|
|
2960
|
+
quickReference: [{ section: "read", usage: "templates", description: "List task templates" }]
|
|
2961
|
+
},
|
|
2962
|
+
{
|
|
2963
|
+
name: "config",
|
|
2964
|
+
description: "Manage CLI configuration",
|
|
2965
|
+
quickReference: [
|
|
2966
|
+
{ section: "configuration", usage: "config", description: "Manage CLI configuration" }
|
|
2967
|
+
]
|
|
2968
|
+
},
|
|
2969
|
+
{
|
|
2970
|
+
name: "completion",
|
|
2971
|
+
description: "Output shell completion script (bash, zsh, fish)",
|
|
2972
|
+
quickReference: [
|
|
2973
|
+
{
|
|
2974
|
+
section: "configuration",
|
|
2975
|
+
usage: "completion <shell>",
|
|
2976
|
+
description: "Output shell completion script"
|
|
2977
|
+
}
|
|
2978
|
+
]
|
|
2979
|
+
}
|
|
2980
|
+
];
|
|
2981
|
+
function parseCommandFlags(flags = []) {
|
|
2982
|
+
const parsed = [];
|
|
2983
|
+
for (const flag of flags) {
|
|
2984
|
+
if (flag.startsWith("--")) {
|
|
2985
|
+
const previous = parsed.at(-1);
|
|
2986
|
+
if (previous && previous.long === "") {
|
|
2987
|
+
previous.long = flag;
|
|
2988
|
+
} else {
|
|
2989
|
+
parsed.push({ long: flag });
|
|
2990
|
+
}
|
|
2991
|
+
continue;
|
|
2992
|
+
}
|
|
2993
|
+
parsed.push({ short: flag, long: "" });
|
|
2994
|
+
}
|
|
2995
|
+
return parsed.map((flag) => ({
|
|
2996
|
+
short: flag.short,
|
|
2997
|
+
long: flag.long
|
|
2998
|
+
}));
|
|
2999
|
+
}
|
|
3000
|
+
function commandDescription(command, programName = "cup") {
|
|
3001
|
+
if (command.name === "init") {
|
|
3002
|
+
return `Set up ${programName} for the first time`;
|
|
3003
|
+
}
|
|
3004
|
+
return command.description;
|
|
3005
|
+
}
|
|
3006
|
+
function topLevelCommandDefinitions(programName = "cup") {
|
|
3007
|
+
return commandMetadata.map((command) => ({
|
|
3008
|
+
name: command.name,
|
|
3009
|
+
description: commandDescription(command, programName),
|
|
3010
|
+
flags: parseCommandFlags("flags" in command ? command.flags : [])
|
|
3011
|
+
}));
|
|
3012
|
+
}
|
|
3013
|
+
function topLevelCommandNames() {
|
|
3014
|
+
return commandMetadata.map((command) => command.name);
|
|
3015
|
+
}
|
|
3016
|
+
|
|
2171
3017
|
// src/commands/completion.ts
|
|
3018
|
+
var bashSpecialCaseCommands = /* @__PURE__ */ new Set(["checklist", "time", "bulk", "config", "completion"]);
|
|
3019
|
+
function escapeSingleQuotes(value) {
|
|
3020
|
+
return value.replaceAll("'", "'\\''");
|
|
3021
|
+
}
|
|
3022
|
+
function renderBashCommandCases() {
|
|
3023
|
+
return commandMetadata.filter(
|
|
3024
|
+
(command) => !bashSpecialCaseCommands.has(command.name) && ((command.flags?.length ?? 0) > 0 || command.bashFileCompletion)
|
|
3025
|
+
).map((command) => {
|
|
3026
|
+
if (command.bashFileCompletion) {
|
|
3027
|
+
return ` ${command.name})
|
|
3028
|
+
if [[ "$cur" == -* ]]; then
|
|
3029
|
+
COMPREPLY=($(compgen -W "${command.flags?.join(" ") ?? ""}" -- "$cur"))
|
|
3030
|
+
else
|
|
3031
|
+
COMPREPLY=($(compgen -f -- "$cur"))
|
|
3032
|
+
fi
|
|
3033
|
+
;;`;
|
|
3034
|
+
}
|
|
3035
|
+
return ` ${command.name})
|
|
3036
|
+
COMPREPLY=($(compgen -W "${command.flags?.join(" ") ?? ""}" -- "$cur"))
|
|
3037
|
+
;;`;
|
|
3038
|
+
}).join("\n");
|
|
3039
|
+
}
|
|
3040
|
+
function renderZshTopLevelCommands(name) {
|
|
3041
|
+
return topLevelCommandDefinitions(name).map((command) => ` '${command.name}:${escapeSingleQuotes(command.description)}'`).join("\n");
|
|
3042
|
+
}
|
|
3043
|
+
function renderFishTopLevelCommands(name) {
|
|
3044
|
+
return topLevelCommandDefinitions(name).map(
|
|
3045
|
+
(command) => `complete -c ${name} -n __fish_use_subcommand -a ${command.name} -d '${escapeSingleQuotes(command.description)}'`
|
|
3046
|
+
).join("\n");
|
|
3047
|
+
}
|
|
3048
|
+
function renderFishFlagDefinition(name, commandName, flag) {
|
|
3049
|
+
const parts = [`complete -c ${name} -n '__fish_seen_subcommand_from ${commandName}'`];
|
|
3050
|
+
if (flag.short) {
|
|
3051
|
+
parts.push(`-s ${flag.short.slice(1)}`);
|
|
3052
|
+
}
|
|
3053
|
+
parts.push(`-l ${flag.long.slice(2)}`);
|
|
3054
|
+
return parts.join(" ");
|
|
3055
|
+
}
|
|
3056
|
+
function renderFishTopLevelFlags(name) {
|
|
3057
|
+
return topLevelCommandDefinitions().filter((command) => command.flags.length > 0).flatMap(
|
|
3058
|
+
(command) => command.flags.map((flag) => renderFishFlagDefinition(name, command.name, flag))
|
|
3059
|
+
).join("\n");
|
|
3060
|
+
}
|
|
2172
3061
|
function bashCompletion(name) {
|
|
2173
3062
|
return `_${name}_completions() {
|
|
2174
3063
|
local cur prev words cword
|
|
@@ -2182,7 +3071,7 @@ function bashCompletion(name) {
|
|
|
2182
3071
|
cword=$COMP_CWORD
|
|
2183
3072
|
fi
|
|
2184
3073
|
|
|
2185
|
-
local commands="
|
|
3074
|
+
local commands="${topLevelCommandNames().join(" ")}"
|
|
2186
3075
|
|
|
2187
3076
|
if [[ $cword -eq 1 ]]; then
|
|
2188
3077
|
COMPREPLY=($(compgen -W "$commands --help --version" -- "$cur"))
|
|
@@ -2203,81 +3092,7 @@ function bashCompletion(name) {
|
|
|
2203
3092
|
esac
|
|
2204
3093
|
|
|
2205
3094
|
case "$cmd" in
|
|
2206
|
-
|
|
2207
|
-
COMPREPLY=($(compgen -W "--status --list --space --name --type --include-closed --json" -- "$cur"))
|
|
2208
|
-
;;
|
|
2209
|
-
task)
|
|
2210
|
-
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2211
|
-
;;
|
|
2212
|
-
update)
|
|
2213
|
-
COMPREPLY=($(compgen -W "-n --name -d --description -s --status --priority --due-date --time-estimate --assignee --parent --json" -- "$cur"))
|
|
2214
|
-
;;
|
|
2215
|
-
create)
|
|
2216
|
-
COMPREPLY=($(compgen -W "-l --list -n --name -d --description -p --parent -s --status --priority --due-date --assignee --tags --custom-item-id --time-estimate --json" -- "$cur"))
|
|
2217
|
-
;;
|
|
2218
|
-
sprint)
|
|
2219
|
-
COMPREPLY=($(compgen -W "--status --space --folder --include-closed --json" -- "$cur"))
|
|
2220
|
-
;;
|
|
2221
|
-
sprints)
|
|
2222
|
-
COMPREPLY=($(compgen -W "--space --json" -- "$cur"))
|
|
2223
|
-
;;
|
|
2224
|
-
subtasks)
|
|
2225
|
-
COMPREPLY=($(compgen -W "--status --name --include-closed --json" -- "$cur"))
|
|
2226
|
-
;;
|
|
2227
|
-
comment)
|
|
2228
|
-
COMPREPLY=($(compgen -W "-m --message --notify-all --json" -- "$cur"))
|
|
2229
|
-
;;
|
|
2230
|
-
comments)
|
|
2231
|
-
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2232
|
-
;;
|
|
2233
|
-
activity)
|
|
2234
|
-
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2235
|
-
;;
|
|
2236
|
-
lists)
|
|
2237
|
-
COMPREPLY=($(compgen -W "--name --json" -- "$cur"))
|
|
2238
|
-
;;
|
|
2239
|
-
spaces)
|
|
2240
|
-
COMPREPLY=($(compgen -W "--name --my --json" -- "$cur"))
|
|
2241
|
-
;;
|
|
2242
|
-
inbox)
|
|
2243
|
-
COMPREPLY=($(compgen -W "--include-closed --json --days" -- "$cur"))
|
|
2244
|
-
;;
|
|
2245
|
-
assigned)
|
|
2246
|
-
COMPREPLY=($(compgen -W "--status --include-closed --json" -- "$cur"))
|
|
2247
|
-
;;
|
|
2248
|
-
open)
|
|
2249
|
-
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2250
|
-
;;
|
|
2251
|
-
search)
|
|
2252
|
-
COMPREPLY=($(compgen -W "--status --include-closed --json" -- "$cur"))
|
|
2253
|
-
;;
|
|
2254
|
-
summary)
|
|
2255
|
-
COMPREPLY=($(compgen -W "--hours --json" -- "$cur"))
|
|
2256
|
-
;;
|
|
2257
|
-
overdue)
|
|
2258
|
-
COMPREPLY=($(compgen -W "--include-closed --json" -- "$cur"))
|
|
2259
|
-
;;
|
|
2260
|
-
assign)
|
|
2261
|
-
COMPREPLY=($(compgen -W "--to --remove --json" -- "$cur"))
|
|
2262
|
-
;;
|
|
2263
|
-
auth)
|
|
2264
|
-
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2265
|
-
;;
|
|
2266
|
-
depend)
|
|
2267
|
-
COMPREPLY=($(compgen -W "--on --blocks --remove --json" -- "$cur"))
|
|
2268
|
-
;;
|
|
2269
|
-
move)
|
|
2270
|
-
COMPREPLY=($(compgen -W "--to --remove --json" -- "$cur"))
|
|
2271
|
-
;;
|
|
2272
|
-
field)
|
|
2273
|
-
COMPREPLY=($(compgen -W "--set --remove --json" -- "$cur"))
|
|
2274
|
-
;;
|
|
2275
|
-
delete)
|
|
2276
|
-
COMPREPLY=($(compgen -W "--confirm --json" -- "$cur"))
|
|
2277
|
-
;;
|
|
2278
|
-
tag)
|
|
2279
|
-
COMPREPLY=($(compgen -W "--add --remove --json" -- "$cur"))
|
|
2280
|
-
;;
|
|
3095
|
+
${renderBashCommandCases()}
|
|
2281
3096
|
checklist)
|
|
2282
3097
|
if [[ $cword -eq 2 ]]; then
|
|
2283
3098
|
COMPREPLY=($(compgen -W "view create delete add-item edit-item delete-item" -- "$cur"))
|
|
@@ -2285,89 +3100,14 @@ function bashCompletion(name) {
|
|
|
2285
3100
|
;;
|
|
2286
3101
|
time)
|
|
2287
3102
|
if [[ $cword -eq 2 ]]; then
|
|
2288
|
-
COMPREPLY=($(compgen -W "start stop status log list" -- "$cur"))
|
|
3103
|
+
COMPREPLY=($(compgen -W "start stop status log list update delete" -- "$cur"))
|
|
2289
3104
|
fi
|
|
2290
3105
|
;;
|
|
2291
|
-
comment-edit)
|
|
2292
|
-
COMPREPLY=($(compgen -W "-m --message --resolved --unresolved --json" -- "$cur"))
|
|
2293
|
-
;;
|
|
2294
|
-
comment-delete)
|
|
2295
|
-
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2296
|
-
;;
|
|
2297
|
-
replies)
|
|
2298
|
-
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2299
|
-
;;
|
|
2300
|
-
reply)
|
|
2301
|
-
COMPREPLY=($(compgen -W "-m --message --notify-all --json" -- "$cur"))
|
|
2302
|
-
;;
|
|
2303
|
-
link)
|
|
2304
|
-
COMPREPLY=($(compgen -W "--remove --json" -- "$cur"))
|
|
2305
|
-
;;
|
|
2306
|
-
attach)
|
|
2307
|
-
COMPREPLY=($(compgen -f -- "$cur"))
|
|
2308
|
-
;;
|
|
2309
|
-
docs)
|
|
2310
|
-
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2311
|
-
;;
|
|
2312
|
-
doc)
|
|
2313
|
-
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2314
|
-
;;
|
|
2315
|
-
doc-pages)
|
|
2316
|
-
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2317
|
-
;;
|
|
2318
|
-
tags)
|
|
2319
|
-
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2320
|
-
;;
|
|
2321
|
-
tag-create)
|
|
2322
|
-
COMPREPLY=($(compgen -W "--fg --bg --json" -- "$cur"))
|
|
2323
|
-
;;
|
|
2324
|
-
tag-delete)
|
|
2325
|
-
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2326
|
-
;;
|
|
2327
|
-
members)
|
|
2328
|
-
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2329
|
-
;;
|
|
2330
|
-
fields)
|
|
2331
|
-
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2332
|
-
;;
|
|
2333
|
-
duplicate)
|
|
2334
|
-
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2335
|
-
;;
|
|
2336
3106
|
bulk)
|
|
2337
3107
|
if [[ $cword -eq 2 ]]; then
|
|
2338
3108
|
COMPREPLY=($(compgen -W "status" -- "$cur"))
|
|
2339
3109
|
fi
|
|
2340
3110
|
;;
|
|
2341
|
-
goals)
|
|
2342
|
-
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2343
|
-
;;
|
|
2344
|
-
goal-create)
|
|
2345
|
-
COMPREPLY=($(compgen -W "-d --description --color --json" -- "$cur"))
|
|
2346
|
-
;;
|
|
2347
|
-
goal-update)
|
|
2348
|
-
COMPREPLY=($(compgen -W "-n --name -d --description --color --json" -- "$cur"))
|
|
2349
|
-
;;
|
|
2350
|
-
key-results)
|
|
2351
|
-
COMPREPLY=($(compgen -W "--json" -- "$cur"))
|
|
2352
|
-
;;
|
|
2353
|
-
key-result-create)
|
|
2354
|
-
COMPREPLY=($(compgen -W "--type --target --json" -- "$cur"))
|
|
2355
|
-
;;
|
|
2356
|
-
key-result-update)
|
|
2357
|
-
COMPREPLY=($(compgen -W "--progress --note --json" -- "$cur"))
|
|
2358
|
-
;;
|
|
2359
|
-
folders)
|
|
2360
|
-
COMPREPLY=($(compgen -W "--name --json" -- "$cur"))
|
|
2361
|
-
;;
|
|
2362
|
-
doc-create)
|
|
2363
|
-
COMPREPLY=($(compgen -W "-c --content --json" -- "$cur"))
|
|
2364
|
-
;;
|
|
2365
|
-
doc-page-create)
|
|
2366
|
-
COMPREPLY=($(compgen -W "-c --content --parent-page --json" -- "$cur"))
|
|
2367
|
-
;;
|
|
2368
|
-
doc-page-edit)
|
|
2369
|
-
COMPREPLY=($(compgen -W "--name -c --content --json" -- "$cur"))
|
|
2370
|
-
;;
|
|
2371
3111
|
config)
|
|
2372
3112
|
if [[ $cword -eq 2 ]]; then
|
|
2373
3113
|
COMPREPLY=($(compgen -W "get set path" -- "$cur"))
|
|
@@ -2394,62 +3134,7 @@ function zshCompletion(name) {
|
|
|
2394
3134
|
_${name}() {
|
|
2395
3135
|
local -a commands
|
|
2396
3136
|
commands=(
|
|
2397
|
-
|
|
2398
|
-
'auth:Validate API token and show current user'
|
|
2399
|
-
'tasks:List tasks assigned to me'
|
|
2400
|
-
'task:Get task details'
|
|
2401
|
-
'update:Update a task'
|
|
2402
|
-
'create:Create a new task'
|
|
2403
|
-
'sprint:List my tasks in the current active sprint'
|
|
2404
|
-
'sprints:List all sprints in sprint folders'
|
|
2405
|
-
'subtasks:List subtasks of a task or initiative'
|
|
2406
|
-
'comment:Post a comment on a task'
|
|
2407
|
-
'comments:List comments on a task'
|
|
2408
|
-
'activity:Show task details and comments combined'
|
|
2409
|
-
'lists:List all lists in a space'
|
|
2410
|
-
'spaces:List spaces in your workspace'
|
|
2411
|
-
'inbox:Recently updated tasks grouped by time period'
|
|
2412
|
-
'assigned:Show all tasks assigned to me'
|
|
2413
|
-
'open:Open a task in the browser by ID or name'
|
|
2414
|
-
'search:Search my tasks by name'
|
|
2415
|
-
'summary:Daily standup summary'
|
|
2416
|
-
'overdue:List tasks that are past their due date'
|
|
2417
|
-
'assign:Assign or unassign users from a task'
|
|
2418
|
-
'depend:Add or remove task dependencies'
|
|
2419
|
-
'move:Add or remove a task from a list'
|
|
2420
|
-
'field:Set or remove a custom field value on a task'
|
|
2421
|
-
'delete:Delete a task'
|
|
2422
|
-
'tag:Add or remove tags from a task'
|
|
2423
|
-
'checklist:Manage checklists on a task'
|
|
2424
|
-
'time:Track time on tasks'
|
|
2425
|
-
'comment-edit:Edit an existing comment'
|
|
2426
|
-
'comment-delete:Delete a comment'
|
|
2427
|
-
'replies:List threaded replies on a comment'
|
|
2428
|
-
'reply:Reply to a comment'
|
|
2429
|
-
'link:Add or remove a link between two tasks'
|
|
2430
|
-
'attach:Upload a file attachment to a task'
|
|
2431
|
-
'docs:List workspace docs'
|
|
2432
|
-
'doc:View a doc or doc page'
|
|
2433
|
-
'doc-create:Create a new doc'
|
|
2434
|
-
'doc-pages:List all pages in a doc with content'
|
|
2435
|
-
'doc-page-create:Create a page in a doc'
|
|
2436
|
-
'doc-page-edit:Edit a doc page'
|
|
2437
|
-
'tags:List tags in a space'
|
|
2438
|
-
'tag-create:Create a tag in a space'
|
|
2439
|
-
'tag-delete:Delete a tag from a space'
|
|
2440
|
-
'members:List workspace members'
|
|
2441
|
-
'fields:List custom fields for a list'
|
|
2442
|
-
'duplicate:Duplicate a task'
|
|
2443
|
-
'bulk:Bulk task operations'
|
|
2444
|
-
'goals:List goals in your workspace'
|
|
2445
|
-
'goal-create:Create a goal'
|
|
2446
|
-
'goal-update:Update a goal'
|
|
2447
|
-
'key-results:List key results for a goal'
|
|
2448
|
-
'key-result-create:Create a key result on a goal'
|
|
2449
|
-
'key-result-update:Update a key result'
|
|
2450
|
-
'folders:List folders in a space'
|
|
2451
|
-
'config:Manage CLI configuration'
|
|
2452
|
-
'completion:Output shell completion script'
|
|
3137
|
+
${renderZshTopLevelCommands(name)}
|
|
2453
3138
|
)
|
|
2454
3139
|
|
|
2455
3140
|
_arguments -C \\
|
|
@@ -2505,6 +3190,7 @@ _${name}() {
|
|
|
2505
3190
|
'--tags[Comma-separated tag names]:tags:' \\
|
|
2506
3191
|
'--custom-item-id[Custom task type ID]:id:' \\
|
|
2507
3192
|
'--time-estimate[Time estimate]:duration:' \\
|
|
3193
|
+
'--template[Create from a task template]:template_id:' \\
|
|
2508
3194
|
'--json[Force JSON output]'
|
|
2509
3195
|
;;
|
|
2510
3196
|
sprint)
|
|
@@ -2693,6 +3379,8 @@ _${name}() {
|
|
|
2693
3379
|
'status:Show the currently running timer'
|
|
2694
3380
|
'log:Log a manual time entry'
|
|
2695
3381
|
'list:List recent time entries'
|
|
3382
|
+
'update:Update a time entry'
|
|
3383
|
+
'delete:Delete a time entry'
|
|
2696
3384
|
)
|
|
2697
3385
|
_arguments -C \\
|
|
2698
3386
|
'1:time command:->time_cmd' \\
|
|
@@ -2728,6 +3416,18 @@ _${name}() {
|
|
|
2728
3416
|
'--task[Filter by task ID]:task_id:' \\
|
|
2729
3417
|
'--json[Force JSON output]'
|
|
2730
3418
|
;;
|
|
3419
|
+
update)
|
|
3420
|
+
_arguments \\
|
|
3421
|
+
'1:time_entry_id:' \\
|
|
3422
|
+
'(-d --description)'{-d,--description}'[New description]:text:' \\
|
|
3423
|
+
'--duration[New duration]:duration:' \\
|
|
3424
|
+
'--json[Force JSON output]'
|
|
3425
|
+
;;
|
|
3426
|
+
delete)
|
|
3427
|
+
_arguments \\
|
|
3428
|
+
'1:time_entry_id:' \\
|
|
3429
|
+
'--json[Force JSON output]'
|
|
3430
|
+
;;
|
|
2731
3431
|
esac
|
|
2732
3432
|
;;
|
|
2733
3433
|
esac
|
|
@@ -2879,38 +3579,76 @@ _${name}() {
|
|
|
2879
3579
|
'--note[Progress note]:text:' \\
|
|
2880
3580
|
'--json[Force JSON output]'
|
|
2881
3581
|
;;
|
|
2882
|
-
|
|
3582
|
+
key-result-delete)
|
|
2883
3583
|
_arguments \\
|
|
2884
|
-
'1:
|
|
2885
|
-
'--name[Filter by folder name]:text:' \\
|
|
3584
|
+
'1:key_result_id:' \\
|
|
2886
3585
|
'--json[Force JSON output]'
|
|
2887
3586
|
;;
|
|
2888
|
-
|
|
3587
|
+
goal-delete)
|
|
2889
3588
|
_arguments \\
|
|
2890
|
-
'1:
|
|
2891
|
-
'(-c --content)'{-c,--content}'[Initial content]:text:' \\
|
|
3589
|
+
'1:goal_id:' \\
|
|
2892
3590
|
'--json[Force JSON output]'
|
|
2893
3591
|
;;
|
|
2894
|
-
doc-
|
|
3592
|
+
doc-delete)
|
|
2895
3593
|
_arguments \\
|
|
2896
3594
|
'1:doc_id:' \\
|
|
2897
|
-
'2:name:' \\
|
|
2898
|
-
'(-c --content)'{-c,--content}'[Page content]:text:' \\
|
|
2899
|
-
'--parent-page[Parent page ID]:page_id:' \\
|
|
2900
3595
|
'--json[Force JSON output]'
|
|
2901
3596
|
;;
|
|
2902
|
-
doc-page-
|
|
3597
|
+
doc-page-delete)
|
|
2903
3598
|
_arguments \\
|
|
2904
3599
|
'1:doc_id:' \\
|
|
2905
3600
|
'2:page_id:' \\
|
|
2906
|
-
'--name[New page name]:text:' \\
|
|
2907
|
-
'(-c --content)'{-c,--content}'[New page content]:text:' \\
|
|
2908
3601
|
'--json[Force JSON output]'
|
|
2909
3602
|
;;
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
'
|
|
3603
|
+
tag-update)
|
|
3604
|
+
_arguments \\
|
|
3605
|
+
'1:space_id:' \\
|
|
3606
|
+
'2:tag_name:' \\
|
|
3607
|
+
'--name[New tag name]:text:' \\
|
|
3608
|
+
'--fg[New foreground color]:color:' \\
|
|
3609
|
+
'--bg[New background color]:color:' \\
|
|
3610
|
+
'--json[Force JSON output]'
|
|
3611
|
+
;;
|
|
3612
|
+
task-types)
|
|
3613
|
+
_arguments \\
|
|
3614
|
+
'--json[Force JSON output]'
|
|
3615
|
+
;;
|
|
3616
|
+
templates)
|
|
3617
|
+
_arguments \\
|
|
3618
|
+
'--json[Force JSON output]'
|
|
3619
|
+
;;
|
|
3620
|
+
folders)
|
|
3621
|
+
_arguments \\
|
|
3622
|
+
'1:space_id:' \\
|
|
3623
|
+
'--name[Filter by folder name]:text:' \\
|
|
3624
|
+
'--json[Force JSON output]'
|
|
3625
|
+
;;
|
|
3626
|
+
doc-create)
|
|
3627
|
+
_arguments \\
|
|
3628
|
+
'1:title:' \\
|
|
3629
|
+
'(-c --content)'{-c,--content}'[Initial content]:text:' \\
|
|
3630
|
+
'--json[Force JSON output]'
|
|
3631
|
+
;;
|
|
3632
|
+
doc-page-create)
|
|
3633
|
+
_arguments \\
|
|
3634
|
+
'1:doc_id:' \\
|
|
3635
|
+
'2:name:' \\
|
|
3636
|
+
'(-c --content)'{-c,--content}'[Page content]:text:' \\
|
|
3637
|
+
'--parent-page[Parent page ID]:page_id:' \\
|
|
3638
|
+
'--json[Force JSON output]'
|
|
3639
|
+
;;
|
|
3640
|
+
doc-page-edit)
|
|
3641
|
+
_arguments \\
|
|
3642
|
+
'1:doc_id:' \\
|
|
3643
|
+
'2:page_id:' \\
|
|
3644
|
+
'--name[New page name]:text:' \\
|
|
3645
|
+
'(-c --content)'{-c,--content}'[New page content]:text:' \\
|
|
3646
|
+
'--json[Force JSON output]'
|
|
3647
|
+
;;
|
|
3648
|
+
config)
|
|
3649
|
+
local -a config_cmds
|
|
3650
|
+
config_cmds=(
|
|
3651
|
+
'get:Print a config value'
|
|
2914
3652
|
'set:Set a config value'
|
|
2915
3653
|
'path:Print config file path'
|
|
2916
3654
|
)
|
|
@@ -2947,170 +3685,13 @@ function fishCompletion(name) {
|
|
|
2947
3685
|
complete -c ${name} -n __fish_use_subcommand -s h -l help -d 'Show help'
|
|
2948
3686
|
complete -c ${name} -n __fish_use_subcommand -s V -l version -d 'Show version'
|
|
2949
3687
|
|
|
2950
|
-
|
|
2951
|
-
complete -c ${name} -n __fish_use_subcommand -a auth -d 'Validate API token and show current user'
|
|
2952
|
-
complete -c ${name} -n __fish_use_subcommand -a tasks -d 'List tasks assigned to me'
|
|
2953
|
-
complete -c ${name} -n __fish_use_subcommand -a task -d 'Get task details'
|
|
2954
|
-
complete -c ${name} -n __fish_use_subcommand -a update -d 'Update a task'
|
|
2955
|
-
complete -c ${name} -n __fish_use_subcommand -a create -d 'Create a new task'
|
|
2956
|
-
complete -c ${name} -n __fish_use_subcommand -a sprint -d 'List my tasks in the current active sprint'
|
|
2957
|
-
complete -c ${name} -n __fish_use_subcommand -a sprints -d 'List all sprints in sprint folders'
|
|
2958
|
-
complete -c ${name} -n __fish_use_subcommand -a subtasks -d 'List subtasks of a task or initiative'
|
|
2959
|
-
complete -c ${name} -n __fish_use_subcommand -a comment -d 'Post a comment on a task'
|
|
2960
|
-
complete -c ${name} -n __fish_use_subcommand -a comments -d 'List comments on a task'
|
|
2961
|
-
complete -c ${name} -n __fish_use_subcommand -a activity -d 'Show task details and comments combined'
|
|
2962
|
-
complete -c ${name} -n __fish_use_subcommand -a lists -d 'List all lists in a space'
|
|
2963
|
-
complete -c ${name} -n __fish_use_subcommand -a spaces -d 'List spaces in your workspace'
|
|
2964
|
-
complete -c ${name} -n __fish_use_subcommand -a inbox -d 'Recently updated tasks grouped by time period'
|
|
2965
|
-
complete -c ${name} -n __fish_use_subcommand -a assigned -d 'Show all tasks assigned to me'
|
|
2966
|
-
complete -c ${name} -n __fish_use_subcommand -a open -d 'Open a task in the browser by ID or name'
|
|
2967
|
-
complete -c ${name} -n __fish_use_subcommand -a search -d 'Search my tasks by name'
|
|
2968
|
-
complete -c ${name} -n __fish_use_subcommand -a summary -d 'Daily standup summary'
|
|
2969
|
-
complete -c ${name} -n __fish_use_subcommand -a overdue -d 'List tasks that are past their due date'
|
|
2970
|
-
complete -c ${name} -n __fish_use_subcommand -a assign -d 'Assign or unassign users from a task'
|
|
2971
|
-
complete -c ${name} -n __fish_use_subcommand -a depend -d 'Add or remove task dependencies'
|
|
2972
|
-
complete -c ${name} -n __fish_use_subcommand -a move -d 'Add or remove a task from a list'
|
|
2973
|
-
complete -c ${name} -n __fish_use_subcommand -a field -d 'Set or remove a custom field value on a task'
|
|
2974
|
-
complete -c ${name} -n __fish_use_subcommand -a delete -d 'Delete a task'
|
|
2975
|
-
complete -c ${name} -n __fish_use_subcommand -a tag -d 'Add or remove tags from a task'
|
|
2976
|
-
complete -c ${name} -n __fish_use_subcommand -a checklist -d 'Manage checklists on a task'
|
|
2977
|
-
complete -c ${name} -n __fish_use_subcommand -a time -d 'Track time on tasks'
|
|
2978
|
-
complete -c ${name} -n __fish_use_subcommand -a comment-edit -d 'Edit an existing comment'
|
|
2979
|
-
complete -c ${name} -n __fish_use_subcommand -a comment-delete -d 'Delete a comment'
|
|
2980
|
-
complete -c ${name} -n __fish_use_subcommand -a replies -d 'List threaded replies on a comment'
|
|
2981
|
-
complete -c ${name} -n __fish_use_subcommand -a reply -d 'Reply to a comment'
|
|
2982
|
-
complete -c ${name} -n __fish_use_subcommand -a link -d 'Add or remove a link between two tasks'
|
|
2983
|
-
complete -c ${name} -n __fish_use_subcommand -a attach -d 'Upload a file attachment to a task'
|
|
2984
|
-
complete -c ${name} -n __fish_use_subcommand -a docs -d 'List workspace docs'
|
|
2985
|
-
complete -c ${name} -n __fish_use_subcommand -a doc -d 'View a doc or doc page'
|
|
2986
|
-
complete -c ${name} -n __fish_use_subcommand -a doc-create -d 'Create a new doc'
|
|
2987
|
-
complete -c ${name} -n __fish_use_subcommand -a doc-pages -d 'List all pages in a doc with content'
|
|
2988
|
-
complete -c ${name} -n __fish_use_subcommand -a doc-page-create -d 'Create a page in a doc'
|
|
2989
|
-
complete -c ${name} -n __fish_use_subcommand -a doc-page-edit -d 'Edit a doc page'
|
|
2990
|
-
complete -c ${name} -n __fish_use_subcommand -a tags -d 'List tags in a space'
|
|
2991
|
-
complete -c ${name} -n __fish_use_subcommand -a tag-create -d 'Create a tag in a space'
|
|
2992
|
-
complete -c ${name} -n __fish_use_subcommand -a tag-delete -d 'Delete a tag from a space'
|
|
2993
|
-
complete -c ${name} -n __fish_use_subcommand -a members -d 'List workspace members'
|
|
2994
|
-
complete -c ${name} -n __fish_use_subcommand -a fields -d 'List custom fields for a list'
|
|
2995
|
-
complete -c ${name} -n __fish_use_subcommand -a duplicate -d 'Duplicate a task'
|
|
2996
|
-
complete -c ${name} -n __fish_use_subcommand -a bulk -d 'Bulk task operations'
|
|
2997
|
-
complete -c ${name} -n __fish_use_subcommand -a goals -d 'List goals in your workspace'
|
|
2998
|
-
complete -c ${name} -n __fish_use_subcommand -a goal-create -d 'Create a goal'
|
|
2999
|
-
complete -c ${name} -n __fish_use_subcommand -a goal-update -d 'Update a goal'
|
|
3000
|
-
complete -c ${name} -n __fish_use_subcommand -a key-results -d 'List key results for a goal'
|
|
3001
|
-
complete -c ${name} -n __fish_use_subcommand -a key-result-create -d 'Create a key result on a goal'
|
|
3002
|
-
complete -c ${name} -n __fish_use_subcommand -a key-result-update -d 'Update a key result'
|
|
3003
|
-
complete -c ${name} -n __fish_use_subcommand -a folders -d 'List folders in a space'
|
|
3004
|
-
complete -c ${name} -n __fish_use_subcommand -a config -d 'Manage CLI configuration'
|
|
3005
|
-
complete -c ${name} -n __fish_use_subcommand -a completion -d 'Output shell completion script'
|
|
3006
|
-
|
|
3007
|
-
complete -c ${name} -n '__fish_seen_subcommand_from auth' -l json -d 'Force JSON output'
|
|
3008
|
-
|
|
3009
|
-
complete -c ${name} -n '__fish_seen_subcommand_from tasks' -l status -d 'Filter by status'
|
|
3010
|
-
complete -c ${name} -n '__fish_seen_subcommand_from tasks' -l list -d 'Filter by list ID'
|
|
3011
|
-
complete -c ${name} -n '__fish_seen_subcommand_from tasks' -l space -d 'Filter by space ID'
|
|
3012
|
-
complete -c ${name} -n '__fish_seen_subcommand_from tasks' -l name -d 'Filter by name'
|
|
3013
|
-
complete -c ${name} -n '__fish_seen_subcommand_from tasks' -l type -d 'Filter by task type'
|
|
3014
|
-
complete -c ${name} -n '__fish_seen_subcommand_from tasks' -l include-closed -d 'Include done/closed tasks'
|
|
3015
|
-
complete -c ${name} -n '__fish_seen_subcommand_from tasks' -l json -d 'Force JSON output'
|
|
3016
|
-
|
|
3017
|
-
complete -c ${name} -n '__fish_seen_subcommand_from task' -l json -d 'Force JSON output'
|
|
3018
|
-
|
|
3019
|
-
complete -c ${name} -n '__fish_seen_subcommand_from update' -s n -l name -d 'New task name'
|
|
3020
|
-
complete -c ${name} -n '__fish_seen_subcommand_from update' -s d -l description -d 'New description'
|
|
3021
|
-
complete -c ${name} -n '__fish_seen_subcommand_from update' -s s -l status -d 'New status'
|
|
3022
|
-
complete -c ${name} -n '__fish_seen_subcommand_from update' -l priority -d 'Priority level' -a 'urgent high normal low'
|
|
3023
|
-
complete -c ${name} -n '__fish_seen_subcommand_from update' -l due-date -d 'Due date'
|
|
3024
|
-
complete -c ${name} -n '__fish_seen_subcommand_from update' -l time-estimate -d 'Time estimate'
|
|
3025
|
-
complete -c ${name} -n '__fish_seen_subcommand_from update' -l assignee -d 'Add assignee'
|
|
3026
|
-
complete -c ${name} -n '__fish_seen_subcommand_from update' -l parent -d 'Set parent task'
|
|
3027
|
-
complete -c ${name} -n '__fish_seen_subcommand_from update' -l json -d 'Force JSON output'
|
|
3028
|
-
|
|
3029
|
-
complete -c ${name} -n '__fish_seen_subcommand_from create' -s l -l list -d 'Target list ID'
|
|
3030
|
-
complete -c ${name} -n '__fish_seen_subcommand_from create' -s n -l name -d 'Task name'
|
|
3031
|
-
complete -c ${name} -n '__fish_seen_subcommand_from create' -s d -l description -d 'Task description'
|
|
3032
|
-
complete -c ${name} -n '__fish_seen_subcommand_from create' -s p -l parent -d 'Parent task ID'
|
|
3033
|
-
complete -c ${name} -n '__fish_seen_subcommand_from create' -s s -l status -d 'Initial status'
|
|
3034
|
-
complete -c ${name} -n '__fish_seen_subcommand_from create' -l priority -d 'Priority level' -a 'urgent high normal low'
|
|
3035
|
-
complete -c ${name} -n '__fish_seen_subcommand_from create' -l due-date -d 'Due date'
|
|
3036
|
-
complete -c ${name} -n '__fish_seen_subcommand_from create' -l assignee -d 'Assignee user ID'
|
|
3037
|
-
complete -c ${name} -n '__fish_seen_subcommand_from create' -l tags -d 'Comma-separated tag names'
|
|
3038
|
-
complete -c ${name} -n '__fish_seen_subcommand_from create' -l custom-item-id -d 'Custom task type ID'
|
|
3039
|
-
complete -c ${name} -n '__fish_seen_subcommand_from create' -l time-estimate -d 'Time estimate'
|
|
3040
|
-
complete -c ${name} -n '__fish_seen_subcommand_from create' -l json -d 'Force JSON output'
|
|
3041
|
-
|
|
3042
|
-
complete -c ${name} -n '__fish_seen_subcommand_from sprint' -l status -d 'Filter by status'
|
|
3043
|
-
complete -c ${name} -n '__fish_seen_subcommand_from sprint' -l space -d 'Narrow sprint search to a space'
|
|
3044
|
-
complete -c ${name} -n '__fish_seen_subcommand_from sprint' -l folder -d 'Sprint folder ID'
|
|
3045
|
-
complete -c ${name} -n '__fish_seen_subcommand_from sprint' -l include-closed -d 'Include done/closed tasks'
|
|
3046
|
-
complete -c ${name} -n '__fish_seen_subcommand_from sprint' -l json -d 'Force JSON output'
|
|
3047
|
-
|
|
3048
|
-
complete -c ${name} -n '__fish_seen_subcommand_from sprints' -l space -d 'Filter by space'
|
|
3049
|
-
complete -c ${name} -n '__fish_seen_subcommand_from sprints' -l json -d 'Force JSON output'
|
|
3050
|
-
|
|
3051
|
-
complete -c ${name} -n '__fish_seen_subcommand_from subtasks' -l status -d 'Filter by status'
|
|
3052
|
-
complete -c ${name} -n '__fish_seen_subcommand_from subtasks' -l name -d 'Filter by name'
|
|
3053
|
-
complete -c ${name} -n '__fish_seen_subcommand_from subtasks' -l include-closed -d 'Include closed/done subtasks'
|
|
3054
|
-
complete -c ${name} -n '__fish_seen_subcommand_from subtasks' -l json -d 'Force JSON output'
|
|
3055
|
-
|
|
3056
|
-
complete -c ${name} -n '__fish_seen_subcommand_from comment' -s m -l message -d 'Comment text'
|
|
3057
|
-
complete -c ${name} -n '__fish_seen_subcommand_from comment' -l notify-all -d 'Notify all assignees'
|
|
3058
|
-
complete -c ${name} -n '__fish_seen_subcommand_from comment' -l json -d 'Force JSON output'
|
|
3059
|
-
|
|
3060
|
-
complete -c ${name} -n '__fish_seen_subcommand_from comments' -l json -d 'Force JSON output'
|
|
3061
|
-
|
|
3062
|
-
complete -c ${name} -n '__fish_seen_subcommand_from activity' -l json -d 'Force JSON output'
|
|
3063
|
-
|
|
3064
|
-
complete -c ${name} -n '__fish_seen_subcommand_from lists' -l name -d 'Filter by name'
|
|
3065
|
-
complete -c ${name} -n '__fish_seen_subcommand_from lists' -l json -d 'Force JSON output'
|
|
3066
|
-
|
|
3067
|
-
complete -c ${name} -n '__fish_seen_subcommand_from spaces' -l name -d 'Filter spaces by name'
|
|
3068
|
-
complete -c ${name} -n '__fish_seen_subcommand_from spaces' -l my -d 'Show only spaces where I have assigned tasks'
|
|
3069
|
-
complete -c ${name} -n '__fish_seen_subcommand_from spaces' -l json -d 'Force JSON output'
|
|
3070
|
-
|
|
3071
|
-
complete -c ${name} -n '__fish_seen_subcommand_from inbox' -l include-closed -d 'Include done/closed tasks'
|
|
3072
|
-
complete -c ${name} -n '__fish_seen_subcommand_from inbox' -l json -d 'Force JSON output'
|
|
3073
|
-
complete -c ${name} -n '__fish_seen_subcommand_from inbox' -l days -d 'Lookback period in days'
|
|
3074
|
-
|
|
3075
|
-
complete -c ${name} -n '__fish_seen_subcommand_from assigned' -l status -d 'Show only tasks with this status'
|
|
3076
|
-
complete -c ${name} -n '__fish_seen_subcommand_from assigned' -l include-closed -d 'Include done/closed tasks'
|
|
3077
|
-
complete -c ${name} -n '__fish_seen_subcommand_from assigned' -l json -d 'Force JSON output'
|
|
3078
|
-
|
|
3079
|
-
complete -c ${name} -n '__fish_seen_subcommand_from open' -l json -d 'Output task JSON instead of opening'
|
|
3080
|
-
|
|
3081
|
-
complete -c ${name} -n '__fish_seen_subcommand_from search' -l status -d 'Filter by status'
|
|
3082
|
-
complete -c ${name} -n '__fish_seen_subcommand_from search' -l include-closed -d 'Include done/closed tasks in search'
|
|
3083
|
-
complete -c ${name} -n '__fish_seen_subcommand_from search' -l json -d 'Force JSON output'
|
|
3084
|
-
|
|
3085
|
-
complete -c ${name} -n '__fish_seen_subcommand_from summary' -l hours -d 'Completed-tasks lookback in hours'
|
|
3086
|
-
complete -c ${name} -n '__fish_seen_subcommand_from summary' -l json -d 'Force JSON output'
|
|
3087
|
-
|
|
3088
|
-
complete -c ${name} -n '__fish_seen_subcommand_from overdue' -l include-closed -d 'Include done/closed overdue tasks'
|
|
3089
|
-
complete -c ${name} -n '__fish_seen_subcommand_from overdue' -l json -d 'Force JSON output'
|
|
3090
|
-
|
|
3091
|
-
complete -c ${name} -n '__fish_seen_subcommand_from assign' -l to -d 'Add assignee'
|
|
3092
|
-
complete -c ${name} -n '__fish_seen_subcommand_from assign' -l remove -d 'Remove assignee'
|
|
3093
|
-
complete -c ${name} -n '__fish_seen_subcommand_from assign' -l json -d 'Force JSON output'
|
|
3094
|
-
|
|
3095
|
-
complete -c ${name} -n '__fish_seen_subcommand_from depend' -l on -d 'Task that this task depends on'
|
|
3096
|
-
complete -c ${name} -n '__fish_seen_subcommand_from depend' -l blocks -d 'Task that this task blocks'
|
|
3097
|
-
complete -c ${name} -n '__fish_seen_subcommand_from depend' -l remove -d 'Remove the dependency'
|
|
3098
|
-
complete -c ${name} -n '__fish_seen_subcommand_from depend' -l json -d 'Force JSON output'
|
|
3099
|
-
|
|
3100
|
-
complete -c ${name} -n '__fish_seen_subcommand_from move' -l to -d 'Add task to this list'
|
|
3101
|
-
complete -c ${name} -n '__fish_seen_subcommand_from move' -l remove -d 'Remove task from this list'
|
|
3102
|
-
complete -c ${name} -n '__fish_seen_subcommand_from move' -l json -d 'Force JSON output'
|
|
3688
|
+
${renderFishTopLevelCommands(name)}
|
|
3103
3689
|
|
|
3104
|
-
|
|
3105
|
-
complete -c ${name} -n '__fish_seen_subcommand_from field' -l remove -d 'Remove field value by name'
|
|
3106
|
-
complete -c ${name} -n '__fish_seen_subcommand_from field' -l json -d 'Force JSON output'
|
|
3690
|
+
${renderFishTopLevelFlags(name)}
|
|
3107
3691
|
|
|
3108
|
-
complete -c ${name} -n '__fish_seen_subcommand_from
|
|
3109
|
-
complete -c ${name} -n '__fish_seen_subcommand_from
|
|
3110
|
-
|
|
3111
|
-
complete -c ${name} -n '__fish_seen_subcommand_from tag' -l add -d 'Comma-separated tag names to add'
|
|
3112
|
-
complete -c ${name} -n '__fish_seen_subcommand_from tag' -l remove -d 'Comma-separated tag names to remove'
|
|
3113
|
-
complete -c ${name} -n '__fish_seen_subcommand_from tag' -l json -d 'Force JSON output'
|
|
3692
|
+
complete -c ${name} -n '__fish_seen_subcommand_from update' -l priority -a 'urgent high normal low'
|
|
3693
|
+
complete -c ${name} -n '__fish_seen_subcommand_from create' -l priority -a 'urgent high normal low'
|
|
3694
|
+
complete -c ${name} -n '__fish_seen_subcommand_from key-result-create' -l type -a 'number percentage'
|
|
3114
3695
|
|
|
3115
3696
|
complete -c ${name} -n '__fish_seen_subcommand_from checklist; and not __fish_seen_subcommand_from view create delete add-item edit-item delete-item' -a view -d 'View checklists on a task'
|
|
3116
3697
|
complete -c ${name} -n '__fish_seen_subcommand_from checklist; and not __fish_seen_subcommand_from view create delete add-item edit-item delete-item' -a create -d 'Create a checklist on a task'
|
|
@@ -3124,94 +3705,26 @@ complete -c ${name} -n '__fish_seen_subcommand_from edit-item' -l resolved -d 'M
|
|
|
3124
3705
|
complete -c ${name} -n '__fish_seen_subcommand_from edit-item' -l unresolved -d 'Mark item as unresolved'
|
|
3125
3706
|
complete -c ${name} -n '__fish_seen_subcommand_from edit-item' -l assignee -d 'Assign user by ID'
|
|
3126
3707
|
|
|
3127
|
-
complete -c ${name} -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list' -a start -d 'Start tracking time on a task'
|
|
3128
|
-
complete -c ${name} -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list' -a stop -d 'Stop the running timer'
|
|
3129
|
-
complete -c ${name} -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list' -a status -d 'Show the currently running timer'
|
|
3130
|
-
complete -c ${name} -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list' -a log -d 'Log a manual time entry'
|
|
3131
|
-
complete -c ${name} -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list' -a list -d 'List recent time entries'
|
|
3132
|
-
complete -c ${name} -n '__fish_seen_subcommand_from start stop status log list
|
|
3708
|
+
complete -c ${name} -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list update delete' -a start -d 'Start tracking time on a task'
|
|
3709
|
+
complete -c ${name} -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list update delete' -a stop -d 'Stop the running timer'
|
|
3710
|
+
complete -c ${name} -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list update delete' -a status -d 'Show the currently running timer'
|
|
3711
|
+
complete -c ${name} -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list update delete' -a log -d 'Log a manual time entry'
|
|
3712
|
+
complete -c ${name} -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list update delete' -a list -d 'List recent time entries'
|
|
3713
|
+
complete -c ${name} -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list update delete' -a update -d 'Update a time entry'
|
|
3714
|
+
complete -c ${name} -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list update delete' -a delete -d 'Delete a time entry'
|
|
3715
|
+
complete -c ${name} -n '__fish_seen_subcommand_from start stop status log list update delete; and __fish_seen_subcommand_from time' -l json -d 'Force JSON output'
|
|
3133
3716
|
complete -c ${name} -n '__fish_seen_subcommand_from start; and __fish_seen_subcommand_from time' -s d -l description -d 'Description'
|
|
3134
3717
|
complete -c ${name} -n '__fish_seen_subcommand_from log; and __fish_seen_subcommand_from time' -s d -l description -d 'Description'
|
|
3135
3718
|
complete -c ${name} -n '__fish_seen_subcommand_from list; and __fish_seen_subcommand_from time' -l days -d 'Number of days to look back'
|
|
3136
3719
|
complete -c ${name} -n '__fish_seen_subcommand_from list; and __fish_seen_subcommand_from time' -l task -d 'Filter by task ID'
|
|
3720
|
+
complete -c ${name} -n '__fish_seen_subcommand_from update; and __fish_seen_subcommand_from time' -s d -l description -d 'New description'
|
|
3721
|
+
complete -c ${name} -n '__fish_seen_subcommand_from update; and __fish_seen_subcommand_from time' -l duration -d 'New duration'
|
|
3137
3722
|
|
|
3138
|
-
complete -c ${name} -n '__fish_seen_subcommand_from comment-delete' -l json -d 'Force JSON output'
|
|
3139
|
-
|
|
3140
|
-
complete -c ${name} -n '__fish_seen_subcommand_from replies' -l json -d 'Force JSON output'
|
|
3141
|
-
|
|
3142
|
-
complete -c ${name} -n '__fish_seen_subcommand_from reply' -s m -l message -d 'Reply text'
|
|
3143
|
-
complete -c ${name} -n '__fish_seen_subcommand_from reply' -l notify-all -d 'Notify all assignees'
|
|
3144
|
-
complete -c ${name} -n '__fish_seen_subcommand_from reply' -l json -d 'Force JSON output'
|
|
3145
|
-
|
|
3146
|
-
complete -c ${name} -n '__fish_seen_subcommand_from link' -l remove -d 'Remove the link'
|
|
3147
|
-
complete -c ${name} -n '__fish_seen_subcommand_from link' -l json -d 'Force JSON output'
|
|
3148
|
-
|
|
3149
|
-
complete -c ${name} -n '__fish_seen_subcommand_from attach' -l json -d 'Force JSON output'
|
|
3150
3723
|
complete -c ${name} -n '__fish_seen_subcommand_from attach' -F
|
|
3151
3724
|
|
|
3152
|
-
complete -c ${name} -n '__fish_seen_subcommand_from comment-edit' -s m -l message -d 'New comment text'
|
|
3153
|
-
complete -c ${name} -n '__fish_seen_subcommand_from comment-edit' -l resolved -d 'Mark comment as resolved'
|
|
3154
|
-
complete -c ${name} -n '__fish_seen_subcommand_from comment-edit' -l unresolved -d 'Mark comment as unresolved'
|
|
3155
|
-
complete -c ${name} -n '__fish_seen_subcommand_from comment-edit' -l json -d 'Force JSON output'
|
|
3156
|
-
|
|
3157
|
-
complete -c ${name} -n '__fish_seen_subcommand_from docs' -l json -d 'Force JSON output'
|
|
3158
|
-
|
|
3159
|
-
complete -c ${name} -n '__fish_seen_subcommand_from doc' -l json -d 'Force JSON output'
|
|
3160
|
-
|
|
3161
|
-
complete -c ${name} -n '__fish_seen_subcommand_from doc-pages' -l json -d 'Force JSON output'
|
|
3162
|
-
|
|
3163
|
-
complete -c ${name} -n '__fish_seen_subcommand_from tags' -l json -d 'Force JSON output'
|
|
3164
|
-
|
|
3165
|
-
complete -c ${name} -n '__fish_seen_subcommand_from tag-create' -l fg -d 'Foreground color'
|
|
3166
|
-
complete -c ${name} -n '__fish_seen_subcommand_from tag-create' -l bg -d 'Background color'
|
|
3167
|
-
complete -c ${name} -n '__fish_seen_subcommand_from tag-create' -l json -d 'Force JSON output'
|
|
3168
|
-
|
|
3169
|
-
complete -c ${name} -n '__fish_seen_subcommand_from tag-delete' -l json -d 'Force JSON output'
|
|
3170
|
-
|
|
3171
|
-
complete -c ${name} -n '__fish_seen_subcommand_from members' -l json -d 'Force JSON output'
|
|
3172
|
-
|
|
3173
|
-
complete -c ${name} -n '__fish_seen_subcommand_from fields' -l json -d 'Force JSON output'
|
|
3174
|
-
|
|
3175
|
-
complete -c ${name} -n '__fish_seen_subcommand_from duplicate' -l json -d 'Force JSON output'
|
|
3176
|
-
|
|
3177
3725
|
complete -c ${name} -n '__fish_seen_subcommand_from bulk; and not __fish_seen_subcommand_from status' -a status -d 'Update status of multiple tasks'
|
|
3178
3726
|
complete -c ${name} -n '__fish_seen_subcommand_from status; and __fish_seen_subcommand_from bulk' -l json -d 'Force JSON output'
|
|
3179
3727
|
|
|
3180
|
-
complete -c ${name} -n '__fish_seen_subcommand_from goals' -l json -d 'Force JSON output'
|
|
3181
|
-
|
|
3182
|
-
complete -c ${name} -n '__fish_seen_subcommand_from goal-create' -s d -l description -d 'Goal description'
|
|
3183
|
-
complete -c ${name} -n '__fish_seen_subcommand_from goal-create' -l color -d 'Goal color'
|
|
3184
|
-
complete -c ${name} -n '__fish_seen_subcommand_from goal-create' -l json -d 'Force JSON output'
|
|
3185
|
-
|
|
3186
|
-
complete -c ${name} -n '__fish_seen_subcommand_from goal-update' -s n -l name -d 'New goal name'
|
|
3187
|
-
complete -c ${name} -n '__fish_seen_subcommand_from goal-update' -s d -l description -d 'New description'
|
|
3188
|
-
complete -c ${name} -n '__fish_seen_subcommand_from goal-update' -l color -d 'New color'
|
|
3189
|
-
complete -c ${name} -n '__fish_seen_subcommand_from goal-update' -l json -d 'Force JSON output'
|
|
3190
|
-
|
|
3191
|
-
complete -c ${name} -n '__fish_seen_subcommand_from key-results' -l json -d 'Force JSON output'
|
|
3192
|
-
|
|
3193
|
-
complete -c ${name} -n '__fish_seen_subcommand_from key-result-create' -l type -d 'Key result type' -a 'number percentage'
|
|
3194
|
-
complete -c ${name} -n '__fish_seen_subcommand_from key-result-create' -l target -d 'Target value'
|
|
3195
|
-
complete -c ${name} -n '__fish_seen_subcommand_from key-result-create' -l json -d 'Force JSON output'
|
|
3196
|
-
|
|
3197
|
-
complete -c ${name} -n '__fish_seen_subcommand_from key-result-update' -l progress -d 'Current progress'
|
|
3198
|
-
complete -c ${name} -n '__fish_seen_subcommand_from key-result-update' -l note -d 'Progress note'
|
|
3199
|
-
complete -c ${name} -n '__fish_seen_subcommand_from key-result-update' -l json -d 'Force JSON output'
|
|
3200
|
-
|
|
3201
|
-
complete -c ${name} -n '__fish_seen_subcommand_from folders' -l name -d 'Filter by folder name'
|
|
3202
|
-
complete -c ${name} -n '__fish_seen_subcommand_from folders' -l json -d 'Force JSON output'
|
|
3203
|
-
|
|
3204
|
-
complete -c ${name} -n '__fish_seen_subcommand_from doc-create' -s c -l content -d 'Initial content'
|
|
3205
|
-
complete -c ${name} -n '__fish_seen_subcommand_from doc-create' -l json -d 'Force JSON output'
|
|
3206
|
-
|
|
3207
|
-
complete -c ${name} -n '__fish_seen_subcommand_from doc-page-create' -s c -l content -d 'Page content'
|
|
3208
|
-
complete -c ${name} -n '__fish_seen_subcommand_from doc-page-create' -l parent-page -d 'Parent page ID'
|
|
3209
|
-
complete -c ${name} -n '__fish_seen_subcommand_from doc-page-create' -l json -d 'Force JSON output'
|
|
3210
|
-
|
|
3211
|
-
complete -c ${name} -n '__fish_seen_subcommand_from doc-page-edit' -l name -d 'New page name'
|
|
3212
|
-
complete -c ${name} -n '__fish_seen_subcommand_from doc-page-edit' -s c -l content -d 'New page content'
|
|
3213
|
-
complete -c ${name} -n '__fish_seen_subcommand_from doc-page-edit' -l json -d 'Force JSON output'
|
|
3214
|
-
|
|
3215
3728
|
complete -c ${name} -n '__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from get set path' -a get -d 'Print a config value'
|
|
3216
3729
|
complete -c ${name} -n '__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from get set path' -a set -d 'Set a config value'
|
|
3217
3730
|
complete -c ${name} -n '__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from get set path' -a path -d 'Print config file path'
|
|
@@ -3699,6 +4212,14 @@ async function editDocPage(config, docId, pageId, updates) {
|
|
|
3699
4212
|
const client = new ClickUpClient(config);
|
|
3700
4213
|
return client.editDocPage(config.teamId, docId, pageId, updates);
|
|
3701
4214
|
}
|
|
4215
|
+
async function deleteDoc(config, docId) {
|
|
4216
|
+
const client = new ClickUpClient(config);
|
|
4217
|
+
await client.deleteDoc(config.teamId, docId);
|
|
4218
|
+
}
|
|
4219
|
+
async function deleteDocPage(config, docId, pageId) {
|
|
4220
|
+
const client = new ClickUpClient(config);
|
|
4221
|
+
await client.deleteDocPage(config.teamId, docId, pageId);
|
|
4222
|
+
}
|
|
3702
4223
|
|
|
3703
4224
|
// src/commands/folders.ts
|
|
3704
4225
|
import chalk9 from "chalk";
|
|
@@ -3826,6 +4347,14 @@ async function deleteSpaceTag(config, spaceId, tagName) {
|
|
|
3826
4347
|
const client = new ClickUpClient(config);
|
|
3827
4348
|
await client.deleteSpaceTag(spaceId, tagName);
|
|
3828
4349
|
}
|
|
4350
|
+
async function updateSpaceTag(config, spaceId, tagName, updates) {
|
|
4351
|
+
const client = new ClickUpClient(config);
|
|
4352
|
+
await client.updateSpaceTag(spaceId, tagName, {
|
|
4353
|
+
name: updates.name,
|
|
4354
|
+
tag_fg: updates.fg,
|
|
4355
|
+
tag_bg: updates.bg
|
|
4356
|
+
});
|
|
4357
|
+
}
|
|
3829
4358
|
function formatTags(tags) {
|
|
3830
4359
|
if (tags.length === 0) return "No tags found";
|
|
3831
4360
|
return tags.map((t) => chalk11.bold(t.name)).join(", ");
|
|
@@ -3874,6 +4403,7 @@ function formatFieldsMarkdown(fields) {
|
|
|
3874
4403
|
}
|
|
3875
4404
|
|
|
3876
4405
|
// src/commands/duplicate.ts
|
|
4406
|
+
var PRIORITY_MAP2 = { urgent: 1, high: 2, normal: 3, low: 4 };
|
|
3877
4407
|
async function duplicateTask(config, taskId) {
|
|
3878
4408
|
const client = new ClickUpClient(config);
|
|
3879
4409
|
const task = await client.getTask(taskId);
|
|
@@ -3881,7 +4411,7 @@ async function duplicateTask(config, taskId) {
|
|
|
3881
4411
|
name: `${task.name} (copy)`,
|
|
3882
4412
|
description: task.description,
|
|
3883
4413
|
markdown_content: task.markdown_content,
|
|
3884
|
-
priority: task.priority ?
|
|
4414
|
+
priority: task.priority ? PRIORITY_MAP2[task.priority.priority.toLowerCase()] : void 0,
|
|
3885
4415
|
tags: task.tags?.map((t) => t.name),
|
|
3886
4416
|
time_estimate: task.time_estimate ?? void 0
|
|
3887
4417
|
});
|
|
@@ -3895,8 +4425,9 @@ async function bulkUpdateStatus(config, taskIds, status) {
|
|
|
3895
4425
|
for (const id of taskIds) {
|
|
3896
4426
|
try {
|
|
3897
4427
|
await client.updateTask(id, { status });
|
|
3898
|
-
} catch {
|
|
3899
|
-
|
|
4428
|
+
} catch (err) {
|
|
4429
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
4430
|
+
failed.push({ id, reason });
|
|
3900
4431
|
}
|
|
3901
4432
|
}
|
|
3902
4433
|
return { updated: taskIds.length - failed.length, failed };
|
|
@@ -3916,6 +4447,14 @@ async function updateGoal(config, goalId, updates) {
|
|
|
3916
4447
|
const client = new ClickUpClient(config);
|
|
3917
4448
|
return client.updateGoal(goalId, updates);
|
|
3918
4449
|
}
|
|
4450
|
+
async function deleteGoal(config, goalId) {
|
|
4451
|
+
const client = new ClickUpClient(config);
|
|
4452
|
+
await client.deleteGoal(goalId);
|
|
4453
|
+
}
|
|
4454
|
+
async function deleteKeyResult(config, keyResultId) {
|
|
4455
|
+
const client = new ClickUpClient(config);
|
|
4456
|
+
await client.deleteKeyResult(keyResultId);
|
|
4457
|
+
}
|
|
3919
4458
|
async function listKeyResults(config, goalId) {
|
|
3920
4459
|
const client = new ClickUpClient(config);
|
|
3921
4460
|
return client.getKeyResults(goalId);
|
|
@@ -3962,892 +4501,1042 @@ function formatKeyResultsMarkdown(keyResults) {
|
|
|
3962
4501
|
}).join("\n");
|
|
3963
4502
|
}
|
|
3964
4503
|
|
|
4504
|
+
// src/commands/task-types.ts
|
|
4505
|
+
import chalk15 from "chalk";
|
|
4506
|
+
async function listTaskTypes(config) {
|
|
4507
|
+
const client = new ClickUpClient(config);
|
|
4508
|
+
return client.getCustomTaskTypes(config.teamId);
|
|
4509
|
+
}
|
|
4510
|
+
function formatTaskTypes(types) {
|
|
4511
|
+
if (types.length === 0) return "No custom task types";
|
|
4512
|
+
return types.map((t) => `${chalk15.bold(t.name)} ${chalk15.dim(`(${t.id})`)}`).join("\n");
|
|
4513
|
+
}
|
|
4514
|
+
function formatTaskTypesMarkdown(types) {
|
|
4515
|
+
if (types.length === 0) return "No custom task types";
|
|
4516
|
+
return types.map((t) => `- **${t.name}** (${t.id})`).join("\n");
|
|
4517
|
+
}
|
|
4518
|
+
|
|
4519
|
+
// src/commands/templates.ts
|
|
4520
|
+
import chalk16 from "chalk";
|
|
4521
|
+
async function listTemplates(config) {
|
|
4522
|
+
const client = new ClickUpClient(config);
|
|
4523
|
+
return client.getTaskTemplates(config.teamId);
|
|
4524
|
+
}
|
|
4525
|
+
function formatTemplates(templates) {
|
|
4526
|
+
if (templates.length === 0) return "No task templates";
|
|
4527
|
+
return templates.map((t) => `${chalk16.bold(t.name)} ${chalk16.dim(`(${t.id})`)}`).join("\n");
|
|
4528
|
+
}
|
|
4529
|
+
function formatTemplatesMarkdown(templates) {
|
|
4530
|
+
if (templates.length === 0) return "No task templates";
|
|
4531
|
+
return templates.map((t) => `- **${t.name}** (${t.id})`).join("\n");
|
|
4532
|
+
}
|
|
4533
|
+
|
|
3965
4534
|
// src/index.ts
|
|
3966
4535
|
var require2 = createRequire(import.meta.url);
|
|
3967
4536
|
var { version } = require2("../package.json");
|
|
3968
|
-
var programName = basename(process.argv[1] ?? "cup");
|
|
3969
4537
|
function wrapAction(fn) {
|
|
3970
|
-
return (...args) => {
|
|
3971
|
-
fn(...args).catch((err) => {
|
|
4538
|
+
return async (...args) => {
|
|
4539
|
+
await fn(...args).catch((err) => {
|
|
3972
4540
|
console.error(err instanceof Error ? err.message : String(err));
|
|
3973
4541
|
process.exit(1);
|
|
3974
4542
|
});
|
|
3975
4543
|
};
|
|
3976
4544
|
}
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
}
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
}
|
|
3995
|
-
})
|
|
3996
|
-
);
|
|
3997
|
-
program.command("tasks").description("List tasks assigned to me").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(
|
|
3998
|
-
"--type <type>",
|
|
3999
|
-
'Filter by task type (e.g. "task", "initiative", or custom type name/ID)'
|
|
4000
|
-
).option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").action(
|
|
4001
|
-
wrapAction(async (opts) => {
|
|
4002
|
-
const config = loadConfig();
|
|
4003
|
-
const tasks = await fetchMyTasks(config, {
|
|
4004
|
-
typeFilter: opts.type,
|
|
4005
|
-
statuses: opts.status ? [opts.status] : void 0,
|
|
4006
|
-
listIds: opts.list ? [opts.list] : void 0,
|
|
4007
|
-
spaceIds: opts.space ? [opts.space] : void 0,
|
|
4008
|
-
name: opts.name,
|
|
4009
|
-
includeClosed: opts.includeClosed
|
|
4010
|
-
});
|
|
4011
|
-
await printTasks(tasks, opts.json ?? false, config);
|
|
4012
|
-
})
|
|
4013
|
-
);
|
|
4014
|
-
program.command("task <taskId>").description("Get task details").option("--json", "Force JSON output even in terminal").action(
|
|
4015
|
-
wrapAction(async (taskId, opts) => {
|
|
4016
|
-
const config = loadConfig();
|
|
4017
|
-
const result = await getTask(config, taskId);
|
|
4018
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4019
|
-
console.log(JSON.stringify(result, null, 2));
|
|
4020
|
-
} else if (!isTTY()) {
|
|
4021
|
-
console.log(formatTaskDetailMarkdown(result));
|
|
4022
|
-
} else {
|
|
4023
|
-
console.log(formatTaskDetail(result));
|
|
4024
|
-
}
|
|
4025
|
-
})
|
|
4026
|
-
);
|
|
4027
|
-
program.command("update <taskId>").description("Update a task").option("-n, --name <text>", "New task name").option("-d, --description <text>", "New description (markdown supported)").option("-s, --status <status>", 'New status (e.g. "in progress", "done")').option("--priority <level>", "Priority: urgent, high, normal, low (or 1-4)").option("--due-date <date>", "Due date (YYYY-MM-DD)").option("--time-estimate <duration>", 'Time estimate (e.g. "2h", "30m", "1h30m")').option("--assignee <userId>", 'Add assignee by user ID or "me"').option("--parent <taskId>", "Set parent task (makes this a subtask)").option("--json", "Force JSON output even in terminal").action(
|
|
4028
|
-
wrapAction(async (taskId, opts) => {
|
|
4029
|
-
const config = loadConfig();
|
|
4030
|
-
if (opts.assignee === "me") {
|
|
4031
|
-
const client = new ClickUpClient(config);
|
|
4032
|
-
opts.assignee = String(await resolveAssigneeId(client, "me"));
|
|
4033
|
-
}
|
|
4034
|
-
const payload = buildUpdatePayload(opts);
|
|
4035
|
-
const result = await updateTask(config, taskId, payload);
|
|
4036
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4037
|
-
console.log(JSON.stringify(result, null, 2));
|
|
4038
|
-
} else {
|
|
4039
|
-
console.log(formatUpdateConfirmation(result.id, result.name));
|
|
4040
|
-
}
|
|
4041
|
-
})
|
|
4042
|
-
);
|
|
4043
|
-
program.command("create").description("Create a new task").option("-l, --list <listId>", "Target list ID (auto-detected from --parent if omitted)").requiredOption("-n, --name <name>", "Task name").option("-d, --description <text>", "Task description (markdown supported)").option("-p, --parent <taskId>", "Parent task ID (list auto-detected from parent)").option("-s, --status <status>", "Initial status").option("--priority <level>", "Priority: urgent, high, normal, low (or 1-4)").option("--due-date <date>", "Due date (YYYY-MM-DD)").option("--assignee <userId>", 'Assignee user ID or "me"').option("--tags <tags>", "Comma-separated tag names").option("--custom-item-id <id>", "Custom task type ID (use to create initiatives)").option("--time-estimate <duration>", 'Time estimate (e.g. "2h", "30m", "1h30m")').option("--json", "Force JSON output even in terminal").action(
|
|
4044
|
-
wrapAction(async (opts) => {
|
|
4045
|
-
const config = loadConfig();
|
|
4046
|
-
if (opts.assignee === "me") {
|
|
4047
|
-
const client = new ClickUpClient(config);
|
|
4048
|
-
opts.assignee = String(await resolveAssigneeId(client, "me"));
|
|
4049
|
-
}
|
|
4050
|
-
const result = await createTask(config, opts);
|
|
4051
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4052
|
-
console.log(JSON.stringify(result, null, 2));
|
|
4053
|
-
} else {
|
|
4054
|
-
console.log(formatCreateConfirmation(result.id, result.name, result.url));
|
|
4055
|
-
}
|
|
4056
|
-
})
|
|
4057
|
-
);
|
|
4058
|
-
program.command("sprint").description("List my tasks in the current active sprint (auto-detected)").option("--status <status>", "Filter by status").option("--space <nameOrId>", "Narrow sprint search to a specific space (partial name or ID)").option("--folder <folderId>", "Sprint folder ID (overrides config and auto-detection)").option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").action(
|
|
4059
|
-
wrapAction(
|
|
4060
|
-
async (opts) => {
|
|
4545
|
+
function parseOptionalNumberOption(value, optionName) {
|
|
4546
|
+
const parsed = Number(value);
|
|
4547
|
+
if (!Number.isFinite(parsed)) {
|
|
4548
|
+
throw new Error(`${optionName} must be a number or "null"`);
|
|
4549
|
+
}
|
|
4550
|
+
return parsed;
|
|
4551
|
+
}
|
|
4552
|
+
function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
4553
|
+
const program = new Command();
|
|
4554
|
+
program.name(programName).description("ClickUp CLI for AI agents").version(version).allowExcessArguments(false);
|
|
4555
|
+
program.command("init").description(`Set up ${programName} for the first time`).action(
|
|
4556
|
+
wrapAction(async () => {
|
|
4557
|
+
await runInitCommand();
|
|
4558
|
+
})
|
|
4559
|
+
);
|
|
4560
|
+
program.command("auth").description("Validate API token and show current user").option("--json", "Force JSON output even in terminal").action(
|
|
4561
|
+
wrapAction(async (opts) => {
|
|
4061
4562
|
const config = loadConfig();
|
|
4062
|
-
await
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
)
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
);
|
|
4072
|
-
program.command("
|
|
4073
|
-
|
|
4074
|
-
|
|
4563
|
+
const result = await checkAuth(config);
|
|
4564
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4565
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4566
|
+
} else if (result.authenticated && result.user) {
|
|
4567
|
+
console.log(`Authenticated as @${result.user.username} (id: ${result.user.id})`);
|
|
4568
|
+
} else {
|
|
4569
|
+
throw new Error(`Authentication failed: ${result.error ?? "unknown error"}`);
|
|
4570
|
+
}
|
|
4571
|
+
})
|
|
4572
|
+
);
|
|
4573
|
+
program.command("tasks").description("List tasks assigned to me").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(
|
|
4574
|
+
"--type <type>",
|
|
4575
|
+
'Filter by task type (e.g. "task", "initiative", or custom type name/ID)'
|
|
4576
|
+
).option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").action(
|
|
4577
|
+
wrapAction(async (opts) => {
|
|
4578
|
+
const config = loadConfig();
|
|
4579
|
+
const tasks = await fetchMyTasks(config, {
|
|
4580
|
+
typeFilter: opts.type,
|
|
4581
|
+
statuses: opts.status ? [opts.status] : void 0,
|
|
4582
|
+
listIds: opts.list ? [opts.list] : void 0,
|
|
4583
|
+
spaceIds: opts.space ? [opts.space] : void 0,
|
|
4584
|
+
name: opts.name,
|
|
4585
|
+
includeClosed: opts.includeClosed
|
|
4586
|
+
});
|
|
4587
|
+
await printTasks(tasks, opts.json ?? false, config);
|
|
4588
|
+
})
|
|
4589
|
+
);
|
|
4590
|
+
program.command("task <taskId>").description("Get task details").option("--json", "Force JSON output even in terminal").action(
|
|
4591
|
+
wrapAction(async (taskId, opts) => {
|
|
4592
|
+
const config = loadConfig();
|
|
4593
|
+
const result = await getTask(config, taskId);
|
|
4594
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4595
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4596
|
+
} else if (!isTTY()) {
|
|
4597
|
+
console.log(formatTaskDetailMarkdown(result));
|
|
4598
|
+
} else {
|
|
4599
|
+
console.log(formatTaskDetail(result));
|
|
4600
|
+
}
|
|
4601
|
+
})
|
|
4602
|
+
);
|
|
4603
|
+
program.command("update <taskId>").description("Update a task").option("-n, --name <text>", "New task name").option("-d, --description <text>", "New description (markdown supported)").option("-s, --status <status>", 'New status (e.g. "in progress", "done")').option("--priority <level>", "Priority: urgent, high, normal, low (or 1-4)").option("--due-date <date>", "Due date (YYYY-MM-DD)").option("--time-estimate <duration>", 'Time estimate (e.g. "2h", "30m", "1h30m")').option("--assignee <userId>", 'Add assignee by user ID or "me"').option("--parent <taskId>", "Set parent task (makes this a subtask)").option("--json", "Force JSON output even in terminal").action(
|
|
4604
|
+
wrapAction(async (taskId, opts) => {
|
|
4075
4605
|
const config = loadConfig();
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
tasks = tasks.filter((t) => t.status.toLowerCase() === lower);
|
|
4606
|
+
if (opts.assignee === "me") {
|
|
4607
|
+
const client = new ClickUpClient(config);
|
|
4608
|
+
opts.assignee = String(await resolveAssigneeId(client, "me"));
|
|
4080
4609
|
}
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4610
|
+
const payload = buildUpdatePayload(opts);
|
|
4611
|
+
const result = await updateTask(config, taskId, payload);
|
|
4612
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4613
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4614
|
+
} else {
|
|
4615
|
+
console.log(formatUpdateConfirmation(result.id, result.name));
|
|
4084
4616
|
}
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
)
|
|
4088
|
-
)
|
|
4089
|
-
program.command("comment <taskId>").description("Post a comment on a task").requiredOption("-m, --message <text>", "Comment text").option("--notify-all", "Notify all assignees").option("--json", "Force JSON output even in terminal").action(
|
|
4090
|
-
wrapAction(
|
|
4091
|
-
async (taskId, opts) => {
|
|
4617
|
+
})
|
|
4618
|
+
);
|
|
4619
|
+
program.command("create").description("Create a new task").option("-l, --list <listId>", "Target list ID (auto-detected from --parent if omitted)").requiredOption("-n, --name <name>", "Task name").option("-d, --description <text>", "Task description (markdown supported)").option("-p, --parent <taskId>", "Parent task ID (list auto-detected from parent)").option("-s, --status <status>", "Initial status").option("--priority <level>", "Priority: urgent, high, normal, low (or 1-4)").option("--due-date <date>", "Due date (YYYY-MM-DD)").option("--assignee <userId>", 'Assignee user ID or "me"').option("--tags <tags>", "Comma-separated tag names").option("--custom-item-id <id>", "Custom task type ID (use to create initiatives)").option("--time-estimate <duration>", 'Time estimate (e.g. "2h", "30m", "1h30m")').option("--template <id>", "Create from a task template").option("--json", "Force JSON output even in terminal").action(
|
|
4620
|
+
wrapAction(async (opts) => {
|
|
4092
4621
|
const config = loadConfig();
|
|
4093
|
-
|
|
4622
|
+
if (opts.assignee === "me") {
|
|
4623
|
+
const client = new ClickUpClient(config);
|
|
4624
|
+
opts.assignee = String(await resolveAssigneeId(client, "me"));
|
|
4625
|
+
}
|
|
4626
|
+
const result = await createTask(config, opts);
|
|
4094
4627
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4095
4628
|
console.log(JSON.stringify(result, null, 2));
|
|
4096
4629
|
} else {
|
|
4097
|
-
console.log(
|
|
4630
|
+
console.log(formatCreateConfirmation(result.id, result.name, result.url));
|
|
4098
4631
|
}
|
|
4099
|
-
}
|
|
4100
|
-
)
|
|
4101
|
-
)
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
);
|
|
4109
|
-
program.command("
|
|
4110
|
-
|
|
4111
|
-
async (commentId, opts) => {
|
|
4632
|
+
})
|
|
4633
|
+
);
|
|
4634
|
+
program.command("sprint").description("List my tasks in the current active sprint (auto-detected)").option("--status <status>", "Filter by status").option("--space <nameOrId>", "Narrow sprint search to a specific space (partial name or ID)").option("--folder <folderId>", "Sprint folder ID (overrides config and auto-detection)").option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").action(
|
|
4635
|
+
wrapAction(
|
|
4636
|
+
async (opts) => {
|
|
4637
|
+
const config = loadConfig();
|
|
4638
|
+
await runSprintCommand(config, opts);
|
|
4639
|
+
}
|
|
4640
|
+
)
|
|
4641
|
+
);
|
|
4642
|
+
program.command("sprints").description("List all sprints in sprint folders").option("--space <nameOrId>", "Filter by space (partial name or ID)").option("--json", "Force JSON output even in terminal").action(
|
|
4643
|
+
wrapAction(async (opts) => {
|
|
4112
4644
|
const config = loadConfig();
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4645
|
+
await listSprints(config, opts);
|
|
4646
|
+
})
|
|
4647
|
+
);
|
|
4648
|
+
program.command("subtasks <taskId>").description("List subtasks of a task or initiative").option("--status <status>", "Filter by status").option("--name <partial>", "Filter by name (case-insensitive contains)").option("--include-closed", "Include closed/done subtasks").option("--json", "Force JSON output even in terminal").action(
|
|
4649
|
+
wrapAction(
|
|
4650
|
+
async (taskId, opts) => {
|
|
4651
|
+
const config = loadConfig();
|
|
4652
|
+
let tasks = await fetchSubtasks(config, taskId, { includeClosed: opts.includeClosed });
|
|
4653
|
+
if (opts.status) {
|
|
4654
|
+
const lower = opts.status.toLowerCase();
|
|
4655
|
+
tasks = tasks.filter((t) => t.status.toLowerCase() === lower);
|
|
4656
|
+
}
|
|
4657
|
+
if (opts.name) {
|
|
4658
|
+
const query = opts.name.toLowerCase();
|
|
4659
|
+
tasks = tasks.filter((t) => t.name.toLowerCase().includes(query));
|
|
4660
|
+
}
|
|
4661
|
+
await printTasks(tasks, opts.json ?? false, config);
|
|
4662
|
+
}
|
|
4663
|
+
)
|
|
4664
|
+
);
|
|
4665
|
+
program.command("comment <taskId>").description("Post a comment on a task").requiredOption("-m, --message <text>", "Comment text").option("--notify-all", "Notify all assignees").option("--json", "Force JSON output even in terminal").action(
|
|
4666
|
+
wrapAction(
|
|
4667
|
+
async (taskId, opts) => {
|
|
4668
|
+
const config = loadConfig();
|
|
4669
|
+
const result = await postComment(config, taskId, opts.message, opts.notifyAll);
|
|
4670
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4671
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4672
|
+
} else {
|
|
4673
|
+
console.log(formatCommentConfirmation(result.id));
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4676
|
+
)
|
|
4677
|
+
);
|
|
4678
|
+
program.command("comments <taskId>").description("List comments on a task").option("--json", "Force JSON output even in terminal").action(
|
|
4679
|
+
wrapAction(async (taskId, opts) => {
|
|
4680
|
+
const config = loadConfig();
|
|
4681
|
+
const comments = await fetchComments(config, taskId);
|
|
4682
|
+
printComments(comments, opts.json ?? false);
|
|
4683
|
+
})
|
|
4684
|
+
);
|
|
4685
|
+
program.command("comment-edit <commentId>").description("Edit an existing comment").requiredOption("-m, --message <text>", "New comment text").option("--resolved", "Mark comment as resolved").option("--unresolved", "Mark comment as unresolved").option("--json", "Force JSON output even in terminal").action(
|
|
4686
|
+
wrapAction(
|
|
4687
|
+
async (commentId, opts) => {
|
|
4688
|
+
const config = loadConfig();
|
|
4689
|
+
let resolved;
|
|
4690
|
+
if (opts.resolved) resolved = true;
|
|
4691
|
+
if (opts.unresolved) resolved = false;
|
|
4692
|
+
await editComment(config, commentId, opts.message, resolved);
|
|
4693
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4694
|
+
console.log(JSON.stringify({ success: true, commentId }, null, 2));
|
|
4695
|
+
} else {
|
|
4696
|
+
console.log(`Comment ${commentId} updated`);
|
|
4697
|
+
}
|
|
4698
|
+
}
|
|
4699
|
+
)
|
|
4700
|
+
);
|
|
4701
|
+
program.command("comment-delete <commentId>").description("Delete a comment").option("--json", "Force JSON output even in terminal").action(
|
|
4702
|
+
wrapAction(async (commentId, opts) => {
|
|
4703
|
+
const config = loadConfig();
|
|
4704
|
+
await deleteComment(config, commentId);
|
|
4117
4705
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4118
4706
|
console.log(JSON.stringify({ success: true, commentId }, null, 2));
|
|
4119
4707
|
} else {
|
|
4120
|
-
console.log(`
|
|
4708
|
+
console.log(`Deleted comment ${commentId}`);
|
|
4121
4709
|
}
|
|
4122
|
-
}
|
|
4123
|
-
)
|
|
4124
|
-
)
|
|
4125
|
-
|
|
4126
|
-
wrapAction(async (commentId, opts) => {
|
|
4127
|
-
const config = loadConfig();
|
|
4128
|
-
await deleteComment(config, commentId);
|
|
4129
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4130
|
-
console.log(JSON.stringify({ success: true, commentId }, null, 2));
|
|
4131
|
-
} else {
|
|
4132
|
-
console.log(`Deleted comment ${commentId}`);
|
|
4133
|
-
}
|
|
4134
|
-
})
|
|
4135
|
-
);
|
|
4136
|
-
program.command("replies <commentId>").description("List threaded replies on a comment").option("--json", "Force JSON output even in terminal").action(
|
|
4137
|
-
wrapAction(async (commentId, opts) => {
|
|
4138
|
-
const config = loadConfig();
|
|
4139
|
-
const replies = await getReplies(config, commentId);
|
|
4140
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4141
|
-
console.log(JSON.stringify(replies, null, 2));
|
|
4142
|
-
} else if (isTTY()) {
|
|
4143
|
-
console.log(formatReplies(replies));
|
|
4144
|
-
} else {
|
|
4145
|
-
console.log(formatRepliesMarkdown(replies));
|
|
4146
|
-
}
|
|
4147
|
-
})
|
|
4148
|
-
);
|
|
4149
|
-
program.command("reply <commentId>").description("Reply to a comment").requiredOption("-m, --message <text>", "Reply text").option("--notify-all", "Notify all assignees").option("--json", "Force JSON output even in terminal").action(
|
|
4150
|
-
wrapAction(
|
|
4151
|
-
async (commentId, opts) => {
|
|
4710
|
+
})
|
|
4711
|
+
);
|
|
4712
|
+
program.command("replies <commentId>").description("List threaded replies on a comment").option("--json", "Force JSON output even in terminal").action(
|
|
4713
|
+
wrapAction(async (commentId, opts) => {
|
|
4152
4714
|
const config = loadConfig();
|
|
4153
|
-
await
|
|
4715
|
+
const replies = await getReplies(config, commentId);
|
|
4154
4716
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4155
|
-
console.log(JSON.stringify(
|
|
4717
|
+
console.log(JSON.stringify(replies, null, 2));
|
|
4718
|
+
} else if (isTTY()) {
|
|
4719
|
+
console.log(formatReplies(replies));
|
|
4156
4720
|
} else {
|
|
4157
|
-
console.log(
|
|
4721
|
+
console.log(formatRepliesMarkdown(replies));
|
|
4158
4722
|
}
|
|
4159
|
-
}
|
|
4160
|
-
)
|
|
4161
|
-
)
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
)
|
|
4176
|
-
program.command("spaces").description("List spaces in your workspace").option("--name <partial>", "Filter spaces by name (case-insensitive contains)").option("--my", "Show only spaces where I have assigned tasks").option("--json", "Force JSON output even in terminal").action(
|
|
4177
|
-
wrapAction(async (opts) => {
|
|
4178
|
-
const config = loadConfig();
|
|
4179
|
-
await listSpaces(config, opts);
|
|
4180
|
-
})
|
|
4181
|
-
);
|
|
4182
|
-
program.command("inbox").description("Recently updated tasks grouped by time period").option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").option("--days <n>", "Lookback period in days", "30").action(
|
|
4183
|
-
wrapAction(async (opts) => {
|
|
4184
|
-
const config = loadConfig();
|
|
4185
|
-
const days = Number(opts.days ?? 30);
|
|
4186
|
-
if (!Number.isFinite(days) || days <= 0) {
|
|
4187
|
-
throw new Error("--days must be a positive number");
|
|
4188
|
-
}
|
|
4189
|
-
const tasks = await fetchInbox(config, days, { includeClosed: opts.includeClosed });
|
|
4190
|
-
await printInbox(tasks, opts.json ?? false, config);
|
|
4191
|
-
})
|
|
4192
|
-
);
|
|
4193
|
-
program.command("assigned").description("Show all tasks assigned to me, grouped by status").option("--status <status>", "Show only tasks with this status").option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").action(
|
|
4194
|
-
wrapAction(async (opts) => {
|
|
4195
|
-
const config = loadConfig();
|
|
4196
|
-
await runAssignedCommand(config, opts);
|
|
4197
|
-
})
|
|
4198
|
-
);
|
|
4199
|
-
program.command("open <query>").description("Open a task in the browser by ID or name").option("--json", "Output task JSON instead of opening").action(
|
|
4200
|
-
wrapAction(async (query, opts) => {
|
|
4201
|
-
const config = loadConfig();
|
|
4202
|
-
await openTask(config, query, opts);
|
|
4203
|
-
})
|
|
4204
|
-
);
|
|
4205
|
-
program.command("search <query>").description("Search my tasks by name").option("--status <status>", "Filter by status").option("--include-closed", "Include done/closed tasks in search").option("--json", "Force JSON output even in terminal").action(
|
|
4206
|
-
wrapAction(
|
|
4207
|
-
async (query, opts) => {
|
|
4723
|
+
})
|
|
4724
|
+
);
|
|
4725
|
+
program.command("reply <commentId>").description("Reply to a comment").requiredOption("-m, --message <text>", "Reply text").option("--notify-all", "Notify all assignees").option("--json", "Force JSON output even in terminal").action(
|
|
4726
|
+
wrapAction(
|
|
4727
|
+
async (commentId, opts) => {
|
|
4728
|
+
const config = loadConfig();
|
|
4729
|
+
await createReply(config, commentId, opts.message, opts.notifyAll);
|
|
4730
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4731
|
+
console.log(JSON.stringify({ success: true, commentId }, null, 2));
|
|
4732
|
+
} else {
|
|
4733
|
+
console.log(`Replied to comment ${commentId}`);
|
|
4734
|
+
}
|
|
4735
|
+
}
|
|
4736
|
+
)
|
|
4737
|
+
);
|
|
4738
|
+
program.command("activity <taskId>").description("Show task details and comments combined").option("--json", "Force JSON output even in terminal").action(
|
|
4739
|
+
wrapAction(async (taskId, opts) => {
|
|
4208
4740
|
const config = loadConfig();
|
|
4209
|
-
const
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4741
|
+
const result = await fetchActivity(config, taskId);
|
|
4742
|
+
printActivity(result, opts.json ?? false);
|
|
4743
|
+
})
|
|
4744
|
+
);
|
|
4745
|
+
program.command("lists <spaceId>").description("List all lists in a space (including lists inside folders)").option("--name <partial>", "Filter by name (case-insensitive contains)").option("--json", "Force JSON output even in terminal").action(
|
|
4746
|
+
wrapAction(async (spaceId, opts) => {
|
|
4747
|
+
const config = loadConfig();
|
|
4748
|
+
const lists = await fetchLists(config, spaceId, { name: opts.name });
|
|
4749
|
+
printLists(lists, opts.json ?? false);
|
|
4750
|
+
})
|
|
4751
|
+
);
|
|
4752
|
+
program.command("spaces").description("List spaces in your workspace").option("--name <partial>", "Filter spaces by name (case-insensitive contains)").option("--my", "Show only spaces where I have assigned tasks").option("--json", "Force JSON output even in terminal").action(
|
|
4753
|
+
wrapAction(async (opts) => {
|
|
4754
|
+
const config = loadConfig();
|
|
4755
|
+
await listSpaces(config, opts);
|
|
4756
|
+
})
|
|
4757
|
+
);
|
|
4758
|
+
program.command("inbox").description("Recently updated tasks grouped by time period").option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").option("--days <n>", "Lookback period in days", "30").action(
|
|
4759
|
+
wrapAction(async (opts) => {
|
|
4760
|
+
const config = loadConfig();
|
|
4761
|
+
const days = Number(opts.days ?? 30);
|
|
4762
|
+
if (!Number.isFinite(days) || days <= 0) {
|
|
4763
|
+
throw new Error("--days must be a positive number");
|
|
4764
|
+
}
|
|
4765
|
+
const tasks = await fetchInbox(config, days, { includeClosed: opts.includeClosed });
|
|
4766
|
+
await printInbox(tasks, opts.json ?? false, config);
|
|
4767
|
+
})
|
|
4768
|
+
);
|
|
4769
|
+
program.command("assigned").description("Show all tasks assigned to me, grouped by status").option("--status <status>", "Show only tasks with this status").option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").action(
|
|
4770
|
+
wrapAction(async (opts) => {
|
|
4771
|
+
const config = loadConfig();
|
|
4772
|
+
await runAssignedCommand(config, opts);
|
|
4773
|
+
})
|
|
4774
|
+
);
|
|
4775
|
+
program.command("open <query>").description("Open a task in the browser by ID or name").option("--json", "Output task JSON instead of opening").action(
|
|
4776
|
+
wrapAction(async (query, opts) => {
|
|
4777
|
+
const config = loadConfig();
|
|
4778
|
+
await openTask(config, query, opts);
|
|
4779
|
+
})
|
|
4780
|
+
);
|
|
4781
|
+
program.command("search <query>").description("Search my tasks by name").option("--status <status>", "Filter by status").option("--include-closed", "Include done/closed tasks in search").option("--json", "Force JSON output even in terminal").action(
|
|
4782
|
+
wrapAction(
|
|
4783
|
+
async (query, opts) => {
|
|
4784
|
+
const config = loadConfig();
|
|
4785
|
+
const tasks = await searchTasks(config, query, {
|
|
4786
|
+
status: opts.status,
|
|
4787
|
+
includeClosed: opts.includeClosed
|
|
4788
|
+
});
|
|
4789
|
+
await printTasks(tasks, opts.json ?? false, config);
|
|
4790
|
+
}
|
|
4791
|
+
)
|
|
4792
|
+
);
|
|
4793
|
+
program.command("summary").description("Daily standup summary: completed, in-progress, overdue").option("--hours <n>", "Completed-tasks lookback in hours", "24").option("--json", "Force JSON output even in terminal").action(
|
|
4794
|
+
wrapAction(async (opts) => {
|
|
4795
|
+
const config = loadConfig();
|
|
4796
|
+
const hours = Number(opts.hours ?? 24);
|
|
4797
|
+
if (!Number.isFinite(hours) || hours <= 0) {
|
|
4798
|
+
throw new Error("--hours must be a positive number");
|
|
4799
|
+
}
|
|
4800
|
+
await runSummaryCommand(config, { hours, json: opts.json ?? false });
|
|
4801
|
+
})
|
|
4802
|
+
);
|
|
4803
|
+
program.command("overdue").description("List tasks that are past their due date").option("--include-closed", "Include done/closed overdue tasks").option("--json", "Force JSON output even in terminal").action(
|
|
4804
|
+
wrapAction(async (opts) => {
|
|
4805
|
+
const config = loadConfig();
|
|
4806
|
+
const tasks = await fetchOverdueTasks(config, { includeClosed: opts.includeClosed });
|
|
4213
4807
|
await printTasks(tasks, opts.json ?? false, config);
|
|
4214
|
-
}
|
|
4215
|
-
)
|
|
4216
|
-
)
|
|
4217
|
-
|
|
4218
|
-
wrapAction(async (opts) => {
|
|
4219
|
-
const config = loadConfig();
|
|
4220
|
-
const hours = Number(opts.hours ?? 24);
|
|
4221
|
-
if (!Number.isFinite(hours) || hours <= 0) {
|
|
4222
|
-
throw new Error("--hours must be a positive number");
|
|
4223
|
-
}
|
|
4224
|
-
await runSummaryCommand(config, { hours, json: opts.json ?? false });
|
|
4225
|
-
})
|
|
4226
|
-
);
|
|
4227
|
-
program.command("overdue").description("List tasks that are past their due date").option("--include-closed", "Include done/closed overdue tasks").option("--json", "Force JSON output even in terminal").action(
|
|
4228
|
-
wrapAction(async (opts) => {
|
|
4229
|
-
const config = loadConfig();
|
|
4230
|
-
const tasks = await fetchOverdueTasks(config, { includeClosed: opts.includeClosed });
|
|
4231
|
-
await printTasks(tasks, opts.json ?? false, config);
|
|
4232
|
-
})
|
|
4233
|
-
);
|
|
4234
|
-
program.command("assign <taskId>").description("Assign or unassign users from a task").option("--to <userId>", 'Add assignee (user ID or "me")').option("--remove <userId>", 'Remove assignee (user ID or "me")').option("--json", "Force JSON output even in terminal").action(
|
|
4235
|
-
wrapAction(async (taskId, opts) => {
|
|
4236
|
-
const config = loadConfig();
|
|
4237
|
-
const result = await assignTask(config, taskId, opts);
|
|
4238
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4239
|
-
console.log(JSON.stringify(result, null, 2));
|
|
4240
|
-
} else {
|
|
4241
|
-
console.log(formatAssignConfirmation(taskId, { to: opts.to, remove: opts.remove }));
|
|
4242
|
-
}
|
|
4243
|
-
})
|
|
4244
|
-
);
|
|
4245
|
-
program.command("depend <taskId>").description("Add or remove task dependencies").option("--on <taskId>", "Task that this task depends on (waiting on)").option("--blocks <taskId>", "Task that this task blocks").option("--remove", "Remove the dependency instead of adding it").option("--json", "Force JSON output even in terminal").action(
|
|
4246
|
-
wrapAction(async (taskId, opts) => {
|
|
4247
|
-
const config = loadConfig();
|
|
4248
|
-
const message = await manageDependency(config, taskId, opts);
|
|
4249
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4250
|
-
console.log(
|
|
4251
|
-
JSON.stringify(
|
|
4252
|
-
{ taskId, on: opts.on, blocks: opts.blocks, remove: opts.remove, message },
|
|
4253
|
-
null,
|
|
4254
|
-
2
|
|
4255
|
-
)
|
|
4256
|
-
);
|
|
4257
|
-
} else {
|
|
4258
|
-
console.log(message);
|
|
4259
|
-
}
|
|
4260
|
-
})
|
|
4261
|
-
);
|
|
4262
|
-
program.command("link <taskId> <linksTo>").description("Add or remove a link between two tasks").option("--remove", "Remove the link instead of adding it").option("--json", "Force JSON output even in terminal").action(
|
|
4263
|
-
wrapAction(
|
|
4264
|
-
async (taskId, linksTo, opts) => {
|
|
4808
|
+
})
|
|
4809
|
+
);
|
|
4810
|
+
program.command("assign <taskId>").description("Assign or unassign users from a task").option("--to <userId>", 'Add assignee (user ID or "me")').option("--remove <userId>", 'Remove assignee (user ID or "me")').option("--json", "Force JSON output even in terminal").action(
|
|
4811
|
+
wrapAction(async (taskId, opts) => {
|
|
4265
4812
|
const config = loadConfig();
|
|
4266
|
-
const result = await
|
|
4813
|
+
const result = await assignTask(config, taskId, opts);
|
|
4814
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4815
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4816
|
+
} else {
|
|
4817
|
+
console.log(formatAssignConfirmation(taskId, { to: opts.to, remove: opts.remove }));
|
|
4818
|
+
}
|
|
4819
|
+
})
|
|
4820
|
+
);
|
|
4821
|
+
program.command("depend <taskId>").description("Add or remove task dependencies").option("--on <taskId>", "Task that this task depends on (waiting on)").option("--blocks <taskId>", "Task that this task blocks").option("--remove", "Remove the dependency instead of adding it").option("--json", "Force JSON output even in terminal").action(
|
|
4822
|
+
wrapAction(async (taskId, opts) => {
|
|
4823
|
+
const config = loadConfig();
|
|
4824
|
+
const message = await manageDependency(config, taskId, opts);
|
|
4267
4825
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4268
4826
|
console.log(
|
|
4269
4827
|
JSON.stringify(
|
|
4270
|
-
{
|
|
4828
|
+
{ taskId, on: opts.on, blocks: opts.blocks, remove: opts.remove, message },
|
|
4271
4829
|
null,
|
|
4272
4830
|
2
|
|
4273
4831
|
)
|
|
4274
4832
|
);
|
|
4275
4833
|
} else {
|
|
4276
|
-
console.log(
|
|
4834
|
+
console.log(message);
|
|
4277
4835
|
}
|
|
4278
|
-
}
|
|
4279
|
-
)
|
|
4280
|
-
)
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
);
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
const config = loadConfig();
|
|
4296
|
-
const message = await moveTask(config, taskId, opts);
|
|
4297
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4298
|
-
console.log(JSON.stringify({ taskId, to: opts.to, remove: opts.remove, message }, null, 2));
|
|
4299
|
-
} else {
|
|
4300
|
-
console.log(message);
|
|
4301
|
-
}
|
|
4302
|
-
})
|
|
4303
|
-
);
|
|
4304
|
-
program.command("field <taskId>").description("Set or remove a custom field value on a task").option("--set <nameAndValue...>", 'Set field: --set "Field Name" value').option("--remove <fieldName>", "Remove field value by name").option("--json", "Force JSON output even in terminal").action(
|
|
4305
|
-
wrapAction(
|
|
4306
|
-
async (taskId, opts) => {
|
|
4307
|
-
const config = loadConfig();
|
|
4308
|
-
const fieldOpts = {};
|
|
4309
|
-
if (opts.set) {
|
|
4310
|
-
if (opts.set.length !== 2) {
|
|
4311
|
-
throw new Error("--set requires exactly two arguments: field name and value");
|
|
4836
|
+
})
|
|
4837
|
+
);
|
|
4838
|
+
program.command("link <taskId> <linksTo>").description("Add or remove a link between two tasks").option("--remove", "Remove the link instead of adding it").option("--json", "Force JSON output even in terminal").action(
|
|
4839
|
+
wrapAction(
|
|
4840
|
+
async (taskId, linksTo, opts) => {
|
|
4841
|
+
const config = loadConfig();
|
|
4842
|
+
const result = await manageTaskLink(config, taskId, linksTo, opts.remove ?? false);
|
|
4843
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4844
|
+
console.log(
|
|
4845
|
+
JSON.stringify(
|
|
4846
|
+
{ success: true, taskId, linksTo, action: opts.remove ? "removed" : "added" },
|
|
4847
|
+
null,
|
|
4848
|
+
2
|
|
4849
|
+
)
|
|
4850
|
+
);
|
|
4851
|
+
} else {
|
|
4852
|
+
console.log(result);
|
|
4312
4853
|
}
|
|
4313
|
-
fieldOpts.set = [opts.set[0], opts.set[1]];
|
|
4314
4854
|
}
|
|
4315
|
-
|
|
4316
|
-
|
|
4855
|
+
)
|
|
4856
|
+
);
|
|
4857
|
+
program.command("attach <taskId> <filePath>").description("Upload a file attachment to a task").option("--json", "Force JSON output even in terminal").action(
|
|
4858
|
+
wrapAction(async (taskId, filePath, opts) => {
|
|
4859
|
+
const config = loadConfig();
|
|
4860
|
+
const result = await attachFile(config, taskId, filePath);
|
|
4861
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4862
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4863
|
+
} else {
|
|
4864
|
+
console.log(`Uploaded "${result.title}" to task ${taskId}`);
|
|
4865
|
+
console.log(` ${result.url}`);
|
|
4317
4866
|
}
|
|
4318
|
-
|
|
4867
|
+
})
|
|
4868
|
+
);
|
|
4869
|
+
program.command("move <taskId>").description("Add or remove a task from a list").option("--to <listId>", "Add task to this list").option("--remove <listId>", "Remove task from this list").option("--json", "Force JSON output even in terminal").action(
|
|
4870
|
+
wrapAction(async (taskId, opts) => {
|
|
4871
|
+
const config = loadConfig();
|
|
4872
|
+
const message = await moveTask(config, taskId, opts);
|
|
4319
4873
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4320
|
-
console.log(
|
|
4874
|
+
console.log(
|
|
4875
|
+
JSON.stringify({ taskId, to: opts.to, remove: opts.remove, message }, null, 2)
|
|
4876
|
+
);
|
|
4321
4877
|
} else {
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4878
|
+
console.log(message);
|
|
4879
|
+
}
|
|
4880
|
+
})
|
|
4881
|
+
);
|
|
4882
|
+
program.command("field <taskId>").description("Set or remove a custom field value on a task").option("--set <nameAndValue...>", 'Set field: --set "Field Name" value').option("--remove <fieldName>", "Remove field value by name").option("--json", "Force JSON output even in terminal").action(
|
|
4883
|
+
wrapAction(
|
|
4884
|
+
async (taskId, opts) => {
|
|
4885
|
+
const config = loadConfig();
|
|
4886
|
+
const fieldOpts = {};
|
|
4887
|
+
if (opts.set) {
|
|
4888
|
+
if (opts.set.length !== 2) {
|
|
4889
|
+
throw new Error("--set requires exactly two arguments: field name and value");
|
|
4890
|
+
}
|
|
4891
|
+
fieldOpts.set = [opts.set[0], opts.set[1]];
|
|
4892
|
+
}
|
|
4893
|
+
if (opts.remove) {
|
|
4894
|
+
fieldOpts.remove = opts.remove;
|
|
4895
|
+
}
|
|
4896
|
+
const { results } = await setCustomField(config, taskId, fieldOpts);
|
|
4897
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4898
|
+
console.log(JSON.stringify(results, null, 2));
|
|
4899
|
+
} else {
|
|
4900
|
+
for (const r of results) {
|
|
4901
|
+
if (r.action === "set") {
|
|
4902
|
+
console.log(`Set "${r.field}" to ${JSON.stringify(r.value)} on ${r.taskId}`);
|
|
4903
|
+
} else {
|
|
4904
|
+
console.log(`Removed "${r.field}" from ${r.taskId}`);
|
|
4905
|
+
}
|
|
4327
4906
|
}
|
|
4328
4907
|
}
|
|
4329
4908
|
}
|
|
4330
|
-
|
|
4331
|
-
)
|
|
4332
|
-
)
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
}
|
|
4342
|
-
|
|
4343
|
-
)
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
)
|
|
4358
|
-
|
|
4359
|
-
checklistCmd.command("
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
const checklists = await viewChecklists(config, taskId);
|
|
4363
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4364
|
-
console.log(JSON.stringify(checklists, null, 2));
|
|
4365
|
-
} else if (isTTY()) {
|
|
4366
|
-
console.log(formatChecklists(checklists));
|
|
4367
|
-
} else {
|
|
4368
|
-
console.log(formatChecklistsMarkdown(checklists));
|
|
4369
|
-
}
|
|
4370
|
-
})
|
|
4371
|
-
);
|
|
4372
|
-
checklistCmd.command("create <taskId> <name>").description("Create a checklist on a task").option("--json", "Force JSON output even in terminal").action(
|
|
4373
|
-
wrapAction(async (taskId, name, opts) => {
|
|
4374
|
-
const config = loadConfig();
|
|
4375
|
-
const result = await createChecklist(config, taskId, name);
|
|
4376
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4377
|
-
console.log(JSON.stringify(result, null, 2));
|
|
4378
|
-
} else {
|
|
4379
|
-
console.log(`Created checklist "${result.name}" (id: ${result.id})`);
|
|
4380
|
-
}
|
|
4381
|
-
})
|
|
4382
|
-
);
|
|
4383
|
-
checklistCmd.command("delete <checklistId>").description("Delete a checklist").option("--json", "Force JSON output even in terminal").action(
|
|
4384
|
-
wrapAction(async (checklistId, opts) => {
|
|
4385
|
-
const config = loadConfig();
|
|
4386
|
-
const result = await deleteChecklist(config, checklistId);
|
|
4387
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4388
|
-
console.log(JSON.stringify(result, null, 2));
|
|
4389
|
-
} else {
|
|
4390
|
-
console.log(`Deleted checklist ${result.checklistId}`);
|
|
4391
|
-
}
|
|
4392
|
-
})
|
|
4393
|
-
);
|
|
4394
|
-
checklistCmd.command("add-item <checklistId> <name>").description("Add an item to a checklist").option("--json", "Force JSON output even in terminal").action(
|
|
4395
|
-
wrapAction(async (checklistId, name, opts) => {
|
|
4396
|
-
const config = loadConfig();
|
|
4397
|
-
const result = await addChecklistItem(config, checklistId, name);
|
|
4398
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4399
|
-
console.log(JSON.stringify(result, null, 2));
|
|
4400
|
-
} else {
|
|
4401
|
-
console.log(`Added item "${name}" to checklist ${checklistId}`);
|
|
4402
|
-
}
|
|
4403
|
-
})
|
|
4404
|
-
);
|
|
4405
|
-
checklistCmd.command("edit-item <checklistId> <checklistItemId>").description("Edit a checklist item").option("--name <name>", "New item name").option("--resolved", "Mark item as resolved").option("--unresolved", "Mark item as unresolved").option("--assignee <userId>", 'Assign user by ID (use "null" to unassign)').option("--json", "Force JSON output even in terminal").action(
|
|
4406
|
-
wrapAction(
|
|
4407
|
-
async (checklistId, checklistItemId, opts) => {
|
|
4909
|
+
)
|
|
4910
|
+
);
|
|
4911
|
+
program.command("delete <taskId>").description("Delete a task (requires confirmation)").option("--confirm", "Skip confirmation prompt (required in non-interactive mode)").option("--json", "Force JSON output even in terminal").action(
|
|
4912
|
+
wrapAction(async (taskId, opts) => {
|
|
4913
|
+
const config = loadConfig();
|
|
4914
|
+
const result = await deleteTaskCommand(config, taskId, opts);
|
|
4915
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4916
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4917
|
+
} else {
|
|
4918
|
+
console.log(`Deleted task ${result.taskId}`);
|
|
4919
|
+
}
|
|
4920
|
+
})
|
|
4921
|
+
);
|
|
4922
|
+
program.command("tag <taskId>").description("Add or remove tags from a task").option("--add <tags>", "Comma-separated tag names to add").option("--remove <tags>", "Comma-separated tag names to remove").option("--json", "Force JSON output even in terminal").action(
|
|
4923
|
+
wrapAction(
|
|
4924
|
+
async (taskId, opts) => {
|
|
4925
|
+
const config = loadConfig();
|
|
4926
|
+
const result = await manageTags(config, taskId, opts);
|
|
4927
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4928
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4929
|
+
} else {
|
|
4930
|
+
const parts = [];
|
|
4931
|
+
if (result.added.length > 0) parts.push(`Added tags: ${result.added.join(", ")}`);
|
|
4932
|
+
if (result.removed.length > 0) parts.push(`Removed tags: ${result.removed.join(", ")}`);
|
|
4933
|
+
console.log(parts.join("; "));
|
|
4934
|
+
}
|
|
4935
|
+
}
|
|
4936
|
+
)
|
|
4937
|
+
);
|
|
4938
|
+
const checklistCmd = program.command("checklist").description("Manage checklists on a task");
|
|
4939
|
+
checklistCmd.command("view <taskId>").description("View checklists on a task").option("--json", "Force JSON output even in terminal").action(
|
|
4940
|
+
wrapAction(async (taskId, opts) => {
|
|
4408
4941
|
const config = loadConfig();
|
|
4409
|
-
const
|
|
4410
|
-
if (opts.
|
|
4411
|
-
|
|
4412
|
-
if (
|
|
4413
|
-
|
|
4414
|
-
|
|
4942
|
+
const checklists = await viewChecklists(config, taskId);
|
|
4943
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4944
|
+
console.log(JSON.stringify(checklists, null, 2));
|
|
4945
|
+
} else if (isTTY()) {
|
|
4946
|
+
console.log(formatChecklists(checklists));
|
|
4947
|
+
} else {
|
|
4948
|
+
console.log(formatChecklistsMarkdown(checklists));
|
|
4415
4949
|
}
|
|
4416
|
-
|
|
4950
|
+
})
|
|
4951
|
+
);
|
|
4952
|
+
checklistCmd.command("create <taskId> <name>").description("Create a checklist on a task").option("--json", "Force JSON output even in terminal").action(
|
|
4953
|
+
wrapAction(async (taskId, name, opts) => {
|
|
4954
|
+
const config = loadConfig();
|
|
4955
|
+
const result = await createChecklist(config, taskId, name);
|
|
4417
4956
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4418
4957
|
console.log(JSON.stringify(result, null, 2));
|
|
4419
4958
|
} else {
|
|
4420
|
-
console.log(`
|
|
4959
|
+
console.log(`Created checklist "${result.name}" (id: ${result.id})`);
|
|
4421
4960
|
}
|
|
4422
|
-
}
|
|
4423
|
-
)
|
|
4424
|
-
)
|
|
4425
|
-
|
|
4426
|
-
wrapAction(async (checklistId, checklistItemId, opts) => {
|
|
4427
|
-
const config = loadConfig();
|
|
4428
|
-
const result = await deleteChecklistItem(config, checklistId, checklistItemId);
|
|
4429
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4430
|
-
console.log(JSON.stringify(result, null, 2));
|
|
4431
|
-
} else {
|
|
4432
|
-
console.log(`Deleted checklist item ${result.checklistItemId}`);
|
|
4433
|
-
}
|
|
4434
|
-
})
|
|
4435
|
-
);
|
|
4436
|
-
var timeCmd = program.command("time").description("Track time on tasks");
|
|
4437
|
-
timeCmd.command("start <taskId>").description("Start tracking time on a task").option("-d, --description <text>", "Description for the time entry").option("--json", "Force JSON output even in terminal").action(
|
|
4438
|
-
wrapAction(async (taskId, opts) => {
|
|
4439
|
-
const config = loadConfig();
|
|
4440
|
-
const result = await startTimer(config, taskId, opts.description);
|
|
4441
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4442
|
-
console.log(JSON.stringify(result, null, 2));
|
|
4443
|
-
} else {
|
|
4444
|
-
const taskName = result.task?.name ?? taskId;
|
|
4445
|
-
console.log(`Started timer on "${taskName}"`);
|
|
4446
|
-
}
|
|
4447
|
-
})
|
|
4448
|
-
);
|
|
4449
|
-
timeCmd.command("stop").description("Stop the running timer").option("--json", "Force JSON output even in terminal").action(
|
|
4450
|
-
wrapAction(async (opts) => {
|
|
4451
|
-
const config = loadConfig();
|
|
4452
|
-
const result = await stopTimer(config);
|
|
4453
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4454
|
-
console.log(JSON.stringify(result, null, 2));
|
|
4455
|
-
} else if (isTTY()) {
|
|
4456
|
-
console.log(formatTimeEntry(result));
|
|
4457
|
-
} else {
|
|
4458
|
-
console.log(formatTimeEntryMarkdown(result));
|
|
4459
|
-
}
|
|
4460
|
-
})
|
|
4461
|
-
);
|
|
4462
|
-
timeCmd.command("status").description("Show the currently running timer").option("--json", "Force JSON output even in terminal").action(
|
|
4463
|
-
wrapAction(async (opts) => {
|
|
4464
|
-
const config = loadConfig();
|
|
4465
|
-
const result = await timerStatus(config);
|
|
4466
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4467
|
-
console.log(JSON.stringify(result, null, 2));
|
|
4468
|
-
} else if (!result) {
|
|
4469
|
-
console.log("No timer running");
|
|
4470
|
-
} else if (isTTY()) {
|
|
4471
|
-
console.log(formatTimeEntry(result));
|
|
4472
|
-
} else {
|
|
4473
|
-
console.log(formatTimeEntryMarkdown(result));
|
|
4474
|
-
}
|
|
4475
|
-
})
|
|
4476
|
-
);
|
|
4477
|
-
timeCmd.command("log <taskId> <duration>").description('Log a manual time entry (e.g. "2h", "30m", "1h30m")').option("-d, --description <text>", "Description for the time entry").option("--json", "Force JSON output even in terminal").action(
|
|
4478
|
-
wrapAction(
|
|
4479
|
-
async (taskId, duration, opts) => {
|
|
4961
|
+
})
|
|
4962
|
+
);
|
|
4963
|
+
checklistCmd.command("delete <checklistId>").description("Delete a checklist").option("--json", "Force JSON output even in terminal").action(
|
|
4964
|
+
wrapAction(async (checklistId, opts) => {
|
|
4480
4965
|
const config = loadConfig();
|
|
4481
|
-
const result = await
|
|
4966
|
+
const result = await deleteChecklist(config, checklistId);
|
|
4482
4967
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4483
4968
|
console.log(JSON.stringify(result, null, 2));
|
|
4484
4969
|
} else {
|
|
4485
|
-
console.log(`
|
|
4970
|
+
console.log(`Deleted checklist ${result.checklistId}`);
|
|
4486
4971
|
}
|
|
4487
|
-
}
|
|
4488
|
-
)
|
|
4489
|
-
)
|
|
4490
|
-
|
|
4491
|
-
wrapAction(async (opts) => {
|
|
4492
|
-
const config = loadConfig();
|
|
4493
|
-
const days = opts.days ? Number(opts.days) : 7;
|
|
4494
|
-
if (!Number.isFinite(days) || days <= 0) {
|
|
4495
|
-
throw new Error("--days must be a positive number");
|
|
4496
|
-
}
|
|
4497
|
-
const entries = await listTimeEntries(config, { days, taskId: opts.task });
|
|
4498
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4499
|
-
console.log(JSON.stringify(entries, null, 2));
|
|
4500
|
-
} else if (isTTY()) {
|
|
4501
|
-
console.log(formatTimeEntries(entries));
|
|
4502
|
-
} else {
|
|
4503
|
-
console.log(formatTimeEntriesMarkdown(entries));
|
|
4504
|
-
}
|
|
4505
|
-
})
|
|
4506
|
-
);
|
|
4507
|
-
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(
|
|
4508
|
-
wrapAction(
|
|
4509
|
-
async (timeEntryId, opts) => {
|
|
4972
|
+
})
|
|
4973
|
+
);
|
|
4974
|
+
checklistCmd.command("add-item <checklistId> <name>").description("Add an item to a checklist").option("--json", "Force JSON output even in terminal").action(
|
|
4975
|
+
wrapAction(async (checklistId, name, opts) => {
|
|
4510
4976
|
const config = loadConfig();
|
|
4511
|
-
const
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
}
|
|
4977
|
+
const result = await addChecklistItem(config, checklistId, name);
|
|
4978
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4979
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4980
|
+
} else {
|
|
4981
|
+
console.log(`Added item "${name}" to checklist ${checklistId}`);
|
|
4982
|
+
}
|
|
4983
|
+
})
|
|
4984
|
+
);
|
|
4985
|
+
checklistCmd.command("edit-item <checklistId> <checklistItemId>").description("Edit a checklist item").option("--name <name>", "New item name").option("--resolved", "Mark item as resolved").option("--unresolved", "Mark item as unresolved").option("--assignee <userId>", 'Assign user by ID (use "null" to unassign)').option("--json", "Force JSON output even in terminal").action(
|
|
4986
|
+
wrapAction(
|
|
4987
|
+
async (checklistId, checklistItemId, opts) => {
|
|
4988
|
+
const config = loadConfig();
|
|
4989
|
+
const updates = {};
|
|
4990
|
+
if (opts.name) updates.name = opts.name;
|
|
4991
|
+
if (opts.resolved) updates.resolved = true;
|
|
4992
|
+
if (opts.unresolved) updates.resolved = false;
|
|
4993
|
+
if (opts.assignee !== void 0) {
|
|
4994
|
+
updates.assignee = opts.assignee === "null" ? null : parseOptionalNumberOption(opts.assignee, "--assignee");
|
|
4995
|
+
}
|
|
4996
|
+
const result = await editChecklistItem(config, checklistId, checklistItemId, updates);
|
|
4997
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
4998
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4999
|
+
} else {
|
|
5000
|
+
console.log(`Updated checklist item ${checklistItemId}`);
|
|
5001
|
+
}
|
|
5002
|
+
}
|
|
5003
|
+
)
|
|
5004
|
+
);
|
|
5005
|
+
checklistCmd.command("delete-item <checklistId> <checklistItemId>").description("Delete a checklist item").option("--json", "Force JSON output even in terminal").action(
|
|
5006
|
+
wrapAction(async (checklistId, checklistItemId, opts) => {
|
|
5007
|
+
const config = loadConfig();
|
|
5008
|
+
const result = await deleteChecklistItem(config, checklistId, checklistItemId);
|
|
5009
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5010
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5011
|
+
} else {
|
|
5012
|
+
console.log(`Deleted checklist item ${result.checklistItemId}`);
|
|
5013
|
+
}
|
|
5014
|
+
})
|
|
5015
|
+
);
|
|
5016
|
+
const timeCmd = program.command("time").description("Track time on tasks");
|
|
5017
|
+
timeCmd.command("start <taskId>").description("Start tracking time on a task").option("-d, --description <text>", "Description for the time entry").option("--json", "Force JSON output even in terminal").action(
|
|
5018
|
+
wrapAction(async (taskId, opts) => {
|
|
5019
|
+
const config = loadConfig();
|
|
5020
|
+
const result = await startTimer(config, taskId, opts.description);
|
|
5021
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5022
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5023
|
+
} else {
|
|
5024
|
+
const taskName = result.task?.name ?? taskId;
|
|
5025
|
+
console.log(`Started timer on "${taskName}"`);
|
|
5026
|
+
}
|
|
5027
|
+
})
|
|
5028
|
+
);
|
|
5029
|
+
timeCmd.command("stop").description("Stop the running timer").option("--json", "Force JSON output even in terminal").action(
|
|
5030
|
+
wrapAction(async (opts) => {
|
|
5031
|
+
const config = loadConfig();
|
|
5032
|
+
const result = await stopTimer(config);
|
|
4515
5033
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4516
|
-
console.log(JSON.stringify(
|
|
5034
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4517
5035
|
} else if (isTTY()) {
|
|
4518
|
-
console.log(formatTimeEntry(
|
|
5036
|
+
console.log(formatTimeEntry(result));
|
|
4519
5037
|
} else {
|
|
4520
|
-
console.log(formatTimeEntryMarkdown(
|
|
5038
|
+
console.log(formatTimeEntryMarkdown(result));
|
|
4521
5039
|
}
|
|
4522
|
-
}
|
|
4523
|
-
)
|
|
4524
|
-
)
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
);
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
5040
|
+
})
|
|
5041
|
+
);
|
|
5042
|
+
timeCmd.command("status").description("Show the currently running timer").option("--json", "Force JSON output even in terminal").action(
|
|
5043
|
+
wrapAction(async (opts) => {
|
|
5044
|
+
const config = loadConfig();
|
|
5045
|
+
const result = await timerStatus(config);
|
|
5046
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5047
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5048
|
+
} else if (!result) {
|
|
5049
|
+
console.log("No timer running");
|
|
5050
|
+
} else if (isTTY()) {
|
|
5051
|
+
console.log(formatTimeEntry(result));
|
|
5052
|
+
} else {
|
|
5053
|
+
console.log(formatTimeEntryMarkdown(result));
|
|
5054
|
+
}
|
|
5055
|
+
})
|
|
5056
|
+
);
|
|
5057
|
+
timeCmd.command("log <taskId> <duration>").description('Log a manual time entry (e.g. "2h", "30m", "1h30m")').option("-d, --description <text>", "Description for the time entry").option("--json", "Force JSON output even in terminal").action(
|
|
5058
|
+
wrapAction(
|
|
5059
|
+
async (taskId, duration, opts) => {
|
|
5060
|
+
const config = loadConfig();
|
|
5061
|
+
const result = await logTime(config, taskId, duration, opts.description);
|
|
5062
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5063
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5064
|
+
} else {
|
|
5065
|
+
console.log(`Logged ${duration} on task ${taskId}`);
|
|
5066
|
+
}
|
|
5067
|
+
}
|
|
5068
|
+
)
|
|
5069
|
+
);
|
|
5070
|
+
timeCmd.command("list").description("List recent time entries (default: last 7 days)").option("--days <n>", "Number of days to look back", "7").option("--task <taskId>", "Filter by task ID").option("--json", "Force JSON output even in terminal").action(
|
|
5071
|
+
wrapAction(async (opts) => {
|
|
5072
|
+
const config = loadConfig();
|
|
5073
|
+
const days = opts.days ? Number(opts.days) : 7;
|
|
5074
|
+
if (!Number.isFinite(days) || days <= 0) {
|
|
5075
|
+
throw new Error("--days must be a positive number");
|
|
5076
|
+
}
|
|
5077
|
+
const entries = await listTimeEntries(config, { days, taskId: opts.task });
|
|
5078
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5079
|
+
console.log(JSON.stringify(entries, null, 2));
|
|
5080
|
+
} else if (isTTY()) {
|
|
5081
|
+
console.log(formatTimeEntries(entries));
|
|
5082
|
+
} else {
|
|
5083
|
+
console.log(formatTimeEntriesMarkdown(entries));
|
|
5084
|
+
}
|
|
5085
|
+
})
|
|
5086
|
+
);
|
|
5087
|
+
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(
|
|
5088
|
+
wrapAction(
|
|
5089
|
+
async (timeEntryId, opts) => {
|
|
5090
|
+
const config = loadConfig();
|
|
5091
|
+
const entry = await updateTimeEntry(config, timeEntryId, {
|
|
5092
|
+
description: opts.description,
|
|
5093
|
+
duration: opts.duration
|
|
5094
|
+
});
|
|
5095
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5096
|
+
console.log(JSON.stringify(entry, null, 2));
|
|
5097
|
+
} else if (isTTY()) {
|
|
5098
|
+
console.log(formatTimeEntry(entry));
|
|
5099
|
+
} else {
|
|
5100
|
+
console.log(formatTimeEntryMarkdown(entry));
|
|
5101
|
+
}
|
|
5102
|
+
}
|
|
5103
|
+
)
|
|
5104
|
+
);
|
|
5105
|
+
timeCmd.command("delete <timeEntryId>").description("Delete a time entry").option("--json", "Force JSON output even in terminal").action(
|
|
5106
|
+
wrapAction(async (timeEntryId, opts) => {
|
|
4552
5107
|
const config = loadConfig();
|
|
4553
|
-
await
|
|
5108
|
+
await deleteTimeEntry(config, timeEntryId);
|
|
5109
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5110
|
+
console.log(JSON.stringify({ deleted: timeEntryId }));
|
|
5111
|
+
} else {
|
|
5112
|
+
console.log(`Deleted time entry ${timeEntryId}`);
|
|
5113
|
+
}
|
|
5114
|
+
})
|
|
5115
|
+
);
|
|
5116
|
+
program.command("tags <spaceId>").description("List tags in a space").option("--json", "Force JSON output even in terminal").action(
|
|
5117
|
+
wrapAction(async (spaceId, opts) => {
|
|
5118
|
+
const config = loadConfig();
|
|
5119
|
+
const tags = await listSpaceTags(config, spaceId);
|
|
5120
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5121
|
+
console.log(JSON.stringify(tags, null, 2));
|
|
5122
|
+
} else if (isTTY()) {
|
|
5123
|
+
console.log(formatTags(tags));
|
|
5124
|
+
} else {
|
|
5125
|
+
console.log(formatTagsMarkdown(tags));
|
|
5126
|
+
}
|
|
5127
|
+
})
|
|
5128
|
+
);
|
|
5129
|
+
program.command("tag-create <spaceId> <name>").description("Create a tag in a space").option("--fg <color>", "Foreground color (hex)").option("--bg <color>", "Background color (hex)").option("--json", "Force JSON output even in terminal").action(
|
|
5130
|
+
wrapAction(
|
|
5131
|
+
async (spaceId, name, opts) => {
|
|
5132
|
+
const config = loadConfig();
|
|
5133
|
+
await createSpaceTag(config, spaceId, name, opts.fg, opts.bg);
|
|
5134
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5135
|
+
console.log(JSON.stringify({ success: true, spaceId, tag: name }, null, 2));
|
|
5136
|
+
} else {
|
|
5137
|
+
console.log(`Created tag "${name}" in space ${spaceId}`);
|
|
5138
|
+
}
|
|
5139
|
+
}
|
|
5140
|
+
)
|
|
5141
|
+
);
|
|
5142
|
+
program.command("tag-delete <spaceId> <name>").description("Delete a tag from a space").option("--json", "Force JSON output even in terminal").action(
|
|
5143
|
+
wrapAction(async (spaceId, name, opts) => {
|
|
5144
|
+
const config = loadConfig();
|
|
5145
|
+
await deleteSpaceTag(config, spaceId, name);
|
|
4554
5146
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4555
5147
|
console.log(JSON.stringify({ success: true, spaceId, tag: name }, null, 2));
|
|
4556
5148
|
} else {
|
|
4557
|
-
console.log(`
|
|
5149
|
+
console.log(`Deleted tag "${name}" from space ${spaceId}`);
|
|
4558
5150
|
}
|
|
4559
|
-
}
|
|
4560
|
-
)
|
|
4561
|
-
)
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
})
|
|
4572
|
-
);
|
|
4573
|
-
program.command("members").description("List workspace members").option("--json", "Force JSON output even in terminal").action(
|
|
4574
|
-
wrapAction(async (opts) => {
|
|
4575
|
-
const config = loadConfig();
|
|
4576
|
-
const members = await listMembers(config);
|
|
4577
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4578
|
-
console.log(JSON.stringify(members, null, 2));
|
|
4579
|
-
} else if (isTTY()) {
|
|
4580
|
-
console.log(formatMembers(members));
|
|
4581
|
-
} else {
|
|
4582
|
-
console.log(formatMembersMarkdown(members));
|
|
4583
|
-
}
|
|
4584
|
-
})
|
|
4585
|
-
);
|
|
4586
|
-
program.command("fields <listId>").description("List custom fields for a list").option("--json", "Force JSON output even in terminal").action(
|
|
4587
|
-
wrapAction(async (listId, opts) => {
|
|
4588
|
-
const config = loadConfig();
|
|
4589
|
-
const fields = await listFields(config, listId);
|
|
4590
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4591
|
-
console.log(JSON.stringify(fields, null, 2));
|
|
4592
|
-
} else if (isTTY()) {
|
|
4593
|
-
console.log(formatFields(fields));
|
|
4594
|
-
} else {
|
|
4595
|
-
console.log(formatFieldsMarkdown(fields));
|
|
4596
|
-
}
|
|
4597
|
-
})
|
|
4598
|
-
);
|
|
4599
|
-
program.command("duplicate <taskId>").description("Duplicate a task").option("--json", "Force JSON output even in terminal").action(
|
|
4600
|
-
wrapAction(async (taskId, opts) => {
|
|
4601
|
-
const config = loadConfig();
|
|
4602
|
-
const result = await duplicateTask(config, taskId);
|
|
4603
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4604
|
-
console.log(JSON.stringify(result, null, 2));
|
|
4605
|
-
} else {
|
|
4606
|
-
console.log(`Duplicated as "${result.name}" (${result.id})`);
|
|
4607
|
-
}
|
|
4608
|
-
})
|
|
4609
|
-
);
|
|
4610
|
-
var bulkCmd = program.command("bulk").description("Bulk task operations");
|
|
4611
|
-
bulkCmd.command("status <status> <taskIds...>").description("Update status of multiple tasks").option("--json", "Force JSON output even in terminal").action(
|
|
4612
|
-
wrapAction(async (status, taskIds, opts) => {
|
|
4613
|
-
const config = loadConfig();
|
|
4614
|
-
const result = await bulkUpdateStatus(config, taskIds, status);
|
|
4615
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4616
|
-
console.log(JSON.stringify(result, null, 2));
|
|
4617
|
-
} else {
|
|
4618
|
-
console.log(`Updated ${result.updated} tasks to "${status}"`);
|
|
4619
|
-
if (result.failed.length > 0) {
|
|
4620
|
-
console.log(`Failed: ${result.failed.join(", ")}`);
|
|
5151
|
+
})
|
|
5152
|
+
);
|
|
5153
|
+
program.command("members").description("List workspace members").option("--json", "Force JSON output even in terminal").action(
|
|
5154
|
+
wrapAction(async (opts) => {
|
|
5155
|
+
const config = loadConfig();
|
|
5156
|
+
const members = await listMembers(config);
|
|
5157
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5158
|
+
console.log(JSON.stringify(members, null, 2));
|
|
5159
|
+
} else if (isTTY()) {
|
|
5160
|
+
console.log(formatMembers(members));
|
|
5161
|
+
} else {
|
|
5162
|
+
console.log(formatMembersMarkdown(members));
|
|
4621
5163
|
}
|
|
4622
|
-
}
|
|
4623
|
-
|
|
4624
|
-
)
|
|
4625
|
-
|
|
4626
|
-
wrapAction(async (opts) => {
|
|
4627
|
-
const config = loadConfig();
|
|
4628
|
-
const goals = await listGoals(config);
|
|
4629
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4630
|
-
console.log(JSON.stringify(goals, null, 2));
|
|
4631
|
-
} else if (isTTY()) {
|
|
4632
|
-
console.log(formatGoals(goals));
|
|
4633
|
-
} else {
|
|
4634
|
-
console.log(formatGoalsMarkdown(goals));
|
|
4635
|
-
}
|
|
4636
|
-
})
|
|
4637
|
-
);
|
|
4638
|
-
program.command("goal-create <name>").description("Create a goal").option("-d, --description <text>", "Goal description").option("--color <hex>", "Goal color (hex)").option("--json", "Force JSON output even in terminal").action(
|
|
4639
|
-
wrapAction(
|
|
4640
|
-
async (name, opts) => {
|
|
5164
|
+
})
|
|
5165
|
+
);
|
|
5166
|
+
program.command("fields <listId>").description("List custom fields for a list").option("--json", "Force JSON output even in terminal").action(
|
|
5167
|
+
wrapAction(async (listId, opts) => {
|
|
4641
5168
|
const config = loadConfig();
|
|
4642
|
-
const
|
|
4643
|
-
description: opts.description,
|
|
4644
|
-
color: opts.color
|
|
4645
|
-
});
|
|
5169
|
+
const fields = await listFields(config, listId);
|
|
4646
5170
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4647
|
-
console.log(JSON.stringify(
|
|
5171
|
+
console.log(JSON.stringify(fields, null, 2));
|
|
5172
|
+
} else if (isTTY()) {
|
|
5173
|
+
console.log(formatFields(fields));
|
|
4648
5174
|
} else {
|
|
4649
|
-
console.log(
|
|
5175
|
+
console.log(formatFieldsMarkdown(fields));
|
|
4650
5176
|
}
|
|
4651
|
-
}
|
|
4652
|
-
)
|
|
4653
|
-
)
|
|
4654
|
-
|
|
4655
|
-
wrapAction(
|
|
4656
|
-
async (goalId, opts) => {
|
|
5177
|
+
})
|
|
5178
|
+
);
|
|
5179
|
+
program.command("duplicate <taskId>").description("Duplicate a task").option("--json", "Force JSON output even in terminal").action(
|
|
5180
|
+
wrapAction(async (taskId, opts) => {
|
|
4657
5181
|
const config = loadConfig();
|
|
4658
|
-
const
|
|
4659
|
-
name: opts.name,
|
|
4660
|
-
description: opts.description,
|
|
4661
|
-
color: opts.color
|
|
4662
|
-
});
|
|
5182
|
+
const result = await duplicateTask(config, taskId);
|
|
4663
5183
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4664
|
-
console.log(JSON.stringify(
|
|
5184
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4665
5185
|
} else {
|
|
4666
|
-
console.log(`
|
|
5186
|
+
console.log(`Duplicated as "${result.name}" (${result.id})`);
|
|
4667
5187
|
}
|
|
4668
|
-
}
|
|
4669
|
-
)
|
|
4670
|
-
);
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
const config = loadConfig();
|
|
4674
|
-
const krs = await listKeyResults(config, goalId);
|
|
4675
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4676
|
-
console.log(JSON.stringify(krs, null, 2));
|
|
4677
|
-
} else if (isTTY()) {
|
|
4678
|
-
console.log(formatKeyResults(krs));
|
|
4679
|
-
} else {
|
|
4680
|
-
console.log(formatKeyResultsMarkdown(krs));
|
|
4681
|
-
}
|
|
4682
|
-
})
|
|
4683
|
-
);
|
|
4684
|
-
program.command("key-result-create <goalId> <name>").description("Create a key result on a goal").option("--type <type>", "Key result type (number or percentage)", "number").option("--target <n>", "Target value", "100").option("--json", "Force JSON output even in terminal").action(
|
|
4685
|
-
wrapAction(
|
|
4686
|
-
async (goalId, name, opts) => {
|
|
5188
|
+
})
|
|
5189
|
+
);
|
|
5190
|
+
const bulkCmd = program.command("bulk").description("Bulk task operations");
|
|
5191
|
+
bulkCmd.command("status <status> <taskIds...>").description("Update status of multiple tasks").option("--json", "Force JSON output even in terminal").action(
|
|
5192
|
+
wrapAction(async (status, taskIds, opts) => {
|
|
4687
5193
|
const config = loadConfig();
|
|
4688
|
-
const
|
|
4689
|
-
if (
|
|
4690
|
-
|
|
5194
|
+
const result = await bulkUpdateStatus(config, taskIds, status);
|
|
5195
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5196
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5197
|
+
} else {
|
|
5198
|
+
console.log(`Updated ${result.updated} tasks to "${status}"`);
|
|
5199
|
+
if (result.failed.length > 0) {
|
|
5200
|
+
for (const f of result.failed) {
|
|
5201
|
+
console.log(` Failed ${f.id}: ${f.reason}`);
|
|
5202
|
+
}
|
|
5203
|
+
}
|
|
4691
5204
|
}
|
|
4692
|
-
|
|
5205
|
+
})
|
|
5206
|
+
);
|
|
5207
|
+
program.command("goals").description("List goals in your workspace").option("--json", "Force JSON output even in terminal").action(
|
|
5208
|
+
wrapAction(async (opts) => {
|
|
5209
|
+
const config = loadConfig();
|
|
5210
|
+
const goals = await listGoals(config);
|
|
4693
5211
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4694
|
-
console.log(JSON.stringify(
|
|
5212
|
+
console.log(JSON.stringify(goals, null, 2));
|
|
5213
|
+
} else if (isTTY()) {
|
|
5214
|
+
console.log(formatGoals(goals));
|
|
4695
5215
|
} else {
|
|
4696
|
-
console.log(
|
|
5216
|
+
console.log(formatGoalsMarkdown(goals));
|
|
4697
5217
|
}
|
|
4698
|
-
}
|
|
4699
|
-
)
|
|
4700
|
-
)
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
5218
|
+
})
|
|
5219
|
+
);
|
|
5220
|
+
program.command("goal-create <name>").description("Create a goal").option("-d, --description <text>", "Goal description").option("--color <hex>", "Goal color (hex)").option("--json", "Force JSON output even in terminal").action(
|
|
5221
|
+
wrapAction(
|
|
5222
|
+
async (name, opts) => {
|
|
5223
|
+
const config = loadConfig();
|
|
5224
|
+
const goal = await createGoal(config, name, {
|
|
5225
|
+
description: opts.description,
|
|
5226
|
+
color: opts.color
|
|
5227
|
+
});
|
|
5228
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5229
|
+
console.log(JSON.stringify(goal, null, 2));
|
|
5230
|
+
} else {
|
|
5231
|
+
console.log(`Created goal "${goal.name}" (${goal.id})`);
|
|
5232
|
+
}
|
|
5233
|
+
}
|
|
5234
|
+
)
|
|
5235
|
+
);
|
|
5236
|
+
program.command("goal-update <goalId>").description("Update a goal").option("-n, --name <text>", "New goal name").option("-d, --description <text>", "New description").option("--color <hex>", "New color (hex)").option("--json", "Force JSON output even in terminal").action(
|
|
5237
|
+
wrapAction(
|
|
5238
|
+
async (goalId, opts) => {
|
|
5239
|
+
const config = loadConfig();
|
|
5240
|
+
const goal = await updateGoal(config, goalId, {
|
|
5241
|
+
name: opts.name,
|
|
5242
|
+
description: opts.description,
|
|
5243
|
+
color: opts.color
|
|
5244
|
+
});
|
|
5245
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5246
|
+
console.log(JSON.stringify(goal, null, 2));
|
|
5247
|
+
} else {
|
|
5248
|
+
console.log(`Updated goal "${goal.name}" (${goal.id})`);
|
|
5249
|
+
}
|
|
5250
|
+
}
|
|
5251
|
+
)
|
|
5252
|
+
);
|
|
5253
|
+
program.command("goal-delete <goalId>").description("Delete a goal").option("--json", "Force JSON output even in terminal").action(
|
|
5254
|
+
wrapAction(async (goalId, opts) => {
|
|
4704
5255
|
const config = loadConfig();
|
|
4705
|
-
|
|
4706
|
-
if (opts.
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
5256
|
+
await deleteGoal(config, goalId);
|
|
5257
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5258
|
+
console.log(JSON.stringify({ success: true, goalId }, null, 2));
|
|
5259
|
+
} else {
|
|
5260
|
+
console.log(`Deleted goal ${goalId}`);
|
|
4710
5261
|
}
|
|
4711
|
-
|
|
4712
|
-
|
|
5262
|
+
})
|
|
5263
|
+
);
|
|
5264
|
+
program.command("key-results <goalId>").description("List key results for a goal").option("--json", "Force JSON output even in terminal").action(
|
|
5265
|
+
wrapAction(async (goalId, opts) => {
|
|
5266
|
+
const config = loadConfig();
|
|
5267
|
+
const krs = await listKeyResults(config, goalId);
|
|
4713
5268
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4714
|
-
console.log(JSON.stringify(
|
|
5269
|
+
console.log(JSON.stringify(krs, null, 2));
|
|
5270
|
+
} else if (isTTY()) {
|
|
5271
|
+
console.log(formatKeyResults(krs));
|
|
4715
5272
|
} else {
|
|
4716
|
-
console.log(
|
|
5273
|
+
console.log(formatKeyResultsMarkdown(krs));
|
|
4717
5274
|
}
|
|
4718
|
-
}
|
|
4719
|
-
)
|
|
4720
|
-
)
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
5275
|
+
})
|
|
5276
|
+
);
|
|
5277
|
+
program.command("key-result-create <goalId> <name>").description("Create a key result on a goal").option("--type <type>", "Key result type (number or percentage)", "number").option("--target <n>", "Target value", "100").option("--json", "Force JSON output even in terminal").action(
|
|
5278
|
+
wrapAction(
|
|
5279
|
+
async (goalId, name, opts) => {
|
|
5280
|
+
const config = loadConfig();
|
|
5281
|
+
const target = Number(opts.target ?? 100);
|
|
5282
|
+
if (!Number.isFinite(target) || target <= 0) {
|
|
5283
|
+
throw new Error("--target must be a positive number");
|
|
5284
|
+
}
|
|
5285
|
+
const kr = await createKeyResult(config, goalId, name, opts.type ?? "number", target);
|
|
5286
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5287
|
+
console.log(JSON.stringify(kr, null, 2));
|
|
5288
|
+
} else {
|
|
5289
|
+
console.log(`Created key result "${kr.name}" (${kr.id})`);
|
|
5290
|
+
}
|
|
5291
|
+
}
|
|
5292
|
+
)
|
|
5293
|
+
);
|
|
5294
|
+
program.command("key-result-update <keyResultId>").description("Update a key result").option("--progress <n>", "Current progress value").option("--note <text>", "Progress note").option("--json", "Force JSON output even in terminal").action(
|
|
5295
|
+
wrapAction(
|
|
5296
|
+
async (keyResultId, opts) => {
|
|
5297
|
+
const config = loadConfig();
|
|
5298
|
+
const updates = {};
|
|
5299
|
+
if (opts.progress !== void 0) {
|
|
5300
|
+
const p = Number(opts.progress);
|
|
5301
|
+
if (!Number.isFinite(p)) throw new Error("--progress must be a number");
|
|
5302
|
+
updates.progress = p;
|
|
5303
|
+
}
|
|
5304
|
+
if (opts.note !== void 0) updates.note = opts.note;
|
|
5305
|
+
const kr = await updateKeyResult(config, keyResultId, updates);
|
|
5306
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5307
|
+
console.log(JSON.stringify(kr, null, 2));
|
|
5308
|
+
} else {
|
|
5309
|
+
console.log(`Updated key result "${kr.name}" (${kr.id})`);
|
|
5310
|
+
}
|
|
5311
|
+
}
|
|
5312
|
+
)
|
|
5313
|
+
);
|
|
5314
|
+
program.command("key-result-delete <keyResultId>").description("Delete a key result").option("--json", "Force JSON output even in terminal").action(
|
|
5315
|
+
wrapAction(async (keyResultId, opts) => {
|
|
5316
|
+
const config = loadConfig();
|
|
5317
|
+
await deleteKeyResult(config, keyResultId);
|
|
5318
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5319
|
+
console.log(JSON.stringify({ success: true, keyResultId }, null, 2));
|
|
5320
|
+
} else {
|
|
5321
|
+
console.log(`Deleted key result ${keyResultId}`);
|
|
5322
|
+
}
|
|
5323
|
+
})
|
|
5324
|
+
);
|
|
5325
|
+
program.command("docs [query]").description("List workspace docs (optionally filter by name)").option("--json", "Force JSON output even in terminal").action(
|
|
5326
|
+
wrapAction(async (query, opts) => {
|
|
5327
|
+
const config = loadConfig();
|
|
5328
|
+
const docs = await listDocs(config, query);
|
|
4739
5329
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4740
|
-
console.log(JSON.stringify(
|
|
5330
|
+
console.log(JSON.stringify(docs, null, 2));
|
|
5331
|
+
} else if (isTTY()) {
|
|
5332
|
+
console.log(formatDocs(docs));
|
|
4741
5333
|
} else {
|
|
4742
|
-
|
|
5334
|
+
console.log(formatDocsMarkdown(docs));
|
|
5335
|
+
}
|
|
5336
|
+
})
|
|
5337
|
+
);
|
|
5338
|
+
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(
|
|
5339
|
+
wrapAction(async (docId, pageId, opts) => {
|
|
5340
|
+
const config = loadConfig();
|
|
5341
|
+
if (pageId) {
|
|
5342
|
+
const page = await getDocPage(config, docId, pageId);
|
|
5343
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5344
|
+
console.log(JSON.stringify(page, null, 2));
|
|
5345
|
+
} else {
|
|
5346
|
+
if (page.name) console.log(`# ${page.name}
|
|
4743
5347
|
`);
|
|
4744
|
-
|
|
5348
|
+
console.log(page.content ?? "");
|
|
5349
|
+
}
|
|
5350
|
+
} else {
|
|
5351
|
+
const { doc, pages } = await getDocInfo(config, docId);
|
|
5352
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5353
|
+
console.log(JSON.stringify({ ...doc, pages }, null, 2));
|
|
5354
|
+
} else if (isTTY()) {
|
|
5355
|
+
console.log(formatDocInfo(doc, pages));
|
|
5356
|
+
} else {
|
|
5357
|
+
console.log(formatDocInfoMarkdown(doc, pages));
|
|
5358
|
+
}
|
|
4745
5359
|
}
|
|
4746
|
-
}
|
|
4747
|
-
|
|
5360
|
+
})
|
|
5361
|
+
);
|
|
5362
|
+
program.command("doc-pages <docId>").description("List all pages in a doc with content").option("--json", "Force JSON output even in terminal").action(
|
|
5363
|
+
wrapAction(async (docId, opts) => {
|
|
5364
|
+
const config = loadConfig();
|
|
5365
|
+
const pages = await getAllDocPages(config, docId);
|
|
4748
5366
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4749
|
-
console.log(JSON.stringify(
|
|
5367
|
+
console.log(JSON.stringify(pages, null, 2));
|
|
4750
5368
|
} else if (isTTY()) {
|
|
4751
|
-
console.log(
|
|
5369
|
+
console.log(formatDocPages(pages));
|
|
4752
5370
|
} else {
|
|
4753
|
-
console.log(
|
|
5371
|
+
console.log(formatDocPagesMarkdown(pages));
|
|
4754
5372
|
}
|
|
4755
|
-
}
|
|
4756
|
-
|
|
4757
|
-
)
|
|
4758
|
-
|
|
4759
|
-
wrapAction(async (docId, opts) => {
|
|
4760
|
-
const config = loadConfig();
|
|
4761
|
-
const pages = await getAllDocPages(config, docId);
|
|
4762
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4763
|
-
console.log(JSON.stringify(pages, null, 2));
|
|
4764
|
-
} else if (isTTY()) {
|
|
4765
|
-
console.log(formatDocPages(pages));
|
|
4766
|
-
} else {
|
|
4767
|
-
console.log(formatDocPagesMarkdown(pages));
|
|
4768
|
-
}
|
|
4769
|
-
})
|
|
4770
|
-
);
|
|
4771
|
-
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(
|
|
4772
|
-
wrapAction(async (spaceId, opts) => {
|
|
4773
|
-
const config = loadConfig();
|
|
4774
|
-
const folders = await listFolders(config, spaceId, opts.name);
|
|
4775
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4776
|
-
console.log(JSON.stringify(folders, null, 2));
|
|
4777
|
-
} else if (isTTY()) {
|
|
4778
|
-
console.log(formatFolders(folders));
|
|
4779
|
-
} else {
|
|
4780
|
-
console.log(formatFoldersMarkdown(folders));
|
|
4781
|
-
}
|
|
4782
|
-
})
|
|
4783
|
-
);
|
|
4784
|
-
program.command("doc-create <title>").description("Create a new doc").option("-c, --content <text>", "Initial content (markdown)").option("--json", "Force JSON output even in terminal").action(
|
|
4785
|
-
wrapAction(async (title, opts) => {
|
|
4786
|
-
const config = loadConfig();
|
|
4787
|
-
const result = await createDoc(config, title, opts.content);
|
|
4788
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
4789
|
-
console.log(JSON.stringify(result, null, 2));
|
|
4790
|
-
} else {
|
|
4791
|
-
console.log(`Created doc "${result.title}" (${result.id})`);
|
|
4792
|
-
}
|
|
4793
|
-
})
|
|
4794
|
-
);
|
|
4795
|
-
program.command("doc-page-create <docId> <name>").description("Create a page in a doc").option("-c, --content <text>", "Page content (markdown)").option("--parent-page <pageId>", "Parent page ID for nesting").option("--json", "Force JSON output even in terminal").action(
|
|
4796
|
-
wrapAction(
|
|
4797
|
-
async (docId, name, opts) => {
|
|
5373
|
+
})
|
|
5374
|
+
);
|
|
5375
|
+
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(
|
|
5376
|
+
wrapAction(async (spaceId, opts) => {
|
|
4798
5377
|
const config = loadConfig();
|
|
4799
|
-
const
|
|
5378
|
+
const folders = await listFolders(config, spaceId, opts.name);
|
|
4800
5379
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4801
|
-
console.log(JSON.stringify(
|
|
5380
|
+
console.log(JSON.stringify(folders, null, 2));
|
|
5381
|
+
} else if (isTTY()) {
|
|
5382
|
+
console.log(formatFolders(folders));
|
|
4802
5383
|
} else {
|
|
4803
|
-
console.log(
|
|
5384
|
+
console.log(formatFoldersMarkdown(folders));
|
|
4804
5385
|
}
|
|
4805
|
-
}
|
|
4806
|
-
)
|
|
4807
|
-
)
|
|
4808
|
-
|
|
4809
|
-
wrapAction(
|
|
4810
|
-
async (docId, pageId, opts) => {
|
|
5386
|
+
})
|
|
5387
|
+
);
|
|
5388
|
+
program.command("doc-create <title>").description("Create a new doc").option("-c, --content <text>", "Initial content (markdown)").option("--json", "Force JSON output even in terminal").action(
|
|
5389
|
+
wrapAction(async (title, opts) => {
|
|
4811
5390
|
const config = loadConfig();
|
|
4812
|
-
const
|
|
4813
|
-
name: opts.name,
|
|
4814
|
-
content: opts.content
|
|
4815
|
-
});
|
|
5391
|
+
const result = await createDoc(config, title, opts.content);
|
|
4816
5392
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4817
|
-
console.log(JSON.stringify(
|
|
5393
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4818
5394
|
} else {
|
|
4819
|
-
console.log(`
|
|
5395
|
+
console.log(`Created doc "${result.title}" (${result.id})`);
|
|
4820
5396
|
}
|
|
4821
|
-
}
|
|
4822
|
-
)
|
|
4823
|
-
)
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
5397
|
+
})
|
|
5398
|
+
);
|
|
5399
|
+
program.command("doc-page-create <docId> <name>").description("Create a page in a doc").option("-c, --content <text>", "Page content (markdown)").option("--parent-page <pageId>", "Parent page ID for nesting").option("--json", "Force JSON output even in terminal").action(
|
|
5400
|
+
wrapAction(
|
|
5401
|
+
async (docId, name, opts) => {
|
|
5402
|
+
const config = loadConfig();
|
|
5403
|
+
const page = await createDocPage(config, docId, name, opts.content, opts.parentPage);
|
|
5404
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5405
|
+
console.log(JSON.stringify(page, null, 2));
|
|
5406
|
+
} else {
|
|
5407
|
+
console.log(`Created page "${page.name}" (${page.id}) in doc ${docId}`);
|
|
5408
|
+
}
|
|
5409
|
+
}
|
|
5410
|
+
)
|
|
5411
|
+
);
|
|
5412
|
+
program.command("doc-page-edit <docId> <pageId>").description("Edit a doc page").option("--name <text>", "New page name").option("-c, --content <text>", "New page content (markdown)").option("--json", "Force JSON output even in terminal").action(
|
|
5413
|
+
wrapAction(
|
|
5414
|
+
async (docId, pageId, opts) => {
|
|
5415
|
+
const config = loadConfig();
|
|
5416
|
+
const page = await editDocPage(config, docId, pageId, {
|
|
5417
|
+
name: opts.name,
|
|
5418
|
+
content: opts.content
|
|
5419
|
+
});
|
|
5420
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5421
|
+
console.log(JSON.stringify(page, null, 2));
|
|
5422
|
+
} else {
|
|
5423
|
+
console.log(`Updated page "${page.name}" (${page.id})`);
|
|
5424
|
+
}
|
|
5425
|
+
}
|
|
5426
|
+
)
|
|
5427
|
+
);
|
|
5428
|
+
program.command("doc-delete <docId>").description("Delete a doc").option("--json", "Force JSON output even in terminal").action(
|
|
5429
|
+
wrapAction(async (docId, opts) => {
|
|
5430
|
+
const config = loadConfig();
|
|
5431
|
+
await deleteDoc(config, docId);
|
|
5432
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5433
|
+
console.log(JSON.stringify({ success: true, docId }, null, 2));
|
|
5434
|
+
} else {
|
|
5435
|
+
console.log(`Deleted doc ${docId}`);
|
|
5436
|
+
}
|
|
5437
|
+
})
|
|
5438
|
+
);
|
|
5439
|
+
program.command("doc-page-delete <docId> <pageId>").description("Delete a doc page").option("--json", "Force JSON output even in terminal").action(
|
|
5440
|
+
wrapAction(async (docId, pageId, opts) => {
|
|
5441
|
+
const config = loadConfig();
|
|
5442
|
+
await deleteDocPage(config, docId, pageId);
|
|
5443
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5444
|
+
console.log(JSON.stringify({ success: true, docId, pageId }, null, 2));
|
|
5445
|
+
} else {
|
|
5446
|
+
console.log(`Deleted page ${pageId} from doc ${docId}`);
|
|
5447
|
+
}
|
|
5448
|
+
})
|
|
5449
|
+
);
|
|
5450
|
+
program.command("tag-update <spaceId> <tagName>").description("Update a tag in a space").requiredOption("--name <newName>", "New tag name").option("--fg <color>", "New foreground color (hex)").option("--bg <color>", "New background color (hex)").option("--json", "Force JSON output even in terminal").action(
|
|
5451
|
+
wrapAction(
|
|
5452
|
+
async (spaceId, tagName, opts) => {
|
|
5453
|
+
const config = loadConfig();
|
|
5454
|
+
await updateSpaceTag(config, spaceId, tagName, {
|
|
5455
|
+
name: opts.name,
|
|
5456
|
+
fg: opts.fg,
|
|
5457
|
+
bg: opts.bg
|
|
5458
|
+
});
|
|
5459
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5460
|
+
console.log(
|
|
5461
|
+
JSON.stringify(
|
|
5462
|
+
{ success: true, spaceId, oldName: tagName, newName: opts.name },
|
|
5463
|
+
null,
|
|
5464
|
+
2
|
|
5465
|
+
)
|
|
5466
|
+
);
|
|
5467
|
+
} else {
|
|
5468
|
+
console.log(`Renamed tag "${tagName}" to "${opts.name}" in space ${spaceId}`);
|
|
5469
|
+
}
|
|
5470
|
+
}
|
|
5471
|
+
)
|
|
5472
|
+
);
|
|
5473
|
+
program.command("task-types").description("List custom task types in your workspace").option("--json", "Force JSON output even in terminal").action(
|
|
5474
|
+
wrapAction(async (opts) => {
|
|
5475
|
+
const config = loadConfig();
|
|
5476
|
+
const types = await listTaskTypes(config);
|
|
5477
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5478
|
+
console.log(JSON.stringify(types, null, 2));
|
|
5479
|
+
} else if (isTTY()) {
|
|
5480
|
+
console.log(formatTaskTypes(types));
|
|
5481
|
+
} else {
|
|
5482
|
+
console.log(formatTaskTypesMarkdown(types));
|
|
5483
|
+
}
|
|
5484
|
+
})
|
|
5485
|
+
);
|
|
5486
|
+
program.command("templates").description("List task templates in your workspace").option("--json", "Force JSON output even in terminal").action(
|
|
5487
|
+
wrapAction(async (opts) => {
|
|
5488
|
+
const config = loadConfig();
|
|
5489
|
+
const templates = await listTemplates(config);
|
|
5490
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5491
|
+
console.log(JSON.stringify(templates, null, 2));
|
|
5492
|
+
} else if (isTTY()) {
|
|
5493
|
+
console.log(formatTemplates(templates));
|
|
5494
|
+
} else {
|
|
5495
|
+
console.log(formatTemplatesMarkdown(templates));
|
|
5496
|
+
}
|
|
5497
|
+
})
|
|
5498
|
+
);
|
|
5499
|
+
const configCmd = program.command("config").description("Manage CLI configuration");
|
|
5500
|
+
configCmd.command("get <key>").description("Print a config value").action(
|
|
5501
|
+
wrapAction(async (key) => {
|
|
5502
|
+
const value = getConfigValue(key);
|
|
5503
|
+
if (value !== void 0) {
|
|
5504
|
+
console.log(value);
|
|
5505
|
+
}
|
|
5506
|
+
})
|
|
5507
|
+
);
|
|
5508
|
+
configCmd.command("set <key> <value>").description("Set a config value").action(
|
|
5509
|
+
wrapAction(async (key, value) => {
|
|
5510
|
+
setConfigValue(key, value);
|
|
5511
|
+
})
|
|
5512
|
+
);
|
|
5513
|
+
configCmd.command("path").description("Print config file path").action(
|
|
5514
|
+
wrapAction(async () => {
|
|
5515
|
+
console.log(configPath2());
|
|
5516
|
+
})
|
|
5517
|
+
);
|
|
5518
|
+
program.command("completion <shell>").description("Output shell completion script (bash, zsh, fish)").action(
|
|
5519
|
+
wrapAction(async (shell) => {
|
|
5520
|
+
const script = generateCompletion(shell, programName);
|
|
5521
|
+
process.stdout.write(script);
|
|
5522
|
+
})
|
|
5523
|
+
);
|
|
5524
|
+
return program;
|
|
5525
|
+
}
|
|
5526
|
+
async function run(argv = process.argv) {
|
|
5527
|
+
const programName = basename(argv[1] ?? "cup");
|
|
5528
|
+
const program = buildProgram(programName);
|
|
5529
|
+
await program.parseAsync(argv);
|
|
5530
|
+
}
|
|
4849
5531
|
process.on("SIGINT", () => {
|
|
4850
5532
|
process.stderr.write("\nInterrupted\n");
|
|
4851
5533
|
process.exit(130);
|
|
4852
5534
|
});
|
|
4853
|
-
|
|
5535
|
+
var isDirectExecution = process.argv[1] !== void 0 && fileURLToPath(import.meta.url) === resolve(process.argv[1]);
|
|
5536
|
+
if (isDirectExecution) {
|
|
5537
|
+
await run();
|
|
5538
|
+
}
|
|
5539
|
+
export {
|
|
5540
|
+
buildProgram,
|
|
5541
|
+
run
|
|
5542
|
+
};
|