jiradc-cli 1.0.25 → 1.0.26

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 (2) hide show
  1. package/dist/index.js +154 -83
  2. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -25,10 +25,10 @@ function intInRange(min, max) {
25
25
  return (raw) => {
26
26
  const n = parseInt(raw, 10);
27
27
  if (Number.isNaN(n) || !Number.isFinite(n)) {
28
- throw new InvalidArgumentError(`Not a number: "${raw}"`);
28
+ throw new InvalidArgumentError("Must be an integer.");
29
29
  }
30
30
  if (n < min || n > max) {
31
- throw new InvalidArgumentError(`Must be between ${min} and ${max} (got ${n})`);
31
+ throw new InvalidArgumentError(`Must be between ${min} and ${max}.`);
32
32
  }
33
33
  return n;
34
34
  };
@@ -36,37 +36,80 @@ function intInRange(min, max) {
36
36
  function nonNegativeInt(raw) {
37
37
  const n = parseInt(raw, 10);
38
38
  if (Number.isNaN(n) || n < 0) {
39
- throw new InvalidArgumentError(`Must be a non-negative integer (got "${raw}")`);
39
+ throw new InvalidArgumentError("Must be a non-negative integer.");
40
40
  }
41
41
  return n;
42
42
  }
43
43
  function positiveInt(raw) {
44
44
  const n = parseInt(raw, 10);
45
45
  if (Number.isNaN(n) || n < 1) {
46
- throw new InvalidArgumentError(`Must be a positive integer (got "${raw}")`);
46
+ throw new InvalidArgumentError("Must be a positive integer.");
47
47
  }
48
48
  return n;
49
49
  }
50
+ function text(raw) {
51
+ return raw;
52
+ }
53
+ function date(raw) {
54
+ const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(raw);
55
+ if (!m) {
56
+ throw new InvalidArgumentError("Must be a date in YYYY-MM-DD format.");
57
+ }
58
+ const [, y, mo, d] = m;
59
+ const year = Number(y);
60
+ const month = Number(mo);
61
+ const day = Number(d);
62
+ const dt = new Date(Date.UTC(year, month - 1, day));
63
+ if (dt.getUTCFullYear() !== year || dt.getUTCMonth() !== month - 1 || dt.getUTCDate() !== day) {
64
+ throw new InvalidArgumentError("Not a real calendar date.");
65
+ }
66
+ return raw;
67
+ }
68
+ function dateTime(raw) {
69
+ if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(raw) || Number.isNaN(Date.parse(raw))) {
70
+ throw new InvalidArgumentError("Must be an ISO 8601 date-time, e.g. 2026-06-08T14:30:00Z.");
71
+ }
72
+ return raw;
73
+ }
74
+
75
+ // ../../cli-utils/dist/json.js
76
+ import { InvalidArgumentError as InvalidArgumentError2 } from "commander";
77
+ function jsonShape(schema) {
78
+ return (raw) => {
79
+ let parsed;
80
+ try {
81
+ parsed = JSON.parse(raw);
82
+ } catch {
83
+ throw new InvalidArgumentError2("Must be valid JSON.");
84
+ }
85
+ const result = schema.safeParse(parsed);
86
+ if (!result.success) {
87
+ const issues3 = result.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
88
+ throw new InvalidArgumentError2(`Invalid JSON shape \u2014 ${issues3}`);
89
+ }
90
+ return result.data;
91
+ };
92
+ }
50
93
 
51
94
  // ../../cli-utils/dist/text-or-file.js
52
95
  import { readFileSync as readFileSync3 } from "fs";
53
- import { InvalidArgumentError as InvalidArgumentError2, Option } from "commander";
96
+ import { InvalidArgumentError as InvalidArgumentError3, Option } from "commander";
54
97
  var STDIN_REF = "-";
55
98
  function rejectStdinSentinel(value) {
56
99
  if (value === "@-" || value === STDIN_REF) {
57
- throw new InvalidArgumentError2(`"${value}" looks like a stdin redirect, which is not supported here. Pass the text directly, or read it from a file/stdin with the matching --\u2026-file <path|-> option.`);
100
+ throw new InvalidArgumentError3(`"${value}" looks like a stdin redirect, which is not supported here. Pass the text directly, or read it from a file/stdin with the matching --\u2026-file <path|-> option.`);
58
101
  }
59
102
  return value;
60
103
  }
61
104
  function readFileOrStdin(ref) {
62
105
  if (ref === STDIN_REF) {
63
106
  if (process.stdin.isTTY) {
64
- throw new InvalidArgumentError2('"--\u2026-file -" reads stdin, but stdin is a terminal (nothing piped).');
107
+ throw new InvalidArgumentError3('"--\u2026-file -" reads stdin, but stdin is a terminal (nothing piped).');
65
108
  }
66
109
  try {
67
110
  return readFileSync3(0, "utf8");
68
111
  } catch (err) {
69
- throw new InvalidArgumentError2(`failed to read stdin for "--\u2026-file -": ${err.message}`);
112
+ throw new InvalidArgumentError3(`failed to read stdin for "--\u2026-file -": ${err.message}`);
70
113
  }
71
114
  }
72
115
  try {
@@ -74,28 +117,28 @@ function readFileOrStdin(ref) {
74
117
  } catch (err) {
75
118
  const e = err;
76
119
  if (e.code === "ENOENT") {
77
- throw new InvalidArgumentError2(`file not found: "${ref}".`);
120
+ throw new InvalidArgumentError3(`file not found: "${ref}".`);
78
121
  }
79
- throw new InvalidArgumentError2(`failed to read file "${ref}": ${e.message}`);
122
+ throw new InvalidArgumentError3(`failed to read file "${ref}": ${e.message}`);
80
123
  }
81
124
  }
82
125
  function textOrFileOption(cmd, name, opts = {}) {
83
126
  const label = `${name.charAt(0).toUpperCase()}${name.slice(1)} content`;
84
127
  cmd.option(`--${name} <text>`, opts.description ?? label, rejectStdinSentinel);
85
- cmd.addOption(new Option(`--${name}-file <path>`, `Read --${name} from a file, or "-" for stdin (mutually exclusive with --${name})`).conflicts(name));
128
+ cmd.addOption(new Option(`--${name}-file <path>`, `Read --${name} from a file, or "-" for stdin (mutually exclusive with --${name})`).conflicts(name).argParser(text));
86
129
  return cmd;
87
130
  }
88
131
  function resolveTextOrFile(opts, name, { required = true } = {}) {
89
132
  const literal = opts[name];
90
133
  const ref = opts[`${name}File`];
91
134
  if (literal !== void 0 && ref !== void 0) {
92
- throw new InvalidArgumentError2(`--${name} and --${name}-file are mutually exclusive; provide only one.`);
135
+ throw new InvalidArgumentError3(`--${name} and --${name}-file are mutually exclusive; provide only one.`);
93
136
  }
94
137
  if (ref !== void 0) {
95
138
  return readFileOrStdin(ref);
96
139
  }
97
140
  if (literal === void 0 && required) {
98
- throw new InvalidArgumentError2(`a ${name} is required: provide --${name} <text> or --${name}-file <path>.`);
141
+ throw new InvalidArgumentError3(`a ${name} is required: provide --${name} <text> or --${name}-file <path>.`);
99
142
  }
100
143
  return literal;
101
144
  }
@@ -127,7 +170,7 @@ function subjectArg(cmd, name, opts = {}) {
127
170
  function subEntityOption(cmd, entity, opts = {}) {
128
171
  const numeric = opts.numeric ?? SUB_ENTITY_ID_NUMERIC[entity] ?? true;
129
172
  const description = `${entity.charAt(0).toUpperCase()}${entity.slice(1)} id`;
130
- return defineOption(cmd, `--${entity}-id <id>`, description, numeric ? positiveInt : void 0, opts.mandatory);
173
+ return defineOption(cmd, `--${entity}-id <id>`, description, numeric ? positiveInt : text, opts.mandatory);
131
174
  }
132
175
  function bodyOption(cmd, opts = {}) {
133
176
  return textOrFileOption(cmd, "body", { description: "Prose body content", ...opts });
@@ -717,7 +760,7 @@ function transformTransitions(response) {
717
760
 
718
761
  // src/commands/board/issues.ts
719
762
  function issues(parent) {
720
- const cmd = parent.command("issues").description("Get issues for a board").addArgument(new Argument("<id>", "Board ID").argParser(positiveInt)).option("--limit <number>", "Max results (1-50, Jira DC caps at 50)", intInRange(1, 50), 25).option("--start <number>", "Starting index for pagination", nonNegativeInt).option("--fields <fields>", "Comma-separated field names to return").option("--jql <jql>", "Additional JQL filter within the board");
763
+ const cmd = parent.command("issues").description("Get issues for a board").addArgument(new Argument("<id>", "Board ID").argParser(positiveInt)).option("--limit <number>", "Max results (1-50, Jira DC caps at 50)", intInRange(1, 50), 25).option("--start <number>", "Starting index for pagination", nonNegativeInt).option("--fields <fields>", "Comma-separated field names to return", text).option("--jql <jql>", "Additional JQL filter within the board", text);
721
764
  examples(cmd, [
722
765
  "42",
723
766
  "42 --limit 10",
@@ -741,7 +784,7 @@ function issues(parent) {
741
784
  import { Option as Option2 } from "commander";
742
785
  var BOARD_TYPES = ["scrum", "kanban", "simple"];
743
786
  function list(parent) {
744
- const cmd = parent.command("list").description("List agile boards").option("--limit <number>", "Max results (1-1000)", intInRange(1, 1e3), 25).option("--project <key>", "Filter boards by project key or ID").addOption(new Option2("--type <type>", "Board type filter").choices(BOARD_TYPES)).option("--name <name>", "Filter boards by name");
787
+ const cmd = parent.command("list").description("List agile boards").option("--limit <number>", "Max results (1-1000)", intInRange(1, 1e3), 25).option("--project <key>", "Filter boards by project key or ID", text).addOption(new Option2("--type <type>", "Board type filter").choices(BOARD_TYPES)).option("--name <name>", "Filter boards by name", text);
745
788
  examples(cmd, ["", "--limit 10", "--project PROJ", '--type scrum --name "Team Board"']);
746
789
  cmd.action(async (opts) => {
747
790
  const client = getClient();
@@ -772,7 +815,7 @@ var ASSIGNEE_TYPES = [
772
815
  "UNASSIGNED"
773
816
  ];
774
817
  function create(parent) {
775
- const cmd = 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("--lead <username>", "Username of the component lead").addOption(new Option3("--assignee-type <type>", "Assignee strategy").choices(ASSIGNEE_TYPES));
818
+ const cmd = parent.command("create").description("Create a new component in a project").requiredOption("--project <key>", "Project key (e.g., AI)", text).requiredOption("--name <name>", "Component name", text).option("--lead <username>", "Username of the component lead", text).addOption(new Option3("--assignee-type <type>", "Assignee strategy").choices(ASSIGNEE_TYPES));
776
819
  textOrFileOption(cmd, "description", { description: "Component description" });
777
820
  examples(cmd, [
778
821
  "--project AI --name Backend",
@@ -797,40 +840,40 @@ function create(parent) {
797
840
 
798
841
  // src/commands/component/delete.ts
799
842
  function deleteComponent(parent) {
800
- const cmd = 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");
843
+ const cmd = parent.command("delete").description("Delete a component, optionally reassigning its issues to another component").argument("<id>", "Component ID", positiveInt).option("--move-issues-to <id>", "Reassign existing issues to this component ID before deletion", text);
801
844
  examples(cmd, ["11289", "11289 --move-issues-to 11290"]);
802
845
  cmd.action(async (id, opts) => {
803
846
  const client = getClient();
804
- await client.components.delete({ id, moveIssuesTo: opts.moveIssuesTo });
847
+ await client.components.delete({ id: String(id), moveIssuesTo: opts.moveIssuesTo });
805
848
  output({ deleted: true, componentId: id, ...opts.moveIssuesTo && { movedIssuesTo: opts.moveIssuesTo } });
806
849
  });
807
850
  }
808
851
 
809
852
  // src/commands/component/get.ts
810
853
  function get(parent) {
811
- const cmd = parent.command("get <id>").description("Get a component by ID");
854
+ const cmd = parent.command("get").description("Get a component by ID").argument("<id>", "Component ID", positiveInt);
812
855
  examples(cmd, ["11289"]);
813
856
  cmd.action(async (id) => {
814
857
  const client = getClient();
815
- const result = await client.components.get({ id });
858
+ const result = await client.components.get({ id: String(id) });
816
859
  output(transformComponent(result));
817
860
  });
818
861
  }
819
862
 
820
863
  // src/commands/component/issue-count.ts
821
864
  function issueCount(parent) {
822
- const cmd = parent.command("issue-count <id>").description("Get the number of issues currently using this component");
865
+ const cmd = parent.command("issue-count").description("Get the number of issues currently using this component").argument("<id>", "Component ID", positiveInt);
823
866
  examples(cmd, ["11289"]);
824
867
  cmd.action(async (id) => {
825
868
  const client = getClient();
826
- const result = await client.components.getRelatedIssueCounts({ id });
869
+ const result = await client.components.getRelatedIssueCounts({ id: String(id) });
827
870
  output(transformComponentIssueCounts(result));
828
871
  });
829
872
  }
830
873
 
831
874
  // src/commands/component/list.ts
832
875
  function list2(parent) {
833
- const cmd = parent.command("list").description("List all components for a project").requiredOption("--project <key>", "Project key (e.g., AI)");
876
+ const cmd = parent.command("list").description("List all components for a project").requiredOption("--project <key>", "Project key (e.g., AI)", text);
834
877
  examples(cmd, ["--project AI"]);
835
878
  cmd.action(async (opts) => {
836
879
  const client = getClient();
@@ -848,7 +891,7 @@ var ASSIGNEE_TYPES2 = [
848
891
  "UNASSIGNED"
849
892
  ];
850
893
  function update(parent) {
851
- const cmd = parent.command("update <id>").description("Update an existing component (only provided fields are changed)").option("--name <name>", "New component name").option("--lead <username>", "Username of the component lead (empty string clears it)").addOption(new Option4("--assignee-type <type>", "New assignee strategy").choices(ASSIGNEE_TYPES2));
894
+ const cmd = parent.command("update").description("Update an existing component (only provided fields are changed)").argument("<id>", "Component ID", positiveInt).option("--name <name>", "New component name", text).option("--lead <username>", "Username of the component lead (empty string clears it)", text).addOption(new Option4("--assignee-type <type>", "New assignee strategy").choices(ASSIGNEE_TYPES2));
852
895
  textOrFileOption(cmd, "description", { description: "New component description" });
853
896
  examples(cmd, [
854
897
  "11289 --name Backend",
@@ -863,7 +906,7 @@ function update(parent) {
863
906
  }
864
907
  const client = getClient();
865
908
  const result = await client.components.update({
866
- id,
909
+ id: String(id),
867
910
  name: opts.name,
868
911
  description,
869
912
  leadUserName: opts.lead,
@@ -895,7 +938,7 @@ function registerComponentCommands(program) {
895
938
 
896
939
  // src/commands/field/options.ts
897
940
  function options(parent) {
898
- const cmd = parent.command("options <id>").description("Get available options for a custom field").option("--query <text>", "Filter options by text").option("--limit <number>", "Max results to return (1-1000)", intInRange(1, 1e3), 25).option("--start <number>", "Page number (1-indexed)", positiveInt);
941
+ const cmd = parent.command("options").description("Get available options for a custom field").argument("<id>", "Field ID", text).option("--query <text>", "Filter options by text", text).option("--limit <number>", "Max results to return (1-1000)", intInRange(1, 1e3), 25).option("--start <number>", "Page number (1-indexed)", positiveInt);
899
942
  examples(cmd, ["10001", '10001 --query "High"', "10001 --limit 20 --start 2"]);
900
943
  cmd.action(async (id, opts) => {
901
944
  const client = getClient();
@@ -911,7 +954,7 @@ function options(parent) {
911
954
 
912
955
  // src/commands/field/search.ts
913
956
  function search(parent) {
914
- const cmd = 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);
957
+ const cmd = parent.command("search").description("Search for fields by name or ID").argument("<keyword>", "Search keyword", text).option("--limit <number>", "Maximum number of results (1-1000)", intInRange(1, 1e3), 25);
915
958
  examples(cmd, ["epic", "customfield_10100", "priority --limit 5"]);
916
959
  cmd.action(async (keyword, opts) => {
917
960
  const client = getClient();
@@ -944,9 +987,18 @@ async function resolveUserToken(token) {
944
987
  return token;
945
988
  }
946
989
 
990
+ // src/utils/validators.ts
991
+ import { InvalidArgumentError as InvalidArgumentError4 } from "commander";
992
+ function issueKey(raw) {
993
+ if (!/^(\d+|[A-Z][A-Z0-9]+-\d+)$/.test(raw)) {
994
+ throw new InvalidArgumentError4("Must be a Jira issue key (e.g. PROJ-123) or a numeric issue id.");
995
+ }
996
+ return raw;
997
+ }
998
+
947
999
  // src/commands/issue/assign.ts
948
1000
  function assign(parent) {
949
- const cmd = parent.command("assign <key>").description('Assign an issue. --assignee is a username, "me", or "none" to unassign.').requiredOption("--assignee <user>", 'Username to assign, "me" for the current user, or "none" to unassign');
1001
+ const cmd = parent.command("assign").description('Assign an issue. --assignee is a username, "me", or "none" to unassign.').argument("<key>", "Issue key", issueKey).requiredOption("--assignee <user>", 'Username to assign, "me" for the current user, or "none" to unassign', text);
950
1002
  examples(cmd, ["PROJ-123 --assignee jsmith", "PROJ-123 --assignee me", "PROJ-123 --assignee none"]);
951
1003
  cmd.action(async (key, opts) => {
952
1004
  const resolved = await resolveUserToken(opts.assignee);
@@ -961,7 +1013,7 @@ function assign(parent) {
961
1013
 
962
1014
  // src/commands/issue/attachment/delete.ts
963
1015
  function deleteAttachment(parent) {
964
- const cmd = parent.command("delete <key>").description("Delete an attachment by ID");
1016
+ const cmd = parent.command("delete").description("Delete an attachment by ID").argument("<key>", "Issue key", issueKey);
965
1017
  subEntityOption(cmd, "attachment", { mandatory: true });
966
1018
  examples(cmd, ["PROJ-123 --attachment-id 12345"]);
967
1019
  cmd.action(async (key, opts) => {
@@ -975,7 +1027,7 @@ function deleteAttachment(parent) {
975
1027
  import { mkdirSync as mkdirSync2 } from "fs";
976
1028
  import { join as join3 } from "path";
977
1029
  function downloadAll(parent) {
978
- const cmd = parent.command("download-all <key>").description("Download all attachments from an issue").requiredOption("--output <dir>", "Local directory to save attachments into");
1030
+ const cmd = parent.command("download-all").description("Download all attachments from an issue").argument("<key>", "Issue key", issueKey).requiredOption("--output <dir>", "Local directory to save attachments into", text);
979
1031
  examples(cmd, ["PROJ-123 --output ./downloads"]);
980
1032
  cmd.action(async (key, opts) => {
981
1033
  const client = getClient();
@@ -1016,9 +1068,9 @@ function downloadAll(parent) {
1016
1068
 
1017
1069
  // src/commands/issue/attachment/download.ts
1018
1070
  function download(parent) {
1019
- const cmd = parent.command("download <key>").description("Download a single attachment by ID");
1071
+ const cmd = parent.command("download").description("Download a single attachment by ID").argument("<key>", "Issue key", issueKey);
1020
1072
  subEntityOption(cmd, "attachment", { mandatory: true });
1021
- cmd.requiredOption("--output <path>", "Local file path to save the attachment");
1073
+ cmd.requiredOption("--output <path>", "Local file path to save the attachment", text);
1022
1074
  examples(cmd, ["PROJ-123 --attachment-id 12345 --output ./report.pdf"]);
1023
1075
  cmd.action(async (key, opts) => {
1024
1076
  const client = getClient();
@@ -1043,7 +1095,7 @@ function download(parent) {
1043
1095
 
1044
1096
  // src/commands/issue/attachment/list.ts
1045
1097
  function list3(parent) {
1046
- const cmd = parent.command("list <key>").description("List attachments on an issue");
1098
+ const cmd = parent.command("list").description("List attachments on an issue").argument("<key>", "Issue key", issueKey);
1047
1099
  examples(cmd, ["PROJ-123"]);
1048
1100
  cmd.action(async (key) => {
1049
1101
  const client = getClient();
@@ -1068,7 +1120,7 @@ function list3(parent) {
1068
1120
 
1069
1121
  // src/commands/issue/attachment/upload.ts
1070
1122
  function upload(parent) {
1071
- const cmd = parent.command("upload <key>").description("Upload attachments to an issue").requiredOption("--files <paths>", "Comma-separated file paths to upload");
1123
+ const cmd = parent.command("upload").description("Upload attachments to an issue").argument("<key>", "Issue key", issueKey).requiredOption("--files <paths>", "Comma-separated file paths to upload", text);
1072
1124
  examples(cmd, ["PROJ-123 --files ./report.pdf", "PROJ-123 --files ./a.txt,./b.png"]);
1073
1125
  cmd.action(async (key, opts) => {
1074
1126
  const client = getClient();
@@ -1111,7 +1163,7 @@ function registerAttachmentCommands(parent) {
1111
1163
 
1112
1164
  // src/commands/issue/batch-changelog.ts
1113
1165
  function batchChangelog(parent) {
1114
- const cmd = parent.command("batch-changelog <keys>").description("Get changelogs for multiple issues at once").option("--limit <number>", "Max changelog entries per issue (1-50, Jira DC caps at 50)", intInRange(1, 50), 25);
1166
+ const cmd = parent.command("batch-changelog").description("Get changelogs for multiple issues at once").argument("<keys>", "Comma-separated issue keys", text).option("--limit <number>", "Max changelog entries per issue (1-50, Jira DC caps at 50)", intInRange(1, 50), 25);
1115
1167
  examples(cmd, ["PROJ-1,PROJ-2,PROJ-3", "PROJ-123,PROJ-124 --limit 10"]);
1116
1168
  cmd.action(async (keys, opts) => {
1117
1169
  const client = getClient();
@@ -1131,14 +1183,16 @@ function batchChangelog(parent) {
1131
1183
  }
1132
1184
 
1133
1185
  // src/commands/issue/batch-create.ts
1186
+ import { z } from "zod";
1187
+ var issuesSchema = z.array(z.record(z.unknown())).min(1, "must be a non-empty array");
1134
1188
  function batchCreate(parent) {
1135
- const cmd = parent.command("batch-create").description("Create multiple issues from a JSON array").requiredOption("--issues <json>", "JSON array of issue objects");
1189
+ const cmd = parent.command("batch-create").description("Create multiple issues from a JSON array").requiredOption("--issues <json>", "JSON array of issue objects", jsonShape(issuesSchema));
1136
1190
  examples(cmd, [
1137
1191
  `--issues '[{"projectKeyOrId":"PROJ","issueTypeName":"Task","summary":"Task 1"},{"projectKeyOrId":"PROJ","issueTypeName":"Task","summary":"Task 2"}]'`
1138
1192
  ]);
1139
1193
  cmd.action(async (opts) => {
1140
1194
  const client = getClient();
1141
- const parsed = JSON.parse(opts.issues);
1195
+ const parsed = opts.issues;
1142
1196
  const results = [];
1143
1197
  for (const issue of parsed) {
1144
1198
  try {
@@ -1154,7 +1208,7 @@ function batchCreate(parent) {
1154
1208
 
1155
1209
  // src/commands/issue/changelog.ts
1156
1210
  function changelog(parent) {
1157
- const cmd = parent.command("changelog <key>").description("Get changelog for an issue").option("--limit <number>", "Max changelog entries (1-50, Jira DC caps at 50)", intInRange(1, 50), 25);
1211
+ const cmd = parent.command("changelog").description("Get changelog for an issue").argument("<key>", "Issue key", issueKey).option("--limit <number>", "Max changelog entries (1-50, Jira DC caps at 50)", intInRange(1, 50), 25);
1158
1212
  examples(cmd, ["PROJ-123", "PROJ-123 --limit 10"]);
1159
1213
  cmd.action(async (key, opts) => {
1160
1214
  const client = getClient();
@@ -1182,7 +1236,7 @@ var CLONE_FIELDS = [
1182
1236
  "issuelinks"
1183
1237
  ];
1184
1238
  function clone(parent) {
1185
- const cmd = parent.command("clone <key>").description("Clone an issue (create a duplicate with the same fields)").option("--summary <text>", 'Override the summary (default: "CLONE - <original>")').option("--project <key>", "Create in a different project").option("--assignee <username>", "Override assignee").option("--include-attachments", "Copy attachments to the cloned issue").option("--include-links", "Copy issue links to the cloned issue");
1239
+ const cmd = parent.command("clone").description("Clone an issue (create a duplicate with the same fields)").argument("<key>", "Issue key", issueKey).option("--summary <text>", 'Override the summary (default: "CLONE - <original>")', text).option("--project <key>", "Create in a different project", text).option("--assignee <username>", "Override assignee", text).option("--include-attachments", "Copy attachments to the cloned issue").option("--include-links", "Copy issue links to the cloned issue");
1186
1240
  examples(cmd, [
1187
1241
  "PROJ-123",
1188
1242
  'PROJ-123 --summary "Cloned: new title"',
@@ -1259,7 +1313,7 @@ function clone(parent) {
1259
1313
 
1260
1314
  // src/commands/issue/comment/create.ts
1261
1315
  function create2(parent) {
1262
- const cmd = parent.command("create <key>").description("Add a comment to an issue");
1316
+ const cmd = parent.command("create").description("Add a comment to an issue").argument("<key>", "Issue key", issueKey);
1263
1317
  bodyOption(cmd);
1264
1318
  examples(cmd, ['PROJ-123 --body "Fixed in latest build"']);
1265
1319
  cmd.action(async (key, opts) => {
@@ -1272,7 +1326,7 @@ function create2(parent) {
1272
1326
 
1273
1327
  // src/commands/issue/comment/delete.ts
1274
1328
  function deleteComment(parent) {
1275
- const cmd = parent.command("delete <key>").description("Delete a comment from an issue");
1329
+ const cmd = parent.command("delete").description("Delete a comment from an issue").argument("<key>", "Issue key", issueKey);
1276
1330
  subEntityOption(cmd, "comment", { mandatory: true });
1277
1331
  examples(cmd, ["PROJ-123 --comment-id 12345"]);
1278
1332
  cmd.action(async (key, opts) => {
@@ -1284,7 +1338,7 @@ function deleteComment(parent) {
1284
1338
 
1285
1339
  // src/commands/issue/comment/update.ts
1286
1340
  function update2(parent) {
1287
- const cmd = parent.command("update <key>").description("Update an existing comment");
1341
+ const cmd = parent.command("update").description("Update an existing comment").argument("<key>", "Issue key", issueKey);
1288
1342
  subEntityOption(cmd, "comment", { mandatory: true });
1289
1343
  bodyOption(cmd);
1290
1344
  examples(cmd, ['PROJ-123 --comment-id 12345 --body "Updated comment text"']);
@@ -1314,8 +1368,14 @@ function registerCommentCommands(parent) {
1314
1368
  }
1315
1369
 
1316
1370
  // src/commands/issue/create.ts
1371
+ import { z as z2 } from "zod";
1372
+ var customFieldsSchema = z2.record(z2.unknown());
1317
1373
  function create3(parent) {
1318
- const cmd = 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("--assignee <user>", 'Assignee. Username, "me", or "none" to leave unassigned.').option("--reporter <user>", 'Reporter. Username or "me".').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"}')`);
1374
+ const cmd = parent.command("create").description("Create a new issue").requiredOption("--project <key>", "Project key or ID", text).requiredOption("--type <name>", "Issue type name (e.g., Task, Bug, Story)", text).requiredOption("--summary <text>", "Issue summary/title", text).option("--assignee <user>", 'Assignee. Username, "me", or "none" to leave unassigned.', text).option("--reporter <user>", 'Reporter. Username or "me".', text).option("--priority <name>", "Priority name (e.g., High, Medium, Low)", text).option("--labels <labels>", "Comma-separated labels", text).option("--components <names>", "Comma-separated component names", text).option("--fix-versions <versions>", "Comma-separated fix version names", text).option("--due-date <date>", "Due date in YYYY-MM-DD format", date).option("--parent <key>", "Parent issue key (for subtasks)", issueKey).option(
1375
+ "--custom-fields <json>",
1376
+ `Additional custom fields as JSON (e.g., '{"customfield_10100": "EPIC-1"}')`,
1377
+ jsonShape(customFieldsSchema)
1378
+ );
1319
1379
  textOrFileOption(cmd, "description", { description: "Issue description in wiki markup" });
1320
1380
  examples(cmd, [
1321
1381
  '--project PROJ --type Task --summary "Fix login bug"',
@@ -1341,7 +1401,7 @@ function create3(parent) {
1341
1401
  fixVersions: opts.fixVersions?.split(",").map((v) => v.trim()),
1342
1402
  dueDate: opts.dueDate,
1343
1403
  parent: opts.parent,
1344
- customFields: opts.customFields ? JSON.parse(opts.customFields) : void 0
1404
+ customFields: opts.customFields
1345
1405
  });
1346
1406
  output(transformCreatedIssue(result));
1347
1407
  }
@@ -1350,7 +1410,7 @@ function create3(parent) {
1350
1410
 
1351
1411
  // src/commands/issue/delete.ts
1352
1412
  function deleteIssue(parent) {
1353
- const cmd = parent.command("delete <key>").description("Delete an issue").option("--delete-subtasks", "Also delete subtasks (default: false)");
1413
+ const cmd = parent.command("delete").description("Delete an issue").argument("<key>", "Issue key", issueKey).option("--delete-subtasks", "Also delete subtasks (default: false)");
1354
1414
  examples(cmd, ["PROJ-123", "PROJ-123 --delete-subtasks"]);
1355
1415
  cmd.action(async (key, opts) => {
1356
1416
  const client = getClient();
@@ -1361,7 +1421,7 @@ function deleteIssue(parent) {
1361
1421
 
1362
1422
  // src/commands/issue/dev-status.ts
1363
1423
  function devStatus(parent) {
1364
- const cmd = parent.command("dev-status <key>").description("Get development status (PRs, commits, branches, builds) for an issue").option("--detail", "Include PR URLs, commit IDs, and other details");
1424
+ const cmd = parent.command("dev-status").description("Get development status (PRs, commits, branches, builds) for an issue").argument("<key>", "Issue key", issueKey).option("--detail", "Include PR URLs, commit IDs, and other details");
1365
1425
  examples(cmd, ["PROJ-123", "PROJ-123 --detail"]);
1366
1426
  cmd.action(async (key, opts) => {
1367
1427
  const client = getClient();
@@ -1455,7 +1515,7 @@ var DEFAULT_FIELDS = [
1455
1515
 
1456
1516
  // src/commands/issue/get.ts
1457
1517
  function get2(parent) {
1458
- const cmd = 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")');
1518
+ const cmd = parent.command("get").description("Get issue details").argument("<key>", "Issue key", issueKey).option("--fields <fields>", "Comma-separated fields to return (defaults to essential fields)", text).option("--all-fields", "Return all fields instead of defaults").option("--expand <expand>", 'Expand options (e.g., "transitions", "changelog")', text);
1459
1519
  examples(cmd, [
1460
1520
  "PROJ-123",
1461
1521
  "PROJ-123 --fields summary,status,assignee",
@@ -1476,7 +1536,7 @@ function get2(parent) {
1476
1536
 
1477
1537
  // src/commands/issue/link-epic.ts
1478
1538
  function linkEpic(parent) {
1479
- const cmd = parent.command("link-epic <keys...>").description("Link one or more issues to an epic").requiredOption("--epic <epicKey>", "Epic issue key");
1539
+ const cmd = parent.command("link-epic").description("Link one or more issues to an epic").argument("<keys...>", "Issue keys to link", issueKey).requiredOption("--epic <epicKey>", "Epic issue key", issueKey);
1480
1540
  examples(cmd, ["PROJ-456 --epic PROJ-123", "PROJ-456 PROJ-457 PROJ-458 --epic PROJ-123"]);
1481
1541
  cmd.action(async (keys, opts) => {
1482
1542
  const client = getClient();
@@ -1519,7 +1579,7 @@ function linkTypes(parent) {
1519
1579
 
1520
1580
  // src/commands/issue/link.ts
1521
1581
  function link(parent) {
1522
- const cmd = parent.command("link").description("Link two issues together").requiredOption("--type <name>", "Link type name (e.g., 'Blocks', 'Duplicate', 'Relates')").requiredOption("--from <key>", 'Source issue key (e.g., the issue that "blocks")').requiredOption("--to <key>", 'Target issue key (e.g., the issue that "is blocked by")');
1582
+ const cmd = parent.command("link").description("Link two issues together").requiredOption("--type <name>", "Link type name (e.g., 'Blocks', 'Duplicate', 'Relates')", text).requiredOption("--from <key>", 'Source issue key (e.g., the issue that "blocks")', issueKey).requiredOption("--to <key>", 'Target issue key (e.g., the issue that "is blocked by")', issueKey);
1523
1583
  commentOption(cmd, { description: "Optional comment" });
1524
1584
  examples(cmd, [
1525
1585
  "--type Relates --from AI-154 --to AI-149",
@@ -1545,7 +1605,7 @@ function link(parent) {
1545
1605
 
1546
1606
  // src/commands/issue/search.ts
1547
1607
  function search2(parent) {
1548
- const cmd = parent.command("search <jql>").description("Search issues using JQL").option("--limit <number>", "Max results (1-50, Jira DC caps at 50)", intInRange(1, 50), 25).option("--start <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");
1608
+ const cmd = parent.command("search").description("Search issues using JQL").argument("<jql>", "JQL query string", text).option("--limit <number>", "Max results (1-50, Jira DC caps at 50)", intInRange(1, 50), 25).option("--start <number>", "Starting index for pagination", nonNegativeInt).option("--fields <fields>", "Comma-separated fields to return (defaults to essential fields)", text).option("--all-fields", "Return all fields instead of defaults");
1549
1609
  examples(cmd, [
1550
1610
  '"project = PROJ AND status = Open"',
1551
1611
  '"assignee = currentUser()" --limit 10 --fields summary,status',
@@ -1566,7 +1626,7 @@ function search2(parent) {
1566
1626
 
1567
1627
  // src/commands/issue/transition.ts
1568
1628
  function transition(parent) {
1569
- const cmd = parent.command("transition <key>").description("Transition issue to a new status").requiredOption("--to <idOrName>", "Transition ID, or status name (case-insensitive)");
1629
+ const cmd = parent.command("transition").description("Transition issue to a new status").argument("<key>", "Issue key", issueKey).requiredOption("--to <idOrName>", "Transition ID, or status name (case-insensitive)", text);
1570
1630
  commentOption(cmd, { description: "Comment to add during transition" });
1571
1631
  examples(cmd, [
1572
1632
  "PROJ-123 --to 31",
@@ -1604,7 +1664,7 @@ function transition(parent) {
1604
1664
 
1605
1665
  // src/commands/issue/transitions.ts
1606
1666
  function transitions(parent) {
1607
- const cmd = parent.command("transitions <key>").description("Get available transitions for an issue");
1667
+ const cmd = parent.command("transitions").description("Get available transitions for an issue").argument("<key>", "Issue key", issueKey);
1608
1668
  examples(cmd, ["PROJ-123"]);
1609
1669
  cmd.action(async (key) => {
1610
1670
  const client = getClient();
@@ -1618,30 +1678,33 @@ function transitions(parent) {
1618
1678
 
1619
1679
  // src/commands/issue/unlink.ts
1620
1680
  function unlink2(parent) {
1621
- const cmd = parent.command("unlink <id>").description("Remove a link between two issues");
1681
+ const cmd = parent.command("unlink").description("Remove a link between two issues").argument("<id>", "Link ID", positiveInt);
1622
1682
  examples(cmd, ["12345"]);
1623
1683
  cmd.action(async (id) => {
1624
1684
  const client = getClient();
1625
- await client.links.remove({ linkId: id });
1685
+ await client.links.remove({ linkId: String(id) });
1626
1686
  output({ removed: true, linkId: id });
1627
1687
  });
1628
1688
  }
1629
1689
 
1690
+ // src/commands/issue/update.ts
1691
+ import { z as z3 } from "zod";
1692
+
1630
1693
  // src/utils/multi-value.ts
1631
- import { InvalidArgumentError as InvalidArgumentError3 } from "commander";
1694
+ import { InvalidArgumentError as InvalidArgumentError5 } from "commander";
1632
1695
  function parseMultiValue(flagName, raw) {
1633
1696
  const items = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
1634
1697
  if (items.length === 0) {
1635
- throw new InvalidArgumentError3(`${flagName} cannot be empty`);
1698
+ throw new InvalidArgumentError5(`${flagName} cannot be empty`);
1636
1699
  }
1637
1700
  const lonePrefix = items.find((s) => s === "+" || s === "-");
1638
1701
  if (lonePrefix !== void 0) {
1639
- throw new InvalidArgumentError3(`${flagName} has an empty value after '${lonePrefix}' prefix`);
1702
+ throw new InvalidArgumentError5(`${flagName} has an empty value after '${lonePrefix}' prefix`);
1640
1703
  }
1641
1704
  const prefixed = items.filter((s) => s.startsWith("+") || s.startsWith("-"));
1642
1705
  const bare = items.filter((s) => !s.startsWith("+") && !s.startsWith("-"));
1643
1706
  if (prefixed.length > 0 && bare.length > 0) {
1644
- throw new InvalidArgumentError3(
1707
+ throw new InvalidArgumentError5(
1645
1708
  `${flagName} mixes set and mutate syntax. Either all values have +/- prefix, or none do.`
1646
1709
  );
1647
1710
  }
@@ -1654,6 +1717,7 @@ function parseMultiValue(flagName, raw) {
1654
1717
  }
1655
1718
 
1656
1719
  // src/commands/issue/update.ts
1720
+ var fieldsSchema = z3.record(z3.unknown());
1657
1721
  function buildUpdateOps(parsed, wrap) {
1658
1722
  if (parsed.mode !== "mutate") return void 0;
1659
1723
  return [...parsed.adds.map((v) => ({ add: wrap(v) })), ...parsed.removes.map((v) => ({ remove: wrap(v) }))];
@@ -1663,7 +1727,11 @@ function buildSetValue(parsed, wrap) {
1663
1727
  return parsed.values.map(wrap);
1664
1728
  }
1665
1729
  function update3(parent) {
1666
- const cmd = parent.command("update <key>").description("Update issue fields").option("--fields <json>", "JSON string of fields to update (advanced; merges with shortcuts, wins on conflict)").option("--no-notify-users", "Suppress notification emails (default: notify)").option("--attachments <paths>", "Comma-separated local file paths to attach").option("--summary <text>", "Set the issue summary").option("--priority <name>", "Set the priority by name (e.g. High)").option("--assignee <user>", 'Set the assignee. Username, "me", or "none" to unassign.').option("--labels <list>", 'Set labels ("a,b,c") or mutate ("+add,-remove")').option("--components <list>", 'Set components ("a,b") or mutate ("+add,-remove")').option("--fix-versions <list>", 'Set fix versions ("1.0,2.0") or mutate ("+1.0,-0.9")');
1730
+ const cmd = parent.command("update").description("Update issue fields").argument("<key>", "Issue key", issueKey).option(
1731
+ "--fields <json>",
1732
+ "JSON string of fields to update (advanced; merges with shortcuts, wins on conflict)",
1733
+ jsonShape(fieldsSchema)
1734
+ ).option("--no-notify-users", "Suppress notification emails (default: notify)").option("--attachments <paths>", "Comma-separated local file paths to attach", text).option("--summary <text>", "Set the issue summary", text).option("--priority <name>", "Set the priority by name (e.g. High)", text).option("--assignee <user>", 'Set the assignee. Username, "me", or "none" to unassign.', text).option("--labels <list>", 'Set labels ("a,b,c") or mutate ("+add,-remove")', text).option("--components <list>", 'Set components ("a,b") or mutate ("+add,-remove")', text).option("--fix-versions <list>", 'Set fix versions ("1.0,2.0") or mutate ("+1.0,-0.9")', text);
1667
1735
  textOrFileOption(cmd, "description", { description: "Set the issue description (wiki markup)" });
1668
1736
  examples(cmd, [
1669
1737
  'PROJ-123 --summary "New title"',
@@ -1712,8 +1780,7 @@ function update3(parent) {
1712
1780
  if (ops) updateOps.fixVersions = ops;
1713
1781
  }
1714
1782
  if (opts.fields) {
1715
- const parsedFields = JSON.parse(opts.fields);
1716
- Object.assign(fields, parsedFields);
1783
+ Object.assign(fields, opts.fields);
1717
1784
  }
1718
1785
  const client = getClient();
1719
1786
  const didFieldUpdate = Object.keys(fields).length > 0 || Object.keys(updateOps).length > 0;
@@ -1745,7 +1812,7 @@ function update3(parent) {
1745
1812
 
1746
1813
  // src/commands/issue/worklog/create.ts
1747
1814
  function create4(parent) {
1748
- const cmd = parent.command("create <key>").description("Log time spent on an issue").requiredOption("--time <timeSpent>", "Time spent (e.g., '2h', '30m', '1d 4h')").option("--started <datetime>", "Start time in ISO 8601 format");
1815
+ const cmd = parent.command("create").description("Log time spent on an issue").argument("<key>", "Issue key", issueKey).requiredOption("--time <timeSpent>", "Time spent (e.g., '2h', '30m', '1d 4h')", text).option("--started <datetime>", "Start time in ISO 8601 format", dateTime);
1749
1816
  commentOption(cmd, { description: "Worklog comment" });
1750
1817
  examples(cmd, [
1751
1818
  "PROJ-123 --time 2h",
@@ -1769,11 +1836,12 @@ function create4(parent) {
1769
1836
  import { Option as Option5 } from "commander";
1770
1837
  var ADJUST_ESTIMATE = ["new", "leave", "manual", "auto"];
1771
1838
  function deleteWorklog(parent) {
1772
- const cmd = parent.command("delete <key>").description("Delete a worklog entry");
1839
+ const cmd = parent.command("delete").description("Delete a worklog entry").argument("<key>", "Issue key", issueKey);
1773
1840
  subEntityOption(cmd, "worklog", { mandatory: true });
1774
- cmd.addOption(new Option5("--adjust-estimate <mode>", "How to adjust the remaining estimate").choices(ADJUST_ESTIMATE)).option("--new-estimate <estimate>", 'New remaining estimate; required when --adjust-estimate is "new"').option(
1841
+ cmd.addOption(new Option5("--adjust-estimate <mode>", "How to adjust the remaining estimate").choices(ADJUST_ESTIMATE)).option("--new-estimate <estimate>", 'New remaining estimate; required when --adjust-estimate is "new"', text).option(
1775
1842
  "--increase-by <amount>",
1776
- 'Amount to increase the estimate by; required when --adjust-estimate is "manual"'
1843
+ 'Amount to increase the estimate by; required when --adjust-estimate is "manual"',
1844
+ text
1777
1845
  );
1778
1846
  examples(cmd, [
1779
1847
  "PROJ-123 --worklog-id 12345",
@@ -1797,7 +1865,7 @@ function deleteWorklog(parent) {
1797
1865
 
1798
1866
  // src/commands/issue/worklog/list.ts
1799
1867
  function list4(parent) {
1800
- const cmd = parent.command("list <key>").description("Get worklogs for an issue").option("--start <number>", "Starting index for pagination", nonNegativeInt).option("--limit <number>", "Max results per page (1-1000)", intInRange(1, 1e3), 25);
1868
+ const cmd = parent.command("list").description("Get worklogs for an issue").argument("<key>", "Issue key", issueKey).option("--start <number>", "Starting index for pagination", nonNegativeInt).option("--limit <number>", "Max results per page (1-1000)", intInRange(1, 1e3), 25);
1801
1869
  examples(cmd, ["PROJ-123", "PROJ-123 --limit 10", "PROJ-123 --start 10 --limit 5"]);
1802
1870
  cmd.action(async (key, opts) => {
1803
1871
  const client = getClient();
@@ -1814,9 +1882,9 @@ function list4(parent) {
1814
1882
  import { Option as Option6 } from "commander";
1815
1883
  var ADJUST_ESTIMATE2 = ["new", "leave", "auto"];
1816
1884
  function update4(parent) {
1817
- const cmd = parent.command("update <key>").description("Update an existing worklog entry");
1885
+ const cmd = parent.command("update").description("Update an existing worklog entry").argument("<key>", "Issue key", issueKey);
1818
1886
  subEntityOption(cmd, "worklog", { mandatory: true });
1819
- cmd.option("--time <timeSpent>", "Time spent (e.g., '2h', '30m', '1d 4h')").option("--started <datetime>", "Start time in ISO 8601 format").addOption(new Option6("--adjust-estimate <mode>", "How to adjust the remaining estimate").choices(ADJUST_ESTIMATE2)).option("--new-estimate <estimate>", 'New remaining estimate; required when --adjust-estimate is "new"');
1887
+ cmd.option("--time <timeSpent>", "Time spent (e.g., '2h', '30m', '1d 4h')", text).option("--started <datetime>", "Start time in ISO 8601 format", dateTime).addOption(new Option6("--adjust-estimate <mode>", "How to adjust the remaining estimate").choices(ADJUST_ESTIMATE2)).option("--new-estimate <estimate>", 'New remaining estimate; required when --adjust-estimate is "new"', text);
1820
1888
  commentOption(cmd, { description: "Worklog comment" });
1821
1889
  examples(cmd, [
1822
1890
  'PROJ-123 --worklog-id 12345 --time "1h 30m"',
@@ -1891,7 +1959,7 @@ function registerIssueCommands(program) {
1891
1959
 
1892
1960
  // src/commands/project/list.ts
1893
1961
  function list5(parent) {
1894
- const cmd = parent.command("list").description("List all projects").option("--expand <expand>", 'Expand options (e.g., "description,lead")').option("--include-archived", "Include archived projects (default: false)");
1962
+ const cmd = parent.command("list").description("List all projects").option("--expand <expand>", 'Expand options (e.g., "description,lead")', text).option("--include-archived", "Include archived projects (default: false)");
1895
1963
  examples(cmd, ["", "--expand description,lead", "--include-archived"]);
1896
1964
  cmd.action(async (opts) => {
1897
1965
  const client = getClient();
@@ -1902,7 +1970,7 @@ function list5(parent) {
1902
1970
 
1903
1971
  // src/commands/project/versions.ts
1904
1972
  function versions(parent) {
1905
- const cmd = parent.command("versions <key>").description("Get all versions for a project").option("--expand <expand>", "Expand options");
1973
+ const cmd = parent.command("versions").description("Get all versions for a project").argument("<key>", "Project key", text).option("--expand <expand>", "Expand options", text);
1906
1974
  examples(cmd, ["PROJ", "PROJ --expand operations"]);
1907
1975
  cmd.action(async (key, opts) => {
1908
1976
  const client = getClient();
@@ -1921,7 +1989,7 @@ function registerProjectCommands(program) {
1921
1989
 
1922
1990
  // src/commands/sprint/create.ts
1923
1991
  function create5(parent) {
1924
- const cmd = 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");
1992
+ const cmd = parent.command("create").description("Create a new sprint").requiredOption("--board <id>", "Board ID to create sprint in", positiveInt).requiredOption("--name <name>", "Sprint name", text).option("--start-date <date>", "Start date in ISO 8601 format", text).option("--end-date <date>", "End date in ISO 8601 format", text).option("--goal <goal>", "Sprint goal", text);
1925
1993
  examples(cmd, [
1926
1994
  '--board 42 --name "Sprint 10"',
1927
1995
  '--board 42 --name "Sprint 10" --start-date 2026-03-20 --end-date 2026-04-03 --goal "Complete auth module"'
@@ -1954,7 +2022,7 @@ function deleteSprint(parent) {
1954
2022
  // src/commands/sprint/issues.ts
1955
2023
  import { Argument as Argument3 } from "commander";
1956
2024
  function issues2(parent) {
1957
- const cmd = parent.command("issues").description("Get issues in a sprint").addArgument(new Argument3("<id>", "Sprint ID").argParser(positiveInt)).option("--limit <number>", "Max results (1-50, Jira DC caps at 50)", intInRange(1, 50), 25).option("--start <number>", "Starting index for pagination", nonNegativeInt).option("--fields <fields>", "Comma-separated field names to return").option("--jql <jql>", "Additional JQL filter within the sprint");
2025
+ const cmd = parent.command("issues").description("Get issues in a sprint").addArgument(new Argument3("<id>", "Sprint ID").argParser(positiveInt)).option("--limit <number>", "Max results (1-50, Jira DC caps at 50)", intInRange(1, 50), 25).option("--start <number>", "Starting index for pagination", nonNegativeInt).option("--fields <fields>", "Comma-separated field names to return", text).option("--jql <jql>", "Additional JQL filter within the sprint", text);
1958
2026
  examples(cmd, [
1959
2027
  "100",
1960
2028
  "100 --limit 20",
@@ -1994,7 +2062,7 @@ function list6(parent) {
1994
2062
  import { Argument as Argument4, Option as Option8 } from "commander";
1995
2063
  var SPRINT_STATES2 = ["future", "active", "closed"];
1996
2064
  function update5(parent) {
1997
- const cmd = parent.command("update").description("Update an existing sprint").addArgument(new Argument4("<id>", "Sprint ID").argParser(positiveInt)).option("--name <name>", "New sprint name").addOption(new Option8("--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");
2065
+ const cmd = parent.command("update").description("Update an existing sprint").addArgument(new Argument4("<id>", "Sprint ID").argParser(positiveInt)).option("--name <name>", "New sprint name", text).addOption(new Option8("--state <state>", "New sprint state").choices(SPRINT_STATES2)).option("--start-date <date>", "New start date in ISO 8601 format", text).option("--end-date <date>", "New end date in ISO 8601 format", text).option("--goal <goal>", "New sprint goal", text);
1998
2066
  examples(cmd, [
1999
2067
  '100 --name "Sprint 10 - Extended"',
2000
2068
  "100 --state active",
@@ -2052,13 +2120,14 @@ function getTokenClient(options2 = {}) {
2052
2120
 
2053
2121
  // src/commands/token/create.ts
2054
2122
  function create6(parent) {
2055
- const cmd = parent.command("create").description("Create a Personal Access Token. The secret is returned exactly once.").requiredOption("--name <name>", "Token name").option(
2123
+ const cmd = parent.command("create").description("Create a Personal Access Token. The secret is returned exactly once.").requiredOption("--name <name>", "Token name", text).option(
2056
2124
  "--expiration-duration <days>",
2057
2125
  "Token lifetime in days. Omit for a non-expiring token (admin policy permitting).",
2058
2126
  positiveInt
2059
- ).option("--basic-username <u>", "Override $JIRA_BASIC_USERNAME").option(
2127
+ ).option("--basic-username <u>", "Override $JIRA_BASIC_USERNAME", text).option(
2060
2128
  "--basic-password <p>",
2061
- "Override $JIRA_BASIC_PASSWORD (caution: visible in process table; prefer the env var)"
2129
+ "Override $JIRA_BASIC_PASSWORD (caution: visible in process table; prefer the env var)",
2130
+ text
2062
2131
  );
2063
2132
  examples(cmd, [["--name my-pat", "non-expiring"], "--name svc-token --expiration-duration 365"]);
2064
2133
  cmd.action(async (opts) => {
@@ -2078,9 +2147,10 @@ function create6(parent) {
2078
2147
 
2079
2148
  // src/commands/token/list.ts
2080
2149
  function list7(parent) {
2081
- const cmd = parent.command("list").description("List Personal Access Tokens owned by the authenticated user (secrets not included)").option("--basic-username <u>", "Override $JIRA_BASIC_USERNAME").option(
2150
+ const cmd = parent.command("list").description("List Personal Access Tokens owned by the authenticated user (secrets not included)").option("--basic-username <u>", "Override $JIRA_BASIC_USERNAME", text).option(
2082
2151
  "--basic-password <p>",
2083
- "Override $JIRA_BASIC_PASSWORD (caution: visible in process table; prefer the env var)"
2152
+ "Override $JIRA_BASIC_PASSWORD (caution: visible in process table; prefer the env var)",
2153
+ text
2084
2154
  );
2085
2155
  examples(cmd, [""]);
2086
2156
  cmd.action(async (opts) => {
@@ -2094,9 +2164,10 @@ function list7(parent) {
2094
2164
 
2095
2165
  // src/commands/token/revoke.ts
2096
2166
  function revoke(parent) {
2097
- const cmd = parent.command("revoke").description("Revoke a Personal Access Token by id").option("--basic-username <u>", "Override $JIRA_BASIC_USERNAME").option(
2167
+ const cmd = parent.command("revoke").description("Revoke a Personal Access Token by id").option("--basic-username <u>", "Override $JIRA_BASIC_USERNAME", text).option(
2098
2168
  "--basic-password <p>",
2099
- "Override $JIRA_BASIC_PASSWORD (caution: visible in process table; prefer the env var)"
2169
+ "Override $JIRA_BASIC_PASSWORD (caution: visible in process table; prefer the env var)",
2170
+ text
2100
2171
  );
2101
2172
  subjectArg(cmd, "tokenId", { parser: positiveInt, description: "Token id to revoke" });
2102
2173
  examples(cmd, ["173"]);
@@ -2125,7 +2196,7 @@ function registerTokenCommands(program) {
2125
2196
 
2126
2197
  // src/commands/user/get.ts
2127
2198
  function get3(parent) {
2128
- const cmd = parent.command("get <username>").description("Get a user profile by exact username or key").option("--by-key", "Treat the positional argument as a user key instead of a username");
2199
+ const cmd = parent.command("get").description("Get a user profile by exact username or key").argument("<username>", "Username or user key", text).option("--by-key", "Treat the positional argument as a user key instead of a username");
2129
2200
  examples(cmd, ["jsmith", "JIRAUSER10100 --by-key"]);
2130
2201
  cmd.action(async (identifier, opts) => {
2131
2202
  const client = getClient();
@@ -2147,7 +2218,7 @@ function me(parent) {
2147
2218
 
2148
2219
  // src/commands/user/search.ts
2149
2220
  function search3(parent) {
2150
- const cmd = parent.command("search <query>").description("Search users by partial username, display name or email").option("--limit <n>", "Maximum results (1-50)", intInRange(1, 50), 25).option("--start <n>", "Starting index (pagination offset)", nonNegativeInt, 0).option("--include-inactive", "Include inactive users in results", false);
2221
+ const cmd = parent.command("search").description("Search users by partial username, display name or email").argument("<query>", "Search query", text).option("--limit <n>", "Maximum results (1-50)", intInRange(1, 50), 25).option("--start <n>", "Starting index (pagination offset)", nonNegativeInt, 0).option("--include-inactive", "Include inactive users in results", false);
2151
2222
  examples(cmd, ["Smith", '"John Smith"', "jsmith@example.com --limit 5"]);
2152
2223
  cmd.action(async (query, opts) => {
2153
2224
  const client = getClient();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jiradc-cli",
3
- "version": "1.0.25",
3
+ "version": "1.0.26",
4
4
  "publish": true,
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -12,6 +12,7 @@
12
12
  ],
13
13
  "dependencies": {
14
14
  "commander": "^13.1.0",
15
+ "zod": "^3.25.67",
15
16
  "jira-data-center-client": "1.0.39"
16
17
  },
17
18
  "devDependencies": {