jira-pilot 2.1.2 → 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.
Files changed (114) hide show
  1. package/README.md +54 -0
  2. package/bin/jira.ts +2 -0
  3. package/dist/bin/jira.js +2 -0
  4. package/dist/bin/jira.js.map +1 -1
  5. package/dist/src/commands/ai-actions/plan.js +1 -1
  6. package/dist/src/commands/ai-actions/plan.js.map +1 -1
  7. package/dist/src/commands/ai-actions/review.js +5 -4
  8. package/dist/src/commands/ai-actions/review.js.map +1 -1
  9. package/dist/src/commands/ai-actions/standup.js +1 -1
  10. package/dist/src/commands/ai-actions/standup.js.map +1 -1
  11. package/dist/src/commands/ai.js +1 -1
  12. package/dist/src/commands/ai.js.map +1 -1
  13. package/dist/src/commands/board.js +10 -5
  14. package/dist/src/commands/board.js.map +1 -1
  15. package/dist/src/commands/bulk.js +11 -10
  16. package/dist/src/commands/bulk.js.map +1 -1
  17. package/dist/src/commands/config.js +1 -1
  18. package/dist/src/commands/config.js.map +1 -1
  19. package/dist/src/commands/dashboard.js +19 -12
  20. package/dist/src/commands/dashboard.js.map +1 -1
  21. package/dist/src/commands/filter.js +7 -4
  22. package/dist/src/commands/filter.js.map +1 -1
  23. package/dist/src/commands/git.js +1 -1
  24. package/dist/src/commands/git.js.map +1 -1
  25. package/dist/src/commands/issue-attach.js +1 -1
  26. package/dist/src/commands/issue-attach.js.map +1 -1
  27. package/dist/src/commands/issue-pr.js +1 -1
  28. package/dist/src/commands/issue-pr.js.map +1 -1
  29. package/dist/src/commands/issue-worklog.js +10 -5
  30. package/dist/src/commands/issue-worklog.js.map +1 -1
  31. package/dist/src/commands/issue.js +173 -122
  32. package/dist/src/commands/issue.js.map +1 -1
  33. package/dist/src/commands/project.js +10 -5
  34. package/dist/src/commands/project.js.map +1 -1
  35. package/dist/src/commands/sprint.js +19 -8
  36. package/dist/src/commands/sprint.js.map +1 -1
  37. package/dist/src/commands/tui.d.ts +2 -0
  38. package/dist/src/commands/tui.js +10 -0
  39. package/dist/src/commands/tui.js.map +1 -0
  40. package/dist/src/server/mcp-server.js +209 -27
  41. package/dist/src/server/mcp-server.js.map +1 -1
  42. package/dist/src/services/ai-service.js +7 -4
  43. package/dist/src/services/ai-service.js.map +1 -1
  44. package/dist/src/services/api-service.d.ts +2 -0
  45. package/dist/src/services/api-service.js +32 -20
  46. package/dist/src/services/api-service.js.map +1 -1
  47. package/dist/src/tui/App.d.ts +1 -0
  48. package/dist/src/tui/App.js +26 -0
  49. package/dist/src/tui/App.js.map +1 -0
  50. package/dist/src/tui/index.d.ts +1 -0
  51. package/dist/src/tui/index.js +8 -0
  52. package/dist/src/tui/index.js.map +1 -0
  53. package/dist/src/tui/screens/BoardList.d.ts +1 -0
  54. package/dist/src/tui/screens/BoardList.js +71 -0
  55. package/dist/src/tui/screens/BoardList.js.map +1 -0
  56. package/dist/src/tui/screens/Dashboard.d.ts +1 -0
  57. package/dist/src/tui/screens/Dashboard.js +41 -0
  58. package/dist/src/tui/screens/Dashboard.js.map +1 -0
  59. package/dist/src/tui/screens/IssueDetail.d.ts +6 -0
  60. package/dist/src/tui/screens/IssueDetail.js +40 -0
  61. package/dist/src/tui/screens/IssueDetail.js.map +1 -0
  62. package/dist/src/tui/screens/IssueList.d.ts +1 -0
  63. package/dist/src/tui/screens/IssueList.js +72 -0
  64. package/dist/src/tui/screens/IssueList.js.map +1 -0
  65. package/dist/src/tui/screens/KanbanBoard.d.ts +6 -0
  66. package/dist/src/tui/screens/KanbanBoard.js +86 -0
  67. package/dist/src/tui/screens/KanbanBoard.js.map +1 -0
  68. package/dist/src/tui/utils/adf-render.d.ts +1 -0
  69. package/dist/src/tui/utils/adf-render.js +29 -0
  70. package/dist/src/tui/utils/adf-render.js.map +1 -0
  71. package/dist/src/utils/api-paths.d.ts +31 -0
  72. package/dist/src/utils/api-paths.js +32 -0
  73. package/dist/src/utils/api-paths.js.map +1 -0
  74. package/dist/src/utils/error-handler.d.ts +2 -2
  75. package/dist/src/utils/error-handler.js.map +1 -1
  76. package/dist/src/utils/http.d.ts +27 -0
  77. package/dist/src/utils/http.js +95 -0
  78. package/dist/src/utils/http.js.map +1 -0
  79. package/dist/src/utils/spinner.d.ts +21 -0
  80. package/dist/src/utils/spinner.js +79 -0
  81. package/dist/src/utils/spinner.js.map +1 -0
  82. package/package.json +10 -5
  83. package/src/commands/ai-actions/plan.ts +1 -1
  84. package/src/commands/ai-actions/review.ts +5 -4
  85. package/src/commands/ai-actions/standup.ts +1 -1
  86. package/src/commands/ai.ts +1 -1
  87. package/src/commands/board.ts +10 -5
  88. package/src/commands/bulk.ts +11 -10
  89. package/src/commands/config.ts +1 -1
  90. package/src/commands/dashboard.ts +20 -12
  91. package/src/commands/filter.ts +8 -5
  92. package/src/commands/git.ts +1 -1
  93. package/src/commands/issue-attach.ts +1 -1
  94. package/src/commands/issue-pr.ts +1 -1
  95. package/src/commands/issue-worklog.ts +10 -5
  96. package/src/commands/issue.ts +181 -124
  97. package/src/commands/project.ts +10 -5
  98. package/src/commands/sprint.ts +19 -8
  99. package/src/commands/tui.ts +11 -0
  100. package/src/server/mcp-server.ts +234 -27
  101. package/src/services/ai-service.ts +7 -4
  102. package/src/services/api-service.ts +34 -21
  103. package/src/tui/App.tsx +61 -0
  104. package/src/tui/index.tsx +8 -0
  105. package/src/tui/screens/BoardList.tsx +102 -0
  106. package/src/tui/screens/Dashboard.tsx +75 -0
  107. package/src/tui/screens/IssueDetail.tsx +93 -0
  108. package/src/tui/screens/IssueList.tsx +116 -0
  109. package/src/tui/screens/KanbanBoard.tsx +133 -0
  110. package/src/tui/utils/adf-render.ts +30 -0
  111. package/src/utils/api-paths.ts +32 -0
  112. package/src/utils/error-handler.ts +2 -2
  113. package/src/utils/http.ts +128 -0
  114. package/src/utils/spinner.ts +87 -0
