jiradc-cli 1.0.25 → 1.0.26-g6336787.1

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 +157 -83
  2. package/package.json +4 -3
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,83 @@ 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 listOf(item) {
51
+ return (raw, previous) => [...Array.isArray(previous) ? previous : [], item(raw)];
52
+ }
53
+ function text(raw) {
54
+ return raw;
55
+ }
56
+ function date(raw) {
57
+ const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(raw);
58
+ if (!m) {
59
+ throw new InvalidArgumentError("Must be a date in YYYY-MM-DD format.");
60
+ }
61
+ const [, y, mo, d] = m;
62
+ const year = Number(y);
63
+ const month = Number(mo);
64
+ const day = Number(d);
65
+ const dt = new Date(Date.UTC(year, month - 1, day));
66
+ if (dt.getUTCFullYear() !== year || dt.getUTCMonth() !== month - 1 || dt.getUTCDate() !== day) {
67
+ throw new InvalidArgumentError("Not a real calendar date.");
68
+ }
69
+ return raw;
70
+ }
71
+ function dateTime(raw) {
72
+ if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(raw) || Number.isNaN(Date.parse(raw))) {
73
+ throw new InvalidArgumentError("Must be an ISO 8601 date-time, e.g. 2026-06-08T14:30:00Z.");
74
+ }
75
+ return raw;
76
+ }
77
+
78
+ // ../../cli-utils/dist/json.js
79
+ import { InvalidArgumentError as InvalidArgumentError2 } from "commander";
80
+ function jsonShape(schema) {
81
+ return (raw) => {
82
+ let parsed;
83
+ try {
84
+ parsed = JSON.parse(raw);
85
+ } catch {
86
+ throw new InvalidArgumentError2("Must be valid JSON.");
87
+ }
88
+ const result = schema.safeParse(parsed);
89
+ if (!result.success) {
90
+ const issues3 = result.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
91
+ throw new InvalidArgumentError2(`Invalid JSON shape \u2014 ${issues3}`);
92
+ }
93
+ return result.data;
94
+ };
95
+ }
50
96
 
51
97
  // ../../cli-utils/dist/text-or-file.js
52
98
  import { readFileSync as readFileSync3 } from "fs";
53
- import { InvalidArgumentError as InvalidArgumentError2, Option } from "commander";
99
+ import { InvalidArgumentError as InvalidArgumentError3, Option } from "commander";
54
100
  var STDIN_REF = "-";
