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