jiradc-cli 1.0.10 → 1.0.12

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 (3) hide show
  1. package/README.md +143 -0
  2. package/dist/index.js +153 -35
  3. package/package.json +4 -4
package/README.md ADDED
@@ -0,0 +1,143 @@
1
+ # jiradc-cli
2
+
3
+ Command-line interface for [Jira Data Center](https://developer.atlassian.com/server/jira/platform/rest-apis/). 35 commands across 6 domains — issues, projects, boards, sprints, fields, and users.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g jiradc-cli
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ ```bash
14
+ export JIRA_URL="https://jira.example.com" # Base URL of your Jira instance
15
+ export JIRA_TOKEN="your-personal-access-token" # HTTP Access Token from Jira
16
+ ```
17
+
18
+ ## Commands
19
+
20
+ All commands output JSON. Add `--pretty` to pretty-print.
21
+
22
+ ### issue
23
+
24
+ | Command | Description |
25
+ |---------|-------------|
26
+ | `jiradc issue get <key>` | Get issue details (`--fields` to select, `--expand` for changelog/transitions) |
27
+ | `jiradc issue search <jql>` | Search issues with JQL |
28
+ | `jiradc issue create` | Create an issue (`--project`, `--type`, `--summary`, `--description`, `--custom-fields`) |
29
+ | `jiradc issue update <key>` | Update an issue |
30
+ | `jiradc issue delete <key>` | Delete an issue |
31
+ | `jiradc issue transition <key> <transitionId>` | Transition issue to a new status |
32
+ | `jiradc issue transitions <key>` | List available transitions |
33
+ | `jiradc issue comment <key>` | Add a comment |
34
+ | `jiradc issue comment-edit <key> <commentId>` | Edit a comment |
35
+ | `jiradc issue link <key> <targetKey>` | Link two issues (`--type` link type name) |
36
+ | `jiradc issue unlink <linkId>` | Remove a link |
37
+ | `jiradc issue link-types` | List available link types |
38
+ | `jiradc issue link-epic <epicKey> <issueKey>` | Link an issue to an epic |
39
+ | `jiradc issue worklog <key>` | Add a work log entry |
40
+ | `jiradc issue get-worklog <key>` | Get work log entries |
41
+ | `jiradc issue changelog <key>` | Get issue changelog |
42
+ | `jiradc issue batch-changelog` | Get changelog for multiple issues (`--keys`) |
43
+ | `jiradc issue clone <key>` | Clone an issue with subtasks |
44
+ | `jiradc issue batch-create` | Create multiple issues from JSON |
45
+ | `jiradc issue dev-status <key>` | Get development status (branches, PRs, commits) |
46
+
47
+ #### issue attachment
48
+
49
+ | Command | Description |
50
+ |---------|-------------|
51
+ | `jiradc issue attachment list <key>` | List attachments |
52
+ | `jiradc issue attachment download <key> <attachmentId>` | Download a specific attachment |
53
+ | `jiradc issue attachment download-all <key>` | Download all attachments |
54
+ | `jiradc issue attachment upload <key> <files...>` | Upload files |
55
+ | `jiradc issue attachment delete <attachmentId>` | Delete an attachment |
56
+
57
+ ### project
58
+
59
+ | Command | Description |
60
+ |---------|-------------|
61
+ | `jiradc project list` | List projects |
62
+ | `jiradc project versions <key>` | List versions for a project |
63
+ | `jiradc project components <key>` | List components for a project |
64
+
65
+ ### board
66
+
67
+ | Command | Description |
68
+ |---------|-------------|
69
+ | `jiradc board list` | List boards (`--project`, `--type`: scrum/kanban/simple, `--name`) |
70
+ | `jiradc board issues <boardId>` | Get issues on a board |
71
+
72
+ ### sprint
73
+
74
+ | Command | Description |
75
+ |---------|-------------|
76
+ | `jiradc sprint list <boardId>` | List sprints (`--state`: future/active/closed) |
77
+ | `jiradc sprint issues <boardId> <sprintId>` | Get issues in a sprint |
78
+ | `jiradc sprint create <boardId>` | Create a sprint |
79
+ | `jiradc sprint update <sprintId>` | Update a sprint |
80
+
81
+ ### field
82
+
83
+ | Command | Description |
84
+ |---------|-------------|
85
+ | `jiradc field search` | Search for fields (`--query`, `--type`: custom/system) |
86
+ | `jiradc field options <fieldKey>` | Get allowed values for a field (`--project`, `--issue-type`) |
87
+
88
+ ### user
89
+
90
+ | Command | Description |
91
+ |---------|-------------|
92
+ | `jiradc user me` | Get current user info |
93
+
94
+ ## Pagination
95
+
96
+ Search and list commands accept `--max` to control page size (Jira DC caps at 50 for agile endpoints). Responses include `nextPage` — pass it back as `--start-at` to fetch the next page. When `nextPage` is `null`, there are no more results.
97
+
98
+ ## Examples
99
+
100
+ ```bash
101
+ # Get an issue with default fields
102
+ jiradc issue get AI-123
103
+
104
+ # Get an issue with specific fields
105
+ jiradc issue get AI-123 --fields summary,status,assignee,customfield_10100
106
+
107
+ # Search with JQL
108
+ jiradc issue search 'project = AI AND status = "In Development" ORDER BY updated DESC'
109
+
110
+ # Create an issue
111
+ jiradc issue create --project AI --type Task --summary "Implement feature X" --description "Details here"
112
+
113
+ # Create with custom fields
114
+ jiradc issue create --project AI --type Story --summary "User login" --custom-fields '{"customfield_10100": "value"}'
115
+
116
+ # Transition an issue (find transition ID first)
117
+ jiradc issue transitions AI-123
118
+ jiradc issue transition AI-123 31
119
+
120
+ # Add a comment
121
+ jiradc issue comment AI-123 --body "Fixed in commit abc123"
122
+
123
+ # Link two issues
124
+ jiradc issue link AI-123 AI-456 --type "blocks"
125
+
126
+ # Log work
127
+ jiradc issue worklog AI-123 --time "2h 30m" --comment "Code review"
128
+
129
+ # List active sprints
130
+ jiradc sprint list 42 --state active
131
+
132
+ # Get sprint issues
133
+ jiradc sprint issues 42 100
134
+
135
+ # Find a custom field key
136
+ jiradc field search --query "story points"
137
+
138
+ # Clone an issue with subtasks
139
+ jiradc issue clone AI-123
140
+
141
+ # Get dev status (linked branches, PRs)
142
+ jiradc issue dev-status AI-123
143
+ ```
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { readFileSync } from "fs";
5
5
  import { dirname, join as join4 } from "path";
6
6
  import { fileURLToPath } from "url";
7
7
  import { styleText } from "util";
8
- import { Command as Command6 } from "commander";
8
+ import { Command as Command8 } from "commander";
9
9
 
10
10
  // src/commands/board/issues.ts
11
11
  import { Argument } from "commander";
@@ -226,6 +226,135 @@ Examples:
226
226
  issues(board);
227
227
  }
