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.
- package/README.md +31 -0
- package/dist/src/commands/bulk.js +10 -9
- package/dist/src/commands/bulk.js.map +1 -1
- package/dist/src/commands/dashboard.js +8 -7
- package/dist/src/commands/dashboard.js.map +1 -1
- package/dist/src/commands/issue.js +34 -38
- package/dist/src/commands/issue.js.map +1 -1
- package/dist/src/server/mcp-server.js +209 -27
- package/dist/src/server/mcp-server.js.map +1 -1
- package/dist/src/services/api-service.d.ts +1 -1
- package/dist/src/services/api-service.js +9 -6
- package/dist/src/services/api-service.js.map +1 -1
- package/dist/src/utils/api-paths.d.ts +31 -0
- package/dist/src/utils/api-paths.js +32 -0
- package/dist/src/utils/api-paths.js.map +1 -0
- package/package.json +1 -1
- package/src/commands/bulk.ts +10 -9
- package/src/commands/dashboard.ts +9 -7
- package/src/commands/issue.ts +35 -38
- package/src/server/mcp-server.ts +234 -27
- package/src/services/api-service.ts +11 -6
- package/src/utils/api-paths.ts +32 -0
package/src/commands/issue.ts
CHANGED
|
@@ -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
|
-
|
|
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:
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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) {
|