@@ -0,0 +1,31 @@
1
+ export declare const API: {
2
+ SEARCH: {
3
+ JQL: string;
4
+ };
5
+ ISSUE: {
6
+ BASE: string;
7
+ GET: (key: string) => string;
8
+ TRANSITIONS: (key: string) => string;
9
+ COMMENT: (key: string) => string;
10
+ ASSIGNEE: (key: string) => string;
11
+ WORKLOG: (key: string) => string;
12
+ ATTACHMENTS: (key: string) => string;
13
+ CREATEMETA: (projectKey: string) => string;
14
+ };
15
+ PROJECT: {
16
+ SEARCH: string;
17
+ GET: (key: string) => string;
18
+ COMPONENTS: (key: string) => string;
19
+ VERSIONS: (key: string) => string;
20
+ };
21
+ USER: {
22
+ MYSELF: string;
23
+ SEARCH: string;
24
+ };
25
+ PRIORITY: {
26
+ ALL: string;
27
+ };
28
+ SERVER: {
29
+ INFO: string;
30
+ };
31
+ };
@@ -0,0 +1,32 @@
1
+ export const API = {
2
+ SEARCH: {
3
+ JQL: '/search/jql',
4
+ },
5
+ ISSUE: {
6
+ BASE: '/issue',
7
+ GET: (key) => `/issue/${key}`,
8
+ TRANSITIONS: (key) => `/issue/${key}/transitions`,
9
+ COMMENT: (key) => `/issue/${key}/comment`,
10
+ ASSIGNEE: (key) => `/issue/${key}/assignee`,
11
+ WORKLOG: (key) => `/issue/${key}/worklog`,
12
+ ATTACHMENTS: (key) => `/issue/${key}/attachments`,
13
+ CREATEMETA: (projectKey) => `/issue/createmeta/${projectKey}/issuetypes`,
14
+ },
15
+ PROJECT: {
16
+ SEARCH: '/project/search',
17
+ GET: (key) => `/project/${key}`,
18
+ COMPONENTS: (key) => `/project/${key}/components`,
19
+ VERSIONS: (key) => `/project/${key}/versions`,
20
+ },
21
+ USER: {
22
+ MYSELF: '/myself',
23
+ SEARCH: '/user/search',
24
+ },
25
+ PRIORITY: {
26
+ ALL: '/priority',
27
+ },
28
+ SERVER: {
29
+ INFO: '/serverInfo',
30
+ }
31
+ };
32
+ //# sourceMappingURL=api-paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-paths.js","sourceRoot":"","sources":["../../../src/utils/api-paths.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,GAAG,GAAG;IACf,MAAM,EAAE;QACJ,GAAG,EAAE,aAAa;KACrB;IACD,KAAK,EAAE;QACH,IAAI,EAAE,QAAQ;QACd,GAAG,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,UAAU,GAAG,EAAE;QACrC,WAAW,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,UAAU,GAAG,cAAc;QACzD,OAAO,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,UAAU,GAAG,UAAU;QACjD,QAAQ,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,UAAU,GAAG,WAAW;QACnD,OAAO,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,UAAU,GAAG,UAAU;QACjD,WAAW,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,UAAU,GAAG,cAAc;QACzD,UAAU,EAAE,CAAC,UAAkB,EAAE,EAAE,CAAC,qBAAqB,UAAU,aAAa;KACnF;IACD,OAAO,EAAE;QACL,MAAM,EAAE,iBAAiB;QACzB,GAAG,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,YAAY,GAAG,EAAE;QACvC,UAAU,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,YAAY,GAAG,aAAa;QACzD,QAAQ,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,YAAY,GAAG,WAAW;KACxD;IACD,IAAI,EAAE;QACF,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,cAAc;KACzB;IACD,QAAQ,EAAE;QACN,GAAG,EAAE,WAAW;KACnB;IACD,MAAM,EAAE;QACJ,IAAI,EAAE,aAAa;KACtB;CACJ,CAAC"}
@@ -1,4 +1,4 @@
1
- import { Ora } from 'ora';
1
+ import { Spinner } from './spinner.js';
2
2
  /**
3
3
  * Standardized error handler for CLI commands.
4
4
  * Stops the spinner and prints a formatted error message.
@@ -7,4 +7,4 @@ import { Ora } from 'ora';
7
7
  * @param {Error} error - The error object
8
8
  * @param {string} [context] - Optional context (e.g., "Failed to list issues")
9
9
  */