55
101
  function rejectStdinSentinel(value) {
56
102
  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.`);
103
+ 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
104
  }
59
105
  return value;
60
106
  }
61
107
  function readFileOrStdin(ref) {
62
108
  if (ref === STDIN_REF) {
63
109
  if (process.stdin.isTTY) {
64
- throw new InvalidArgumentError2('"--\u2026-file -" reads stdin, but stdin is a terminal (nothing piped).');
110
+ throw new InvalidArgumentError3('"--\u2026-file -" reads stdin, but stdin is a terminal (nothing piped).');
65
111
  }
66
112
  try {
67
113
  return readFileSync3(0, "utf8");
68
114
  } catch (err) {
69
- throw new InvalidArgumentError2(`failed to read stdin for "--\u2026-file -": ${err.message}`);
115
+ throw new InvalidArgumentError3(`failed to read stdin for "--\u2026-file -": ${err.message}`);
70
116
  }
71
117
  }
72
118
  try {
@@ -74,28 +120,28 @@ function readFileOrStdin(ref) {
74
120
  } catch (err) {
75
121
  const e = err;
76
122
  if (e.code === "ENOENT") {
77
- throw new InvalidArgumentError2(`file not found: "${ref}".`);
123
+ throw new InvalidArgumentError3(`file not found: "${ref}".`);
78
124
  }
79
- throw new InvalidArgumentError2(`failed to read file "${ref}": ${e.message}`);
125
+ throw new InvalidArgumentError3(`failed to read file "${ref}": ${e.message}`);
80
126
  }
81
127
  }
82
128
  function textOrFileOption(cmd, name, opts = {}) {
83
129
  const label = `${name.charAt(0).toUpperCase()}${name.slice(1)} content`;
84
130
  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));
131
+ cmd.addOption(new Option(`--${name}-file <path>`, `Read --${name} from a file, or "-" for stdin (mutually exclusive with --${name})`).conflicts(name).argParser(text));
86
132
  return cmd;
87
133
  }
88
134
  function resolveTextOrFile(opts, name, { required = true } = {}) {
89
135
  const literal = opts[name];
90
136
  const ref = opts[`${name}File`];
91
137
  if (literal !== void 0 && ref !== void 0) {
92
- throw new InvalidArgumentError2(`--${name} and --${name}-file are mutually exclusive; provide only one.`);
138
+ throw new InvalidArgumentError3(`--${name} and --${name}-file are mutually exclusive; provide only one.`);
93
139
  }
94
140
  if (ref !== void 0) {
95
141
  return readFileOrStdin(ref);
96
142
  }
97
143
  if (literal === void 0 && required) {
98
- throw new InvalidArgumentError2(`a ${name} is required: provide --${name} <text> or --${name}-file <path>.`);
144
+ throw new InvalidArgumentError3(`a ${name} is required: provide --${name} <text> or --${name}-file <path>.`);
99
145
  }
100
146
  return literal;
101
147
  }
@@ -127,7 +173,7 @@ function subjectArg(cmd, name, opts = {}) {
127
173
  function subEntityOption(cmd, entity, opts = {}) {
128
174
  const numeric = opts.numeric ?? SUB_ENTITY_ID_NUMERIC[entity] ?? true;
129
175
  const description = `${entity.charAt(0).toUpperCase()}${entity.slice(1)} id`;
130
- return defineOption(cmd, `--${entity}-id <id>`, description, numeric ? positiveInt : void 0, opts.mandatory);
176
+ return defineOption(cmd, `--${entity}-id <id>`, description, numeric ? positiveInt : text, opts.mandatory);
131
177
  }
132
178
  function bodyOption(cmd, opts = {}) {
133
179
  return textOrFileOption(cmd, "body", { description: "Prose body content", ...opts });
@@ -717,7 +763,7 @@ function transformTransitions(response) {
717
763
 
718
764
  // src/commands/board/issues.ts
719
765
  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");
766
+ 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
767
  examples(cmd, [
722
768
  "42",
723
769
  "42 --limit 10",
@@ -741,7 +787,7 @@ function issues(parent) {
741
787
  import { Option as Option2 } from "commander";
742
788
  var BOARD_TYPES = ["scrum", "kanban", "simple"];
743
789
  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");
790
+ 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
791
  examples(cmd, ["", "--limit 10", "--project PROJ", '--type scrum --name "Team Board"']);
746
792
  cmd.action(async (opts) => {
747
793
  const client = getClient();
@@ -772,7 +818,7 @@ var ASSIGNEE_TYPES = [
772
818
  "UNASSIGNED"
773
819
  ];
774
820
  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));
821
+ 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
822
  textOrFileOption(cmd, "description", { description: "Component description" });
777
823
  examples(cmd, [
778
824
  "--project AI --name Backend",
@@ -797,40 +843,40 @@ function create(parent) {
797
843
 
798
844
  // src/commands/component/delete.ts
799
845
  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");
846
+ 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
847
  examples(cmd, ["11289", "11289 --move-issues-to 11290"]);
802
848
  cmd.action(async (id, opts) => {
803
849
  const client = getClient();
804
- await client.components.delete({ id, moveIssuesTo: opts.moveIssuesTo });
850
+ await client.components.delete({ id: String(id), moveIssuesTo: opts.moveIssuesTo });
805
851
  output({ deleted: true, componentId: id, ...opts.moveIssuesTo && { movedIssuesTo: opts.moveIssuesTo } });
806
852
  });
807
853
  }
808
854
 
809
855
  // src/commands/component/get.ts
810
856
  function get(parent) {
811
- const cmd = parent.command("get <id>").description("Get a component by ID");
857
+ const cmd = parent.command("get").description("Get a component by ID").argument("<id>", "Component ID", positiveInt);
812
858
  examples(cmd, ["11289"]);
813
859
  cmd.action(async (id) => {
814
860
  const client = getClient();
815
- const result = await client.components.get({ id });
861
+ const result = await client.components.get({ id: String(id) });
816
862
  output(transformComponent(result));
817
863
  });
818
864
  }
819
865
 
820
866
  // src/commands/component/issue-count.ts
821
867
  function issueCount(parent) {
822
- const cmd = parent.command("issue-count <id>").description("Get the number of issues currently using this component");
868
+ const cmd = parent.command("issue-count").description("Get the number of issues currently using this component").argument("<id>", "Component ID", positiveInt);
823
869
  examples(cmd, ["11289"]);
824
870
  cmd.action(async (id) => {
825
871
  const client = getClient();
826
- const result = await client.components.getRelatedIssueCounts({ id });
872
+ const result = await client.components.getRelatedIssueCounts({ id: String(id) });
827
873
  output(transformComponentIssueCounts(result));
828
874
  });
829
875
  }
830
876
 
831
877
  // src/commands/component/list.ts
832
878
  function list2(parent) {
833
- const cmd = parent.command("list").description("List all components for a project").requiredOption("--project <key>", "Project key (e.g., AI)");
879
+ const cmd = parent.command("list").description("List all components for a project").requiredOption("--project <key>", "Project key (e.g., AI)", text);
834
880
  examples(cmd, ["--project AI"]);
835
881
  cmd.action(async (opts) => {
836
882
  const client = getClient();
@@ -848,7 +894,7 @@ var ASSIGNEE_TYPES2 = [
848
894
  "UNASSIGNED"
849
895
  ];
850
896
  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));
897
+ 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
898
  textOrFileOption(cmd, "description", { description: "New component description" });
853
899
  examples(cmd, [
854
900
  "11289 --name Backend",
@@ -863,7 +909,7 @@ function update(parent) {
863
909
  }
864
910
  const client = getClient();
865
911
  const result = await client.components.update({
866
- id,
912
+ id: String(id),
867
913
  name: opts.name,
868
914
  description,
869
915
  leadUserName: opts.lead,
@@ -895,7 +941,7 @@ function registerComponentCommands(program) {
895
941
 
896
942
  // src/commands/field/options.ts
897
943
  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);
944
+ 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
945
  examples(cmd, ["10001", '10001 --query "High"', "10001 --limit 20 --start 2"]);
900
946
  cmd.action(async (id, opts) => {
901
947
  const client = getClient();
@@ -911,7 +957,7 @@ function options(parent) {
911
957
 
912
958
  // src/commands/field/search.ts
913
959
  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);
960
+ 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
961
  examples(cmd, ["epic", "customfield_10100", "priority --limit 5"]);
916
962
  cmd.action(async (keyword, opts) => {
917
963
  const client = getClient();
@@ -944,9 +990,18 @@ async function resolveUserToken(token) {
944
990
  return token;
945
991
  }
946
992
 
993
+ // src/utils/validators.ts
994
+ import { InvalidArgumentError as InvalidArgumentError4 } from "commander";
995
+ function issueKey(raw) {
996
+ if (!/^(\d+|[A-Z][A-Z0-9]+-\d+)$/.test(raw)) {
997
+ throw new InvalidArgumentError4("Must be a Jira issue key (e.g. PROJ-123) or a numeric issue id.");
998
+ }
999
+ return raw;
1000
+ }
1001
+
947
1002
  // src/commands/issue/assign.ts
948
1003
  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');
1004
+ 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
1005
  examples(cmd, ["PROJ-123 --assignee jsmith", "PROJ-123 --assignee me", "PROJ-123 --assignee none"]);
951
1006
  cmd.action(async (key, opts) => {
952
1007
  const resolved = await resolveUserToken(opts.assignee);
@@ -961,7 +1016,7 @@ function assign(parent) {
961
1016
 
962
1017
  // src/commands/issue/attachment/delete.ts
963
1018
  function deleteAttachment(parent) {
964
- const cmd = parent.command("delete <key>").description("Delete an attachment by ID");
1019
+ const cmd = parent.command("delete").description("Delete an attachment by ID").argument("<key>", "Issue key", issueKey);
965
1020
  subEntityOption(cmd, "attachment", { mandatory: true });
966
1021
  examples(cmd, ["PROJ-123 --attachment-id 12345"]);
967
1022
  cmd.action(async (key, opts) => {
@@ -975,7 +1030,7 @@ function deleteAttachment(parent) {
975
1030
  import { mkdirSync as mkdirSync2 } from "fs";
976
1031
  import { join as join3 } from "path";
977
1032
  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");
1033
+ 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
1034
  examples(cmd, ["PROJ-123 --output ./downloads"]);
980
1035
  cmd.action(async (key, opts) => {
981
1036
  const client = getClient();
@@ -1016,9 +1071,9 @@ function downloadAll(parent) {
1016
1071
 
1017
1072
  // src/commands/issue/attachment/download.ts
1018
1073
  function download(parent) {
1019
- const cmd = parent.command("download <key>").description("Download a single attachment by ID");
1074
+ const cmd = parent.command("download").description("Download a single attachment by ID").argument("<key>", "Issue key", issueKey);
1020
1075
  subEntityOption(cmd, "attachment", { mandatory: true });
1021
- cmd.requiredOption("--output <path>", "Local file path to save the attachment");
1076
+ cmd.requiredOption("--output <path>", "Local file path to save the attachment", text);
1022
1077
  examples(cmd, ["PROJ-123 --attachment-id 12345 --output ./report.pdf"]);
1023
1078
  cmd.action(async (key, opts) => {
1024
1079
  const client = getClient();
@@ -1043,7 +1098,7 @@ function download(parent) {
1043
1098
 
1044
1099
  // src/commands/issue/attachment/list.ts
1045
1100
  function list3(parent) {
1046
- const cmd = parent.command("list <key>").description("List attachments on an issue");
1101
+ const cmd = parent.command("list").description("List attachments on an issue").argument("<key>", "Issue key", issueKey);
1047
1102
  examples(cmd, ["PROJ-123"]);
1048
1103
  cmd.action(async (key) => {
1049
1104
  const client = getClient();
@@ -1068,7 +1123,7 @@ function list3(parent) {
1068
1123
 
1069
1124
  // src/commands/issue/attachment/upload.ts
1070
1125
  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");
1126
+ 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
1127
  examples(cmd, ["PROJ-123 --files ./report.pdf", "PROJ-123 --files ./a.txt,./b.png"]);
1073
1128
  cmd.action(async (key, opts) => {
1074
1129
  const client = getClient();
@@ -1111,7 +1166,7 @@ function registerAttachmentCommands(parent) {
1111
1166
 
1112
1167
  // src/commands/issue/batch-changelog.ts
1113
1168
  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);
1169
+ 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
1170
  examples(cmd, ["PROJ-1,PROJ-2,PROJ-3", "PROJ-123,PROJ-124 --limit 10"]);
1116
1171
  cmd.action(async (keys, opts) => {
1117
1172
  const client = getClient();
@@ -1131,14 +1186,16 @@ function batchChangelog(parent) {
1131
1186
  }
1132
1187
 
1133
1188
  // src/commands/issue/batch-create.ts
1189
+ import { z } from "zod";
1190
+ var issuesSchema = z.array(z.record(z.unknown())).min(1, "must be a non-empty array");
1134
1191
  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");
1192
+ 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
1193
  examples(cmd, [
1137
1194
  `--issues '[{"projectKeyOrId":"PROJ","issueTypeName":"Task","summary":"Task 1"},{"projectKeyOrId":"PROJ","issueTypeName":"Task","summary":"Task 2"}]'`
1138
1195
  ]);
1139
1196
  cmd.action(async (opts) => {
1140
1197
  const client = getClient();
1141
- const parsed = JSON.parse(opts.issues);
1198
+ const parsed = opts.issues;
1142
1199
  const results = [];
1143
1200
  for (const issue of parsed) {
1144
1201
  try {
@@ -1154,7 +1211,7 @@ function batchCreate(parent) {
1154
1211
 
1155
1212
  // src/commands/issue/changelog.ts
1156
1213
  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);
1214
+ 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
1215
  examples(cmd, ["PROJ-123", "PROJ-123 --limit 10"]);
1159
1216
  cmd.action(async (key, opts) => {
1160
1217
  const client = getClient();
@@ -1182,7 +1239,7 @@ var CLONE_FIELDS = [
1182
1239
  "issuelinks"
1183
1240
  ];
1184
1241
  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");
1242
+ 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
1243
  examples(cmd, [
1187
1244
  "PROJ-123",
1188
1245
  'PROJ-123 --summary "Cloned: new title"',
@@ -1259,7 +1316,7 @@ function clone(parent) {
1259
1316
 
1260
1317
  // src/commands/issue/comment/create.ts
1261
1318
  function create2(parent) {
1262
- const cmd = parent.command("create <key>").description("Add a comment to an issue");
1319
+ const cmd = parent.command("create").description("Add a comment to an issue").argument("<key>", "Issue key", issueKey);
1263
1320
  bodyOption(cmd);
1264
1321
  examples(cmd, ['PROJ-123 --body "Fixed in latest build"']);
1265
1322
  cmd.action(async (key, opts) => {
@@ -1272,7 +1329,7 @@ function create2(parent) {
1272
1329
 
1273
1330
  // src/commands/issue/comment/delete.ts
1274
1331
  function deleteComment(parent) {
1275
- const cmd = parent.command("delete <key>").description("Delete a comment from an issue");
1332
+ const cmd = parent.command("delete").description("Delete a comment from an issue").argument("<key>", "Issue key", issueKey);
1276
1333
  subEntityOption(cmd, "comment", { mandatory: true });
1277
1334
  examples(cmd, ["PROJ-123 --comment-id 12345"]);
1278
1335
  cmd.action(async (key, opts) => {
@@ -1284,7 +1341,7 @@ function deleteComment(parent) {
1284
1341
 
1285
1342
  // src/commands/issue/comment/update.ts
1286
1343
  function update2(parent) {
1287
- const cmd = parent.command("update <key>").description("Update an existing comment");
1344
+ const cmd = parent.command("update").description("Update an existing comment").argument("<key>", "Issue key", issueKey);
1288
1345
  subEntityOption(cmd, "comment", { mandatory: true });
1289
1346
  bodyOption(cmd);
1290
1347
  examples(cmd, ['PROJ-123 --comment-id 12345 --body "Updated comment text"']);
@@ -1314,8 +1371,14 @@ function registerCommentCommands(parent) {
1314
1371
  }
1315
1372
 
1316
1373
  // src/commands/issue/create.ts
1374
+ import { z as z2 } from "zod";
1375
+ var customFieldsSchema = z2.record(z2.unknown());
1317
1376
  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"}')`);
