@shortcut-cli/shortcut-cli 3.8.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +121 -2
- package/build/bin/{short-api.js → short-api.cjs} +12 -10
- package/build/bin/short-create.cjs +58 -0
- package/build/bin/{short-doc.js → short-doc.cjs} +8 -9
- package/build/bin/{short-docs.js → short-docs.cjs} +18 -19
- package/build/bin/{short-epic.js → short-epic.cjs} +8 -9
- package/build/bin/short-epics.cjs +36 -0
- package/build/bin/{short-find.js → short-find.cjs} +1 -1
- package/build/bin/{short-install.js → short-install.cjs} +8 -9
- package/build/bin/short-iteration.cjs +184 -0
- package/build/bin/short-iterations.cjs +66 -0
- package/build/bin/{short-members.js → short-members.cjs} +6 -7
- package/build/bin/{short-projects.js → short-projects.cjs} +7 -8
- package/build/bin/{short-search.js → short-search.cjs} +20 -25
- package/build/bin/{short-story.js → short-story.cjs} +47 -46
- package/build/bin/{short-workflows.js → short-workflows.cjs} +5 -6
- package/build/bin/short-workspace.cjs +64 -0
- package/build/bin/short.cjs +10 -0
- package/build/lib/client.cjs +11 -0
- package/build/lib/{configure.js → configure.cjs} +3 -3
- package/build/lib/{spinner.js → spinner.cjs} +1 -1
- package/build/lib/{stories.js → stories.cjs} +73 -69
- package/build/{package.js → package.cjs} +1 -1
- package/package.json +67 -67
- package/build/bin/short-create.js +0 -56
- package/build/bin/short-epics.js +0 -37
- package/build/bin/short-workspace.js +0 -64
- package/build/bin/short.js +0 -11
- package/build/lib/client.js +0 -11
- /package/build/_virtual/{rolldown_runtime.js → rolldown_runtime.cjs} +0 -0
package/README.md
CHANGED
|
@@ -16,6 +16,7 @@ This is a community-driven command line interface for [Shortcut](https://shortcu
|
|
|
16
16
|
- [Workspace](#workspace)
|
|
17
17
|
- [Members](#members)
|
|
18
18
|
- [Epics](#epics)
|
|
19
|
+
- [Iterations](#iterations)
|
|
19
20
|
- [Docs](#docs)
|
|
20
21
|
- [Workflows](#workflows)
|
|
21
22
|
- [Projects](#projects)
|
|
@@ -88,6 +89,8 @@ short story 3300
|
|
|
88
89
|
create create a story
|
|
89
90
|
workflows list workflows and their states
|
|
90
91
|
epics list epics and their states
|
|
92
|
+
iterations list iterations
|
|
93
|
+
iteration view, create, update, or delete an iteration
|
|
91
94
|
docs list and search docs
|
|
92
95
|
doc view, create, update, or delete a doc
|
|
93
96
|
projects list or search projects
|
|
@@ -366,6 +369,122 @@ Templating variables:
|
|
|
366
369
|
%co Print completed status of epic
|
|
367
370
|
```
|
|
368
371
|
|
|
372
|
+
### Iterations
|
|
373
|
+
|
|
374
|
+
```
|
|
375
|
+
Usage: short iterations [options]
|
|
376
|
+
|
|
377
|
+
Display iterations available for stories
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
Options:
|
|
381
|
+
|
|
382
|
+
-S, --status [status] Filter by status (unstarted, started, done)
|
|
383
|
+
-T, --team [id|name] Filter by team/group id or name
|
|
384
|
+
-C, --current Show only current/active iterations
|
|
385
|
+
-t, --title [query] Filter iterations with name containing query
|
|
386
|
+
-d, --detailed Show more details for each iteration
|
|
387
|
+
-f, --format [template] Format each iteration output by template
|
|
388
|
+
-h, --help output usage information
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
#### Iteration View, Create, Update, Delete
|
|
392
|
+
|
|
393
|
+
```
|
|
394
|
+
Usage: short iteration [command] [options]
|
|
395
|
+
|
|
396
|
+
view, create, update, or delete iterations
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
Commands:
|
|
400
|
+
|
|
401
|
+
view <id> view an iteration by id
|
|
402
|
+
create create a new iteration
|
|
403
|
+
update <id> update an existing iteration
|
|
404
|
+
delete <id> delete an iteration
|
|
405
|
+
stories <id> list stories in an iteration
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
View an iteration:
|
|
409
|
+
|
|
410
|
+
```
|
|
411
|
+
Usage: short iteration view <id> [options]
|
|
412
|
+
|
|
413
|
+
Options:
|
|
414
|
+
|
|
415
|
+
-O, --open Open iteration in browser
|
|
416
|
+
-h, --help output usage information
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
Create an iteration:
|
|
420
|
+
|
|
421
|
+
```
|
|
422
|
+
Usage: short iteration create [options]
|
|
423
|
+
|
|
424
|
+
Options:
|
|
425
|
+
|
|
426
|
+
-n, --name [text] Set name of iteration (required)
|
|
427
|
+
-d, --description [text] Set description of iteration
|
|
428
|
+
--start-date [date] Set start date (YYYY-MM-DD, required)
|
|
429
|
+
--end-date [date] Set end date (YYYY-MM-DD, required)
|
|
430
|
+
-T, --team [id|name] Set team/group of iteration
|
|
431
|
+
-I, --idonly Print only ID of iteration result
|
|
432
|
+
-O, --open Open iteration in browser
|
|
433
|
+
-h, --help output usage information
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Update an iteration:
|
|
437
|
+
|
|
438
|
+
```
|
|
439
|
+
Usage: short iteration update <id> [options]
|
|
440
|
+
|
|
441
|
+
Options:
|
|
442
|
+
|
|
443
|
+
-n, --name [text] Set name of iteration
|
|
444
|
+
-d, --description [text] Set description of iteration
|
|
445
|
+
--start-date [date] Set start date (YYYY-MM-DD)
|
|
446
|
+
--end-date [date] Set end date (YYYY-MM-DD)
|
|
447
|
+
-T, --team [id|name] Set team/group of iteration
|
|
448
|
+
-O, --open Open iteration in browser
|
|
449
|
+
-h, --help output usage information
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
Delete an iteration:
|
|
453
|
+
|
|
454
|
+
```
|
|
455
|
+
Usage: short iteration delete <id>
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
List stories in an iteration:
|
|
459
|
+
|
|
460
|
+
```
|
|
461
|
+
Usage: short iteration stories <id> [options]
|
|
462
|
+
|
|
463
|
+
Options:
|
|
464
|
+
|
|
465
|
+
-f, --format [template] Format each story output by template
|
|
466
|
+
-h, --help output usage information
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
#### Iteration Output Formatting
|
|
470
|
+
|
|
471
|
+
Templating variables:
|
|
472
|
+
|
|
473
|
+
```
|
|
474
|
+
%id Print ID of iteration
|
|
475
|
+
%t Print title/name of iteration
|
|
476
|
+
%s Print iteration status
|
|
477
|
+
%start Print iteration start date
|
|
478
|
+
%end Print iteration end date
|
|
479
|
+
%teams Print teams assigned to iteration
|
|
480
|
+
%stories Print total number of stories
|
|
481
|
+
%done Print number of completed stories
|
|
482
|
+
%points Print total points
|
|
483
|
+
%pdone Print completed points
|
|
484
|
+
%completion Print completion percentage
|
|
485
|
+
%url Print URL of iteration
|
|
486
|
+
```
|
|
487
|
+
|
|
369
488
|
### Docs
|
|
370
489
|
|
|
371
490
|
```
|
|
@@ -515,13 +634,13 @@ Delete a doc:
|
|
|
515
634
|
You can use TypeScript watcher which will recompile your code automatically:
|
|
516
635
|
|
|
517
636
|
```sh
|
|
518
|
-
|
|
637
|
+
pnpm run build:watch
|
|
519
638
|
```
|
|
520
639
|
|
|
521
640
|
You can run shortcut-cli with TypeScript map enabled:
|
|
522
641
|
|
|
523
642
|
```sh
|
|
524
|
-
|
|
643
|
+
pnpm start -- story 1234
|
|
525
644
|
```
|
|
526
645
|
|
|
527
646
|
## Acknowledgments
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
3
|
-
const
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
3
|
+
const require_lib_spinner = require('../lib/spinner.cjs');
|
|
4
|
+
const require_lib_client = require('../lib/client.cjs');
|
|
4
5
|
let commander = require("commander");
|
|
5
|
-
commander = require_rolldown_runtime.__toESM(commander);
|
|
6
6
|
let debug = require("debug");
|
|
7
7
|
debug = require_rolldown_runtime.__toESM(debug);
|
|
8
8
|
|
|
@@ -13,13 +13,13 @@ const logError = console.error;
|
|
|
13
13
|
const spin = require_lib_spinner.default();
|
|
14
14
|
const parseKeyVal = (input, separator = "=") => {
|
|
15
15
|
const parts = input.split(separator);
|
|
16
|
-
return [parts.shift(), parts.join(separator)];
|
|
16
|
+
return [parts.shift() ?? "", parts.join(separator)];
|
|
17
17
|
};
|
|
18
18
|
const collect = (val, memo) => {
|
|
19
19
|
memo.push(val);
|
|
20
20
|
return memo;
|
|
21
21
|
};
|
|
22
|
-
const program = commander.
|
|
22
|
+
const program = new commander.Command().description("Make a request to the Shortcut API.").arguments("<path>").option("-X, --method <method>", "The HTTP method to use.", "GET").option("-H, --header <header>", "Add a header to the request (e.g., \"Content-Type: application/json\"). Can be specified multiple times.", collect, []).option("-f, --raw-field <key=value>", "Add a string parameter. Can be specified multiple times.", collect, []).on("--help", () => {
|
|
23
23
|
log("");
|
|
24
24
|
log("Examples:");
|
|
25
25
|
log(` $ short api /search/iterations -f page_size=10 -f query=123`);
|
|
@@ -27,6 +27,7 @@ const program = commander.default.description("Make a request to the Shortcut AP
|
|
|
27
27
|
log(" # jq can be used to shorten the response output.");
|
|
28
28
|
log(` $ short api /search/iterations -f page_size=10 -f query=123 | jq '.data[] | {id, name}'`);
|
|
29
29
|
}).parse(process.argv);
|
|
30
|
+
const opts = program.opts();
|
|
30
31
|
const main = async () => {
|
|
31
32
|
const [path] = program.args;
|
|
32
33
|
if (!path) {
|
|
@@ -34,15 +35,15 @@ const main = async () => {
|
|
|
34
35
|
program.help();
|
|
35
36
|
process.exit(1);
|
|
36
37
|
}
|
|
37
|
-
const method = (
|
|
38
|
+
const method = (opts.method || "GET").toUpperCase();
|
|
38
39
|
const headers = {};
|
|
39
40
|
const params = {};
|
|
40
|
-
if (
|
|
41
|
+
if (opts.header) opts.header.forEach((h) => {
|
|
41
42
|
const [key, value] = parseKeyVal(h, ":");
|
|
42
43
|
headers[key] = value;
|
|
43
44
|
debug$1(`adding header: ${key}: ${value}`);
|
|
44
45
|
});
|
|
45
|
-
if (
|
|
46
|
+
if (opts.rawField) opts.rawField.forEach((f) => {
|
|
46
47
|
const [key, value] = parseKeyVal(f);
|
|
47
48
|
params[key] = value;
|
|
48
49
|
debug$1(`adding raw field: ${key}: ${value}`);
|
|
@@ -68,7 +69,8 @@ const main = async () => {
|
|
|
68
69
|
log(JSON.stringify(response.data, null, 2));
|
|
69
70
|
} catch (err) {
|
|
70
71
|
spin.stop(true);
|
|
71
|
-
|
|
72
|
+
const error = err;
|
|
73
|
+
logError("Error calling API:", error.response ? JSON.stringify(error.response.data, null, 2) : error.message);
|
|
72
74
|
process.exit(1);
|
|
73
75
|
}
|
|
74
76
|
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
3
|
+
const require_lib_spinner = require('../lib/spinner.cjs');
|
|
4
|
+
const require_lib_configure = require('../lib/configure.cjs');
|
|
5
|
+
const require_lib_client = require('../lib/client.cjs');
|
|
6
|
+
const require_lib_stories = require('../lib/stories.cjs');
|
|
7
|
+
let commander = require("commander");
|
|
8
|
+
let child_process = require("child_process");
|
|
9
|
+
|
|
10
|
+
//#region src/bin/short-create.ts
|
|
11
|
+
const config = require_lib_configure.loadConfig();
|
|
12
|
+
const spin = require_lib_spinner.default();
|
|
13
|
+
const log = console.log;
|
|
14
|
+
const opts = new commander.Command().usage("[options]").description("create a story with provided details").option("-d, --description [text]", "Set description of story", "").option("-e, --estimate [number]", "Set estimate of story").option("--epic [id|name]", "Set epic of story").option("--git-branch", "Checkout git branch from story slug <mention-name>/ch<id>/<type>-<title>\n as required by the Git integration: https://bit.ly/2RKO1FF").option("--git-branch-short", "Checkout git branch from story slug <mention-name>/ch<id>/<title>").option("-i, --iteration [id|name]", "Set iteration of story").option("-I, --idonly", "Print only ID of story result").option("-l, --label [id|name]", "Stories with label id/name, by regex", "").option("-o, --owners [id|name]", "Set owners of story, comma-separated", "").option("-O, --open", "Open story in browser").option("-p, --project [id|name]", "Set project of story, required if --state is not set", "").option("-T, --team [id|name]", "Set team of story", "").option("-t, --title [text]", "Set title of story, required", "").option("-s, --state [id|name]", "Set workflow state of story, required if --project is not set", "").addOption(new commander.Option("-y, --type <name>", "Set type of story").choices([
|
|
15
|
+
"feature",
|
|
16
|
+
"bug",
|
|
17
|
+
"chore"
|
|
18
|
+
]).default("feature")).parse(process.argv).opts();
|
|
19
|
+
const main = async () => {
|
|
20
|
+
const entities = await require_lib_stories.default.fetchEntities();
|
|
21
|
+
if (!opts.idonly) spin.start();
|
|
22
|
+
const update = {
|
|
23
|
+
name: opts.title,
|
|
24
|
+
story_type: opts.type,
|
|
25
|
+
description: `${opts.description}`
|
|
26
|
+
};
|
|
27
|
+
if (opts.project) update.project_id = require_lib_stories.default.findProject(entities, opts.project)?.id;
|
|
28
|
+
if (opts.team) update.group_id = require_lib_stories.default.findGroup(entities, opts.team)?.id;
|
|
29
|
+
if (opts.state) update.workflow_state_id = require_lib_stories.default.findState(entities, opts.state)?.id;
|
|
30
|
+
if (opts.epic) update.epic_id = require_lib_stories.default.findEpic(entities, opts.epic)?.id;
|
|
31
|
+
if (opts.iteration) update.iteration_id = require_lib_stories.default.findIteration(entities, opts.iteration)?.id;
|
|
32
|
+
if (opts.estimate) update.estimate = parseInt(opts.estimate, 10);
|
|
33
|
+
if (opts.owners) update.owner_ids = require_lib_stories.default.findOwnerIds(entities, opts.owners);
|
|
34
|
+
if (opts.label) update.labels = require_lib_stories.default.findLabelNames(entities, opts.label);
|
|
35
|
+
let story;
|
|
36
|
+
if (!update.name) {
|
|
37
|
+
if (!opts.idonly) spin.stop(true);
|
|
38
|
+
log("Must provide --title");
|
|
39
|
+
} else if (!update.project_id && !update.workflow_state_id) {
|
|
40
|
+
if (!opts.idonly) spin.stop(true);
|
|
41
|
+
log("Must provide --project or --state");
|
|
42
|
+
} else try {
|
|
43
|
+
story = await require_lib_client.default.createStory(update).then((r) => r.data);
|
|
44
|
+
} catch (e) {
|
|
45
|
+
log("Error creating story");
|
|
46
|
+
}
|
|
47
|
+
if (!opts.idonly) spin.stop(true);
|
|
48
|
+
if (story) {
|
|
49
|
+
const hydrateStory = require_lib_stories.default.hydrateStory(entities, story);
|
|
50
|
+
require_lib_stories.default.printDetailedStory(hydrateStory);
|
|
51
|
+
if (opts.gitBranch) require_lib_stories.default.checkoutStoryBranch(hydrateStory);
|
|
52
|
+
else if (opts.gitBranchShort) require_lib_stories.default.checkoutStoryBranch(hydrateStory, `${config.mentionName}/sc-${story.id}/`);
|
|
53
|
+
if (opts.open) (0, child_process.exec)("open " + require_lib_stories.default.storyURL(story));
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
main();
|
|
57
|
+
|
|
58
|
+
//#endregion
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.
|
|
3
|
-
const require_lib_spinner = require('../lib/spinner.
|
|
4
|
-
const require_lib_client = require('../lib/client.
|
|
2
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
3
|
+
const require_lib_spinner = require('../lib/spinner.cjs');
|
|
4
|
+
const require_lib_client = require('../lib/client.cjs');
|
|
5
5
|
let commander = require("commander");
|
|
6
|
-
commander = require_rolldown_runtime.__toESM(commander);
|
|
7
6
|
let os = require("os");
|
|
8
7
|
os = require_rolldown_runtime.__toESM(os);
|
|
9
8
|
let child_process = require("child_process");
|
|
@@ -13,7 +12,7 @@ chalk = require_rolldown_runtime.__toESM(chalk);
|
|
|
13
12
|
//#region src/bin/short-doc.ts
|
|
14
13
|
const spin = require_lib_spinner.default();
|
|
15
14
|
const log = console.log;
|
|
16
|
-
const program = commander.
|
|
15
|
+
const program = new commander.Command().usage("[command] [options]").description("view, create, or update a doc");
|
|
17
16
|
program.command("view <id>").description("view a doc by ID").option("--html", "Include HTML content in output").option("-O, --open", "Open doc in browser").option("-q, --quiet", "Print only doc content, no metadata").action(viewDoc);
|
|
18
17
|
program.command("create").description("create a new doc").option("-t, --title <text>", "Set title of doc (required)").option("-c, --content <text>", "Set content of doc (required)").option("--markdown", "Treat content as markdown (default is HTML)").option("-I, --idonly", "Print only ID of doc result").option("-O, --open", "Open doc in browser").action(createDoc);
|
|
19
18
|
program.command("update <id>").description("update an existing doc").option("-t, --title <text>", "Update title of doc").option("-c, --content <text>", "Update content of doc").option("--markdown", "Treat content as markdown (default is HTML)").option("-O, --open", "Open doc in browser").action(updateDoc);
|
|
@@ -48,7 +47,7 @@ async function viewDoc(id, options) {
|
|
|
48
47
|
doc = await require_lib_client.default.getDoc(id, params).then((r) => r.data);
|
|
49
48
|
} catch (e) {
|
|
50
49
|
if (!options.quiet) spin.stop(true);
|
|
51
|
-
log("Error fetching doc:", e.message
|
|
50
|
+
log("Error fetching doc:", e.message ?? String(e));
|
|
52
51
|
process.exit(1);
|
|
53
52
|
}
|
|
54
53
|
if (!options.quiet) spin.stop(true);
|
|
@@ -77,7 +76,7 @@ async function createDoc(options) {
|
|
|
77
76
|
doc = await require_lib_client.default.getDoc(result.data.id).then((r) => r.data);
|
|
78
77
|
} catch (e) {
|
|
79
78
|
if (!options.idonly) spin.stop(true);
|
|
80
|
-
log("Error creating doc:", e.message
|
|
79
|
+
log("Error creating doc:", e.message ?? String(e));
|
|
81
80
|
process.exit(1);
|
|
82
81
|
}
|
|
83
82
|
if (!options.idonly) spin.stop(true);
|
|
@@ -105,7 +104,7 @@ async function updateDoc(id, options) {
|
|
|
105
104
|
doc = await require_lib_client.default.updateDoc(id, docData).then((r) => r.data);
|
|
106
105
|
} catch (e) {
|
|
107
106
|
spin.stop(true);
|
|
108
|
-
log("Error updating doc:", e.message
|
|
107
|
+
log("Error updating doc:", e.message ?? String(e));
|
|
109
108
|
process.exit(1);
|
|
110
109
|
}
|
|
111
110
|
spin.stop(true);
|
|
@@ -124,7 +123,7 @@ async function deleteDoc(id, options) {
|
|
|
124
123
|
await require_lib_client.default.deleteDoc(id, {});
|
|
125
124
|
} catch (e) {
|
|
126
125
|
spin.stop(true);
|
|
127
|
-
log("Error deleting doc:", e.message
|
|
126
|
+
log("Error deleting doc:", e.message ?? String(e));
|
|
128
127
|
process.exit(1);
|
|
129
128
|
}
|
|
130
129
|
spin.stop(true);
|
|
@@ -1,40 +1,39 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.
|
|
3
|
-
const require_lib_spinner = require('../lib/spinner.
|
|
4
|
-
const require_lib_client = require('../lib/client.
|
|
2
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
3
|
+
const require_lib_spinner = require('../lib/spinner.cjs');
|
|
4
|
+
const require_lib_client = require('../lib/client.cjs');
|
|
5
5
|
let commander = require("commander");
|
|
6
|
-
commander = require_rolldown_runtime.__toESM(commander);
|
|
7
6
|
|
|
8
7
|
//#region src/bin/short-docs.ts
|
|
9
8
|
const spin = require_lib_spinner.default("Loading docs... %s ");
|
|
10
9
|
const log = console.log;
|
|
11
|
-
const
|
|
12
|
-
Use --title to search docs by title.`).usage("[options]").option("-a, --archived", "Search for archived docs (requires --title)").option("-m, --mine", "Search for docs created by me (requires --title)").option("-f, --following", "Search for docs I am following (requires --title)").option("-t, --title [text]", "Search docs by title (required for search filters)").option("-q, --quiet", "Print only doc output, no loading dialog").option("-I, --idonly", "Print only IDs of doc results").parse(process.argv);
|
|
10
|
+
const opts = new commander.Command().description(`List and search Shortcut Docs. By default, lists all docs you have access to.
|
|
11
|
+
Use --title to search docs by title.`).usage("[options]").option("-a, --archived", "Search for archived docs (requires --title)").option("-m, --mine", "Search for docs created by me (requires --title)").option("-f, --following", "Search for docs I am following (requires --title)").option("-t, --title [text]", "Search docs by title (required for search filters)").option("-q, --quiet", "Print only doc output, no loading dialog").option("-I, --idonly", "Print only IDs of doc results").parse(process.argv).opts();
|
|
13
12
|
const main = async () => {
|
|
14
|
-
if (!
|
|
13
|
+
if (!opts.quiet) spin.start();
|
|
15
14
|
let docs = [];
|
|
16
15
|
try {
|
|
17
|
-
if (
|
|
18
|
-
const searchParams = { title:
|
|
19
|
-
if (
|
|
20
|
-
if (
|
|
21
|
-
if (
|
|
16
|
+
if (opts.title) {
|
|
17
|
+
const searchParams = { title: opts.title };
|
|
18
|
+
if (opts.archived !== void 0) searchParams.archived = !!opts.archived;
|
|
19
|
+
if (opts.mine) searchParams.created_by_me = true;
|
|
20
|
+
if (opts.following) searchParams.followed_by_me = true;
|
|
22
21
|
docs = (await require_lib_client.default.searchDocuments(searchParams)).data.data;
|
|
23
22
|
} else {
|
|
24
|
-
if (
|
|
25
|
-
if (!
|
|
23
|
+
if (opts.archived || opts.mine || opts.following) {
|
|
24
|
+
if (!opts.quiet) spin.stop(true);
|
|
26
25
|
log("Note: --archived, --mine, and --following require --title for searching.");
|
|
27
26
|
log("Listing all docs instead...");
|
|
28
|
-
if (!
|
|
27
|
+
if (!opts.quiet) spin.start();
|
|
29
28
|
}
|
|
30
29
|
docs = (await require_lib_client.default.listDocs()).data;
|
|
31
30
|
}
|
|
32
31
|
} catch (e) {
|
|
33
|
-
if (!
|
|
34
|
-
log("Error fetching docs:", e.message
|
|
32
|
+
if (!opts.quiet) spin.stop(true);
|
|
33
|
+
log("Error fetching docs:", e.message ?? String(e));
|
|
35
34
|
process.exit(1);
|
|
36
35
|
}
|
|
37
|
-
if (!
|
|
36
|
+
if (!opts.quiet) spin.stop(true);
|
|
38
37
|
if (docs.length === 0) {
|
|
39
38
|
log("No docs found.");
|
|
40
39
|
return;
|
|
@@ -42,7 +41,7 @@ const main = async () => {
|
|
|
42
41
|
docs.forEach((doc) => printDoc(doc));
|
|
43
42
|
};
|
|
44
43
|
const printDoc = (doc) => {
|
|
45
|
-
if (
|
|
44
|
+
if (opts.idonly) return log(doc.id);
|
|
46
45
|
log(`${doc.id} ${doc.title || "(Untitled)"}`);
|
|
47
46
|
log(`\tURL: ${doc.app_url}`);
|
|
48
47
|
};
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.
|
|
3
|
-
const require_lib_spinner = require('../lib/spinner.
|
|
4
|
-
const require_lib_configure = require('../lib/configure.
|
|
5
|
-
const require_lib_client = require('../lib/client.
|
|
6
|
-
const require_lib_stories = require('../lib/stories.
|
|
2
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
3
|
+
const require_lib_spinner = require('../lib/spinner.cjs');
|
|
4
|
+
const require_lib_configure = require('../lib/configure.cjs');
|
|
5
|
+
const require_lib_client = require('../lib/client.cjs');
|
|
6
|
+
const require_lib_stories = require('../lib/stories.cjs');
|
|
7
7
|
let commander = require("commander");
|
|
8
|
-
commander = require_rolldown_runtime.__toESM(commander);
|
|
9
8
|
let child_process = require("child_process");
|
|
10
9
|
|
|
11
10
|
//#region src/bin/short-epic.ts
|
|
12
11
|
const config = require_lib_configure.loadConfig();
|
|
13
12
|
const spin = require_lib_spinner.default();
|
|
14
13
|
const log = console.log;
|
|
15
|
-
const program = commander.
|
|
14
|
+
const program = new commander.Command().usage("[command] [options]").description("create or view epics");
|
|
16
15
|
program.command("create").description("create a new epic").option("-n, --name [text]", "Set name of epic, required", "").option("-d, --description [text]", "Set description of epic", "").option("-s, --state [name]", "Set state of epic (to do, in progress, done)", "").option("--deadline [date]", "Set deadline for epic (YYYY-MM-DD)", "").option("--planned-start [date]", "Set planned start date (YYYY-MM-DD)", "").option("-o, --owners [id|name]", "Set owners of epic, comma-separated", "").option("-T, --team [id|name]", "Set team of epic", "").option("-l, --label [id|name]", "Set labels of epic, comma-separated", "").option("-M, --milestone [id]", "Set milestone of epic (deprecated, use objectives)", "").option("-I, --idonly", "Print only ID of epic result").option("-O, --open", "Open epic in browser").action(createEpic);
|
|
17
16
|
program.parse(process.argv);
|
|
18
17
|
async function createEpic(options) {
|
|
@@ -36,7 +35,7 @@ async function createEpic(options) {
|
|
|
36
35
|
if (options.owners) epicData.owner_ids = require_lib_stories.default.findOwnerIds(entities, options.owners);
|
|
37
36
|
if (options.team) {
|
|
38
37
|
const group = require_lib_stories.default.findGroup(entities, options.team);
|
|
39
|
-
if (group
|
|
38
|
+
if (group?.id) epicData.group_ids = [group.id];
|
|
40
39
|
}
|
|
41
40
|
if (options.label) epicData.labels = require_lib_stories.default.findLabelNames(entities, options.label);
|
|
42
41
|
if (options.milestone) epicData.milestone_id = parseInt(options.milestone, 10);
|
|
@@ -49,7 +48,7 @@ async function createEpic(options) {
|
|
|
49
48
|
epic = await require_lib_client.default.createEpic(epicData).then((r) => r.data);
|
|
50
49
|
} catch (e) {
|
|
51
50
|
if (!options.idonly) spin.stop(true);
|
|
52
|
-
log("Error creating epic:", e.message
|
|
51
|
+
log("Error creating epic:", e.message ?? String(e));
|
|
53
52
|
process.exit(1);
|
|
54
53
|
}
|
|
55
54
|
if (!options.idonly) spin.stop(true);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
3
|
+
const require_lib_spinner = require('../lib/spinner.cjs');
|
|
4
|
+
const require_lib_client = require('../lib/client.cjs');
|
|
5
|
+
let commander = require("commander");
|
|
6
|
+
let chalk = require("chalk");
|
|
7
|
+
chalk = require_rolldown_runtime.__toESM(chalk);
|
|
8
|
+
|
|
9
|
+
//#region src/bin/short-epics.ts
|
|
10
|
+
const log = console.log;
|
|
11
|
+
const spin = require_lib_spinner.default();
|
|
12
|
+
const opts = new commander.Command().description("Display epics available for stories").option("-a, --archived", "List only epics including archived", "").option("-c, --completed", "List only epics that have been completed", "").option("-d, --detailed", "List more details for each epic", "").option("-f, --format [template]", "Format each epic output by template", "").option("-M, --milestone [ID]", "List epics in milestone matching id", "").option("-t, --title [query]", "List epics with name/title containing query", "").option("-s, --started", "List epics that have been started", "").parse(process.argv).opts();
|
|
13
|
+
const main = async () => {
|
|
14
|
+
spin.start();
|
|
15
|
+
const epics = await require_lib_client.default.listEpics(null).then((r) => r.data);
|
|
16
|
+
spin.stop(true);
|
|
17
|
+
const textMatch = new RegExp(opts.title ?? "", "i");
|
|
18
|
+
epics.filter((epic) => {
|
|
19
|
+
return !!`${epic.name} ${epic.name}`.match(textMatch) && !!(opts.milestone ? String(epic.milestone_id) === opts.milestone : true);
|
|
20
|
+
}).map(printItem);
|
|
21
|
+
};
|
|
22
|
+
const printItem = (epic) => {
|
|
23
|
+
if (epic.archived && !opts.archived) return;
|
|
24
|
+
if (!epic.started && opts.started) return;
|
|
25
|
+
if (!epic.completed && opts.completed) return;
|
|
26
|
+
let defaultFormat = `#%id %t\nMilestone:\t%m\nState:\t\t%s\nDeadline:\t%dl\n`;
|
|
27
|
+
defaultFormat += `Points:\t\t%p\nPoints Started: %ps\nPoints Done:\t%pd\nCompletion:\t%c\n`;
|
|
28
|
+
if (epic.archived) defaultFormat += `Archived:\t%ar\n`;
|
|
29
|
+
if (epic.started) defaultFormat += `Started:\t%st\n`;
|
|
30
|
+
if (epic.completed) defaultFormat += `Completed:\t%co\n`;
|
|
31
|
+
if (opts.detailed) defaultFormat += `Description:\t%d\n`;
|
|
32
|
+
log((opts.format || defaultFormat).replace(/%id/, chalk.default.bold(`${epic.id}`)).replace(/%t/, chalk.default.blue(`${epic.name}`)).replace(/%m/, `${epic.milestone_id || "_"}`).replace(/%s/, `${epic.state}`).replace(/%dl/, `${epic.deadline || "_"}`).replace(/%d/, `${epic.description}`).replace(/%p/, `${epic.stats.num_points}`).replace(/%ps/, `${epic.stats.num_points_started}`).replace(/%pd/, `${epic.stats.num_points_done}`).replace(/%c/, `${Math.round(epic.stats.num_points_done / (epic.stats.num_points || 1) * 100)}%`).replace(/%a/, `${epic.archived}`).replace(/%st/, `${epic.started_at}`).replace(/%co/, `${epic.completed_at}`));
|
|
33
|
+
};
|
|
34
|
+
main();
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.
|
|
3
|
-
const require_lib_configure = require('../lib/configure.
|
|
4
|
-
const require_package = require('../package.
|
|
2
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
3
|
+
const require_lib_configure = require('../lib/configure.cjs');
|
|
4
|
+
const require_package = require('../package.cjs');
|
|
5
5
|
let commander = require("commander");
|
|
6
|
-
|
|
7
|
-
let __shortcut_client = require("@shortcut/client");
|
|
6
|
+
let _shortcut_client = require("@shortcut/client");
|
|
8
7
|
let prompt = require("prompt");
|
|
9
8
|
prompt = require_rolldown_runtime.__toESM(prompt);
|
|
10
9
|
|
|
11
10
|
//#region src/bin/short-install.ts
|
|
12
11
|
const extant = require_lib_configure.loadCachedConfig();
|
|
13
12
|
const log = console.log;
|
|
14
|
-
const
|
|
13
|
+
const opts = new commander.Command().version(require_package.version).description("Install access token and other settings for the Shortcut API").option("-f, --force", "Force install/reinstall").option("-r, --refresh", "Refresh the configuration with details from Shortcut.").parse(process.argv).opts();
|
|
15
14
|
const enrichConfigWithMemberDetails = async (config) => {
|
|
16
15
|
log("Fetching user/member details from Shortcut...");
|
|
17
|
-
const member = await new
|
|
16
|
+
const member = await new _shortcut_client.ShortcutClient(config.token).getCurrentMemberInfo().then((r) => r.data);
|
|
18
17
|
return {
|
|
19
18
|
mentionName: member.mention_name,
|
|
20
19
|
urlSlug: member.workspace2.url_slug,
|
|
@@ -22,8 +21,8 @@ const enrichConfigWithMemberDetails = async (config) => {
|
|
|
22
21
|
};
|
|
23
22
|
};
|
|
24
23
|
const main = async () => {
|
|
25
|
-
if (
|
|
26
|
-
else if (!extant.token ||
|
|
24
|
+
if (opts.refresh) require_lib_configure.updateConfig(await enrichConfigWithMemberDetails(extant));
|
|
25
|
+
else if (!extant.token || opts.force) {
|
|
27
26
|
const schema = { properties: { token: {
|
|
28
27
|
message: "API Token -> https://app.shortcut.com/xxxx/settings/account/api-tokens",
|
|
29
28
|
required: true
|