jira-pilot 2.1.3 → 2.2.0

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.
@@ -14,6 +14,7 @@ import { registerWorklogCommand } from './issue-worklog.js';
14
14
  import { registerPrCommand } from './issue-pr.js';
15
15
  import { registerAttachCommand } from './issue-attach.js';
16
16
  import { ConfigService } from '../services/config-service.js';
17
+ import { API } from '../utils/api-paths.js';
17
18
 
18
19
  export function registerIssueCommand(program: Command) {
19
20
  const issueCmd = new Command('issue')
@@ -68,23 +69,19 @@ Examples:
68
69
  if (options.jql) jqlParts.push(options.jql);
69
70
 
70
71
  // Order by updated desc by default if no JQL
71
- if (!options.jql && jqlParts.length === 0) {
72
- jqlParts.push('order by updated DESC');
73
- } else if (jqlParts.length > 0 && !options.jql) {
74
- // Add order if not custom jql
75
- // jqlParts.push('order by updated DESC');
76
- }
77
-
78
72
  const jql = jqlParts.join(' AND ');
79
73
 
80
- const searchApi = '/search/jql';
74
+ // Default to last 30 days if no filter provided to satisfy "unbounded" check
75
+ const defaultJql = 'updated >= -30d ORDER BY updated DESC';
76
+ const finalJql = jql || defaultJql;
77
+
81
78
  const body = {
82
- jql: jql || 'created is not empty',
79
+ jql: finalJql,
83
80
  maxResults: parseInt(options.limit),
84
- fields: ['summary', 'status', 'assignee', 'created', 'updated', 'description']
81
+ fields: ['summary', 'status', 'assignee', 'created', 'updated', 'description', 'priority', 'issuetype', 'project', 'reporter']
85
82
  };
86
83
 
87
- const data = await api.post(searchApi, body);
84
+ const data = await api.post(API.SEARCH.JQL, body);
88
85
  spinner.stop();
89
86
 
90
87
  if (!data.issues || data.issues.length === 0) {
@@ -177,7 +174,7 @@ Examples:
177
174
  if (!check.valid) { console.error(chalk.red(check.message)); return; }
178
175
  const spinner = ora(`Fetching issue ${issueKey}...`).start();
179
176
  try {
180
- const issue = await api.get(`/issue/${issueKey}`);
177
+ const issue = await api.get(API.ISSUE.GET(issueKey));
181
178
  spinner.stop();
182
179
 
183
180
  if (options.output === 'json') {
@@ -260,7 +257,7 @@ Examples:
260
257
  let projectKey = options.project;
261
258
  if (!projectKey) {
262
259
  const spinner = ora('Fetching projects...').start();
263
- const projectData = await api.get('/project/search');
260
+ const projectData = await api.get(API.PROJECT.SEARCH);
264
261
  spinner.stop();
265
262
 
266
263
  if (!projectData.values || projectData.values.length === 0) {
@@ -289,12 +286,12 @@ Examples:
289
286
  let issueTypes = [];
290
287
  try {
291
288
  // Jira Cloud v3 - createmeta endpoint
292
- const metaData = await api.get(`/issue/createmeta/${projectKey}/issuetypes`);
289
+ const metaData = await api.get(API.ISSUE.CREATEMETA(projectKey));
293
290
  issueTypes = metaData.issueTypes || metaData.values || [];
294
291
  } catch (metaErr) {
295
292
  // Fallback: use project-level issue types
296
293
  try {
297
- const projectInfo = await api.get(`/project/${projectKey}`);
294
+ const projectInfo = await api.get(API.PROJECT.GET(projectKey));
298
295
  issueTypes = projectInfo.issueTypes || [];
299
296
  } catch {
300
297
  issueTypes = [
@@ -354,7 +351,7 @@ Examples:
354
351
  if (!priorityName && !options.noInput) {
355
352
  const spinner = ora('Fetching priorities...').start();
356
353
  try {
357
- const priorities = await api.get('/priority');
354
+ const priorities = await api.get(API.PRIORITY.ALL);
358
355
  spinner.stop();
359
356
 
360
357
  if (Array.isArray(priorities) && priorities.length > 0) {
@@ -383,7 +380,7 @@ Examples:
383
380
  if (componentIds.length === 0 && !options.noInput) {
384
381
  const compSpinner = ora('Fetching components...').start();
385
382
  try {
386
- const components = await api.get(`/project/${projectKey}/components`);
383
+ const components = await api.get(API.PROJECT.COMPONENTS(projectKey));
387
384
  compSpinner.stop();
388
385
 
389
386
  if (Array.isArray(components) && components.length > 0) {
@@ -424,7 +421,7 @@ Examples:
424
421
  if (fixVersionIds.length === 0 && !options.noInput) {
425
422
  const verSpinner = ora('Fetching versions...').start();
426
423
  try {
427
- const versions = await api.get(`/project/${projectKey}/versions`);
424
+ const versions = await api.get(API.PROJECT.VERSIONS(projectKey));
428
425
  verSpinner.stop();
429
426
 
430
427
  // Filter unreleased versions usually
@@ -477,7 +474,7 @@ Examples:
477
474
  if (assigneeChoice === 'me') {
478
475
  const spinner = ora('Fetching your account...').start();
479
476
  try {
480
- const myself = await api.get('/myself');
477
+ const myself = await api.get(API.USER.MYSELF);
481
478
  assigneeId = myself.accountId;
482
479
  spinner.stop();
483
480
  } catch {
@@ -494,7 +491,7 @@ Examples:
494
491
  if (searchQuery.trim()) {
495
492
  const spinner = ora('Searching users...').start();
496
493
  try {
497
- const users = await api.get(`/user/search?query=${encodeURIComponent(searchQuery)}`);
494
+ const users = await api.get(`${API.USER.SEARCH}?query=${encodeURIComponent(searchQuery)}`);
498
495
  spinner.stop();
499
496
 
500
497
  if (Array.isArray(users) && users.length > 0) {
@@ -526,7 +523,7 @@ Examples:
526
523
  // --assignee me flag: resolve to account ID
527
524
  const spinner = ora('Fetching your account...').start();
528
525
  try {
529
- const myself = await api.get('/myself');
526
+ const myself = await api.get(API.USER.MYSELF);
530
527
  assigneeId = myself.accountId;
531
528
  spinner.stop();
532
529
  } catch {
@@ -611,7 +608,7 @@ Examples:
611
608
 
612
609
  // ── Create Issue ────────────────────────────────────
613
610
  const spinner = ora('Creating issue...').start();
614
- const result = await api.post('/issue', issueBody);
611
+ const result = await api.post(API.ISSUE.BASE, issueBody);
615
612
  spinner.succeed(chalk.green(`Issue created: ${chalk.bold(result.key)}`));
616
613
 
617
614
  console.log(chalk.grey(`View it: jira issue view ${result.key}`));
@@ -639,11 +636,11 @@ Examples:
639
636
  const spinner = ora(`Fetching transitions for ${issueKey}...`).start();
640
637
  try {
641
638
  // Fetch current issue to show context
642
- const issue = await api.get(`/issue/${issueKey}?fields=summary,status`);
639
+ const issue = await api.get(`${API.ISSUE.GET(issueKey)}?fields=summary,status`);
643
640
  const currentStatus = issue.fields.status.name;
644
641
 
645
642
  // Fetch available transitions
646
- const transData = await api.get(`/issue/${issueKey}/transitions`);
643
+ const transData = await api.get(API.ISSUE.TRANSITIONS(issueKey));
647
644
  spinner.stop();
648
645
 
649
646
  if (!transData.transitions || transData.transitions.length === 0) {
@@ -690,7 +687,7 @@ Examples:
690
687
 
691
688
  // Execute transition
692
689
  const execSpinner = ora(`Transitioning to "${targetTransition.to.name}"...`).start();
693
- await api.post(`/issue/${issueKey}/transitions`, {
690
+ await api.post(API.ISSUE.TRANSITIONS(issueKey), {
694
691
  transition: { id: targetTransition.id }
695
692
  });
696
693
  execSpinner.succeed(chalk.green(`${issueKey} transitioned: ${currentStatus} → ${chalk.bold(targetTransition.to.name)}`));
@@ -721,7 +718,7 @@ Examples:
721
718
  if (!assigneeId) {
722
719
  // Interactive selection
723
720
  const spinner = ora(`Fetching issue ${issueKey}...`).start();
724
- const issue = await api.get(`/issue/${issueKey}?fields=summary,assignee`);
721
+ const issue = await api.get(`${API.ISSUE.GET(issueKey)}?fields=summary,assignee`);
725
722
  spinner.stop();
726
723
 
727
724
  const currentAssignee = issue.fields.assignee?.displayName || 'Unassigned';
@@ -743,7 +740,7 @@ Examples:
743
740
 
744
741
  if (assigneeId === 'me') {
745
742
  const spinner = ora('Fetching your account...').start();
746
- const myself = await api.get('/myself');
743
+ const myself = await api.get(API.USER.MYSELF);
747
744
  assigneeId = myself.accountId;
748
745
  spinner.stop();
749
746
  }
@@ -756,7 +753,7 @@ Examples:
756
753
  }) as any;
757
754
 
758
755
  const spinner = ora('Searching users...').start();
759
- const users = await api.get(`/user/search?query=${encodeURIComponent(searchQuery)}`);
756
+ const users = await api.get(`${API.USER.SEARCH}?query=${encodeURIComponent(searchQuery)}`);
760
757
  spinner.stop();
761
758
 
762
759
  if (!Array.isArray(users) || users.length === 0) {
@@ -781,7 +778,7 @@ Examples:
781
778
  ? { accountId: null }
782
779
  : { accountId: assigneeId };
783
780
 
784
- await api.put(`/issue/${issueKey}/assignee`, body);
781
+ await api.put(API.ISSUE.ASSIGNEE(issueKey), body);
785
782
  spinner.succeed(chalk.green(`${issueKey} ${assigneeId === 'none' ? 'unassigned' : 'assigned'} successfully.`));
786
783
 
787
784
  } catch (e: any) {
@@ -826,7 +823,7 @@ Examples:
826
823
  }
827
824
 
828
825
  const spinner = ora('Adding comment...').start();
829
- await api.post(`/issue/${issueKey}/comment`, {
826
+ await api.post(API.ISSUE.COMMENT(issueKey), {
830
827
  body: textToADF(commentText)
831
828
  });
832
829
  spinner.succeed(chalk.green(`Comment added to ${issueKey}.`));
@@ -856,7 +853,7 @@ Examples:
856
853
  if (!check.valid) { console.error(chalk.red(check.message)); return; }
857
854
  const spinner = ora(`Fetching issue ${issueKey}...`).start();
858
855
  try {
859
- const issue = await api.get(`/issue/${issueKey}?fields=summary,description,priority`);
856
+ const issue = await api.get(`${API.ISSUE.GET(issueKey)}?fields=summary,description,priority`);
860
857
  spinner.stop();
861
858
 
862
859
  const updateBody: any = { fields: {} };
@@ -914,7 +911,7 @@ Examples:
914
911
  if (desc) updateBody.fields.description = textToADF(desc);
915
912
  }
916
913
  if (field === 'priority') {
917
- const priorities = await api.get('/priority');
914
+ const priorities = await api.get(API.PRIORITY.ALL);
918
915
  const prioSelect = new Select({
919
916
  name: 'priority',
920
917
  message: 'Select priority',
@@ -923,7 +920,7 @@ Examples:
923
920
  updateBody.fields.priority = { name: await prioSelect.run() };
924
921
  }
925
922
  if (field === 'components') {
926
- const components = await api.get(`/project/${issue.fields.project.key}/components`);
923
+ const components = await api.get(API.PROJECT.COMPONENTS(issue.fields.project.key));
927
924
  if (components.length > 0) {
928
925
  const compSelect = new Select({ // Using Enquirer directly via 'any' above, but actually Select is single select?
929
926
  // Wait, fieldSelect was initialized from enquirer as any.
@@ -959,7 +956,7 @@ Examples:
959
956
  updateBody.fields.labels = labelStr.split(',').map((l: string) => l.trim()).filter((l: string) => l.length > 0);
960
957
  }
961
958
  if (field === 'fixVersions') {
962
- const versions = await api.get(`/project/${issue.fields.project.key}/versions`);
959
+ const versions = await api.get(API.PROJECT.VERSIONS(issue.fields.project.key));
963
960
  const unreleased = versions.filter((v: any) => !v.released);
964
961
  if (unreleased.length > 0) {
965
962
  const { selectedVersions } = await enquirer.prompt({
@@ -989,7 +986,7 @@ Examples:
989
986
  }
990
987
 
991
988
  const updateSpinner = ora('Updating issue...').start();
992
- await api.put(`/issue/${issueKey}`, updateBody);
989
+ await api.put(API.ISSUE.GET(issueKey), updateBody);
993
990
  updateSpinner.succeed(`${chalk.cyan(issueKey)} updated successfully`);
994
991
 
995
992
  } catch (e: any) {
@@ -1018,7 +1015,7 @@ Examples:
1018
1015
  if (options.project) jqlParts.push(`project = "${options.project}"`);
1019
1016
  const jql = jqlParts.join(' AND ') + ' ORDER BY updated DESC';
1020
1017
 
1021
- const data = await api.post('/search/jql', {
1018
+ const data = await api.post(API.SEARCH.JQL, {
1022
1019
  jql,
1023
1020
  maxResults: parseInt(options.limit),
1024
1021
  fields: ['summary', 'status', 'assignee', 'updated']
@@ -1196,7 +1193,7 @@ Examples:
1196
1193
  } catch (err) {
1197
1194
  // Fallback to project fetch
1198
1195
  try {
1199
- const proj = await api.get(`/project/${projectKey}`);
1196
+ const proj = await api.get(API.PROJECT.GET(projectKey));
1200
1197
  subtaskTypes = (proj.issueTypes || []).filter((t: any) => t.subtask);
1201
1198
  } catch (e) {
1202
1199
  console.error(chalk.red('Failed to fetch project issue types.'));
@@ -1258,7 +1255,7 @@ Examples:
1258
1255
  }
1259
1256
 
1260
1257
  const createSpinner = ora('Creating subtask...').start();
1261
- const result = await api.post('/issue', issueBody);
1258
+ const result = await api.post(API.ISSUE.BASE, issueBody);
1262
1259
  createSpinner.succeed(chalk.green(`Subtask created: ${chalk.bold(result.key)}`));
1263
1260
 
1264
1261
  } catch (e: any) {