@hasna/connectors 0.3.16 → 0.4.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/bin/index.js +71 -1
- package/bin/mcp.js +71 -1
- package/bin/serve.js +70 -0
- package/connectors/connect-asana/.env.example +11 -0
- package/connectors/connect-asana/CLAUDE.md +128 -0
- package/connectors/connect-asana/README.md +193 -0
- package/connectors/connect-asana/package.json +52 -0
- package/connectors/connect-asana/src/api/client.ts +119 -0
- package/connectors/connect-asana/src/api/index.ts +319 -0
- package/connectors/connect-asana/src/cli/index.ts +731 -0
- package/connectors/connect-asana/src/index.ts +19 -0
- package/connectors/connect-asana/src/types/index.ts +270 -0
- package/connectors/connect-asana/src/utils/config.ts +171 -0
- package/connectors/connect-asana/src/utils/output.ts +119 -0
- package/connectors/connect-asana/tsconfig.json +16 -0
- package/connectors/connect-clickup/.env.example +11 -0
- package/connectors/connect-clickup/CLAUDE.md +128 -0
- package/connectors/connect-clickup/README.md +193 -0
- package/connectors/connect-clickup/package.json +52 -0
- package/connectors/connect-clickup/src/api/client.ts +116 -0
- package/connectors/connect-clickup/src/api/index.ts +400 -0
- package/connectors/connect-clickup/src/cli/index.ts +625 -0
- package/connectors/connect-clickup/src/index.ts +19 -0
- package/connectors/connect-clickup/src/types/index.ts +591 -0
- package/connectors/connect-clickup/src/utils/config.ts +157 -0
- package/connectors/connect-clickup/src/utils/output.ts +119 -0
- package/connectors/connect-clickup/tsconfig.json +16 -0
- package/connectors/connect-confluence/.env.example +11 -0
- package/connectors/connect-confluence/CLAUDE.md +272 -0
- package/connectors/connect-confluence/README.md +193 -0
- package/connectors/connect-confluence/package.json +53 -0
- package/connectors/connect-confluence/scripts/release.ts +179 -0
- package/connectors/connect-confluence/src/api/client.ts +213 -0
- package/connectors/connect-confluence/src/api/example.ts +48 -0
- package/connectors/connect-confluence/src/api/index.ts +51 -0
- package/connectors/connect-confluence/src/cli/index.ts +254 -0
- package/connectors/connect-confluence/src/index.ts +103 -0
- package/connectors/connect-confluence/src/types/index.ts +237 -0
- package/connectors/connect-confluence/src/utils/auth.ts +274 -0
- package/connectors/connect-confluence/src/utils/bulk.ts +212 -0
- package/connectors/connect-confluence/src/utils/config.ts +326 -0
- package/connectors/connect-confluence/src/utils/output.ts +175 -0
- package/connectors/connect-confluence/src/utils/settings.ts +114 -0
- package/connectors/connect-confluence/src/utils/storage.ts +198 -0
- package/connectors/connect-confluence/tsconfig.json +16 -0
- package/connectors/connect-jira/.env.example +11 -0
- package/connectors/connect-jira/CLAUDE.md +128 -0
- package/connectors/connect-jira/README.md +193 -0
- package/connectors/connect-jira/package.json +53 -0
- package/connectors/connect-jira/src/api/client.ts +131 -0
- package/connectors/connect-jira/src/api/index.ts +266 -0
- package/connectors/connect-jira/src/cli/index.ts +653 -0
- package/connectors/connect-jira/src/index.ts +23 -0
- package/connectors/connect-jira/src/types/index.ts +448 -0
- package/connectors/connect-jira/src/utils/config.ts +179 -0
- package/connectors/connect-jira/src/utils/output.ts +119 -0
- package/connectors/connect-jira/tsconfig.json +16 -0
- package/connectors/connect-linear/CLAUDE.md +88 -0
- package/connectors/connect-linear/README.md +201 -0
- package/connectors/connect-linear/package.json +45 -0
- package/connectors/connect-linear/src/api/client.ts +62 -0
- package/connectors/connect-linear/src/api/index.ts +46 -0
- package/connectors/connect-linear/src/api/issues.ts +247 -0
- package/connectors/connect-linear/src/api/projects.ts +179 -0
- package/connectors/connect-linear/src/api/teams.ts +125 -0
- package/connectors/connect-linear/src/api/users.ts +112 -0
- package/connectors/connect-linear/src/cli/index.ts +560 -0
- package/connectors/connect-linear/src/index.ts +27 -0
- package/connectors/connect-linear/src/types/index.ts +275 -0
- package/connectors/connect-linear/src/utils/config.ts +249 -0
- package/connectors/connect-linear/src/utils/output.ts +119 -0
- package/connectors/connect-linear/tsconfig.json +16 -0
- package/connectors/connect-slack/.env.example +7 -0
- package/connectors/connect-slack/CLAUDE.md +69 -0
- package/connectors/connect-slack/README.md +150 -0
- package/connectors/connect-slack/package.json +44 -0
- package/connectors/connect-slack/src/api/channels.ts +112 -0
- package/connectors/connect-slack/src/api/client.ts +97 -0
- package/connectors/connect-slack/src/api/index.ts +42 -0
- package/connectors/connect-slack/src/api/messages.ts +127 -0
- package/connectors/connect-slack/src/api/users.ts +110 -0
- package/connectors/connect-slack/src/cli/index.ts +494 -0
- package/connectors/connect-slack/src/index.ts +21 -0
- package/connectors/connect-slack/src/types/index.ts +263 -0
- package/connectors/connect-slack/src/utils/config.ts +297 -0
- package/connectors/connect-slack/src/utils/output.ts +119 -0
- package/connectors/connect-slack/tsconfig.json +16 -0
- package/connectors/connect-telegram/.env.example +2 -0
- package/connectors/connect-telegram/package.json +49 -0
- package/connectors/connect-todoist/.env.example +11 -0
- package/connectors/connect-todoist/CLAUDE.md +104 -0
- package/connectors/connect-todoist/README.md +193 -0
- package/connectors/connect-todoist/package.json +52 -0
- package/connectors/connect-todoist/src/api/client.ts +117 -0
- package/connectors/connect-todoist/src/api/index.ts +188 -0
- package/connectors/connect-todoist/src/cli/index.ts +990 -0
- package/connectors/connect-todoist/src/index.ts +21 -0
- package/connectors/connect-todoist/src/types/index.ts +240 -0
- package/connectors/connect-todoist/src/utils/config.ts +157 -0
- package/connectors/connect-todoist/src/utils/output.ts +119 -0
- package/connectors/connect-todoist/tsconfig.json +16 -0
- package/connectors/connect-trello/.env.example +11 -0
- package/connectors/connect-trello/CLAUDE.md +128 -0
- package/connectors/connect-trello/README.md +193 -0
- package/connectors/connect-trello/package.json +53 -0
- package/connectors/connect-trello/src/api/client.ts +128 -0
- package/connectors/connect-trello/src/api/index.ts +278 -0
- package/connectors/connect-trello/src/cli/index.ts +737 -0
- package/connectors/connect-trello/src/index.ts +21 -0
- package/connectors/connect-trello/src/types/index.ts +314 -0
- package/connectors/connect-trello/src/utils/config.ts +182 -0
- package/connectors/connect-trello/src/utils/output.ts +119 -0
- package/connectors/connect-trello/tsconfig.json +16 -0
- package/connectors/connect-whatsapp/.env.example +11 -0
- package/connectors/connect-whatsapp/CLAUDE.md +113 -0
- package/connectors/connect-whatsapp/README.md +193 -0
- package/connectors/connect-whatsapp/package.json +53 -0
- package/connectors/connect-whatsapp/src/api/client.ts +133 -0
- package/connectors/connect-whatsapp/src/api/index.ts +365 -0
- package/connectors/connect-whatsapp/src/cli/index.ts +686 -0
- package/connectors/connect-whatsapp/src/index.ts +25 -0
- package/connectors/connect-whatsapp/src/types/index.ts +502 -0
- package/connectors/connect-whatsapp/src/utils/config.ts +179 -0
- package/connectors/connect-whatsapp/src/utils/output.ts +119 -0
- package/connectors/connect-whatsapp/tsconfig.json +16 -0
- package/dist/index.js +70 -0
- package/package.json +1 -1
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
// Jira Connector Types
|
|
2
|
+
// Projects, issues, boards, and sprints management
|
|
3
|
+
|
|
4
|
+
// ============================================
|
|
5
|
+
// Configuration
|
|
6
|
+
// ============================================
|
|
7
|
+
|
|
8
|
+
export interface JiraConfig {
|
|
9
|
+
email: string;
|
|
10
|
+
apiToken: string;
|
|
11
|
+
domain: string; // e.g., "mycompany.atlassian.net"
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// ============================================
|
|
16
|
+
// Common Types
|
|
17
|
+
// ============================================
|
|
18
|
+
|
|
19
|
+
export type OutputFormat = 'json' | 'pretty';
|
|
20
|
+
|
|
21
|
+
export interface PaginatedResponse<T> {
|
|
22
|
+
startAt: number;
|
|
23
|
+
maxResults: number;
|
|
24
|
+
total: number;
|
|
25
|
+
values: T[];
|
|
26
|
+
isLast?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface SearchResponse<T> {
|
|
30
|
+
startAt: number;
|
|
31
|
+
maxResults: number;
|
|
32
|
+
total: number;
|
|
33
|
+
issues: T[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ============================================
|
|
37
|
+
// User Types
|
|
38
|
+
// ============================================
|
|
39
|
+
|
|
40
|
+
export interface User {
|
|
41
|
+
accountId: string;
|
|
42
|
+
accountType?: string;
|
|
43
|
+
emailAddress?: string;
|
|
44
|
+
displayName: string;
|
|
45
|
+
active: boolean;
|
|
46
|
+
timeZone?: string;
|
|
47
|
+
locale?: string;
|
|
48
|
+
avatarUrls?: AvatarUrls;
|
|
49
|
+
self?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface AvatarUrls {
|
|
53
|
+
'16x16'?: string;
|
|
54
|
+
'24x24'?: string;
|
|
55
|
+
'32x32'?: string;
|
|
56
|
+
'48x48'?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ============================================
|
|
60
|
+
// Project Types
|
|
61
|
+
// ============================================
|
|
62
|
+
|
|
63
|
+
export interface Project {
|
|
64
|
+
id: string;
|
|
65
|
+
key: string;
|
|
66
|
+
name: string;
|
|
67
|
+
description?: string;
|
|
68
|
+
lead?: User;
|
|
69
|
+
projectTypeKey?: string;
|
|
70
|
+
simplified?: boolean;
|
|
71
|
+
style?: string;
|
|
72
|
+
isPrivate?: boolean;
|
|
73
|
+
avatarUrls?: AvatarUrls;
|
|
74
|
+
self?: string;
|
|
75
|
+
components?: Component[];
|
|
76
|
+
issueTypes?: IssueType[];
|
|
77
|
+
versions?: Version[];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface Component {
|
|
81
|
+
id: string;
|
|
82
|
+
name: string;
|
|
83
|
+
description?: string;
|
|
84
|
+
lead?: User;
|
|
85
|
+
assigneeType?: string;
|
|
86
|
+
project?: string;
|
|
87
|
+
projectId?: number;
|
|
88
|
+
self?: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface Version {
|
|
92
|
+
id: string;
|
|
93
|
+
name: string;
|
|
94
|
+
description?: string;
|
|
95
|
+
archived?: boolean;
|
|
96
|
+
released?: boolean;
|
|
97
|
+
releaseDate?: string;
|
|
98
|
+
startDate?: string;
|
|
99
|
+
projectId?: number;
|
|
100
|
+
self?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ============================================
|
|
104
|
+
// Issue Types
|
|
105
|
+
// ============================================
|
|
106
|
+
|
|
107
|
+
export interface Issue {
|
|
108
|
+
id: string;
|
|
109
|
+
key: string;
|
|
110
|
+
self?: string;
|
|
111
|
+
expand?: string;
|
|
112
|
+
fields: IssueFields;
|
|
113
|
+
changelog?: Changelog;
|
|
114
|
+
renderedFields?: Record<string, unknown>;
|
|
115
|
+
transitions?: Transition[];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface IssueFields {
|
|
119
|
+
summary: string;
|
|
120
|
+
description?: string | AdfDocument;
|
|
121
|
+
issuetype: IssueType;
|
|
122
|
+
project: Project;
|
|
123
|
+
status: Status;
|
|
124
|
+
priority?: Priority;
|
|
125
|
+
assignee?: User;
|
|
126
|
+
reporter?: User;
|
|
127
|
+
creator?: User;
|
|
128
|
+
created?: string;
|
|
129
|
+
updated?: string;
|
|
130
|
+
resolutiondate?: string;
|
|
131
|
+
duedate?: string;
|
|
132
|
+
labels?: string[];
|
|
133
|
+
components?: Component[];
|
|
134
|
+
fixVersions?: Version[];
|
|
135
|
+
versions?: Version[];
|
|
136
|
+
resolution?: Resolution;
|
|
137
|
+
parent?: Issue;
|
|
138
|
+
subtasks?: Issue[];
|
|
139
|
+
issuelinks?: IssueLink[];
|
|
140
|
+
attachment?: Attachment[];
|
|
141
|
+
comment?: CommentPage;
|
|
142
|
+
worklog?: WorklogPage;
|
|
143
|
+
timetracking?: TimeTracking;
|
|
144
|
+
customfield_10000?: unknown; // Sprint field (varies)
|
|
145
|
+
[key: string]: unknown;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export interface IssueType {
|
|
149
|
+
id: string;
|
|
150
|
+
name: string;
|
|
151
|
+
description?: string;
|
|
152
|
+
iconUrl?: string;
|
|
153
|
+
subtask?: boolean;
|
|
154
|
+
avatarId?: number;
|
|
155
|
+
hierarchyLevel?: number;
|
|
156
|
+
self?: string;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export interface Status {
|
|
160
|
+
id: string;
|
|
161
|
+
name: string;
|
|
162
|
+
description?: string;
|
|
163
|
+
iconUrl?: string;
|
|
164
|
+
statusCategory?: StatusCategory;
|
|
165
|
+
self?: string;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export interface StatusCategory {
|
|
169
|
+
id: number;
|
|
170
|
+
key: string;
|
|
171
|
+
name: string;
|
|
172
|
+
colorName?: string;
|
|
173
|
+
self?: string;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export interface Priority {
|
|
177
|
+
id: string;
|
|
178
|
+
name: string;
|
|
179
|
+
description?: string;
|
|
180
|
+
iconUrl?: string;
|
|
181
|
+
statusColor?: string;
|
|
182
|
+
self?: string;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export interface Resolution {
|
|
186
|
+
id: string;
|
|
187
|
+
name: string;
|
|
188
|
+
description?: string;
|
|
189
|
+
self?: string;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface Transition {
|
|
193
|
+
id: string;
|
|
194
|
+
name: string;
|
|
195
|
+
to: Status;
|
|
196
|
+
hasScreen?: boolean;
|
|
197
|
+
isGlobal?: boolean;
|
|
198
|
+
isInitial?: boolean;
|
|
199
|
+
isAvailable?: boolean;
|
|
200
|
+
isConditional?: boolean;
|
|
201
|
+
isLooped?: boolean;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ============================================
|
|
205
|
+
// Comment Types
|
|
206
|
+
// ============================================
|
|
207
|
+
|
|
208
|
+
export interface Comment {
|
|
209
|
+
id: string;
|
|
210
|
+
author: User;
|
|
211
|
+
body: string | AdfDocument;
|
|
212
|
+
created: string;
|
|
213
|
+
updated?: string;
|
|
214
|
+
updateAuthor?: User;
|
|
215
|
+
visibility?: Visibility;
|
|
216
|
+
self?: string;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export interface CommentPage {
|
|
220
|
+
startAt: number;
|
|
221
|
+
maxResults: number;
|
|
222
|
+
total: number;
|
|
223
|
+
comments: Comment[];
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export interface Visibility {
|
|
227
|
+
type: 'group' | 'role';
|
|
228
|
+
value: string;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// ============================================
|
|
232
|
+
// Worklog Types
|
|
233
|
+
// ============================================
|
|
234
|
+
|
|
235
|
+
export interface Worklog {
|
|
236
|
+
id: string;
|
|
237
|
+
author: User;
|
|
238
|
+
updateAuthor?: User;
|
|
239
|
+
comment?: string | AdfDocument;
|
|
240
|
+
created: string;
|
|
241
|
+
updated?: string;
|
|
242
|
+
started: string;
|
|
243
|
+
timeSpent: string;
|
|
244
|
+
timeSpentSeconds: number;
|
|
245
|
+
issueId?: string;
|
|
246
|
+
self?: string;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export interface WorklogPage {
|
|
250
|
+
startAt: number;
|
|
251
|
+
maxResults: number;
|
|
252
|
+
total: number;
|
|
253
|
+
worklogs: Worklog[];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export interface TimeTracking {
|
|
257
|
+
originalEstimate?: string;
|
|
258
|
+
remainingEstimate?: string;
|
|
259
|
+
timeSpent?: string;
|
|
260
|
+
originalEstimateSeconds?: number;
|
|
261
|
+
remainingEstimateSeconds?: number;
|
|
262
|
+
timeSpentSeconds?: number;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// ============================================
|
|
266
|
+
// Attachment Types
|
|
267
|
+
// ============================================
|
|
268
|
+
|
|
269
|
+
export interface Attachment {
|
|
270
|
+
id: string;
|
|
271
|
+
filename: string;
|
|
272
|
+
author: User;
|
|
273
|
+
created: string;
|
|
274
|
+
size: number;
|
|
275
|
+
mimeType: string;
|
|
276
|
+
content?: string;
|
|
277
|
+
thumbnail?: string;
|
|
278
|
+
self?: string;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// ============================================
|
|
282
|
+
// Issue Link Types
|
|
283
|
+
// ============================================
|
|
284
|
+
|
|
285
|
+
export interface IssueLink {
|
|
286
|
+
id: string;
|
|
287
|
+
type: IssueLinkType;
|
|
288
|
+
inwardIssue?: Issue;
|
|
289
|
+
outwardIssue?: Issue;
|
|
290
|
+
self?: string;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export interface IssueLinkType {
|
|
294
|
+
id: string;
|
|
295
|
+
name: string;
|
|
296
|
+
inward: string;
|
|
297
|
+
outward: string;
|
|
298
|
+
self?: string;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ============================================
|
|
302
|
+
// Changelog Types
|
|
303
|
+
// ============================================
|
|
304
|
+
|
|
305
|
+
export interface Changelog {
|
|
306
|
+
startAt: number;
|
|
307
|
+
maxResults: number;
|
|
308
|
+
total: number;
|
|
309
|
+
histories: ChangeHistory[];
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export interface ChangeHistory {
|
|
313
|
+
id: string;
|
|
314
|
+
author: User;
|
|
315
|
+
created: string;
|
|
316
|
+
items: ChangeItem[];
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
export interface ChangeItem {
|
|
320
|
+
field: string;
|
|
321
|
+
fieldtype: string;
|
|
322
|
+
fieldId?: string;
|
|
323
|
+
from?: string;
|
|
324
|
+
fromString?: string;
|
|
325
|
+
to?: string;
|
|
326
|
+
toString?: string;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// ============================================
|
|
330
|
+
// Board Types (Agile)
|
|
331
|
+
// ============================================
|
|
332
|
+
|
|
333
|
+
export interface Board {
|
|
334
|
+
id: number;
|
|
335
|
+
name: string;
|
|
336
|
+
type: 'scrum' | 'kanban' | 'simple';
|
|
337
|
+
self?: string;
|
|
338
|
+
location?: BoardLocation;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export interface BoardLocation {
|
|
342
|
+
projectId?: number;
|
|
343
|
+
projectKey?: string;
|
|
344
|
+
projectName?: string;
|
|
345
|
+
projectTypeKey?: string;
|
|
346
|
+
displayName?: string;
|
|
347
|
+
avatarURI?: string;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// ============================================
|
|
351
|
+
// Sprint Types
|
|
352
|
+
// ============================================
|
|
353
|
+
|
|
354
|
+
export interface Sprint {
|
|
355
|
+
id: number;
|
|
356
|
+
name: string;
|
|
357
|
+
state: 'future' | 'active' | 'closed';
|
|
358
|
+
startDate?: string;
|
|
359
|
+
endDate?: string;
|
|
360
|
+
completeDate?: string;
|
|
361
|
+
originBoardId?: number;
|
|
362
|
+
goal?: string;
|
|
363
|
+
self?: string;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// ============================================
|
|
367
|
+
// ADF (Atlassian Document Format)
|
|
368
|
+
// ============================================
|
|
369
|
+
|
|
370
|
+
export interface AdfDocument {
|
|
371
|
+
version: number;
|
|
372
|
+
type: 'doc';
|
|
373
|
+
content: AdfNode[];
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
export interface AdfNode {
|
|
377
|
+
type: string;
|
|
378
|
+
content?: AdfNode[];
|
|
379
|
+
text?: string;
|
|
380
|
+
attrs?: Record<string, unknown>;
|
|
381
|
+
marks?: AdfMark[];
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export interface AdfMark {
|
|
385
|
+
type: string;
|
|
386
|
+
attrs?: Record<string, unknown>;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// ============================================
|
|
390
|
+
// Input Types
|
|
391
|
+
// ============================================
|
|
392
|
+
|
|
393
|
+
export interface CreateIssueInput {
|
|
394
|
+
fields: {
|
|
395
|
+
project: { key: string } | { id: string };
|
|
396
|
+
summary: string;
|
|
397
|
+
issuetype: { name: string } | { id: string };
|
|
398
|
+
description?: string | AdfDocument;
|
|
399
|
+
assignee?: { accountId: string };
|
|
400
|
+
reporter?: { accountId: string };
|
|
401
|
+
priority?: { name: string } | { id: string };
|
|
402
|
+
labels?: string[];
|
|
403
|
+
components?: Array<{ name: string } | { id: string }>;
|
|
404
|
+
fixVersions?: Array<{ name: string } | { id: string }>;
|
|
405
|
+
duedate?: string;
|
|
406
|
+
parent?: { key: string };
|
|
407
|
+
[key: string]: unknown;
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export interface UpdateIssueInput {
|
|
412
|
+
fields?: Partial<CreateIssueInput['fields']>;
|
|
413
|
+
update?: Record<string, Array<{ add?: unknown; remove?: unknown; set?: unknown }>>;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export interface TransitionIssueInput {
|
|
417
|
+
transition: { id: string };
|
|
418
|
+
fields?: Record<string, unknown>;
|
|
419
|
+
update?: Record<string, Array<{ add?: unknown; remove?: unknown; set?: unknown }>>;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
export interface CreateCommentInput {
|
|
423
|
+
body: string | AdfDocument;
|
|
424
|
+
visibility?: Visibility;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// ============================================
|
|
428
|
+
// API Error Types
|
|
429
|
+
// ============================================
|
|
430
|
+
|
|
431
|
+
export interface JiraError {
|
|
432
|
+
errorMessages?: string[];
|
|
433
|
+
errors?: Record<string, string>;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export class JiraApiError extends Error {
|
|
437
|
+
public readonly statusCode: number;
|
|
438
|
+
public readonly errors?: Record<string, string>;
|
|
439
|
+
public readonly errorMessages?: string[];
|
|
440
|
+
|
|
441
|
+
constructor(message: string, statusCode: number, errorData?: JiraError) {
|
|
442
|
+
super(message);
|
|
443
|
+
this.name = 'JiraApiError';
|
|
444
|
+
this.statusCode = statusCode;
|
|
445
|
+
this.errors = errorData?.errors;
|
|
446
|
+
this.errorMessages = errorData?.errorMessages;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, rmSync } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
|
|
5
|
+
const CONNECTOR_NAME = 'connect-jira';
|
|
6
|
+
const DEFAULT_PROFILE = 'default';
|
|
7
|
+
|
|
8
|
+
export interface ProfileConfig {
|
|
9
|
+
email?: string;
|
|
10
|
+
apiToken?: string;
|
|
11
|
+
domain?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let profileOverride: string | undefined;
|
|
15
|
+
|
|
16
|
+
const CONFIG_DIR = join(homedir(), '.connect', CONNECTOR_NAME);
|
|
17
|
+
const PROFILES_DIR = join(CONFIG_DIR, 'profiles');
|
|
18
|
+
const CURRENT_PROFILE_FILE = join(CONFIG_DIR, 'current_profile');
|
|
19
|
+
|
|
20
|
+
export function setProfileOverride(profile: string | undefined): void {
|
|
21
|
+
profileOverride = profile;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function ensureConfigDir(): void {
|
|
25
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
26
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
if (!existsSync(PROFILES_DIR)) {
|
|
29
|
+
mkdirSync(PROFILES_DIR, { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getProfilePath(profile: string): string {
|
|
34
|
+
return join(PROFILES_DIR, `${profile}.json`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getCurrentProfile(): string {
|
|
38
|
+
if (profileOverride) {
|
|
39
|
+
return profileOverride;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
ensureConfigDir();
|
|
43
|
+
|
|
44
|
+
if (existsSync(CURRENT_PROFILE_FILE)) {
|
|
45
|
+
try {
|
|
46
|
+
const profile = readFileSync(CURRENT_PROFILE_FILE, 'utf-8').trim();
|
|
47
|
+
if (profile && profileExists(profile)) {
|
|
48
|
+
return profile;
|
|
49
|
+
}
|
|
50
|
+
} catch {
|
|
51
|
+
// Fall through to default
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return DEFAULT_PROFILE;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function setCurrentProfile(profile: string): void {
|
|
59
|
+
ensureConfigDir();
|
|
60
|
+
|
|
61
|
+
if (!profileExists(profile) && profile !== DEFAULT_PROFILE) {
|
|
62
|
+
throw new Error(`Profile "${profile}" does not exist`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
writeFileSync(CURRENT_PROFILE_FILE, profile);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function profileExists(profile: string): boolean {
|
|
69
|
+
return existsSync(getProfilePath(profile));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function listProfiles(): string[] {
|
|
73
|
+
ensureConfigDir();
|
|
74
|
+
|
|
75
|
+
if (!existsSync(PROFILES_DIR)) {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return readdirSync(PROFILES_DIR)
|
|
80
|
+
.filter(f => f.endsWith('.json'))
|
|
81
|
+
.map(f => f.replace('.json', ''))
|
|
82
|
+
.sort();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function createProfile(profile: string, config: ProfileConfig = {}): boolean {
|
|
86
|
+
ensureConfigDir();
|
|
87
|
+
|
|
88
|
+
if (profileExists(profile)) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(profile)) {
|
|
93
|
+
throw new Error('Profile name can only contain letters, numbers, hyphens, and underscores');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
writeFileSync(getProfilePath(profile), JSON.stringify(config, null, 2));
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function deleteProfile(profile: string): boolean {
|
|
101
|
+
if (profile === DEFAULT_PROFILE) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!profileExists(profile)) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (getCurrentProfile() === profile) {
|
|
110
|
+
setCurrentProfile(DEFAULT_PROFILE);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
rmSync(getProfilePath(profile));
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function loadProfile(profile?: string): ProfileConfig {
|
|
118
|
+
ensureConfigDir();
|
|
119
|
+
const profileName = profile || getCurrentProfile();
|
|
120
|
+
const profilePath = getProfilePath(profileName);
|
|
121
|
+
|
|
122
|
+
if (!existsSync(profilePath)) {
|
|
123
|
+
return {};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
return JSON.parse(readFileSync(profilePath, 'utf-8'));
|
|
128
|
+
} catch {
|
|
129
|
+
return {};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function saveProfile(config: ProfileConfig, profile?: string): void {
|
|
134
|
+
ensureConfigDir();
|
|
135
|
+
const profileName = profile || getCurrentProfile();
|
|
136
|
+
writeFileSync(getProfilePath(profileName), JSON.stringify(config, null, 2));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function getEmail(): string | undefined {
|
|
140
|
+
return process.env.JIRA_EMAIL || loadProfile().email;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function setEmail(email: string): void {
|
|
144
|
+
const config = loadProfile();
|
|
145
|
+
config.email = email;
|
|
146
|
+
saveProfile(config);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function getApiToken(): string | undefined {
|
|
150
|
+
return process.env.JIRA_API_TOKEN || loadProfile().apiToken;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function setApiToken(apiToken: string): void {
|
|
154
|
+
const config = loadProfile();
|
|
155
|
+
config.apiToken = apiToken;
|
|
156
|
+
saveProfile(config);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function getDomain(): string | undefined {
|
|
160
|
+
return process.env.JIRA_DOMAIN || loadProfile().domain;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function setDomain(domain: string): void {
|
|
164
|
+
const config = loadProfile();
|
|
165
|
+
config.domain = domain;
|
|
166
|
+
saveProfile(config);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function clearConfig(): void {
|
|
170
|
+
saveProfile({});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function getConfigDir(): string {
|
|
174
|
+
return CONFIG_DIR;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function getActiveProfileName(): string {
|
|
178
|
+
return getCurrentProfile();
|
|
179
|
+
}
|