jira-pilot 2.0.2 → 2.0.3

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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Jira Pilot ✈️
2
2
 
3
- **The AI-Powered Jira CLI for Humans and Agents.**
3
+ **The AI-Powered Jira CLI and MCP Server for Humans and Agents.**
4
4
 
5
5
  `jira-pilot` is a next-generation CLI that combines traditional developer tools with modern AI capabilities.
6
6
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "jira-pilot",
3
- "version": "2.0.2",
4
- "description": "AI-powered Jira CLI for humans and agents — manage issues, sprints, boards with interactive wizards, multi-provider AI (OpenAI/Gemini/Anthropic), and an 8-tool MCP server for AI assistants",
3
+ "version": "2.0.3",
4
+ "description": "AI-powered Jira CLI and MCP server for humans and agents — manage issues, sprints, boards with interactive wizards, multi-provider AI (OpenAI/Gemini/Anthropic), and an 8-tool MCP server for AI assistants",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
7
7
  "bin": {
@@ -5,6 +5,7 @@ import { api } from '../../services/api-service.js';
5
5
  import { aiService } from '../../services/ai-service.js';
6
6
  import { validateIssueKey } from '../../utils/validators.js';
7
7
  import { parseADF } from '../../utils/adf-parser.js';
8
+ import { handleCommandError } from '../../utils/error-handler.js';
8
9
 
9
10
  export async function planAction(epicKey, options) {
10
11
  const check = validateIssueKey(epicKey);
@@ -113,7 +114,6 @@ export async function planAction(epicKey, options) {
113
114
  console.log(chalk.green(`\nDone! Created ${results.length} issues linked to ${epicKey}.`));
114
115
 
115
116
  } catch (e) {
116
- spinner.stop();
117
- console.error(chalk.red(`Error: ${e.message}`));
117
+ handleCommandError(spinner, e, `Failed to plan ${epicKey}`);
118
118
  }
119
119
  }
@@ -7,6 +7,7 @@ import { aiService } from '../../services/ai-service.js';
7
7
  import { validateIssueKey } from '../../utils/validators.js';
8
8
  import { getCredentials } from '../../utils/config.js';
9
9
  import { parseADF } from '../../utils/adf-parser.js';
10
+ import { handleCommandError } from '../../utils/error-handler.js';
10
11
 
11
12
  export async function reviewAction(issueKey, options) {
12
13
  const check = validateIssueKey(issueKey);
@@ -96,14 +97,6 @@ export async function reviewAction(issueKey, options) {
96
97
  console.log(chalk.dim(`\nPR Link: ${pr.html_url}`));
97
98
 
98
99
  } catch (e) {
99
- spinner.stop();
100
- if (e.response?.status === 404) {
101
- console.error(chalk.red(`Resource not found (Issue or Repo). Check permissions.`));
102
- } else if (e.response?.status === 401) {
103
- console.error(chalk.red(`GitHub/Jira Authentication failed. Check your tokens.`));
104
- } else {
105
- console.error(chalk.red(`Error: ${e.message}`));
106
- if (e.response?.data) console.error(chalk.dim(JSON.stringify(e.response.data)));
107
- }
100
+ handleCommandError(spinner, e, `Failed to review ${issueKey}`);
108
101
  }
109
102
  }
@@ -3,6 +3,7 @@ import ora from 'ora';
3
3
  import { api } from '../../services/api-service.js';
4
4
  import { aiService } from '../../services/ai-service.js';
5
5
  import { parseADF } from '../../utils/adf-parser.js';
6
+ import { handleCommandError } from '../../utils/error-handler.js';
6
7
 
7
8
  export async function standupAction(options) {
8
9
  const spinner = ora('Analyzing your recent activity...').start();
@@ -36,7 +37,6 @@ export async function standupAction(options) {
36
37
  console.log(report);
37
38
 
38
39
  } catch (e) {
39
- spinner.stop();
40
- console.error(chalk.red(`Error: ${e.message}`));
40
+ handleCommandError(spinner, e, 'Failed to generate standup');
41
41
  }
42
42
  }
@@ -6,6 +6,7 @@ import { api } from '../services/api-service.js';
6
6
  import { aiService } from '../services/ai-service.js';
7
7
  import { parseADF } from '../utils/adf-parser.js';
8
8
  import { validateIssueKey } from '../utils/validators.js';
9
+ import { handleCommandError } from '../utils/error-handler.js';
9
10
  import { reviewAction } from './ai-actions/review.js';
10
11
  import { planAction } from './ai-actions/plan.js';
11
12
  import { standupAction } from './ai-actions/standup.js';
@@ -60,17 +61,7 @@ Provide a concise summary of the current status, key discussion points, and next
60
61
  console.log(aiResponse);
61
62
 
62
63
  } catch (e) {
63
- spinner.stop();
64
- if (e.response && e.response.config && e.response.config.url.includes('/issue/')) {
65
- console.error(chalk.red(`\nError: Issue "${issueKey}" not found.`));
66
- } else {
67
- console.error(chalk.red('\nFailed to generate summary:'));
68
- if (e.response) {
69
- console.error(chalk.red(`API Error ${e.response.status}: `), e.response.data);
70
- } else {
71
- console.error(chalk.red(e.message));
72
- }
73
- }
64
+ handleCommandError(spinner, e, `Failed to summarize ${issueKey}`);
74
65
  }
