jiradc-cli 1.0.9 → 1.0.11

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 +115 -52
  3. package/package.json +2 -2
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
@@ -1,8 +1,43 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
+ import { readFileSync } from "fs";
5
+ import { dirname, join as join4 } from "path";
6
+ import { fileURLToPath } from "url";
4
7
  import { styleText } from "util";
5
- import { Command } from "commander";
8
+ import { Command as Command6 } from "commander";
9
+
10
+ // src/commands/board/issues.ts
11
+ import { Argument } from "commander";
12
+
13
+ // src/utils/cli.ts
14
+ import { InvalidArgumentError } from "commander";
15
+ function intInRange(min, max) {
16
+ return (raw) => {
17
+ const n = parseInt(raw, 10);
18
+ if (Number.isNaN(n) || !Number.isFinite(n)) {
19
+ throw new InvalidArgumentError(`Not a number: "${raw}"`);
20
+ }
21
+ if (n < min || n > max) {
22
+ throw new InvalidArgumentError(`Must be between ${min} and ${max} (got ${n})`);
23
+ }
24
+ return n;
25
+ };
26
+ }
27
+ function nonNegativeInt(raw) {
28
+ const n = parseInt(raw, 10);
29
+ if (Number.isNaN(n) || n < 0) {
30
+ throw new InvalidArgumentError(`Must be a non-negative integer (got "${raw}")`);
31
+ }
32
+ return n;
33
+ }
34
+ function positiveInt(raw) {
35
+ const n = parseInt(raw, 10);
36
+ if (Number.isNaN(n) || n < 1) {
37
+ throw new InvalidArgumentError(`Must be a positive integer (got "${raw}")`);
38
+ }
39
+ return n;
40
+ }
6
41
 
7
42
  // src/utils/client.ts
8
43
  import { JiraClient } from "jira-data-center-client";