10
- export declare function handleCommandError(spinner: Ora | null, error: any, context?: string): void;
10
+ export declare function handleCommandError(spinner: Spinner | null, error: any, context?: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../../src/utils/error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAmB,EAAE,KAAU,EAAE,OAAO,GAAG,kBAAkB;IAC5F,gDAAgD;IAChD,IAAI,KAAK,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,EAAE,CAAC,EAAE,CAAC;QAClD,IAAI,OAAO;YAAE,OAAO,CAAC,IAAI,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;QAC1C,OAAO;IACX,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACV,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1B,CAAC;SAAM,CAAC;QACJ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACjB,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;QACrC,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACjB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC,CAAC;QACzE,CAAC;aAAM,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACxB,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;YACjC,MAAM,QAAQ,GAAG,IAAI,EAAE,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM;gBAC7D,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;gBACtE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YAC5B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,QAAQ,EAAE,CAAC,CAAC,CAAC;QACzD,CAAC;aAAM,CAAC;YACJ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,MAAM,IAAI,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACvE,CAAC;IACL,CAAC;SAAM,CAAC;QACJ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAC5C,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../../src/utils/error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAuB,EAAE,KAAU,EAAE,OAAO,GAAG,kBAAkB;IAChG,gDAAgD;IAChD,IAAI,KAAK,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,EAAE,CAAC,EAAE,CAAC;QAClD,IAAI,OAAO;YAAE,OAAO,CAAC,IAAI,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;QAC1C,OAAO;IACX,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACV,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1B,CAAC;SAAM,CAAC;QACJ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACjB,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;QACrC,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACjB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC,CAAC;QACzE,CAAC;aAAM,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACxB,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;YACjC,MAAM,QAAQ,GAAG,IAAI,EAAE,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM;gBAC7D,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;gBACtE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YAC5B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,QAAQ,EAAE,CAAC,CAAC,CAAC;QACzD,CAAC;aAAM,CAAC;YACJ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,MAAM,IAAI,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACvE,CAAC;IACL,CAAC;SAAM,CAAC;QACJ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAC5C,CAAC;AACL,CAAC"}
@@ -0,0 +1,27 @@
1
+ import https from 'https';
2
+ interface HelperConfig {
3
+ baseURL?: string;
4
+ headers?: Record<string, string>;
5
+ validateStatus?: (status: number) => boolean;
6
+ httpsAgent?: https.Agent;
7
+ }
8
+ interface RequestConfig extends HelperConfig {
9
+ params?: Record<string, any>;
10
+ }
11
+ interface Response<T = any> {
12
+ data: T;
13
+ status: number;
14
+ statusText: string;
15
+ headers: Record<string, string>;
16
+ }
17
+ export declare class HttpClient {
18
+ private defaults;
19
+ constructor(defaults?: HelperConfig);
20
+ static create(config?: HelperConfig): HttpClient;
21
+ request<T = any>(url: string, options?: RequestInit & RequestConfig): Promise<Response<T>>;
22
+ get<T = any>(url: string, config?: RequestConfig): Promise<Response<T>>;
23
+ post<T = any>(url: string, data?: any, config?: RequestConfig): Promise<Response<T>>;
24
+ put<T = any>(url: string, data?: any, config?: RequestConfig): Promise<Response<T>>;
25
+ delete<T = any>(url: string, config?: RequestConfig): Promise<Response<T>>;
26
+ }
27
+ export default HttpClient;
@@ -0,0 +1,95 @@
1
+ export class HttpClient {
2
+ defaults;
3
+ constructor(defaults = {}) {
4
+ this.defaults = defaults;
5
+ }
6
+ static create(config = {}) {
7
+ return new HttpClient(config);
8
+ }
9
+ async request(url, options = {}) {
10
+ const baseURL = options.baseURL || this.defaults.baseURL || '';
11
+ const fullUrl = new URL(url.startsWith('http') ? url : `${baseURL}${url}`);
12
+ if (options.params) {
13
+ Object.entries(options.params).forEach(([key, value]) => {
14
+ if (value !== undefined)
15
+ fullUrl.searchParams.append(key, String(value));
16
+ });
17
+ }
18
+ const headers = {
19
+ ...this.defaults.headers,
20
+ ...options.headers
21
+ };
22
+ // Handle body for JSON
23
+ let body = options.body;
24
+ if (body && typeof body === 'object') {
25
+ const explicitContentType = headers['Content-Type'];
26
+ if (!explicitContentType || explicitContentType.includes('application/json')) {
27
+ if (!explicitContentType) {
28
+ headers['Content-Type'] = 'application/json';
29
+ }
30
+ body = JSON.stringify(body);
31
+ }
32
+ }
33
+ const fetchOptions = {
34
+ method: options.method || 'GET',
35
+ headers,
36
+ body: body,
37
+ // Node native fetch doesn't support 'agent' directly in standard RequestInit
38
+ // but we can pass it via 'dispatcher' in undici, or ignore if using global fetch.
39
+ // For simple usage we usually ignore httpsAgent unless strictly needed.
40
+ };
41
+ const response = await fetch(fullUrl.toString(), fetchOptions);
42
+ let data;
43
+ const contentType = response.headers.get('content-type');
44
+ const contentLength = response.headers.get('content-length');
45
+ if (response.status === 204 || (contentLength && parseInt(contentLength) === 0)) {
46
+ data = null;
47
+ }
48
+ else if (contentType && contentType.includes('application/json')) {
49
+ try {
50
+ data = await response.json();
51
+ }
52
+ catch (error) {
53
+ // If JSON parsing fails (e.g. empty body despite content-type), fallback to text or null
54
+ const text = await response.text();
55
+ try {
56
+ data = JSON.parse(text);
57
+ }
58
+ catch {
59
+ data = text || null;
60
+ }
61
+ }
62
+ }
63
+ else {
64
+ data = await response.text();
65
+ }
66
+ const res = {
67
+ data,
68
+ status: response.status,
69
+ statusText: response.statusText,
70
+ headers: Object.fromEntries(response.headers.entries())
71
+ };
72
+ const validateStatus = options.validateStatus || this.defaults.validateStatus || ((s) => s >= 200 && s < 300);
73
+ if (!validateStatus(res.status)) {
74
+ const error = new Error(`Request failed with status ${res.status}`);
75
+ error.response = res;
76
+ error.status = res.status;
77
+ throw error;
78
+ }
79
+ return res;
80
+ }
81
+ async get(url, config = {}) {
82
+ return this.request(url, { ...config, method: 'GET' });
83
+ }
84
+ async post(url, data, config = {}) {
85
+ return this.request(url, { ...config, method: 'POST', body: data });
86
+ }
87
+ async put(url, data, config = {}) {
88
+ return this.request(url, { ...config, method: 'PUT', body: data });
89
+ }
90
+ async delete(url, config = {}) {
91
+ return this.request(url, { ...config, method: 'DELETE' });
92
+ }
93
+ }
94
+ export default HttpClient;
95
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/utils/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export declare class Spinner {
2
+ private timer;
3
+ private frameIndex;
4
+ private frames;
5
+ text: string;
6
+ constructor(text: string | {
7
+ text: string;
8
+ });
9
+ start(text?: string): Spinner;
10
+ stop(): Spinner;
11
+ succeed(text?: string): Spinner;
12
+ fail(text?: string): Spinner;
13
+ info(text?: string): Spinner;
14
+ warn(text?: string): Spinner;
15
+ private clearLine;
16
+ private write;
17
+ private color;
18
+ }
19
+ export default function ora(options?: string | {
20
+ text: string;
21
+ }): Spinner;
@@ -0,0 +1,79 @@
1
+ export class Spinner {
2
+ timer = null;
3
+ frameIndex = 0;
4
+ frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
5
+ text;
6
+ constructor(text) {
7
+ this.text = typeof text === 'string' ? text : (text?.text || '');
8
+ }
9
+ start(text) {
10
+ if (text)
11
+ this.text = text;
12
+ this.frameIndex = 0;
13
+ // Only start animation if TTY and not CI (basic check)
14
+ if (process.stdout.isTTY) {
15
+ this.timer = setInterval(() => {
16
+ const frame = this.frames[this.frameIndex];
17
+ this.frameIndex = (this.frameIndex + 1) % this.frames.length;
18
+ this.write(`\r${frame} ${this.text}`);
19
+ }, 80);
20
+ }
21
+ else {
22
+ console.log(this.text);
23
+ }
24
+ return this;
25
+ }
26
+ stop() {
27
+ if (this.timer) {
28
+ clearInterval(this.timer);
29
+ this.timer = null;
30
+ this.clearLine();
31
+ }
32
+ return this;
33
+ }
34
+ succeed(text) {
35
+ this.stop();
36
+ const msg = text || this.text;
37
+ console.log(`${this.color('green', '✔')} ${msg}`);
38
+ return this;
39
+ }
40
+ fail(text) {
41
+ this.stop();
42
+ const msg = text || this.text;
43
+ console.log(`${this.color('red', '✖')} ${msg}`);
44
+ return this;
45
+ }
46
+ info(text) {
47
+ this.stop();
48
+ console.log(`${this.color('blue', 'ℹ')} ${text || this.text}`);
49
+ return this;
50
+ }
51
+ warn(text) {
52
+ this.stop();
53
+ console.log(`${this.color('yellow', '⚠')} ${text || this.text}`);
54
+ return this;
55
+ }
56
+ clearLine() {
57
+ if (process.stdout.isTTY) {
58
+ process.stdout.clearLine(0);
59
+ process.stdout.cursorTo(0);
60
+ }
61
+ }
62
+ write(str) {
63
+ process.stdout.write(str);
64
+ }
65
+ color(color, str) {
66
+ const colors = {
67
+ green: '\x1b[32m',
68
+ red: '\x1b[31m',
69
+ blue: '\x1b[34m',
70
+ yellow: '\x1b[33m',
71
+ reset: '\x1b[0m'
72
+ };
73
+ return `${colors[color] || ''}${str}${colors.reset}`;
74
+ }
75
+ }
76
+ export default function ora(options = '') {
77
+ return new Spinner(options);
78
+ }
79
+ //# sourceMappingURL=spinner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spinner.js","sourceRoot":"","sources":["../../../src/utils/spinner.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jira-pilot",
3
- "version": "2.1.2",
3
+ "version": "2.2.0",
4
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 14-tool MCP server for AI assistants",
5
5
  "main": "dist/src/index.js",
6
6
  "type": "module",
@@ -82,16 +82,21 @@
82
82
  "license": "ISC",
83
83
  "dependencies": {
84
84
  "@modelcontextprotocol/sdk": "^1.26.0",
85
- "axios": "^1.13.5",
86
85
  "chalk": "^5.3.0",
87
- "cli-table3": "^0.6.5",
86
+ "cmd-table": "^0.1.0",
88
87
  "commander": "^14.0.3",
89
88
  "enquirer": "^2.4.1",
90
- "open": "^11.0.0",
91
- "ora": "^9.3.0"
89
+ "ink": "^6.7.0",
90
+ "ink-select-input": "^6.2.0",
91
+ "ink-spinner": "^5.0.0",
92
+ "ink-table": "^3.1.0",
93
+ "ink-text-input": "^6.0.0",
94
+ "react": "^19.2.4"
92
95
  },
93
96
  "devDependencies": {
97
+ "@types/ink": "^0.5.2",
94
98
  "@types/node": "^25.2.3",
99
+ "@types/react": "^19.2.14",
95
100
  "@vitest/coverage-v8": "^4.0.18",
96
101
  "rimraf": "^6.1.2",
97
102
  "tsx": "^4.21.0",
@@ -1,5 +1,5 @@
1
1
  import chalk from 'chalk';
2
- import ora from 'ora';
2
+ import ora from '../../utils/spinner.js';
3
3
  import enquirer from 'enquirer';
4
4
  import { api } from '../../services/api-service.js';
5
5
  import { aiService } from '../../services/ai-service.js';
@@ -1,6 +1,6 @@
1
1
  import chalk from 'chalk';
2
- import ora from 'ora';
3
- import axios from 'axios';
2
+ import ora from '../../utils/spinner.js';
3
+ import { HttpClient } from '../../utils/http.js';
4
4
  import { execSync } from 'child_process';
5
5
  import { api } from '../../services/api-service.js';
6
6
  import { aiService } from '../../services/ai-service.js';
@@ -52,7 +52,8 @@ export async function reviewAction(issueKey: string, options: any) {
52
52
 
53
53
  // 3. Search GitHub PRs
54
54
  // We search for PRs that mention the issue key in title or branch name
55
- const searchRes = await axios.get(`https://api.github.com/search/issues`, {
55
+ const http = new HttpClient();
56
+ const searchRes = await http.get(`https://api.github.com/search/issues`, {
56
57
  params: {
57
58
  q: `repo:${repoOwner}/${repoName} is:pr ${issueKey}`
58
59
  },
@@ -73,7 +74,7 @@ export async function reviewAction(issueKey: string, options: any) {
73
74
  spinner.text = `Analyzing PR #${pr.number}: ${pr.title}...`;
74
75
 
75
76
  // 4. Fetch Diff
76
- const diffRes = await axios.get(pr.pull_request.url, {
77
+ const diffRes = await http.get(pr.pull_request.url, {
77
78
  headers: {
78
79
  'Authorization': `token ${githubToken}`,
79
80
  'Accept': 'application/vnd.github.v3.diff'
@@ -1,5 +1,5 @@
1
1
  import chalk from 'chalk';
2
- import ora from 'ora';
2
+ import ora from '../../utils/spinner.js';
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';
@@ -1,6 +1,6 @@
1
1
  import { Command } from 'commander';
2
2
  import chalk from 'chalk';
3
- import ora from 'ora';
3
+ import ora from '../utils/spinner.js';
4
4
  import enquirer from 'enquirer';
5
5
  import { api } from '../services/api-service.js';
6
6
  import { aiService } from '../services/ai-service.js';
@@ -1,8 +1,8 @@
1
1
  import { Command } from 'commander';
2
2
  import chalk from 'chalk';
3
- import Table from 'cli-table3';
3
+ import { Table } from 'cmd-table';
4
4
  import { api } from '../services/api-service.js';
5
- import ora from 'ora';
5
+ import ora from '../utils/spinner.js';
6
6
  import { handleCommandError } from '../utils/error-handler.js';
7
7
 
8
8
  export function registerBoardCommand(program: Command) {
@@ -51,11 +51,16 @@ Common Actions:
51
51
  }
52
52
 
53
53
  const table = new Table({
54
- head: [chalk.bold('ID'), chalk.bold('Name'), chalk.bold('Type'), chalk.bold('Project')]
54
+ columns: [
55
+ { name: chalk.bold('ID') },
56
+ { name: chalk.bold('Name') },
57
+ { name: chalk.bold('Type') },
58
+ { name: chalk.bold('Project') }
59
+ ]
55
60
  });
56
61
 
57
62
  data.values.forEach((b: any) => {
58
- table.push([
63
+ table.addRow([
59
64
  b.id,
60
65
  b.name,
61
66
  b.type,
@@ -63,7 +68,7 @@ Common Actions:
63
68
  ]);
64
69
  });
65
70
 
66
- console.log(table.toString());
71
+ console.log(table.render());
67
72
  console.log(chalk.grey(`Showing ${data.values.length} board(s)`));
68
73
 
69
74
  } catch (e: any) {
@@ -1,9 +1,10 @@
1
1
  import { Command } from 'commander';
2
2
  import chalk from 'chalk';
3
- import ora from 'ora';
3
+ import ora from '../utils/spinner.js';
4
4
  import enquirer from 'enquirer';
5
5
  import { api } from '../services/api-service.js';
6
6
  import { handleCommandError } from '../utils/error-handler.js';
7
+ import { API } from '../utils/api-paths.js';
7
8
 
8
9
  export function registerBulkCommand(program: Command) {
9
10
  const bulkCmd = new Command('bulk')
@@ -29,7 +30,7 @@ Examples:
29
30
  .action(async (options: any) => {
30
31
  const spinner = ora('Finding matching issues...').start();
31
32
  try {
32
- const data = await api.post('/search/jql', {
33
+ const data = await api.post(API.SEARCH.JQL, {
33
34
  jql: options.jql,
34
35
  maxResults: parseInt(options.limit),
35
36
  fields: ['summary', 'status']
@@ -50,7 +51,7 @@ Examples:
50
51
 
51
52
  if (!targetStatus) {
52
53
  // Get transitions from the first issue to show available statuses
53
- const transData = await api.get(`/issue/${data.issues[0].key}/transitions`);
54
+ const transData = await api.get(API.ISSUE.TRANSITIONS(data.issues[0].key));
54
55
  const { Select } = enquirer as any;
55
56
  const statusSelect = new Select({
56
57
  name: 'status',
@@ -78,13 +79,13 @@ Examples:
78
79
 
79
80
  for (const issue of data.issues) {
80
81
  try {
81
- const transData = await api.get(`/issue/${issue.key}/transitions`);
82
+ const transData = await api.get(API.ISSUE.TRANSITIONS(issue.key));
82
83
  const transition = transData.transitions.find(
83
84
  (t: any) => t.name.toLowerCase() === targetStatus.toLowerCase()
84
85
  );
85
86
 
86
87
  if (transition) {
87
- await api.post(`/issue/${issue.key}/transitions`, {
88
+ await api.post(API.ISSUE.TRANSITIONS(issue.key), {
88
89
  transition: { id: transition.id }
89
90
  });
90
91
  success++;
@@ -114,7 +115,7 @@ Examples:
114
115
  .action(async (options: any) => {
115
116
  const spinner = ora('Finding issues...').start();
116
117
  try {
117
- const data = await api.post('/search/jql', {
118
+ const data = await api.post(API.SEARCH.JQL, {
118
119
  jql: options.jql,
119
120
  maxResults: 50,
120
121
  fields: ['summary', 'assignee']
@@ -141,7 +142,7 @@ Examples:
141
142
  }
142
143
 
143
144
  if (assigneeId === 'me') {
144
- const me = await api.get('/myself');
145
+ const me = await api.get(API.USER.MYSELF);
145
146
  assigneeId = me.accountId;
146
147
  }
147
148
 
@@ -156,7 +157,7 @@ Examples:
156
157
 
157
158
  const processSpinner = ora('Assigning...').start();
158
159
  for (const issue of data.issues) {
159
- await api.put(`/issue/${issue.key}/assignee`, { accountId: assigneeId });
160
+ await api.put(API.ISSUE.ASSIGNEE(issue.key), { accountId: assigneeId });
160
161
  }
161
162
  processSpinner.succeed('Bulk assign complete.');
162
163
 
@@ -181,7 +182,7 @@ Examples:
181
182
 
182
183
  const spinner = ora('Finding issues...').start();
183
184
  try {
184
- const data = await api.post('/search/jql', {
185
+ const data = await api.post(API.SEARCH.JQL, {
185
186
  jql: options.jql,
186
187
  maxResults: 50,
187
188
  fields: ['summary', 'labels']
@@ -215,7 +216,7 @@ Examples:
215
216
  addList.forEach((l: string) => newLabels.add(l));
216
217
  removeList.forEach((l: string) => newLabels.delete(l));
217
218
 
218
- await api.put(`/issue/${issue.key}`, {
219
+ await api.put(API.ISSUE.GET(issue.key), {
219
220
  fields: { labels: Array.from(newLabels) }
220
221
  });
221
222
  }
@@ -3,7 +3,7 @@ import chalk from 'chalk';
3
3
  import enquirer from 'enquirer';
4
4
  import { setCredentials, getCredentials, clearCredentials, saveProfile, loadProfile, deleteProfile, listProfiles, getActiveProfile } from '../utils/config.js';
5
5
  import ConfigStore from '../utils/config-store.js';
6
- import ora from 'ora';
6
+ import ora from '../utils/spinner.js';
7
7
  import { api } from '../services/api-service.js';
8
8
 
9
9
  export function registerConfigCommand(program: Command) {