228
228
 
229
+ // src/commands/component/create.ts
230
+ import { Option as Option2 } from "commander";
231
+ var ASSIGNEE_TYPES = [
232
+ "PROJECT_DEFAULT",
233
+ "COMPONENT_LEAD",
234
+ "PROJECT_LEAD",
235
+ "UNASSIGNED"
236
+ ];
237
+ function create(parent) {
238
+ parent.command("create").description("Create a new component in a project").requiredOption("--project <key>", "Project key (e.g., AI)").requiredOption("--name <name>", "Component name").option("--description <text>", "Component description").option("--lead <username>", "Username of the component lead").addOption(new Option2("--assignee-type <type>", "Assignee strategy").choices(ASSIGNEE_TYPES)).addHelpText(
239
+ "after",
240
+ `
241
+ Examples:
242
+ jiradc component create --project AI --name Backend
243
+ jiradc component create --project AI --name Frontend --description "UI work" --lead jsmith
244
+ jiradc component create --project AI --name Infra --assignee-type COMPONENT_LEAD --lead jsmith`
245
+ ).action(
246
+ async (opts) => {
247
+ const client = getClient();
248
+ const result = await client.components.create({
249
+ project: opts.project,
250
+ name: opts.name,
251
+ description: opts.description,
252
+ leadUserName: opts.lead,
253
+ assigneeType: opts.assigneeType
254
+ });
255
+ output(result);
256
+ }
257
+ );
258
+ }
259
+
260
+ // src/commands/component/delete.ts
261
+ function deleteComponent(parent) {
262
+ parent.command("delete <id>").description("Delete a component, optionally reassigning its issues to another component").option("--move-issues-to <id>", "Reassign existing issues to this component ID before deletion").addHelpText(
263
+ "after",
264
+ `
265
+ Examples:
266
+ jiradc component delete 11289
267
+ jiradc component delete 11289 --move-issues-to 11290`
268
+ ).action(async (id, opts) => {
269
+ const client = getClient();
270
+ await client.components.delete({ id, moveIssuesTo: opts.moveIssuesTo });
271
+ output({ deleted: true, componentId: id, ...opts.moveIssuesTo && { movedIssuesTo: opts.moveIssuesTo } });
272
+ });
273
+ }
274
+
275
+ // src/commands/component/get.ts
276
+ function get(parent) {
277
+ parent.command("get <id>").description("Get a component by ID").addHelpText("after", "\nExamples:\n jiradc component get 11289").action(async (id) => {
278
+ const client = getClient();
279
+ const result = await client.components.get({ id });
280
+ output(result);
281
+ });
282
+ }
283
+
284
+ // src/commands/component/issue-count.ts
285
+ function issueCount(parent) {
286
+ parent.command("issue-count <id>").description("Get the number of issues currently using this component").addHelpText("after", "\nExamples:\n jiradc component issue-count 11289").action(async (id) => {
287
+ const client = getClient();
288
+ const result = await client.components.getRelatedIssueCounts({ id });
289
+ output(result);
290
+ });
291
+ }
292
+
293
+ // src/commands/component/list.ts
294
+ function list2(parent) {
295
+ parent.command("list <projectKey>").description("List all components for a project").addHelpText("after", "\nExamples:\n jiradc component list AI").action(async (projectKey) => {
296
+ const client = getClient();
297
+ const result = await client.components.list({ projectKeyOrId: projectKey });
298
+ output(result);
299
+ });
300
+ }
301
+
302
+ // src/commands/component/update.ts
303
+ import { Option as Option3 } from "commander";
304
+ var ASSIGNEE_TYPES2 = [
305
+ "PROJECT_DEFAULT",
306
+ "COMPONENT_LEAD",
307
+ "PROJECT_LEAD",
308
+ "UNASSIGNED"
309
+ ];
310
+ function update(parent) {
311
+ parent.command("update <id>").description("Update an existing component (only provided fields are changed)").option("--name <name>", "New component name").option("--description <text>", "New component description").option("--lead <username>", "Username of the component lead (empty string clears it)").addOption(new Option3("--assignee-type <type>", "New assignee strategy").choices(ASSIGNEE_TYPES2)).addHelpText(
312
+ "after",
313
+ `
314
+ Examples:
315
+ jiradc component update 11289 --name Backend
316
+ jiradc component update 11289 --description "Server-side code"
317
+ jiradc component update 11289 --lead jsmith --assignee-type COMPONENT_LEAD`
318
+ ).action(
319
+ async (id, opts) => {
320
+ if (opts.name === void 0 && opts.description === void 0 && opts.lead === void 0 && opts.assigneeType === void 0) {
321
+ throw new Error("Provide at least one of --name, --description, --lead, --assignee-type");
322
+ }
323
+ const client = getClient();
324
+ const result = await client.components.update({
325
+ id,
326
+ name: opts.name,
327
+ description: opts.description,
328
+ leadUserName: opts.lead,
329
+ assigneeType: opts.assigneeType
330
+ });
331
+ output(result);
332
+ }
333
+ );
334
+ }
335
+
336
+ // src/commands/component/index.ts
337
+ function registerComponentCommands(program2) {
338
+ const component = program2.command("component").description("Project component operations").addHelpText(
339
+ "after",
340
+ `
341
+ Examples:
342
+ $ jiradc component list AI
343
+ $ jiradc component get 11289
344
+ $ jiradc component create --project AI --name Backend
345
+ $ jiradc component update 11289 --name Backend
346
+ $ jiradc component delete 11289 --move-issues-to 11290
347
+ $ jiradc component issue-count 11289
348
+ `
349
+ );
350
+ list2(component);
351
+ get(component);
352
+ create(component);
353
+ update(component);
354
+ deleteComponent(component);
355
+ issueCount(component);
356
+ }
357
+
229
358
  // src/commands/field/options.ts
