jiradc-cli 1.0.24 → 1.0.25-g6beae79.4

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 +159 -86
  2. package/package.json +3 -2
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 (!/^[A-Z][A-Z0-9]+-\d+$/.test(raw)) {
994
+ throw new InvalidArgumentError4("Must be a Jira issue key like PROJ-123.");
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,32 +1368,40 @@ 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 <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"}')`);
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"',
1322
- '--project PROJ --type Story --summary "New feature" --assignee jsmith --priority High',
1382
+ '--project PROJ --type Story --summary "New feature" --assignee me --priority High',
1323
1383
  '--project PROJ --type Bug --summary "Urgent" --labels urgent,production --components Backend'
1324
1384
  ]);
1325
1385
  cmd.action(
1326
1386
  async (opts) => {
1327
1387
  const description = resolveTextOrFile(opts, "description", { required: false });
1388
+ const assignee = opts.assignee !== void 0 ? await resolveUserToken(opts.assignee) : void 0;
1389
+ const reporter = opts.reporter !== void 0 ? await resolveUserToken(opts.reporter) : void 0;
1328
1390
  const client = getClient();
1329
1391
  const result = await client.issues.create({
1330
1392
  projectKeyOrId: opts.project,
1331
1393
  issueTypeName: opts.type,
1332
1394
  summary: opts.summary,
1333
1395
  description,
1334
- assignee: opts.assignee,
1335
- reporter: opts.reporter,
1396
+ assignee: assignee ?? void 0,
1397
+ reporter: reporter ?? void 0,
1336
1398
  priority: opts.priority,
1337
1399
  labels: opts.labels?.split(",").map((l) => l.trim()),
1338
1400
  components: opts.components?.split(",").map((c) => c.trim()),
1339
1401
  fixVersions: opts.fixVersions?.split(",").map((v) => v.trim()),
1340
1402
  dueDate: opts.dueDate,
1341
1403
  parent: opts.parent,
1342
- customFields: opts.customFields ? JSON.parse(opts.customFields) : void 0
1404
+ customFields: opts.customFields
1343
1405
  });
1344
1406
  output(transformCreatedIssue(result));
1345
1407
  }
@@ -1348,7 +1410,7 @@ function create3(parent) {
1348
1410
 
1349
1411
  // src/commands/issue/delete.ts
1350
1412
  function deleteIssue(parent) {
1351
- 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)");
1352
1414
  examples(cmd, ["PROJ-123", "PROJ-123 --delete-subtasks"]);
1353
1415
  cmd.action(async (key, opts) => {
1354
1416
  const client = getClient();
@@ -1359,7 +1421,7 @@ function deleteIssue(parent) {
1359
1421
 
1360
1422
  // src/commands/issue/dev-status.ts
1361
1423
  function devStatus(parent) {
1362
- 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");
1363
1425
  examples(cmd, ["PROJ-123", "PROJ-123 --detail"]);
1364
1426
  cmd.action(async (key, opts) => {
1365
1427
  const client = getClient();
@@ -1453,7 +1515,7 @@ var DEFAULT_FIELDS = [
1453
1515
 
1454
1516
  // src/commands/issue/get.ts
1455
1517
  function get2(parent) {
1456
- 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);
1457
1519
  examples(cmd, [
1458
1520
  "PROJ-123",
1459
1521
  "PROJ-123 --fields summary,status,assignee",
@@ -1474,7 +1536,7 @@ function get2(parent) {
1474
1536
 
1475
1537
  // src/commands/issue/link-epic.ts
1476
1538
  function linkEpic(parent) {
1477
- 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);
1478
1540
  examples(cmd, ["PROJ-456 --epic PROJ-123", "PROJ-456 PROJ-457 PROJ-458 --epic PROJ-123"]);
1479
1541
  cmd.action(async (keys, opts) => {
1480
1542
  const client = getClient();
@@ -1517,7 +1579,7 @@ function linkTypes(parent) {
1517
1579
 
1518
1580
  // src/commands/issue/link.ts
1519
1581
  function link(parent) {
1520
- 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);
1521
1583
  commentOption(cmd, { description: "Optional comment" });
1522
1584
  examples(cmd, [
1523
1585
  "--type Relates --from AI-154 --to AI-149",
@@ -1543,7 +1605,7 @@ function link(parent) {
1543
1605
 
1544
1606
  // src/commands/issue/search.ts
1545
1607
  function search2(parent) {
1546
- 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");
1547
1609
  examples(cmd, [
1548
1610
  '"project = PROJ AND status = Open"',
1549
1611
  '"assignee = currentUser()" --limit 10 --fields summary,status',
@@ -1564,7 +1626,7 @@ function search2(parent) {
1564
1626
 
1565
1627
  // src/commands/issue/transition.ts
1566
1628
  function transition(parent) {
1567
- 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);
1568
1630
  commentOption(cmd, { description: "Comment to add during transition" });
1569
1631
  examples(cmd, [
1570
1632
  "PROJ-123 --to 31",
@@ -1602,7 +1664,7 @@ function transition(parent) {
1602
1664
 
1603
1665
  // src/commands/issue/transitions.ts
1604
1666
  function transitions(parent) {
1605
- 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);
1606
1668
  examples(cmd, ["PROJ-123"]);
1607
1669
  cmd.action(async (key) => {
1608
1670
  const client = getClient();
@@ -1616,30 +1678,33 @@ function transitions(parent) {
1616
1678
 
1617
1679
  // src/commands/issue/unlink.ts
1618
1680
  function unlink2(parent) {
1619
- 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);
1620
1682
  examples(cmd, ["12345"]);
1621
1683
  cmd.action(async (id) => {
1622
1684
  const client = getClient();
1623
- await client.links.remove({ linkId: id });
1685
+ await client.links.remove({ linkId: String(id) });
1624
1686
  output({ removed: true, linkId: id });
1625
1687
  });
1626
1688
  }
1627
1689
 
1690
+ // src/commands/issue/update.ts
1691
+ import { z as z3 } from "zod";
1692
+
1628
1693
  // src/utils/multi-value.ts
1629
- import { InvalidArgumentError as InvalidArgumentError3 } from "commander";
1694
+ import { InvalidArgumentError as InvalidArgumentError5 } from "commander";
1630
1695
  function parseMultiValue(flagName, raw) {
1631
1696
  const items = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
1632
1697
  if (items.length === 0) {
1633
- throw new InvalidArgumentError3(`${flagName} cannot be empty`);
1698
+ throw new InvalidArgumentError5(`${flagName} cannot be empty`);
1634
1699
  }
1635
1700
  const lonePrefix = items.find((s) => s === "+" || s === "-");
1636
1701
  if (lonePrefix !== void 0) {
1637
- throw new InvalidArgumentError3(`${flagName} has an empty value after '${lonePrefix}' prefix`);
1702
+ throw new InvalidArgumentError5(`${flagName} has an empty value after '${lonePrefix}' prefix`);
1638
1703
  }
1639
1704
  const prefixed = items.filter((s) => s.startsWith("+") || s.startsWith("-"));
1640
1705
  const bare = items.filter((s) => !s.startsWith("+") && !s.startsWith("-"));
1641
1706
  if (prefixed.length > 0 && bare.length > 0) {
1642
- throw new InvalidArgumentError3(
1707
+ throw new InvalidArgumentError5(
1643
1708
  `${flagName} mixes set and mutate syntax. Either all values have +/- prefix, or none do.`
1644
1709
  );
1645
1710
  }
@@ -1652,6 +1717,7 @@ function parseMultiValue(flagName, raw) {
1652
1717
  }
1653
1718
 
1654
1719
  // src/commands/issue/update.ts
1720
+ var fieldsSchema = z3.record(z3.unknown());
1655
1721
  function buildUpdateOps(parsed, wrap) {
1656
1722
  if (parsed.mode !== "mutate") return void 0;
1657
1723
  return [...parsed.adds.map((v) => ({ add: wrap(v) })), ...parsed.removes.map((v) => ({ remove: wrap(v) }))];
@@ -1661,7 +1727,11 @@ function buildSetValue(parsed, wrap) {
1661
1727
  return parsed.values.map(wrap);
1662
1728
  }
1663
1729
  function update3(parent) {
1664
- 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);
1665
1735
  textOrFileOption(cmd, "description", { description: "Set the issue description (wiki markup)" });
1666
1736
  examples(cmd, [
1667
1737
  'PROJ-123 --summary "New title"',
@@ -1710,8 +1780,7 @@ function update3(parent) {
1710
1780
  if (ops) updateOps.fixVersions = ops;
1711
1781
  }
1712
1782
  if (opts.fields) {
1713
- const parsedFields = JSON.parse(opts.fields);
1714
- Object.assign(fields, parsedFields);
1783
+ Object.assign(fields, opts.fields);
1715
1784
  }
1716
1785
  const client = getClient();
1717
1786
  const didFieldUpdate = Object.keys(fields).length > 0 || Object.keys(updateOps).length > 0;
@@ -1743,7 +1812,7 @@ function update3(parent) {
1743
1812
 
1744
1813
  // src/commands/issue/worklog/create.ts
1745
1814
  function create4(parent) {
1746
- 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);
1747
1816
  commentOption(cmd, { description: "Worklog comment" });
1748
1817
  examples(cmd, [
1749
1818
  "PROJ-123 --time 2h",
@@ -1767,11 +1836,12 @@ function create4(parent) {
1767
1836
  import { Option as Option5 } from "commander";
1768
1837
  var ADJUST_ESTIMATE = ["new", "leave", "manual", "auto"];
1769
1838
  function deleteWorklog(parent) {
1770
- 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);
1771
1840
  subEntityOption(cmd, "worklog", { mandatory: true });
1772
- 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(
1773
1842
  "--increase-by <amount>",
1774
- '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
1775
1845
  );
1776
1846
  examples(cmd, [
1777
1847
  "PROJ-123 --worklog-id 12345",
@@ -1795,7 +1865,7 @@ function deleteWorklog(parent) {
1795
1865
 
1796
1866
  // src/commands/issue/worklog/list.ts
1797
1867
  function list4(parent) {
1798
- 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);
1799
1869
  examples(cmd, ["PROJ-123", "PROJ-123 --limit 10", "PROJ-123 --start 10 --limit 5"]);
1800
1870
  cmd.action(async (key, opts) => {
1801
1871
  const client = getClient();
@@ -1812,9 +1882,9 @@ function list4(parent) {
1812
1882
  import { Option as Option6 } from "commander";
1813
1883
  var ADJUST_ESTIMATE2 = ["new", "leave", "auto"];
1814
1884
  function update4(parent) {
1815
- 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);
1816
1886
  subEntityOption(cmd, "worklog", { mandatory: true });
1817
- 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);
1818
1888
  commentOption(cmd, { description: "Worklog comment" });
1819
1889
  examples(cmd, [
1820
1890
  'PROJ-123 --worklog-id 12345 --time "1h 30m"',
@@ -1889,7 +1959,7 @@ function registerIssueCommands(program) {
1889
1959
 
1890
1960
  // src/commands/project/list.ts
1891
1961
  function list5(parent) {
1892
- 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)");
1893
1963
  examples(cmd, ["", "--expand description,lead", "--include-archived"]);
1894
1964
  cmd.action(async (opts) => {
1895
1965
  const client = getClient();
@@ -1900,7 +1970,7 @@ function list5(parent) {
1900
1970
 
1901
1971
  // src/commands/project/versions.ts
1902
1972
  function versions(parent) {
1903
- 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);
1904
1974
  examples(cmd, ["PROJ", "PROJ --expand operations"]);
1905
1975
  cmd.action(async (key, opts) => {
1906
1976
  const client = getClient();
@@ -1919,7 +1989,7 @@ function registerProjectCommands(program) {
1919
1989
 
1920
1990
  // src/commands/sprint/create.ts
1921
1991
  function create5(parent) {
1922
- 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);
1923
1993
  examples(cmd, [
1924
1994
  '--board 42 --name "Sprint 10"',
1925
1995
  '--board 42 --name "Sprint 10" --start-date 2026-03-20 --end-date 2026-04-03 --goal "Complete auth module"'
@@ -1952,7 +2022,7 @@ function deleteSprint(parent) {
1952
2022
  // src/commands/sprint/issues.ts
1953
2023
  import { Argument as Argument3 } from "commander";
1954
2024
  function issues2(parent) {
1955
- 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);
1956
2026
  examples(cmd, [
1957
2027
  "100",
1958
2028
  "100 --limit 20",
@@ -1992,7 +2062,7 @@ function list6(parent) {
1992
2062
  import { Argument as Argument4, Option as Option8 } from "commander";
1993
2063
  var SPRINT_STATES2 = ["future", "active", "closed"];
1994
2064
  function update5(parent) {
1995
- 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);
1996
2066
  examples(cmd, [
1997
2067
  '100 --name "Sprint 10 - Extended"',
1998
2068
  "100 --state active",
@@ -2050,13 +2120,14 @@ function getTokenClient(options2 = {}) {
2050
2120
 
2051
2121
  // src/commands/token/create.ts
2052
2122
  function create6(parent) {
2053
- 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(
2054
2124
  "--expiration-duration <days>",
2055
2125
  "Token lifetime in days. Omit for a non-expiring token (admin policy permitting).",
2056
2126
  positiveInt
2057
- ).option("--basic-username <u>", "Override $JIRA_BASIC_USERNAME").option(
2127
+ ).option("--basic-username <u>", "Override $JIRA_BASIC_USERNAME", text).option(
2058
2128
  "--basic-password <p>",
2059
- "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
2060
2131
  );
2061
2132
  examples(cmd, [["--name my-pat", "non-expiring"], "--name svc-token --expiration-duration 365"]);
2062
2133
  cmd.action(async (opts) => {
@@ -2076,9 +2147,10 @@ function create6(parent) {
2076
2147
 
2077
2148
  // src/commands/token/list.ts
2078
2149
  function list7(parent) {
2079
- 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(
2080
2151
  "--basic-password <p>",
2081
- "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
2082
2154
  );
2083
2155
  examples(cmd, [""]);
2084
2156
  cmd.action(async (opts) => {
@@ -2092,9 +2164,10 @@ function list7(parent) {
2092
2164
 
2093
2165
  // src/commands/token/revoke.ts
2094
2166
  function revoke(parent) {
2095
- 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(
2096
2168
  "--basic-password <p>",
2097
- "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
2098
2171
  );
2099
2172
  subjectArg(cmd, "tokenId", { parser: positiveInt, description: "Token id to revoke" });
2100
2173
  examples(cmd, ["173"]);
@@ -2123,7 +2196,7 @@ function registerTokenCommands(program) {
2123
2196
 
2124
2197
  // src/commands/user/get.ts
2125
2198
  function get3(parent) {
2126
- 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");
2127
2200
  examples(cmd, ["jsmith", "JIRAUSER10100 --by-key"]);
2128
2201
  cmd.action(async (identifier, opts) => {
2129
2202
  const client = getClient();
@@ -2145,7 +2218,7 @@ function me(parent) {
2145
2218
 
2146
2219
  // src/commands/user/search.ts
2147
2220
  function search3(parent) {
2148
- 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);
2149
2222
  examples(cmd, ["Smith", '"John Smith"', "jsmith@example.com --limit 5"]);
2150
2223
  cmd.action(async (query, opts) => {
2151
2224
  const client = getClient();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jiradc-cli",
3
- "version": "1.0.24",
3
+ "version": "1.0.25-g6beae79.4",
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": {
@@ -22,8 +23,8 @@
22
23
  "tsx": "^4.19.2",
23
24
  "typescript": "^5.7.2",
24
25
  "vitest": "^4.0.16",
25
- "cli-utils": "1.0.0",
26
26
  "config-eslint": "0.0.0",
27
+ "cli-utils": "1.0.0",
27
28
  "config-typescript": "0.0.0"
28
29
  },
29
30
  "engines": {