@@ -125,21 +160,29 @@ function handleError(err) {
125
160
  `
126
161
  );
127
162
  } else {
128
- process.stderr.write(`${JSON.stringify({ error: message })}
129
- `);
163
+ const responseData = err?.response?.data;
164
+ const detail = responseData && typeof responseData === "object" ? responseData : void 0;
165
+ process.stderr.write(
166
+ `${JSON.stringify({
167
+ error: message,
168
+ ...axiosStatus !== void 0 && { statusCode: axiosStatus },
169
+ ...detail && { detail }
170
+ })}
171
+ `
172
+ );
130
173
  }
131
174
  process.exit(1);
132
175
  }
133
176
 
134
177
  // src/commands/board/issues.ts
135
178
  function issues(parent) {
136
- parent.command("issues <id>").description("Get issues for a board").option("--max <number>", "Max results", parseInt).option("--start-at <number>", "Starting index for pagination (default: 0)", parseInt).option("--fields <fields>", "Comma-separated field names to return").option("--jql <jql>", "Additional JQL filter within the board").addHelpText(
179
+ parent.command("issues").description("Get issues for a board").addArgument(new Argument("<id>", "Board ID").argParser(positiveInt)).option("--max <number>", "Max results (1-50, Jira DC caps at 50)", intInRange(1, 50), 25).option("--start-at <number>", "Starting index for pagination", nonNegativeInt).option("--fields <fields>", "Comma-separated field names to return").option("--jql <jql>", "Additional JQL filter within the board").addHelpText(
137
180
  "after",
138
181
  '\nExamples:\n jiradc board issues 42\n jiradc board issues 42 --max 10\n jiradc board issues 42 --jql "status = Open" --fields summary,status\n jiradc board issues 42 --start-at 50 --max 25'
139
182
  ).action(async (id, opts) => {
140
183
  const client = getClient();
141
184
  const result = await client.agile.getBoardIssues({
142
- boardId: parseInt(id, 10),
185
+ boardId: id,
143
186
  startAt: opts.startAt,
144
187
  maxResults: opts.max,
145
188
  fields: opts.fields?.split(",").map((f) => f.trim()),
@@ -150,8 +193,10 @@ function issues(parent) {
150
193
  }
151
194
 
152
195
  // src/commands/board/list.ts
196
+ import { Option } from "commander";
197
+ var BOARD_TYPES = ["scrum", "kanban", "simple"];
153
198
  function list(parent) {
154
- parent.command("list").description("List agile boards").option("--max <number>", "Max results", parseInt).option("--project <key>", "Filter boards by project key or ID").option("--type <type>", "Board type filter (scrum, kanban, simple)").option("--name <name>", "Filter boards by name").addHelpText(
199
+ parent.command("list").description("List agile boards").option("--max <number>", "Max results (1-1000)", intInRange(1, 1e3), 25).option("--project <key>", "Filter boards by project key or ID").addOption(new Option("--type <type>", "Board type filter").choices(BOARD_TYPES)).option("--name <name>", "Filter boards by name").addHelpText(
155
200
  "after",
156
201
  '\nExamples:\n jiradc board list\n jiradc board list --max 10\n jiradc board list --project PROJ\n jiradc board list --type scrum --name "Team Board"'
157
202
  ).action(async (opts) => {
@@ -183,7 +228,7 @@ Examples:
183
228
 
184
229
  // src/commands/field/options.ts
185
230
  function options(parent) {
186
- 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", parseInt).option("--page <number>", "Page number", parseInt).addHelpText(
231
+ 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(
187
232
  "after",
188
233
  '\nExamples:\n jiradc field options 10001\n jiradc field options 10001 --query "High"\n jiradc field options 10001 --max 20 --page 2'
189
234
  ).action(async (id, opts) => {
@@ -200,7 +245,7 @@ function options(parent) {
200
245
 
201
246
  // src/commands/field/search.ts
202
247
  function search(parent) {
203
- parent.command("search <keyword>").description("Search for fields by name or ID").option("--limit <number>", "Maximum number of results (default: 10)", parseInt).addHelpText(
248
+ parent.command("search <keyword>").description("Search for fields by name or ID").option("--limit <number>", "Maximum number of results (1-1000)", intInRange(1, 1e3), 25).addHelpText(
204
249
  "after",
205
250
  "\nExamples:\n jiradc field search epic\n jiradc field search customfield_10100\n jiradc field search priority --limit 5"
206
251
  ).action(async (keyword, opts) => {
@@ -410,21 +455,23 @@ function attachments(parent) {
410
455
 
411
456
  // src/commands/issue/batch-changelog.ts
412
457
  function batchChangelog(parent) {
413
- parent.command("batch-changelog <keys>").description("Get changelogs for multiple issues at once").option("--max <number>", "Max changelog entries per issue (default: 50)", parseInt).addHelpText(
458
+ parent.command("batch-changelog <keys>").description("Get changelogs for multiple issues at once").option("--max <number>", "Max changelog entries per issue (1-50, Jira DC caps at 50)", intInRange(1, 50), 25).addHelpText(
414
459
  "after",
415
460
  "\nExamples:\n jiradc issue batch-changelog PROJ-1,PROJ-2,PROJ-3\n jiradc issue batch-changelog PROJ-123,PROJ-124 --max 10"
416
461
  ).action(async (keys, opts) => {
417
462
  const client = getClient();
418
463
  const keyList = keys.split(",").map((k) => k.trim());
419
- const results = {};
420
- for (const key of keyList) {
421
- try {
422
- results[key] = await client.issues.getChangelog({ issueKeyOrId: key, maxResults: opts.max });
423
- } catch (error) {
424
- results[key] = { error: error instanceof Error ? error.message : "Unknown error" };
425
- }
426
- }
427
- output(results);
464
+ const entries = await Promise.all(
465
+ keyList.map(async (key) => {
466
+ try {
467
+ const data = await client.issues.getChangelog({ issueKeyOrId: key, maxResults: opts.max });
468
+ return [key, data];
469
+ } catch (error) {
470
+ return [key, { error: error instanceof Error ? error.message : "Unknown error" }];
471
+ }
472
+ })
473
+ );
474
+ output(Object.fromEntries(entries));
428
475
  });
429
476
  }
430
477
 
@@ -453,7 +500,7 @@ Examples:
453
500
 
454
501
  // src/commands/issue/changelog.ts
455
502
  function changelog(parent) {
456
- parent.command("changelog <key>").description("Get changelog for an issue").option("--max <number>", "Max changelog entries (default: 50)", parseInt).addHelpText("after", "\nExamples:\n jiradc issue changelog PROJ-123\n jiradc issue changelog PROJ-123 --max 10").action(async (key, opts) => {
503
+ parent.command("changelog <key>").description("Get changelog for an issue").option("--max <number>", "Max changelog entries (1-50, Jira DC caps at 50)", intInRange(1, 50), 25).addHelpText("after", "\nExamples:\n jiradc issue changelog PROJ-123\n jiradc issue changelog PROJ-123 --max 10").action(async (key, opts) => {
457
504
  const client = getClient();
458
505
  const result = await client.issues.getChangelog({ issueKeyOrId: key, maxResults: opts.max });
459
506
  output(result);
@@ -511,43 +558,44 @@ Examples:
511
558
  newIssue: result
512
559
  };
513
560
  if (opts.includeAttachments && f.attachment?.length) {
514
- const copied = [];
515
561
  const tmpFiles = [];
516
- for (const att of f.attachment) {
517
- const tmpPath = join3(tmpdir(), `jiradc-clone-${Date.now()}-${att.filename}`);
518
- tmpFiles.push(tmpPath);
519
- await client.issues.downloadAttachment({ url: att.content, destinationPath: tmpPath });
520
- await client.issues.addAttachment({ issueKeyOrId: newKey, filePath: tmpPath });
521
- copied.push(att.filename);
522
- }
562
+ const copied = await Promise.all(
563
+ f.attachment.map(async (att) => {
564
+ const tmpPath = join3(tmpdir(), `jiradc-clone-${Date.now()}-${att.filename}`);
565
+ tmpFiles.push(tmpPath);
566
+ await client.issues.downloadAttachment({ url: att.content, destinationPath: tmpPath });
567
+ await client.issues.addAttachment({ issueKeyOrId: newKey, filePath: tmpPath });
568
+ return att.filename;
569
+ })
570
+ );
523
571
  await Promise.all(tmpFiles.map((p) => unlink(p).catch(() => void 0)));
524
572
  cloneResult.attachmentsCopied = copied.length;
525
573
  cloneResult.attachments = copied;
526
574
  }
527
575
  if (opts.includeLinks && f.issuelinks?.length) {
528
- const linkedCount = { created: 0, skipped: 0 };
529
- for (const link2 of f.issuelinks) {
530
- try {
576
+ const outcomes = await Promise.allSettled(
577
+ f.issuelinks.map((link2) => {
531
578
  if (link2.outwardIssue) {
532
- await client.links.create({
579
+ return client.links.create({
533
580
  typeName: link2.type.name,
534
581
  inwardIssueKey: newKey,
535
582
  outwardIssueKey: link2.outwardIssue.key
536
583
  });
537
- } else if (link2.inwardIssue) {
538
- await client.links.create({
584
+ }
585
+ if (link2.inwardIssue) {
586
+ return client.links.create({
539
587
  typeName: link2.type.name,
540
588
  inwardIssueKey: link2.inwardIssue.key,
541
589
  outwardIssueKey: newKey
542
590
  });
543
591
  }
544
- linkedCount.created++;
545
- } catch {
546
- linkedCount.skipped++;
547
- }
548
- }
549
- cloneResult.linksCopied = linkedCount.created;
550
- if (linkedCount.skipped > 0) cloneResult.linksSkipped = linkedCount.skipped;
592
+ return Promise.resolve();
593
+ })
594
+ );
595
+ const created = outcomes.filter((o) => o.status === "fulfilled").length;
596
+ const skipped = outcomes.filter((o) => o.status === "rejected").length;
597
+ cloneResult.linksCopied = created;
598
+ if (skipped > 0) cloneResult.linksSkipped = skipped;
551
599
  }
552
600
  output(cloneResult);
553
601
  }
@@ -698,7 +746,7 @@ function devStatus(parent) {
698
746
 
699
747
  // src/commands/issue/get-worklog.ts
700
748
  function getWorklog(parent) {
701
- parent.command("get-worklog <key>").description("Get worklogs for an issue").option("--start-at <number>", "Starting index for pagination (default: 0)", parseInt).option("--max <number>", "Max results per page", parseInt).addHelpText(
749
+ parent.command("get-worklog <key>").description("Get worklogs for an issue").option("--start-at <number>", "Starting index for pagination", nonNegativeInt).option("--max <number>", "Max results per page (1-1000)", intInRange(1, 1e3), 25).addHelpText(
702
750
  "after",
703
751
  "\nExamples:\n jiradc issue get-worklog PROJ-123\n jiradc issue get-worklog PROJ-123 --max 10\n jiradc issue get-worklog PROJ-123 --start-at 10 --max 5"
704
752
  ).action(async (key, opts) => {
@@ -785,7 +833,7 @@ function link(parent) {
785
833
 
786
834
  // src/commands/issue/search.ts
787
835
  function search2(parent) {
788
- parent.command("search <jql>").description("Search issues using JQL").option("--max <number>", "Max results (default: 50)", parseInt).option("--start-at <number>", "Starting index for pagination (default: 0)", parseInt).option("--fields <fields>", "Comma-separated fields to return (defaults to essential fields)").option("--all-fields", "Return all fields instead of defaults").addHelpText(
836
+ parent.command("search <jql>").description("Search issues using JQL").option("--max <number>", "Max results (1-50, Jira DC caps at 50)", intInRange(1, 50), 25).option("--start-at <number>", "Starting index for pagination", nonNegativeInt).option("--fields <fields>", "Comma-separated fields to return (defaults to essential fields)").option("--all-fields", "Return all fields instead of defaults").addHelpText(
789
837
  "after",
790
838
  '\nExamples:\n jiradc issue search "project = PROJ AND status = Open"\n jiradc issue search "assignee = currentUser()" --max 10 --fields summary,status\n jiradc issue search "project = PROJ" --start-at 50 --max 50'
791
839
  ).action(async (jql, opts) => {
@@ -971,14 +1019,14 @@ Examples:
971
1019
 
972
1020
  // src/commands/sprint/create.ts
973
1021
  function create2(parent) {
974
- parent.command("create").description("Create a new sprint").requiredOption("--board <id>", "Board ID to create sprint in").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(
1022
+ 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(
975
1023
  "after",
976
1024
  '\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"'
977
1025
  ).action(async (opts) => {
978
1026
  const client = getClient();
979
1027
  const result = await client.agile.createSprint({
980
1028
  name: opts.name,
981
- originBoardId: parseInt(opts.board, 10),
1029
+ originBoardId: opts.board,
982
1030
  startDate: opts.startDate,
983
1031
  endDate: opts.endDate,
984
1032
  goal: opts.goal
@@ -988,14 +1036,15 @@ function create2(parent) {
988
1036
  }
989
1037
 
990
1038
  // src/commands/sprint/issues.ts
1039
+ import { Argument as Argument2 } from "commander";
991
1040
  function issues2(parent) {
992
- parent.command("issues <id>").description("Get issues in a sprint").option("--max <number>", "Max results", parseInt).option("--start-at <number>", "Starting index for pagination (default: 0)", parseInt).option("--fields <fields>", "Comma-separated field names to return").option("--jql <jql>", "Additional JQL filter within the sprint").addHelpText(
1041
+ parent.command("issues").description("Get issues in a sprint").addArgument(new Argument2("<id>", "Sprint ID").argParser(positiveInt)).option("--max <number>", "Max results (1-50, Jira DC caps at 50)", intInRange(1, 50), 25).option("--start-at <number>", "Starting index for pagination", nonNegativeInt).option("--fields <fields>", "Comma-separated field names to return").option("--jql <jql>", "Additional JQL filter within the sprint").addHelpText(
993
1042
  "after",
994
1043
  '\nExamples:\n jiradc sprint issues 100\n jiradc sprint issues 100 --max 20\n jiradc sprint issues 100 --jql "status = Done" --fields summary,status\n jiradc sprint issues 100 --start-at 50 --max 25'
995
1044
  ).action(async (id, opts) => {
996
1045
  const client = getClient();
997
1046
  const result = await client.agile.getSprintIssues({
998
- sprintId: parseInt(id, 10),
1047
+ sprintId: id,
999
1048
  startAt: opts.startAt,
1000
1049
  maxResults: opts.max,
1001
1050
  fields: opts.fields?.split(",").map((f) => f.trim()),
@@ -1006,14 +1055,16 @@ function issues2(parent) {
1006
1055
  }
1007
1056
 
1008
1057
  // src/commands/sprint/list.ts
1058
+ import { Option as Option2 } from "commander";
1059
+ var SPRINT_STATES = ["future", "active", "closed"];
1009
1060
  function list4(parent) {
1010
- parent.command("list").description("List sprints for a board").requiredOption("--board <id>", "Board ID").option("--state <state>", "Filter by sprint state (future, active, closed)").addHelpText(
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(
1011
1062
  "after",
1012
1063
  "\nExamples:\n jiradc sprint list --board 42\n jiradc sprint list --board 42 --state active"
1013
1064
  ).action(async (opts) => {
1014
1065
  const client = getClient();
1015
1066
  const result = await client.agile.getSprints({
1016
- boardId: parseInt(opts.board, 10),
1067
+ boardId: opts.board,
1017
1068
  state: opts.state
1018
1069
  });
1019
1070
  output(result);
@@ -1021,15 +1072,17 @@ function list4(parent) {
1021
1072
  }
1022
1073
 
1023
1074
  // src/commands/sprint/update.ts
1075
+ import { Argument as Argument3, Option as Option3 } from "commander";
1076
+ var SPRINT_STATES2 = ["future", "active", "closed"];
1024
1077
  function update2(parent) {
1025
- parent.command("update <id>").description("Update an existing sprint").option("--name <name>", "New sprint name").option("--state <state>", "New sprint state (future, active, closed)").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(
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(
1026
1079
  "after",
1027
1080
  '\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"'
1028
1081
  ).action(
1029
1082
  async (id, opts) => {
1030
1083
  const client = getClient();
1031
1084
  const result = await client.agile.updateSprint({
1032
- sprintId: parseInt(id, 10),
1085
+ sprintId: id,
1033
1086
  name: opts.name,
1034
1087
  state: opts.state,
1035
1088
  startDate: opts.startDate,
@@ -1082,10 +1135,20 @@ Examples:
1082
1135
  }
1083
1136
 
1084
1137
  // src/index.ts
1138
+ function readPackageVersion() {
1139
+ try {
1140
+ const here = dirname(fileURLToPath(import.meta.url));
1141
+ const pkgPath = join4(here, "..", "package.json");
1142
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
1143
+ return pkg.version ?? "0.0.0";
1144
+ } catch {
1145
+ return "0.0.0";
1146
+ }
1147
+ }
1085
1148
  var DIM = "\x1B[2m";
1086
1149
  var RESET = "\x1B[0m";
1087
- var program = new Command();
1088
- program.name("jiradc").description("Jira Data Center CLI").version("1.0.0").configureHelp({
1150
+ var program = new Command6();
1151
+ program.name("jiradc").description("Jira Data Center CLI").version(readPackageVersion()).configureHelp({
1089
1152
  styleTitle: (str) => styleText("bold", str),
1090
1153
  styleUsage: (str) => styleText("dim", str),
1091
1154
  styleCommandDescription: (str) => styleText("dim", str),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jiradc-cli",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
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.28"
15
+ "jira-data-center-client": "1.0.30"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@types/node": "24.10.4",