@shortcut-cli/shortcut-cli 3.8.0 → 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.
Files changed (30) hide show
  1. package/README.md +121 -2
  2. package/build/bin/{short-api.js → short-api.cjs} +12 -10
  3. package/build/bin/short-create.cjs +58 -0
  4. package/build/bin/{short-doc.js → short-doc.cjs} +8 -9
  5. package/build/bin/{short-docs.js → short-docs.cjs} +18 -19
  6. package/build/bin/{short-epic.js → short-epic.cjs} +8 -9
  7. package/build/bin/short-epics.cjs +36 -0
  8. package/build/bin/{short-find.js → short-find.cjs} +1 -1
  9. package/build/bin/{short-install.js → short-install.cjs} +8 -9
  10. package/build/bin/short-iteration.cjs +184 -0
  11. package/build/bin/short-iterations.cjs +66 -0
  12. package/build/bin/{short-members.js → short-members.cjs} +6 -7
  13. package/build/bin/{short-projects.js → short-projects.cjs} +7 -8
  14. package/build/bin/{short-search.js → short-search.cjs} +20 -25
  15. package/build/bin/{short-story.js → short-story.cjs} +47 -46
  16. package/build/bin/{short-workflows.js → short-workflows.cjs} +5 -6
  17. package/build/bin/short-workspace.cjs +64 -0
  18. package/build/bin/short.cjs +10 -0
  19. package/build/lib/client.cjs +11 -0
  20. package/build/lib/{configure.js → configure.cjs} +3 -3
  21. package/build/lib/{spinner.js → spinner.cjs} +1 -1
  22. package/build/lib/{stories.js → stories.cjs} +73 -69
  23. package/build/{package.js → package.cjs} +1 -1
  24. package/package.json +67 -67
  25. package/build/bin/short-create.js +0 -56
  26. package/build/bin/short-epics.js +0 -37
  27. package/build/bin/short-workspace.js +0 -64
  28. package/build/bin/short.js +0 -11
  29. package/build/lib/client.js +0 -11
  30. /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
- npm run build:watch
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
- npm start -- story 1234
643
+ pnpm start -- story 1234
525
644
  ```
526
645
 
527
646
  ## Acknowledgments
@@ -1,8 +1,8 @@
1
- const require_rolldown_runtime = require('../_virtual/rolldown_runtime.js');
2
- const require_lib_spinner = require('../lib/spinner.js');
3
- const require_lib_client = require('../lib/client.js');
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.default.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", () => {
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 = (program.method || "GET").toUpperCase();
38
+ const method = (opts.method || "GET").toUpperCase();
38
39
  const headers = {};
39
40
  const params = {};
40
- if (program.header) program.header.forEach((h) => {
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 (program.rawField) program.rawField.forEach((f) => {
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
- logError("Error calling API:", err.response ? JSON.stringify(err.response.data, null, 2) : err.message);
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.js');
3
- const require_lib_spinner = require('../lib/spinner.js');
4
- const require_lib_client = require('../lib/client.js');
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.default.usage("[command] [options]").description("view, create, or update a doc");
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 || e);
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 || e);
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 || e);
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 || e);
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.js');
3
- const require_lib_spinner = require('../lib/spinner.js');
4
- const require_lib_client = require('../lib/client.js');
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 program = commander.default.description(`List and search Shortcut Docs. By default, lists all docs you have access to.
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 (!program.quiet) spin.start();
13
+ if (!opts.quiet) spin.start();
15
14
  let docs = [];
16
15
  try {
17
- if (program.title) {
18
- const searchParams = { title: program.title };
19
- if (program.archived !== void 0) searchParams.archived = !!program.archived;
20
- if (program.mine) searchParams.created_by_me = true;
21
- if (program.following) searchParams.followed_by_me = true;
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 (program.archived || program.mine || program.following) {
25
- if (!program.quiet) spin.stop(true);
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 (!program.quiet) spin.start();
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 (!program.quiet) spin.stop(true);
34
- log("Error fetching docs:", e.message || e);
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 (!program.quiet) spin.stop(true);
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 (program.idonly) return log(doc.id);
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.js');
3
- const require_lib_spinner = require('../lib/spinner.js');
4
- const require_lib_configure = require('../lib/configure.js');
5
- const require_lib_client = require('../lib/client.js');
6
- const require_lib_stories = require('../lib/stories.js');
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.default.usage("[command] [options]").description("create or view epics");
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 === null || group === void 0 ? void 0 : group.id) epicData.group_ids = [group.id];
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 || e);
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,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const require_bin_short_search = require('./short-search.js');
2
+ const require_bin_short_search = require('./short-search.cjs');
3
3
 
4
4
  //#region src/bin/short-find.ts
5
5
  require_bin_short_search.main();
@@ -1,20 +1,19 @@
1
1
  #!/usr/bin/env node
2
- const require_rolldown_runtime = require('../_virtual/rolldown_runtime.js');
3
- const require_lib_configure = require('../lib/configure.js');
4
- const require_package = require('../package.js');
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
- commander = require_rolldown_runtime.__toESM(commander);
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 program = commander.default.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);
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 __shortcut_client.ShortcutClient(config.token).getCurrentMemberInfo().then((r) => r.data);
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 (program.refresh) require_lib_configure.updateConfig(await enrichConfigWithMemberDetails(extant));
26
- else if (!extant.token || program.force) {
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