230
359
  function options(parent) {
231
360
  parent.command("options <id>").description("Get available options for a custom field").option("--query <text>", "Filter options by text").option("--max <number>", "Max results to return (1-1000)", intInRange(1, 1e3), 25).option("--page <number>", "Page number (1-indexed)", positiveInt).addHelpText(
@@ -343,7 +472,7 @@ function download(parent) {
343
472
  }
344
473
 
345
474
  // src/commands/issue/attachment/list.ts
346
- function list2(parent) {
475
+ function list3(parent) {
347
476
  parent.command("list <key>").description("List attachments on an issue").addHelpText("after", "\nExamples:\n jiradc issue attachment list PROJ-123").action(async (key) => {
348
477
  const client = getClient();
349
478
  const issue = await client.issues.get({
@@ -406,7 +535,7 @@ Examples:
406
535
  `
407
536
  );
408
537
  upload(attachment);
409
- list2(attachment);
538
+ list3(attachment);
410
539
  download(attachment);
411
540
  downloadAll(attachment);
412
541
  deleteAttachment(attachment);
@@ -621,7 +750,7 @@ function comment(parent) {
621
750
  }
622
751
 
623
752
  // src/commands/issue/create.ts
624
- function create(parent) {
753
+ function create2(parent) {
625
754
  parent.command("create").description("Create a new issue").requiredOption("--project <key>", "Project key or ID").requiredOption("--type <name>", "Issue type name (e.g., Task, Bug, Story)").requiredOption("--summary <text>", "Issue summary/title").option("--description <text>", "Issue description in wiki markup").option("--assignee <username>", "Assignee username").option("--reporter <username>", "Reporter username").option("--priority <name>", "Priority name (e.g., High, Medium, Low)").option("--labels <labels>", "Comma-separated labels").option("--components <names>", "Comma-separated component names").option("--fix-versions <versions>", "Comma-separated fix version names").option("--due-date <date>", "Due date in YYYY-MM-DD format").option("--parent <key>", "Parent issue key (for subtasks)").option("--custom-fields <json>", `Additional custom fields as JSON (e.g., '{"customfield_10100": "EPIC-1"}')`).addHelpText(
626
755
  "after",
627
756
  `
@@ -777,7 +906,7 @@ var DEFAULT_FIELDS = [
777
906
  ];
778
907
 
779
908
  // src/commands/issue/get.ts
780
- function get(parent) {
909
+ function get2(parent) {
781
910
  parent.command("get <key>").description("Get issue details").option("--fields <fields>", "Comma-separated fields to return (defaults to essential fields)").option("--all-fields", "Return all fields instead of defaults").option("--expand <expand>", 'Expand options (e.g., "transitions", "changelog")').addHelpText(
782
911
  "after",
783
912
  "\nExamples:\n jiradc issue get PROJ-123\n jiradc issue get PROJ-123 --fields summary,status,assignee\n jiradc issue get PROJ-123 --all-fields\n jiradc issue get PROJ-123 --expand changelog,transitions"
@@ -880,7 +1009,7 @@ function unlink2(parent) {
880
1009
  }
881
1010
 
882
1011
  // src/commands/issue/update.ts
883
- function update(parent) {
1012
+ function update2(parent) {
884
1013
  parent.command("update <key>").description("Update issue fields").option("--fields <json>", "JSON string of fields to update").option("--notify-users", "Notify users about the update (default: true)").option("--attachments <paths>", "Comma-separated local file paths to attach").addHelpText(
885
1014
  "after",
886
1015
  `
@@ -891,8 +1020,7 @@ Examples:
891
1020
  jiradc issue update PROJ-123 --fields '{"summary": "With attachment"}' --attachments ./report.pdf`
892
1021
  ).action(async (key, opts) => {
893
1022
  if (!opts.fields && !opts.attachments) {
894
- console.error(JSON.stringify({ error: "Provide --fields and/or --attachments" }));
895
- process.exit(1);
1023
+ throw new Error("Provide --fields and/or --attachments");
896
1024
  }
897
1025
  const client = getClient();
898
1026
  if (opts.fields) {
@@ -944,10 +1072,10 @@ Examples:
944
1072
  $ jiradc issue attachment list PROJ-123
945
1073
  `
946
1074
  );
947
- get(issue);
1075
+ get2(issue);
948
1076
  search2(issue);
949
- create(issue);
950
- update(issue);
1077
+ create2(issue);
1078
+ update2(issue);
951
1079
  deleteIssue(issue);
952
1080
  transition(issue);
953
1081
  transitions(issue);
@@ -968,17 +1096,8 @@ Examples:
968
1096
  devStatus(issue);
969
1097
  }
970
1098
 
971
- // src/commands/project/components.ts
972
- function components(parent) {
973
- parent.command("components <key>").description("Get all components for a project").addHelpText("after", "\nExamples:\n jiradc project components PROJ").action(async (key) => {
974
- const client = getClient();
975
- const result = await client.projects.getComponents({ projectKeyOrId: key });
976
- output(result);
977
- });
978
- }
979
-
980
1099
  // src/commands/project/list.ts
981
- function list3(parent) {
1100
+ function list4(parent) {
982
1101
  parent.command("list").description("List all projects").option("--expand <expand>", 'Expand options (e.g., "description,lead")').option("--include-archived", "Include archived projects (default: false)").addHelpText(
983
1102
  "after",
984
1103
  "\nExamples:\n jiradc project list\n jiradc project list --expand description,lead\n jiradc project list --include-archived"
@@ -1009,16 +1128,14 @@ function registerProjectCommands(program2) {
1009
1128
  Examples:
1010
1129
  $ jiradc project list
1011
1130
  $ jiradc project versions PROJ
1012
- $ jiradc project components PROJ
1013
1131
  `
1014
1132
  );
1015
- list3(project);
1133
+ list4(project);
1016
1134
  versions(project);
1017
- components(project);
1018
1135
  }
1019
1136
 
1020
1137
  // src/commands/sprint/create.ts
1021
- function create2(parent) {
1138
+ function create3(parent) {
1022
1139
  parent.command("create").description("Create a new sprint").requiredOption("--board <id>", "Board ID to create sprint in", positiveInt).requiredOption("--name <name>", "Sprint name").option("--start-date <date>", "Start date in ISO 8601 format").option("--end-date <date>", "End date in ISO 8601 format").option("--goal <goal>", "Sprint goal").addHelpText(
1023
1140
  "after",
1024
1141
  '\nExamples:\n jiradc sprint create --board 42 --name "Sprint 10"\n jiradc sprint create --board 42 --name "Sprint 10" --start-date 2026-03-20 --end-date 2026-04-03 --goal "Complete auth module"'
@@ -1055,10 +1172,10 @@ function issues2(parent) {
1055
1172
  }
1056
1173
 
1057
1174
  // src/commands/sprint/list.ts
1058
- import { Option as Option2 } from "commander";
1175
+ import { Option as Option4 } from "commander";
1059
1176
  var SPRINT_STATES = ["future", "active", "closed"];
1060
- function list4(parent) {
1061
- parent.command("list").description("List sprints for a board").requiredOption("--board <id>", "Board ID", positiveInt).addOption(new Option2("--state <state>", "Filter by sprint state").choices(SPRINT_STATES)).addHelpText(
1177
+ function list5(parent) {
1178
+ parent.command("list").description("List sprints for a board").requiredOption("--board <id>", "Board ID", positiveInt).addOption(new Option4("--state <state>", "Filter by sprint state").choices(SPRINT_STATES)).addHelpText(
1062
1179
  "after",
1063
1180
  "\nExamples:\n jiradc sprint list --board 42\n jiradc sprint list --board 42 --state active"
1064
1181
  ).action(async (opts) => {
@@ -1072,10 +1189,10 @@ function list4(parent) {
1072
1189
  }
1073
1190
 
1074
1191
  // src/commands/sprint/update.ts
1075
- import { Argument as Argument3, Option as Option3 } from "commander";
1192
+ import { Argument as Argument3, Option as Option5 } from "commander";
1076
1193
  var SPRINT_STATES2 = ["future", "active", "closed"];
1077
- function update2(parent) {
1078
- parent.command("update").description("Update an existing sprint").addArgument(new Argument3("<id>", "Sprint ID").argParser(positiveInt)).option("--name <name>", "New sprint name").addOption(new Option3("--state <state>", "New sprint state").choices(SPRINT_STATES2)).option("--start-date <date>", "New start date in ISO 8601 format").option("--end-date <date>", "New end date in ISO 8601 format").option("--goal <goal>", "New sprint goal").addHelpText(
1194
+ function update3(parent) {
1195
+ parent.command("update").description("Update an existing sprint").addArgument(new Argument3("<id>", "Sprint ID").argParser(positiveInt)).option("--name <name>", "New sprint name").addOption(new Option5("--state <state>", "New sprint state").choices(SPRINT_STATES2)).option("--start-date <date>", "New start date in ISO 8601 format").option("--end-date <date>", "New end date in ISO 8601 format").option("--goal <goal>", "New sprint goal").addHelpText(
1079
1196
  "after",
1080
1197
  '\nExamples:\n jiradc sprint update 100 --name "Sprint 10 - Extended"\n jiradc sprint update 100 --state active\n jiradc sprint update 100 --end-date 2026-04-10 --goal "Updated goal"'
1081
1198
  ).action(
@@ -1106,10 +1223,10 @@ Examples:
1106
1223
  $ jiradc sprint create --board 42 --name "Sprint 10" --start-date 2026-04-01 --end-date 2026-04-14
1107
1224
  `
1108
1225
  );
1109
- list4(sprint);
1226
+ list5(sprint);
1110
1227
  issues2(sprint);
1111
- create2(sprint);
1112
- update2(sprint);
1228
+ create3(sprint);
1229
+ update3(sprint);
1113
1230
  }
1114
1231
 
1115
1232
  // src/commands/user/me.ts
@@ -1147,7 +1264,7 @@ function readPackageVersion() {
1147
1264
  }
1148
1265
  var DIM = "\x1B[2m";
1149
1266
  var RESET = "\x1B[0m";
1150
- var program = new Command6();
1267
+ var program = new Command8();
1151
1268
  program.name("jiradc").description("Jira Data Center CLI").version(readPackageVersion()).configureHelp({
1152
1269
  styleTitle: (str) => styleText("bold", str),
1153
1270
  styleUsage: (str) => styleText("dim", str),
@@ -1179,6 +1296,7 @@ program.hook("preAction", (thisCommand) => {
1179
1296
  });
1180
1297
  registerIssueCommands(program);
1181
1298
  registerProjectCommands(program);
1299
+ registerComponentCommands(program);
1182
1300
  registerBoardCommands(program);
1183
1301
  registerSprintCommands(program);
1184
1302
  registerFieldCommands(program);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jiradc-cli",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "publish": true,
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -12,7 +12,7 @@
12
12
  ],
13
13
  "dependencies": {
14
14
  "commander": "^13.1.0",
15
- "jira-data-center-client": "1.0.29"
15
+ "jira-data-center-client": "1.0.31"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@types/node": "24.10.4",
@@ -22,8 +22,8 @@
22
22
  "tsx": "^4.19.2",
23
23
  "typescript": "^5.7.2",
24
24
  "vitest": "^4.0.16",
25
- "config-typescript": "0.0.0",
26
- "config-eslint": "0.0.0"
25
+ "config-eslint": "0.0.0",
26
+ "config-typescript": "0.0.0"
27
27
  },
28
28
  "engines": {
29
29
  "node": ">=22.0.0"