75
66
  });
76
67
 
@@ -132,12 +123,7 @@ Keep it professional and concise. Output in plain text (not markdown headers, us
132
123
  console.log(chalk.grey('\nTip: Copy this into "jira issue create" or use it as a starting point.'));
133
124
 
134
125
  } catch (e) {
135
- if (e === '' || e.message === '') {
136
- console.log(chalk.yellow('\nCancelled.'));
137
- return;
138
- }
139
- console.error(chalk.red('\nFailed to generate draft:'));
140
- console.error(chalk.red(e.message));
126
+ handleCommandError(null, e, 'Failed to generate draft');
141
127
  }
142
128
  });
143
129
 
@@ -198,13 +184,7 @@ Keep suggestions actionable and concise.
198
184
  console.log(aiResponse);
199
185
 
200
186
  } catch (e) {
201
- spinner.stop();
202
- if (e.response && e.response.status === 404) {
203
- console.error(chalk.red(`\nError: Issue "${issueKey}" not found.`));
204
- } else {
205
- console.error(chalk.red('\nFailed to generate suggestions:'));
206
- console.error(chalk.red(e.message));
207
- }
187
+ handleCommandError(spinner, e, `Failed to suggest for ${issueKey}`);
208
188
  }
209
189
  });
210
190
 
@@ -5,6 +5,7 @@ import { api } from '../services/api-service.js';
5
5
  import ora from 'ora';
6
6
  import enquirer from 'enquirer';
7
7
  import { validateIssueKey } from '../utils/validators.js';
8
+ import { handleCommandError } from '../utils/error-handler.js';
8
9
 
9
10
  export function registerGitCommand(program) {
10
11
  const gitCmd = new Command('git')
@@ -50,12 +51,7 @@ export function registerGitCommand(program) {
50
51
  }
51
52
 
52
53
  } catch (e) {
53
- spinner.fail('Failed to fetch issue');
54
- if (e.response) {
55
- console.error(chalk.red(`Error ${e.response.status}: `), e.response.data);
56
- } else {
57
- console.error(chalk.red(e.message));
58
- }
54
+ handleCommandError(spinner, e, 'Failed to create branch');
59
55
  }
60
56
  });
61
57
 
@@ -146,12 +146,7 @@ Examples:
146
146
  console.log(table(tableData));
147
147
 
148
148
  } catch (e) {
149
- spinner.fail('Failed to list issues');
150
- if (e.response) {
151
- console.error(chalk.red(`Error ${e.response.status}: `), e.response.data);
152
- } else {
153
- console.error(chalk.red(e.message));
154
- }
149
+ handleCommandError(spinner, e, 'Failed to list issues');
155
150
  }
156
151
  });
157
152
 
@@ -202,16 +197,7 @@ Examples:
202
197
  }
203
198
  console.log('');
204
199
  } catch (e) {
205
- spinner.fail('Failed to fetch issue');
206
- if (e.response) {
207
- if (e.response.status === 404) {
208
- console.error(chalk.red(`Issue "${issueKey}" not found.`));
209
- } else {
210
- console.error(chalk.red(`Error ${e.response.status}: `), e.response.data);
211
- }
212
- } else {
213
- console.error(chalk.red(e.message));
214
- }
200
+ handleCommandError(spinner, e, 'Failed to fetch issue');
215
201
  }
216
202
  });
217
203
 
@@ -481,17 +467,7 @@ Examples:
481
467
  console.log(chalk.grey(`View it: jira issue view ${result.key}`));
482
468
 
483
469
  } catch (e) {
484
- if (e === '' || e.message === '') {
485
- // User cancelled prompt (Ctrl+C)
486
- console.log(chalk.yellow('\nCancelled.'));
487
- return;
488
- }
489
- console.error(chalk.red('\nFailed to create issue:'));
490
- if (e.response) {
491
- console.error(chalk.red(`Error ${e.response.status}: `), JSON.stringify(e.response.data, null, 2));
492
- } else {
493
- console.error(chalk.red(e.message));
494
- }
470
+ handleCommandError(spinner, e, 'Failed to create issue');
495
471
  }
