jira-pilot 2.0.0 → 2.0.2

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.
@@ -1,20 +1,20 @@
1
- import { Command } from 'commander';
2
- import chalk from 'chalk';
3
- import { startServer } from '../server/mcp-server.js';
4
-
5
- export function registerMcpCommand(program) {
6
- const mcpCmd = new Command('mcp')
7
- .description('Start MCP Agent Server (Stdio)')
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.
11
- try {
12
- await startServer();
13
- } catch (e) {
14
- console.error('MCP Server Error:', e);
15
- process.exit(1);
16
- }
17
- });
18
-
19
- program.addCommand(mcpCmd);
20
- }
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { startServer } from '../server/mcp-server.js';
4
+
5
+ export function registerMcpCommand(program) {
6
+ const mcpCmd = new Command('mcp')
7
+ .description('Start MCP Agent Server (Stdio)')
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.
11
+ try {
12
+ await startServer();
13
+ } catch (e) {
14
+ console.error('MCP Server Error:', e);
15
+ process.exit(1);
16
+ }
17
+ });
18
+
19
+ program.addCommand(mcpCmd);
20
+ }
@@ -1,50 +1,59 @@
1
- import { Command } from 'commander';
2
- import chalk from 'chalk';
3
- import { table } from 'table';
4
- import { api } from '../services/api-service.js';
5
- import ora from 'ora';
6
-
7
- export function registerProjectCommand(program) {
8
- const projectCmd = new Command('project')
9
- .description('Manage Jira projects')
10
- .addHelpText('after', `
11
- Common Actions:
12
- $ jira project list # List all projects
13
- `);
14
-
15
- projectCmd
16
- .command('list')
17
- .description('List accessible projects')
18
- .action(async () => {
19
- const spinner = ora('Fetching projects...').start();
20
- try {
21
- const data = await api.get('/project/search');
22
- spinner.stop();
23
-
24
- if (!data.values || data.values.length === 0) {
25
- console.log(chalk.yellow('No projects found.'));
26
- return;
27
- }
28
-
29
- const tableData = [
30
- [chalk.bold('Key'), chalk.bold('Name'), chalk.bold('Leader'), chalk.bold('Style')]
31
- ];
32
-
33
- data.values.forEach(p => {
34
- tableData.push([
35
- chalk.cyan(p.key),
36
- p.name,
37
- p.lead ? p.lead.displayName : 'N/A',
38
- p.style
39
- ]);
40
- });
41
-
42
- console.log(table(tableData));
43
- } catch (e) {
44
- spinner.fail('Failed to list projects');
45
- console.error(e.message);
46
- }
47
- });
48
-
49
- program.addCommand(projectCmd);
50
- }
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { table } from 'table';
4
+ import { api } from '../services/api-service.js';
5
+ import ora from 'ora';
6
+
7
+ export function registerProjectCommand(program) {
8
+ const projectCmd = new Command('project')
9
+ .description('Manage Jira projects')
10
+ .addHelpText('after', `
11
+ Common Actions:
12
+ $ jira project list # List all projects
13
+ `);
14
+
15
+ projectCmd
16
+ .command('list')
17
+ .description('List accessible projects')
18
+ .option('-o, --output <format>', 'Output format (json)')
19
+ .action(async (options) => {
20
+ const spinner = ora('Fetching projects...').start();
21
+ try {
22
+ const data = await api.get('/project/search');
23
+ spinner.stop();
24
+
25
+ if (!data.values || data.values.length === 0) {
26
+ console.log(chalk.yellow('No projects found.'));
27
+ return;
28
+ }
29
+
30
+ if (options.output === 'json') {
31
+ console.log(JSON.stringify(data.values.map(p => ({
32
+ key: p.key, name: p.name,
33
+ lead: p.lead?.displayName || null, style: p.style
34
+ })), null, 2));
35
+ return;
36
+ }
37
+
38
+ const tableData = [
39
+ [chalk.bold('Key'), chalk.bold('Name'), chalk.bold('Leader'), chalk.bold('Style')]
40
+ ];
41
+
42
+ data.values.forEach(p => {
43
+ tableData.push([
44
+ chalk.cyan(p.key),
45
+ p.name,
46
+ p.lead ? p.lead.displayName : 'N/A',
47
+ p.style
48
+ ]);
49
+ });
50
+
51
+ console.log(table(tableData));
52
+ } catch (e) {
53
+ spinner.fail('Failed to list projects');
54
+ console.error(e.message);
55
+ }
56
+ });
57
+
58
+ program.addCommand(projectCmd);
59
+ }
@@ -1,78 +1,153 @@
1
- import { Command } from 'commander';
2
- import chalk from 'chalk';
3
- import { table } from 'table';
4
- import { api } from '../services/api-service.js';
5
- import ora from 'ora';
6
- import { handleCommandError } from '../utils/error-handler.js';
7
-
8
- export function registerSprintCommand(program) {
9
- const sprintCmd = new Command('sprint')
10
- .description('Manage Sprints')
11
- .addHelpText('after', `
12
- Common Actions:
13
- $ jira sprint list --board <ID|Name> # List sprints for a board
14
- `);
15
-
16
- sprintCmd
17
- .command('list')
18
- .description('List sprints for a board')
19
- .requiredOption('-b, --board <id>', 'Board ID or name')
20
- .option('-s, --state <state>', 'State (active, future, closed)', 'active,future')
21
- .action(async (options) => {
22
- const spinner = ora(`Fetching sprints for board ${options.board}...`).start();
23
- try {
24
- let boardId = options.board;
25
-
26
- // If board option is not a number, look it up by name
27
- if (isNaN(boardId)) {
28
- spinner.text = `Looking up board "${options.board}"...`;
29
- const boardData = await api.agileGet(`/board?name=${encodeURIComponent(options.board)}`);
30
-
31
- if (!boardData.values || boardData.values.length === 0) {
32
- throw new Error(`Board with name "${options.board}" not found. Please provide the numeric Board ID.`);
33
- }
34
-
35
- if (boardData.values.length > 1) {
36
- const exact = boardData.values.find(b => b.name.toLowerCase() === options.board.toLowerCase());
37
- if (exact) {
38
- boardId = exact.id;
39
- } else {
40
- console.log(chalk.yellow(`\nMultiple boards found for "${options.board}". Using "${boardData.values[0].name}" (ID: ${boardData.values[0].id}).`));
41
- boardId = boardData.values[0].id;
42
- }
43
- } else {
44
- boardId = boardData.values[0].id;
45
- }
46
- spinner.text = `Fetching sprints for board ${options.board} (ID: ${boardId})...`;
47
- }
48
-
49
- const data = await api.agileGet(`/board/${boardId}/sprint?state=${options.state}`);
50
- spinner.stop();
51
-
52
- if (!data.values || data.values.length === 0) {
53
- console.log(chalk.yellow('No sprints found.'));
54
- return;
55
- }
56
-
57
- const tableData = [
58
- [chalk.bold('ID'), chalk.bold('Name'), chalk.bold('State'), chalk.bold('Dates')]
59
- ];
60
-
61
- data.values.forEach(s => {
62
- tableData.push([
63
- s.id,
64
- s.name,
65
- s.state === 'active' ? chalk.green(s.state) : s.state,
66
- `${s.startDate ? s.startDate.split('T')[0] : ''} -> ${s.endDate ? s.endDate.split('T')[0] : ''}`
67
- ]);
68
- });
69
-
70
- console.log(table(tableData));
71
-
72
- } catch (e) {
73
- handleCommandError(spinner, e, 'Failed to list sprints');
74
- }
75
- });
76
-
77
- program.addCommand(sprintCmd);
78
- }
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { table } from 'table';
4
+ import { api } from '../services/api-service.js';
5
+ import ora from 'ora';
6
+ import { handleCommandError } from '../utils/error-handler.js';
7
+
8
+ export function registerSprintCommand(program) {
9
+ const sprintCmd = new Command('sprint')
10
+ .description('Manage Sprints')
11
+ .addHelpText('after', `
12
+ Common Actions:
13
+ $ jira sprint list --board <ID|Name> # List sprints for a board
14
+ `);
15
+
16
+ sprintCmd
17
+ .command('list')
18
+ .description('List sprints for a board')
19
+ .requiredOption('-b, --board <id>', 'Board ID or name')
20
+ .option('-s, --state <state>', 'State (active, future, closed)', 'active,future')
21
+ .action(async (options) => {
22
+ const spinner = ora(`Fetching sprints for board ${options.board}...`).start();
23
+ try {
24
+ let boardId = options.board;
25
+
26
+ // If board option is not a number, look it up by name
27
+ if (isNaN(boardId)) {
28
+ spinner.text = `Looking up board "${options.board}"...`;
29
+ const boardData = await api.agileGet(`/board?name=${encodeURIComponent(options.board)}`);
30
+
31
+ if (!boardData.values || boardData.values.length === 0) {
32
+ throw new Error(`Board with name "${options.board}" not found. Please provide the numeric Board ID.`);
33
+ }
34
+
35
+ if (boardData.values.length > 1) {
36
+ const exact = boardData.values.find(b => b.name.toLowerCase() === options.board.toLowerCase());
37
+ if (exact) {
38
+ boardId = exact.id;
39
+ } else {
40
+ console.log(chalk.yellow(`\nMultiple boards found for "${options.board}". Using "${boardData.values[0].name}" (ID: ${boardData.values[0].id}).`));
41
+ boardId = boardData.values[0].id;
42
+ }
43
+ } else {
44
+ boardId = boardData.values[0].id;
45
+ }
46
+ spinner.text = `Fetching sprints for board ${options.board} (ID: ${boardId})...`;
47
+ }
48
+
49
+ const data = await api.agileGet(`/board/${boardId}/sprint?state=${options.state}`);
50
+ spinner.stop();
51
+
52
+ if (!data.values || data.values.length === 0) {
53
+ console.log(chalk.yellow('No sprints found.'));
54
+ return;
55
+ }
56
+
57
+ const tableData = [
58
+ [chalk.bold('ID'), chalk.bold('Name'), chalk.bold('State'), chalk.bold('Dates')]
59
+ ];
60
+
61
+ data.values.forEach(s => {
62
+ tableData.push([
63
+ s.id,
64
+ s.name,
65
+ s.state === 'active' ? chalk.green(s.state) : s.state,
66
+ `${s.startDate ? s.startDate.split('T')[0] : ''} -> ${s.endDate ? s.endDate.split('T')[0] : ''}`
67
+ ]);
68
+ });
69
+
70
+ console.log(table(tableData));
71
+
72
+ } catch (e) {
73
+ handleCommandError(spinner, e, 'Failed to list sprints');
74
+ }
75
+ });
76
+
77
+ // ── SPRINT ISSUES ────────────────────────────────────────────────
78
+ sprintCmd
79
+ .command('issues')
80
+ .description('List issues in the active sprint')
81
+ .requiredOption('-b, --board <id>', 'Board ID or name')
82
+ .option('-o, --output <format>', 'Output format (json)')
83
+ .addHelpText('after', `
84
+ Examples:
85
+ $ jira sprint issues --board 5
86
+ $ jira sprint issues --board "My Board" --output json
87
+ `)
88
+ .action(async (options) => {
89
+ const spinner = ora('Fetching active sprint...').start();
90
+ try {
91
+ let boardId = options.board;
92
+
93
+ if (isNaN(boardId)) {
94
+ spinner.text = `Looking up board "${options.board}"...`;
95
+ const boardData = await api.agileGet(`/board?name=${encodeURIComponent(options.board)}`);
96
+ if (!boardData.values || boardData.values.length === 0) {
97
+ throw new Error(`Board "${options.board}" not found.`);
98
+ }
99
+ boardId = boardData.values[0].id;
100
+ }
101
+
102
+ // Get active sprint
103
+ const sprints = await api.agileGet(`/board/${boardId}/sprint?state=active`);
104
+ if (!sprints.values || sprints.values.length === 0) {
105
+ spinner.stop();
106
+ console.log(chalk.yellow('No active sprint found.'));
107
+ return;
108
+ }
109
+
110
+ const activeSprint = sprints.values[0];
111
+ spinner.text = `Fetching issues for sprint "${activeSprint.name}"...`;
112
+
113
+ const issues = await api.agileGet(`/sprint/${activeSprint.id}/issue?maxResults=50&fields=summary,status,assignee,priority`);
114
+ spinner.stop();
115
+
116
+ if (!issues.issues || issues.issues.length === 0) {
117
+ console.log(chalk.yellow('No issues in active sprint.'));
118
+ return;
119
+ }
120
+
121
+ console.log(chalk.bold(`\n🏃 Sprint: ${activeSprint.name}\n`));
122
+
123
+ if (options.output === 'json') {
124
+ console.log(JSON.stringify(issues.issues.map(i => ({
125
+ key: i.key, summary: i.fields.summary,
126
+ status: i.fields.status?.name, assignee: i.fields.assignee?.displayName || null,
127
+ priority: i.fields.priority?.name
128
+ })), null, 2));
129
+ return;
130
+ }
131
+
132
+ const tableData = [
133
+ [chalk.bold('Key'), chalk.bold('Summary'), chalk.bold('Status'), chalk.bold('Assignee'), chalk.bold('Priority')]
134
+ ];
135
+ issues.issues.forEach(i => {
136
+ tableData.push([
137
+ chalk.cyan(i.key),
138
+ i.fields.summary ? (i.fields.summary.length > 50 ? i.fields.summary.substring(0, 47) + '...' : i.fields.summary) : '',
139
+ i.fields.status?.name || '',
140
+ i.fields.assignee?.displayName || 'Unassigned',
141
+ i.fields.priority?.name || ''
142
+ ]);
143
+ });
144
+ console.log(table(tableData));
145
+ console.log(chalk.grey(`${issues.issues.length} issue(s) in sprint`));
146
+
147
+ } catch (e) {
148
+ handleCommandError(spinner, e, 'Failed to list sprint issues');
149
+ }
150
+ });
151
+
152
+ program.addCommand(sprintCmd);
153
+ }