1377
+ 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(
1378
+ "--custom-fields <json>",
1379
+ `Additional custom fields as JSON (e.g., '{"customfield_10100": "EPIC-1"}')`,
1380
+ jsonShape(customFieldsSchema)
1381
+ );
1319
1382
  textOrFileOption(cmd, "description", { description: "Issue description in wiki markup" });
1320
1383
  examples(cmd, [
1321
1384
  '--project PROJ --type Task --summary "Fix login bug"',
@@ -1341,7 +1404,7 @@ function create3(parent) {
1341
1404
  fixVersions: opts.fixVersions?.split(",").map((v) => v.trim()),
1342
1405
  dueDate: opts.dueDate,
1343
1406
  parent: opts.parent,
1344
- customFields: opts.customFields ? JSON.parse(opts.customFields) : void 0
1407
+ customFields: opts.customFields
1345
1408
  });
1346
1409
  output(transformCreatedIssue(result));
1347
1410
  }
@@ -1350,7 +1413,7 @@ function create3(parent) {
1350
1413
 
1351
1414
  // src/commands/issue/delete.ts
1352
1415
  function deleteIssue(parent) {
1353
- const cmd = parent.command("delete <key>").description("Delete an issue").option("--delete-subtasks", "Also delete subtasks (default: false)");
1416
+ const cmd = parent.command("delete").description("Delete an issue").argument("<key>", "Issue key", issueKey).option("--delete-subtasks", "Also delete subtasks (default: false)");
1354
1417
  examples(cmd, ["PROJ-123", "PROJ-123 --delete-subtasks"]);
1355
1418
  cmd.action(async (key, opts) => {
1356
1419
  const client = getClient();
@@ -1361,7 +1424,7 @@ function deleteIssue(parent) {
1361
1424
 
1362
1425
  // src/commands/issue/dev-status.ts
1363
1426
  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");
1427
+ 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
1428
  examples(cmd, ["PROJ-123", "PROJ-123 --detail"]);
1366
1429
  cmd.action(async (key, opts) => {
1367
1430
  const client = getClient();
@@ -1455,7 +1518,7 @@ var DEFAULT_FIELDS = [
1455
1518
 
1456
1519
  // src/commands/issue/get.ts
1457
1520
  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")');
1521
+ 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
1522
  examples(cmd, [
1460
1523
  "PROJ-123",
1461
1524
  "PROJ-123 --fields summary,status,assignee",
@@ -1476,7 +1539,7 @@ function get2(parent) {
1476
1539
 
1477
1540
  // src/commands/issue/link-epic.ts
1478
1541
  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");
1542
+ const cmd = parent.command("link-epic").description("Link one or more issues to an epic").argument("<keys...>", "Issue keys to link", listOf(issueKey)).requiredOption("--epic <epicKey>", "Epic issue key", issueKey);
1480
1543
  examples(cmd, ["PROJ-456 --epic PROJ-123", "PROJ-456 PROJ-457 PROJ-458 --epic PROJ-123"]);
1481
1544
  cmd.action(async (keys, opts) => {
1482
1545
  const client = getClient();
@@ -1519,7 +1582,7 @@ function linkTypes(parent) {
1519
1582
 
1520
1583
  // src/commands/issue/link.ts
1521
1584
  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")');
1585
+ 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
1586
  commentOption(cmd, { description: "Optional comment" });
1524
1587
  examples(cmd, [
1525
1588
  "--type Relates --from AI-154 --to AI-149",
@@ -1545,7 +1608,7 @@ function link(parent) {
1545
1608
 
1546
1609
  // src/commands/issue/search.ts
1547
1610
  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");
1611
+ 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
1612
  examples(cmd, [
1550
1613
  '"project = PROJ AND status = Open"',
1551
1614
  '"assignee = currentUser()" --limit 10 --fields summary,status',
@@ -1566,7 +1629,7 @@ function search2(parent) {
1566
1629
 
1567
1630
  // src/commands/issue/transition.ts
1568
1631
  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)");
1632
+ 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
1633
  commentOption(cmd, { description: "Comment to add during transition" });
1571
1634
  examples(cmd, [
1572
1635
  "PROJ-123 --to 31",
@@ -1604,7 +1667,7 @@ function transition(parent) {
1604
1667
 
1605
1668
  // src/commands/issue/transitions.ts
1606
1669
  function transitions(parent) {
1607
- const cmd = parent.command("transitions <key>").description("Get available transitions for an issue");
1670
+ const cmd = parent.command("transitions").description("Get available transitions for an issue").argument("<key>", "Issue key", issueKey);
1608
1671
  examples(cmd, ["PROJ-123"]);
1609
1672
  cmd.action(async (key) => {
1610
1673
  const client = getClient();
@@ -1618,30 +1681,33 @@ function transitions(parent) {
1618
1681
 
1619
1682
  // src/commands/issue/unlink.ts
1620
1683
  function unlink2(parent) {
1621
- const cmd = parent.command("unlink <id>").description("Remove a link between two issues");
1684
+ const cmd = parent.command("unlink").description("Remove a link between two issues").argument("<id>", "Link ID", positiveInt);
1622
1685
  examples(cmd, ["12345"]);
1623
1686
  cmd.action(async (id) => {
1624
1687
  const client = getClient();
1625
- await client.links.remove({ linkId: id });
1688
+ await client.links.remove({ linkId: String(id) });
1626
1689
  output({ removed: true, linkId: id });
1627
1690
  });
1628
1691
  }
1629
1692
 
1693
+ // src/commands/issue/update.ts
1694
+ import { z as z3 } from "zod";
1695
+
1630
1696
  // src/utils/multi-value.ts
1631
- import { InvalidArgumentError as InvalidArgumentError3 } from "commander";
1697
+ import { InvalidArgumentError as InvalidArgumentError5 } from "commander";
1632
1698
  function parseMultiValue(flagName, raw) {
1633
1699
  const items = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
1634
1700
  if (items.length === 0) {
1635
- throw new InvalidArgumentError3(`${flagName} cannot be empty`);
1701
+ throw new InvalidArgumentError5(`${flagName} cannot be empty`);
1636
1702
  }
1637
1703
  const lonePrefix = items.find((s) => s === "+" || s === "-");
1638
1704
  if (lonePrefix !== void 0) {
1639
- throw new InvalidArgumentError3(`${flagName} has an empty value after '${lonePrefix}' prefix`);
1705
+ throw new InvalidArgumentError5(`${flagName} has an empty value after '${lonePrefix}' prefix`);
1640
1706
  }
1641
1707
  const prefixed = items.filter((s) => s.startsWith("+") || s.startsWith("-"));
1642
1708
  const bare = items.filter((s) => !s.startsWith("+") && !s.startsWith("-"));
1643
1709
  if (prefixed.length > 0 && bare.length > 0) {
1644
- throw new InvalidArgumentError3(
1710
+ throw new InvalidArgumentError5(
1645
1711
  `${flagName} mixes set and mutate syntax. Either all values have +/- prefix, or none do.`
1646
1712
  );
1647
1713
  }
@@ -1654,6 +1720,7 @@ function parseMultiValue(flagName, raw) {
1654
1720
  }
1655
1721
 
1656
1722
  // src/commands/issue/update.ts
1723
+ var fieldsSchema = z3.record(z3.unknown());
1657
1724
  function buildUpdateOps(parsed, wrap) {
1658
1725
  if (parsed.mode !== "mutate") return void 0;
1659
1726
  return [...parsed.adds.map((v) => ({ add: wrap(v) })), ...parsed.removes.map((v) => ({ remove: wrap(v) }))];
@@ -1663,7 +1730,11 @@ function buildSetValue(parsed, wrap) {
1663
1730
  return parsed.values.map(wrap);
1664
1731
  }
1665
1732
  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")');
1733
+ const cmd = parent.command("update").description("Update issue fields").argument("<key>", "Issue key", issueKey).option(
1734
+ "--fields <json>",
1735
+ "JSON string of fields to update (advanced; merges with shortcuts, wins on conflict)",
1736
+ jsonShape(fieldsSchema)
1737
+ ).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
1738
  textOrFileOption(cmd, "description", { description: "Set the issue description (wiki markup)" });
1668
1739
  examples(cmd, [
1669
1740
  'PROJ-123 --summary "New title"',
@@ -1712,8 +1783,7 @@ function update3(parent) {
1712
1783
  if (ops) updateOps.fixVersions = ops;
1713
1784
  }
1714
1785
  if (opts.fields) {
1715
- const parsedFields = JSON.parse(opts.fields);
1716
- Object.assign(fields, parsedFields);
1786
+ Object.assign(fields, opts.fields);
1717
1787
  }
1718
1788
  const client = getClient();
1719
1789
  const didFieldUpdate = Object.keys(fields).length > 0 || Object.keys(updateOps).length > 0;
@@ -1745,7 +1815,7 @@ function update3(parent) {
1745
1815
 
1746
1816
  // src/commands/issue/worklog/create.ts
1747
1817
  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");
1818
+ 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
1819
  commentOption(cmd, { description: "Worklog comment" });
1750
1820
  examples(cmd, [
1751
1821
  "PROJ-123 --time 2h",
@@ -1769,11 +1839,12 @@ function create4(parent) {
1769
1839
  import { Option as Option5 } from "commander";
1770
1840
  var ADJUST_ESTIMATE = ["new", "leave", "manual", "auto"];
1771
1841
  function deleteWorklog(parent) {
1772
- const cmd = parent.command("delete <key>").description("Delete a worklog entry");
1842
+ const cmd = parent.command("delete").description("Delete a worklog entry").argument("<key>", "Issue key", issueKey);
1773
1843
  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(
1844
+ 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
1845
  "--increase-by <amount>",
1776
- 'Amount to increase the estimate by; required when --adjust-estimate is "manual"'
1846
+ 'Amount to increase the estimate by; required when --adjust-estimate is "manual"',
1847
+ text
1777
1848
  );
1778
1849
  examples(cmd, [
1779
1850
  "PROJ-123 --worklog-id 12345",
@@ -1797,7 +1868,7 @@ function deleteWorklog(parent) {
1797
1868
 
1798
1869
  // src/commands/issue/worklog/list.ts
1799
1870
  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);
1871
+ 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
1872
  examples(cmd, ["PROJ-123", "PROJ-123 --limit 10", "PROJ-123 --start 10 --limit 5"]);
1802
1873
  cmd.action(async (key, opts) => {
1803
1874
  const client = getClient();
@@ -1814,9 +1885,9 @@ function list4(parent) {
1814
1885
  import { Option as Option6 } from "commander";
1815
1886
  var ADJUST_ESTIMATE2 = ["new", "leave", "auto"];
1816
1887
  function update4(parent) {
1817
- const cmd = parent.command("update <key>").description("Update an existing worklog entry");
1888
+ const cmd = parent.command("update").description("Update an existing worklog entry").argument("<key>", "Issue key", issueKey);
1818
1889
  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"');
1890
+ 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
1891
  commentOption(cmd, { description: "Worklog comment" });
1821
1892
  examples(cmd, [
1822
1893
  'PROJ-123 --worklog-id 12345 --time "1h 30m"',
@@ -1891,7 +1962,7 @@ function registerIssueCommands(program) {
1891
1962
 
1892
1963
  // src/commands/project/list.ts
1893
1964
  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)");
1965
+ 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
1966
  examples(cmd, ["", "--expand description,lead", "--include-archived"]);
1896
1967
  cmd.action(async (opts) => {
1897
1968
  const client = getClient();
@@ -1902,7 +1973,7 @@ function list5(parent) {
1902
1973
 
1903
1974
  // src/commands/project/versions.ts
1904
1975
  function versions(parent) {
1905
- const cmd = parent.command("versions <key>").description("Get all versions for a project").option("--expand <expand>", "Expand options");
1976
+ const cmd = parent.command("versions").description("Get all versions for a project").argument("<key>", "Project key", text).option("--expand <expand>", "Expand options", text);
1906
1977
  examples(cmd, ["PROJ", "PROJ --expand operations"]);
1907
1978
  cmd.action(async (key, opts) => {
1908
1979
  const client = getClient();
@@ -1921,7 +1992,7 @@ function registerProjectCommands(program) {
1921
1992
 
1922
1993
  // src/commands/sprint/create.ts
1923
1994
  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");
1995
+ 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
1996
  examples(cmd, [
1926
1997
  '--board 42 --name "Sprint 10"',
1927
1998
  '--board 42 --name "Sprint 10" --start-date 2026-03-20 --end-date 2026-04-03 --goal "Complete auth module"'
@@ -1954,7 +2025,7 @@ function deleteSprint(parent) {
1954
2025
  // src/commands/sprint/issues.ts
1955
2026
  import { Argument as Argument3 } from "commander";
1956
2027
  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");
2028
+ 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
2029
  examples(cmd, [
1959
2030
  "100",
1960
2031
  "100 --limit 20",
@@ -1994,7 +2065,7 @@ function list6(parent) {
1994
2065
  import { Argument as Argument4, Option as Option8 } from "commander";
1995
2066
  var SPRINT_STATES2 = ["future", "active", "closed"];
1996
2067
  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");
2068
+ 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
2069
  examples(cmd, [
1999
2070
  '100 --name "Sprint 10 - Extended"',
2000
2071
  "100 --state active",
@@ -2052,13 +2123,14 @@ function getTokenClient(options2 = {}) {
2052
2123
 
2053
2124
  // src/commands/token/create.ts
2054
2125
  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(
2126
+ 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
2127
  "--expiration-duration <days>",
2057
2128
  "Token lifetime in days. Omit for a non-expiring token (admin policy permitting).",
2058
2129
  positiveInt
2059
- ).option("--basic-username <u>", "Override $JIRA_BASIC_USERNAME").option(
2130
+ ).option("--basic-username <u>", "Override $JIRA_BASIC_USERNAME", text).option(
2060
2131
  "--basic-password <p>",
2061
- "Override $JIRA_BASIC_PASSWORD (caution: visible in process table; prefer the env var)"
2132
+ "Override $JIRA_BASIC_PASSWORD (caution: visible in process table; prefer the env var)",
2133
+ text
2062
2134
  );
2063
2135
  examples(cmd, [["--name my-pat", "non-expiring"], "--name svc-token --expiration-duration 365"]);
2064
2136
  cmd.action(async (opts) => {
@@ -2078,9 +2150,10 @@ function create6(parent) {
2078
2150
 
2079
2151
  // src/commands/token/list.ts
2080
2152
  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(
2153
+ 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
2154
  "--basic-password <p>",
2083
- "Override $JIRA_BASIC_PASSWORD (caution: visible in process table; prefer the env var)"
2155
+ "Override $JIRA_BASIC_PASSWORD (caution: visible in process table; prefer the env var)",
2156
+ text
2084
2157
  );
2085
2158
  examples(cmd, [""]);
2086
2159
  cmd.action(async (opts) => {
@@ -2094,9 +2167,10 @@ function list7(parent) {
2094
2167
 
2095
2168
  // src/commands/token/revoke.ts
2096
2169
  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(
2170
+ const cmd = parent.command("revoke").description("Revoke a Personal Access Token by id").option("--basic-username <u>", "Override $JIRA_BASIC_USERNAME", text).option(
2098
2171
  "--basic-password <p>",
2099
- "Override $JIRA_BASIC_PASSWORD (caution: visible in process table; prefer the env var)"
2172
+ "Override $JIRA_BASIC_PASSWORD (caution: visible in process table; prefer the env var)",
2173
+ text
2100
2174
  );
2101
2175
  subjectArg(cmd, "tokenId", { parser: positiveInt, description: "Token id to revoke" });
2102
2176
  examples(cmd, ["173"]);
@@ -2125,7 +2199,7 @@ function registerTokenCommands(program) {
2125
2199
 
2126
2200
  // src/commands/user/get.ts
2127
2201
  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");
2202
+ 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
2203
  examples(cmd, ["jsmith", "JIRAUSER10100 --by-key"]);
2130
2204
  cmd.action(async (identifier, opts) => {
2131
2205
  const client = getClient();
@@ -2147,7 +2221,7 @@ function me(parent) {
2147
2221
 
2148
2222
  // src/commands/user/search.ts
2149
2223
  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);
2224
+ 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
2225
  examples(cmd, ["Smith", '"John Smith"', "jsmith@example.com --limit 5"]);
2152
2226
  cmd.action(async (query, opts) => {
2153
2227
  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-g6336787.1",
4
4
  "publish": true,
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -12,7 +12,8 @@
12
12
  ],
13
13
  "dependencies": {
14
14
  "commander": "^13.1.0",
15
- "jira-data-center-client": "1.0.39"
15
+ "zod": "^3.25.67",
16
+ "jira-data-center-client": "1.0.39-g6336787.1"
16
17
  },
17
18
  "devDependencies": {
18
19
  "@types/node": "24.10.4",
@@ -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": {