496
472
  });
497
473
 
@@ -570,21 +546,7 @@ Examples:
570
546
  execSpinner.succeed(chalk.green(`${issueKey} transitioned: ${currentStatus} → ${chalk.bold(targetTransition.to.name)}`));
571
547
 
572
548
  } catch (e) {
573
- spinner.stop();
574
- if (e === '' || e.message === '') {
575
- console.log(chalk.yellow('\nCancelled.'));
576
- return;
577
- }
578
- console.error(chalk.red('\nFailed to transition issue:'));
579
- if (e.response) {
580
- if (e.response.status === 404) {
581
- console.error(chalk.red(`Issue "${issueKey}" not found.`));
582
- } else {
583
- console.error(chalk.red(`Error ${e.response.status}: `), e.response.data);
584
- }
585
- } else {
586
- console.error(chalk.red(e.message));
587
- }
549
+ handleCommandError(spinner, e, 'Failed to transition issue');
588
550
  }
589
551
  });
590
552
  // ── ASSIGN ────────────────────────────────────────────────────────
@@ -672,16 +634,7 @@ Examples:
672
634
  spinner.succeed(chalk.green(`${issueKey} ${assigneeId === 'none' ? 'unassigned' : 'assigned'} successfully.`));
673
635
 
674
636
  } catch (e) {
675
- if (e === '' || e.message === '') {
676
- console.log(chalk.yellow('\nCancelled.'));
677
- return;
678
- }
679
- console.error(chalk.red('\nFailed to assign issue:'));
680
- if (e.response) {
681
- console.error(chalk.red(`Error ${e.response.status}: `), e.response.data);
682
- } else {
683
- console.error(chalk.red(e.message));
684
- }
637
+ handleCommandError(spinner, e, 'Failed to assign issue');
685
638
  }
686
639
  });
687
640
 
@@ -727,20 +680,7 @@ Examples:
727
680
  spinner.succeed(chalk.green(`Comment added to ${issueKey}.`));
728
681
 
729
682
  } catch (e) {
730
- if (e === '' || e.message === '') {
731
- console.log(chalk.yellow('\nCancelled.'));
732
- return;
733
- }
734
- console.error(chalk.red('\nFailed to add comment:'));
735
- if (e.response) {
736
- if (e.response.status === 404) {
737
- console.error(chalk.red(`Issue "${issueKey}" not found.`));
738
- } else {
739
- console.error(chalk.red(`Error ${e.response.status}: `), e.response.data);
740
- }
741
- } else {
742
- console.error(chalk.red(e.message));
743
- }
683
+ handleCommandError(spinner, e, 'Failed to add comment');
744
684
  }
745
685
  });
746
686
 
@@ -6,8 +6,15 @@ export function registerMcpCommand(program) {
6
6
  const mcpCmd = new Command('mcp')
7
7
  .description('Start MCP Agent Server (Stdio)')
8
8
  .action(async () => {
9
- // MCP server uses stdio, so we shouldn't log anything else to stdout.
10
- // We can log to stderr if needed.
9
+ // MCP server uses stdio for communication.
10
+ // If run directly in a TTY (terminal), warn the user.
11
+ if (process.stdin.isTTY) {
12
+ console.error(chalk.blue('ℹ Jira MCP Server is running...'));
13
+ console.error(chalk.grey(' This command is designed for AI Agents (Claude, Cursor, etc).'));
14
+ console.error(chalk.grey(' It communicates via JSON-RPC on stdin/stdout.'));
15
+ console.error(chalk.grey(' Press Ctrl+C to stop.'));
16
+ }
17
+
11
18
  try {
12
19
  await startServer();
13
20
  } catch (e) {
@@ -3,6 +3,7 @@ import chalk from 'chalk';
3
3
  import { table } from 'table';
4
4
  import { api } from '../services/api-service.js';
5
5
  import ora from 'ora';
6
+ import { handleCommandError } from '../utils/error-handler.js';
6
7
 
7
8
  export function registerProjectCommand(program) {
8
9
  const projectCmd = new Command('project')
@@ -50,8 +51,7 @@ Common Actions:
50
51
 
51
52
  console.log(table(tableData));
52
53
  } catch (e) {
53
- spinner.fail('Failed to list projects');
54
- console.error(e.message);
54
+ handleCommandError(spinner, e, 'Failed to list projects');
55
55
  }
56
56
  });
57
57