panopticon-cli 0.4.32 → 0.5.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 (142) hide show
  1. package/README.md +96 -210
  2. package/dist/{agents-BDFHF4T3.js → agents-E43Y3HNU.js} +10 -7
  3. package/dist/chunk-7SN4L4PH.js +150 -0
  4. package/dist/chunk-7SN4L4PH.js.map +1 -0
  5. package/dist/{chunk-2NIAOCIC.js → chunk-AAFQANKW.js} +358 -97
  6. package/dist/chunk-AAFQANKW.js.map +1 -0
  7. package/dist/chunk-AQXETQHW.js +113 -0
  8. package/dist/chunk-AQXETQHW.js.map +1 -0
  9. package/dist/chunk-B3PF6JPQ.js +212 -0
  10. package/dist/chunk-B3PF6JPQ.js.map +1 -0
  11. package/dist/chunk-CFCUOV3Q.js +669 -0
  12. package/dist/chunk-CFCUOV3Q.js.map +1 -0
  13. package/dist/chunk-CWELWPWQ.js +32 -0
  14. package/dist/chunk-CWELWPWQ.js.map +1 -0
  15. package/dist/chunk-DI7ABPNQ.js +352 -0
  16. package/dist/chunk-DI7ABPNQ.js.map +1 -0
  17. package/dist/{chunk-VU4FLXV5.js → chunk-FQ66DECN.js} +31 -4
  18. package/dist/chunk-FQ66DECN.js.map +1 -0
  19. package/dist/{chunk-VIWUCJ4V.js → chunk-FTCPTHIJ.js} +57 -432
  20. package/dist/chunk-FTCPTHIJ.js.map +1 -0
  21. package/dist/{review-status-GWQYY77L.js → chunk-GFP3PIPB.js} +14 -7
  22. package/dist/chunk-GFP3PIPB.js.map +1 -0
  23. package/dist/chunk-GR6ZZMCX.js +816 -0
  24. package/dist/chunk-GR6ZZMCX.js.map +1 -0
  25. package/dist/chunk-HJSM6E6U.js +1038 -0
  26. package/dist/chunk-HJSM6E6U.js.map +1 -0
  27. package/dist/{chunk-XP2DXWYP.js → chunk-HZT2AOPN.js} +164 -39
  28. package/dist/chunk-HZT2AOPN.js.map +1 -0
  29. package/dist/chunk-JQBV3Q2W.js +29 -0
  30. package/dist/chunk-JQBV3Q2W.js.map +1 -0
  31. package/dist/{chunk-BWGFN44T.js → chunk-JT4O4YVM.js} +28 -16
  32. package/dist/chunk-JT4O4YVM.js.map +1 -0
  33. package/dist/chunk-NTO3EDB3.js +600 -0
  34. package/dist/chunk-NTO3EDB3.js.map +1 -0
  35. package/dist/{chunk-JY7R7V4G.js → chunk-OMNXYPXC.js} +2 -2
  36. package/dist/chunk-OMNXYPXC.js.map +1 -0
  37. package/dist/chunk-PELXV435.js +215 -0
  38. package/dist/chunk-PELXV435.js.map +1 -0
  39. package/dist/chunk-PPRFKTVC.js +154 -0
  40. package/dist/chunk-PPRFKTVC.js.map +1 -0
  41. package/dist/chunk-WQG2TYCB.js +677 -0
  42. package/dist/chunk-WQG2TYCB.js.map +1 -0
  43. package/dist/{chunk-HCTJFIJJ.js → chunk-YLPSQAM2.js} +2 -2
  44. package/dist/{chunk-HCTJFIJJ.js.map → chunk-YLPSQAM2.js.map} +1 -1
  45. package/dist/{chunk-6HXKTOD7.js → chunk-ZTFNYOC7.js} +53 -38
  46. package/dist/chunk-ZTFNYOC7.js.map +1 -0
  47. package/dist/cli/index.js +5103 -3165
  48. package/dist/cli/index.js.map +1 -1
  49. package/dist/{config-BOAMSKTF.js → config-4CJNUE3O.js} +7 -3
  50. package/dist/dashboard/prompts/merge-agent.md +217 -0
  51. package/dist/dashboard/prompts/review-agent.md +409 -0
  52. package/dist/dashboard/prompts/sync-main.md +84 -0
  53. package/dist/dashboard/prompts/test-agent.md +283 -0
  54. package/dist/dashboard/prompts/work-agent.md +249 -0
  55. package/dist/dashboard/public/assets/index-BxpjweAL.css +32 -0
  56. package/dist/dashboard/public/assets/index-DQHkwvvJ.js +743 -0
  57. package/dist/dashboard/public/index.html +2 -2
  58. package/dist/dashboard/server.js +17619 -4044
  59. package/dist/{dns-L3L2BB27.js → dns-7BDJSD3E.js} +4 -2
  60. package/dist/{feedback-writer-AAKF5BTK.js → feedback-writer-LVZ5TFYZ.js} +8 -4
  61. package/dist/feedback-writer-LVZ5TFYZ.js.map +1 -0
  62. package/dist/hume-WMAUBBV2.js +13 -0
  63. package/dist/index.d.ts +162 -40
  64. package/dist/index.js +67 -23
  65. package/dist/index.js.map +1 -1
  66. package/dist/{projects-VXRUCMLM.js → projects-JEIVIYC6.js} +3 -3
  67. package/dist/rally-RKFSWC7E.js +10 -0
  68. package/dist/{remote-agents-Z3R2A5BN.js → remote-agents-TFSMW7GN.js} +2 -2
  69. package/dist/{remote-workspace-2G6V2KNP.js → remote-workspace-AHVHQEES.js} +8 -8
  70. package/dist/review-status-EPFG4XM7.js +19 -0
  71. package/dist/shadow-state-5MDP6YXH.js +30 -0
  72. package/dist/shadow-state-5MDP6YXH.js.map +1 -0
  73. package/dist/{specialist-context-N32QBNNQ.js → specialist-context-ZC6A4M3I.js} +8 -7
  74. package/dist/{specialist-context-N32QBNNQ.js.map → specialist-context-ZC6A4M3I.js.map} +1 -1
  75. package/dist/{specialist-logs-GF3YV4KL.js → specialist-logs-KLGJCEUL.js} +7 -6
  76. package/dist/specialist-logs-KLGJCEUL.js.map +1 -0
  77. package/dist/{specialists-JBIW6MP4.js → specialists-O4HWDJL5.js} +7 -6
  78. package/dist/specialists-O4HWDJL5.js.map +1 -0
  79. package/dist/tldr-daemon-T3THOUGT.js +21 -0
  80. package/dist/tldr-daemon-T3THOUGT.js.map +1 -0
  81. package/dist/traefik-QN7R5I6V.js +19 -0
  82. package/dist/traefik-QN7R5I6V.js.map +1 -0
  83. package/dist/tunnel-W2GZBLEV.js +13 -0
  84. package/dist/tunnel-W2GZBLEV.js.map +1 -0
  85. package/dist/workspace-manager-IE4JL2JP.js +22 -0
  86. package/dist/workspace-manager-IE4JL2JP.js.map +1 -0
  87. package/package.json +2 -2
  88. package/scripts/heartbeat-hook +37 -10
  89. package/scripts/patches/llm-tldr-tsx-support.py +109 -0
  90. package/scripts/pre-tool-hook +26 -15
  91. package/scripts/record-cost-event.js +177 -43
  92. package/scripts/record-cost-event.ts +87 -3
  93. package/scripts/statusline.sh +169 -0
  94. package/scripts/stop-hook +21 -11
  95. package/scripts/tldr-post-edit +72 -0
  96. package/scripts/tldr-read-enforcer +275 -0
  97. package/scripts/work-agent-stop-hook +137 -0
  98. package/skills/check-merged/SKILL.md +143 -0
  99. package/skills/crash-investigation/SKILL.md +301 -0
  100. package/skills/github-cli/SKILL.md +185 -0
  101. package/skills/myn-standards/SKILL.md +351 -0
  102. package/skills/pan-reopen/SKILL.md +65 -0
  103. package/skills/pan-sync-main/SKILL.md +87 -0
  104. package/skills/pan-tldr/SKILL.md +149 -0
  105. package/skills/react-best-practices/SKILL.md +125 -0
  106. package/skills/spec-readiness/REPORT-TEMPLATE.md +158 -0
  107. package/skills/spec-readiness/SCORING-REFERENCE.md +369 -0
  108. package/skills/spec-readiness/SKILL.md +400 -0
  109. package/skills/spec-readiness-setup/SKILL.md +361 -0
  110. package/skills/workspace-status/SKILL.md +56 -0
  111. package/skills/write-spec/SKILL.md +138 -0
  112. package/templates/traefik/dynamic/panopticon.yml.template +0 -5
  113. package/templates/traefik/traefik.yml +0 -8
  114. package/dist/chunk-2NIAOCIC.js.map +0 -1
  115. package/dist/chunk-3XAB4IXF.js +0 -51
  116. package/dist/chunk-3XAB4IXF.js.map +0 -1
  117. package/dist/chunk-6HXKTOD7.js.map +0 -1
  118. package/dist/chunk-BBCUK6N2.js +0 -241
  119. package/dist/chunk-BBCUK6N2.js.map +0 -1
  120. package/dist/chunk-BWGFN44T.js.map +0 -1
  121. package/dist/chunk-ELK6Q7QI.js +0 -545
  122. package/dist/chunk-ELK6Q7QI.js.map +0 -1
  123. package/dist/chunk-JY7R7V4G.js.map +0 -1
  124. package/dist/chunk-LYSBSZYV.js +0 -1523
  125. package/dist/chunk-LYSBSZYV.js.map +0 -1
  126. package/dist/chunk-VIWUCJ4V.js.map +0 -1
  127. package/dist/chunk-VU4FLXV5.js.map +0 -1
  128. package/dist/chunk-XP2DXWYP.js.map +0 -1
  129. package/dist/dashboard/public/assets/index-C7X6LP5Z.css +0 -32
  130. package/dist/dashboard/public/assets/index-ClYqpcAJ.js +0 -645
  131. package/dist/feedback-writer-AAKF5BTK.js.map +0 -1
  132. package/dist/review-status-GWQYY77L.js.map +0 -1
  133. package/dist/traefik-CUJM6K5Z.js +0 -12
  134. /package/dist/{agents-BDFHF4T3.js.map → agents-E43Y3HNU.js.map} +0 -0
  135. /package/dist/{config-BOAMSKTF.js.map → config-4CJNUE3O.js.map} +0 -0
  136. /package/dist/{dns-L3L2BB27.js.map → dns-7BDJSD3E.js.map} +0 -0
  137. /package/dist/{projects-VXRUCMLM.js.map → hume-WMAUBBV2.js.map} +0 -0
  138. /package/dist/{remote-agents-Z3R2A5BN.js.map → projects-JEIVIYC6.js.map} +0 -0
  139. /package/dist/{specialist-logs-GF3YV4KL.js.map → rally-RKFSWC7E.js.map} +0 -0
  140. /package/dist/{specialists-JBIW6MP4.js.map → remote-agents-TFSMW7GN.js.map} +0 -0
  141. /package/dist/{remote-workspace-2G6V2KNP.js.map → remote-workspace-AHVHQEES.js.map} +0 -0
  142. /package/dist/{traefik-CUJM6K5Z.js.map → review-status-EPFG4XM7.js.map} +0 -0
@@ -0,0 +1,600 @@
1
+ import {
2
+ init_config_yaml,
3
+ loadConfig
4
+ } from "./chunk-HJSM6E6U.js";
5
+ import {
6
+ IssueNotFoundError,
7
+ NotImplementedError,
8
+ RallyTracker,
9
+ TrackerAuthError,
10
+ init_interface,
11
+ init_rally
12
+ } from "./chunk-CFCUOV3Q.js";
13
+ import {
14
+ __esm,
15
+ init_esm_shims
16
+ } from "./chunk-ZHC57RCV.js";
17
+
18
+ // src/lib/tracker/linear.ts
19
+ import { LinearClient } from "@linear/sdk";
20
+ var STATE_MAP, LinearTracker;
21
+ var init_linear = __esm({
22
+ "src/lib/tracker/linear.ts"() {
23
+ "use strict";
24
+ init_esm_shims();
25
+ init_interface();
26
+ STATE_MAP = {
27
+ backlog: "open",
28
+ unstarted: "open",
29
+ started: "in_progress",
30
+ completed: "closed",
31
+ canceled: "closed"
32
+ };
33
+ LinearTracker = class {
34
+ name = "linear";
35
+ client;
36
+ defaultTeam;
37
+ constructor(apiKey, options) {
38
+ if (!apiKey) {
39
+ throw new TrackerAuthError("linear", "API key is required");
40
+ }
41
+ this.client = new LinearClient({ apiKey });
42
+ this.defaultTeam = options?.team;
43
+ }
44
+ async listIssues(filters) {
45
+ const team = filters?.team ?? this.defaultTeam;
46
+ const result = await this.client.issues({
47
+ first: filters?.limit ?? 50,
48
+ filter: {
49
+ team: team ? { key: { eq: team } } : void 0,
50
+ state: filters?.state ? { type: { eq: this.reverseMapState(filters.state) } } : filters?.includeClosed ? void 0 : { type: { neq: "completed" } },
51
+ labels: filters?.labels?.length ? { name: { in: filters.labels } } : void 0,
52
+ assignee: filters?.assignee ? { name: { containsIgnoreCase: filters.assignee } } : void 0
53
+ }
54
+ });
55
+ const issues = [];
56
+ for (const node of result.nodes) {
57
+ issues.push(await this.normalizeIssue(node));
58
+ }
59
+ return issues;
60
+ }
61
+ async getIssue(id) {
62
+ try {
63
+ const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id);
64
+ if (isUuid) {
65
+ const issue = await this.client.issue(id);
66
+ if (issue) {
67
+ return this.normalizeIssue(issue);
68
+ }
69
+ } else {
70
+ const match = id.match(/^([A-Z]+)-(\d+)$/i);
71
+ if (match) {
72
+ const [, teamKey, number] = match;
73
+ const results = await this.client.searchIssues(id, { first: 1 });
74
+ if (results.nodes.length > 0) {
75
+ return this.normalizeIssue(results.nodes[0]);
76
+ }
77
+ }
78
+ }
79
+ throw new IssueNotFoundError(id, "linear");
80
+ } catch (error) {
81
+ if (error instanceof IssueNotFoundError) throw error;
82
+ throw new IssueNotFoundError(id, "linear");
83
+ }
84
+ }
85
+ async updateIssue(id, update) {
86
+ const issue = await this.getIssue(id);
87
+ const updatePayload = {};
88
+ if (update.title !== void 0) {
89
+ updatePayload.title = update.title;
90
+ }
91
+ if (update.description !== void 0) {
92
+ updatePayload.description = update.description;
93
+ }
94
+ if (update.priority !== void 0) {
95
+ updatePayload.priority = update.priority;
96
+ }
97
+ if (update.dueDate !== void 0) {
98
+ updatePayload.dueDate = update.dueDate;
99
+ }
100
+ if (update.state !== void 0) {
101
+ await this.transitionIssue(id, update.state);
102
+ }
103
+ if (update.labels !== void 0) {
104
+ }
105
+ if (Object.keys(updatePayload).length > 0) {
106
+ await this.client.updateIssue(issue.id, updatePayload);
107
+ }
108
+ return this.getIssue(id);
109
+ }
110
+ async createIssue(newIssue) {
111
+ const team = newIssue.team ?? this.defaultTeam;
112
+ if (!team) {
113
+ throw new Error("Team is required to create an issue");
114
+ }
115
+ const teams = await this.client.teams({
116
+ filter: { key: { eq: team } }
117
+ });
118
+ if (teams.nodes.length === 0) {
119
+ throw new Error(`Team not found: ${team}`);
120
+ }
121
+ const teamId = teams.nodes[0].id;
122
+ const result = await this.client.createIssue({
123
+ teamId,
124
+ title: newIssue.title,
125
+ description: newIssue.description,
126
+ priority: newIssue.priority,
127
+ dueDate: newIssue.dueDate
128
+ });
129
+ const created = await result.issue;
130
+ if (!created) {
131
+ throw new Error("Failed to create issue");
132
+ }
133
+ return this.normalizeIssue(created);
134
+ }
135
+ async getComments(issueId) {
136
+ const issue = await this.client.issue(issueId);
137
+ const comments = await issue.comments();
138
+ return comments.nodes.map((c) => ({
139
+ id: c.id,
140
+ issueId,
141
+ body: c.body,
142
+ author: c.user?.then((u) => u?.name ?? "Unknown"),
143
+ // Simplified
144
+ createdAt: c.createdAt.toISOString(),
145
+ updatedAt: c.updatedAt.toISOString()
146
+ }));
147
+ }
148
+ async addComment(issueId, body) {
149
+ const result = await this.client.createComment({
150
+ issueId,
151
+ body
152
+ });
153
+ const comment = await result.comment;
154
+ if (!comment) {
155
+ throw new Error("Failed to create comment");
156
+ }
157
+ return {
158
+ id: comment.id,
159
+ issueId,
160
+ body: comment.body,
161
+ author: "Panopticon",
162
+ // Simplified
163
+ createdAt: comment.createdAt.toISOString(),
164
+ updatedAt: comment.updatedAt.toISOString()
165
+ };
166
+ }
167
+ async transitionIssue(id, state) {
168
+ let linearIssue;
169
+ const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id);
170
+ if (isUuid) {
171
+ linearIssue = await this.client.issue(id);
172
+ } else {
173
+ const results = await this.client.searchIssues(id, { first: 1 });
174
+ if (results.nodes.length > 0) {
175
+ linearIssue = results.nodes[0];
176
+ } else {
177
+ throw new IssueNotFoundError(id, "linear");
178
+ }
179
+ }
180
+ const team = await linearIssue.team;
181
+ if (!team) {
182
+ throw new Error("Could not determine issue team");
183
+ }
184
+ const states = await team.states();
185
+ const targetStateType = this.reverseMapState(state);
186
+ const matchingStates = states.nodes.filter((s) => s.type === targetStateType).sort((a, b) => (a.position ?? 0) - (b.position ?? 0));
187
+ const targetState = matchingStates[0];
188
+ if (!targetState) {
189
+ throw new Error(`No state found matching type: ${targetStateType}`);
190
+ }
191
+ await this.client.updateIssue(linearIssue.id, {
192
+ stateId: targetState.id
193
+ });
194
+ }
195
+ async linkPR(issueId, prUrl) {
196
+ const issue = await this.getIssue(issueId);
197
+ await this.client.createAttachment({
198
+ issueId: issue.id,
199
+ title: "Pull Request",
200
+ url: prUrl
201
+ });
202
+ }
203
+ async normalizeIssue(linearIssue) {
204
+ const state = await linearIssue.state;
205
+ const assignee = await linearIssue.assignee;
206
+ const labels = await linearIssue.labels();
207
+ let dueDate;
208
+ if (linearIssue.dueDate) {
209
+ dueDate = linearIssue.dueDate instanceof Date ? linearIssue.dueDate.toISOString() : String(linearIssue.dueDate);
210
+ }
211
+ return {
212
+ id: linearIssue.id,
213
+ ref: linearIssue.identifier,
214
+ title: linearIssue.title,
215
+ description: linearIssue.description ?? "",
216
+ state: this.mapState(state?.type ?? "backlog"),
217
+ labels: labels?.nodes?.map((l) => l.name) ?? [],
218
+ assignee: assignee?.name,
219
+ url: linearIssue.url,
220
+ tracker: "linear",
221
+ priority: linearIssue.priority,
222
+ dueDate,
223
+ createdAt: linearIssue.createdAt instanceof Date ? linearIssue.createdAt.toISOString() : String(linearIssue.createdAt),
224
+ updatedAt: linearIssue.updatedAt instanceof Date ? linearIssue.updatedAt.toISOString() : String(linearIssue.updatedAt)
225
+ };
226
+ }
227
+ mapState(linearState) {
228
+ return STATE_MAP[linearState] ?? "open";
229
+ }
230
+ reverseMapState(state) {
231
+ switch (state) {
232
+ case "open":
233
+ return "unstarted";
234
+ case "in_progress":
235
+ return "started";
236
+ case "closed":
237
+ return "completed";
238
+ default:
239
+ return "unstarted";
240
+ }
241
+ }
242
+ };
243
+ }
244
+ });
245
+
246
+ // src/lib/tracker/github.ts
247
+ import { Octokit } from "@octokit/rest";
248
+ var GitHubTracker;
249
+ var init_github = __esm({
250
+ "src/lib/tracker/github.ts"() {
251
+ "use strict";
252
+ init_esm_shims();
253
+ init_interface();
254
+ GitHubTracker = class {
255
+ name = "github";
256
+ octokit;
257
+ owner;
258
+ repo;
259
+ constructor(token, owner, repo) {
260
+ if (!token) {
261
+ throw new TrackerAuthError("github", "Token is required");
262
+ }
263
+ if (!owner || !repo) {
264
+ throw new Error("GitHub owner and repo are required");
265
+ }
266
+ this.octokit = new Octokit({ auth: token });
267
+ this.owner = owner;
268
+ this.repo = repo;
269
+ }
270
+ async listIssues(filters) {
271
+ const state = this.mapStateToGitHub(filters?.state);
272
+ const response = await this.octokit.issues.listForRepo({
273
+ owner: this.owner,
274
+ repo: this.repo,
275
+ state: filters?.includeClosed ? "all" : state,
276
+ labels: filters?.labels?.join(",") || void 0,
277
+ assignee: filters?.assignee || void 0,
278
+ per_page: filters?.limit ?? 50
279
+ });
280
+ const issues = response.data.filter((item) => !item.pull_request);
281
+ return issues.map((issue) => this.normalizeIssue(issue));
282
+ }
283
+ async getIssue(id) {
284
+ try {
285
+ const issueNumber = parseInt(id.replace(/^#/, ""), 10);
286
+ if (isNaN(issueNumber)) {
287
+ throw new IssueNotFoundError(id, "github");
288
+ }
289
+ const { data: issue } = await this.octokit.issues.get({
290
+ owner: this.owner,
291
+ repo: this.repo,
292
+ issue_number: issueNumber
293
+ });
294
+ return this.normalizeIssue(issue);
295
+ } catch (error) {
296
+ if (error?.status === 404) {
297
+ throw new IssueNotFoundError(id, "github");
298
+ }
299
+ throw error;
300
+ }
301
+ }
302
+ async updateIssue(id, update) {
303
+ const issueNumber = parseInt(id.replace(/^#/, ""), 10);
304
+ const updatePayload = {};
305
+ if (update.title !== void 0) {
306
+ updatePayload.title = update.title;
307
+ }
308
+ if (update.description !== void 0) {
309
+ updatePayload.body = update.description;
310
+ }
311
+ if (update.state !== void 0) {
312
+ updatePayload.state = update.state === "closed" ? "closed" : "open";
313
+ }
314
+ if (update.labels !== void 0) {
315
+ updatePayload.labels = update.labels;
316
+ }
317
+ if (update.assignee !== void 0) {
318
+ updatePayload.assignees = update.assignee ? [update.assignee] : [];
319
+ }
320
+ await this.octokit.issues.update({
321
+ owner: this.owner,
322
+ repo: this.repo,
323
+ issue_number: issueNumber,
324
+ ...updatePayload
325
+ });
326
+ return this.getIssue(id);
327
+ }
328
+ async createIssue(newIssue) {
329
+ const { data: issue } = await this.octokit.issues.create({
330
+ owner: this.owner,
331
+ repo: this.repo,
332
+ title: newIssue.title,
333
+ body: newIssue.description,
334
+ labels: newIssue.labels,
335
+ assignees: newIssue.assignee ? [newIssue.assignee] : void 0
336
+ });
337
+ return this.normalizeIssue(issue);
338
+ }
339
+ async getComments(issueId) {
340
+ const issueNumber = parseInt(issueId.replace(/^#/, ""), 10);
341
+ const { data: comments } = await this.octokit.issues.listComments({
342
+ owner: this.owner,
343
+ repo: this.repo,
344
+ issue_number: issueNumber
345
+ });
346
+ return comments.map((c) => ({
347
+ id: String(c.id),
348
+ issueId,
349
+ body: c.body ?? "",
350
+ author: c.user?.login ?? "Unknown",
351
+ createdAt: c.created_at,
352
+ updatedAt: c.updated_at
353
+ }));
354
+ }
355
+ async addComment(issueId, body) {
356
+ const issueNumber = parseInt(issueId.replace(/^#/, ""), 10);
357
+ const { data: comment } = await this.octokit.issues.createComment({
358
+ owner: this.owner,
359
+ repo: this.repo,
360
+ issue_number: issueNumber,
361
+ body
362
+ });
363
+ return {
364
+ id: String(comment.id),
365
+ issueId,
366
+ body: comment.body ?? "",
367
+ author: comment.user?.login ?? "Unknown",
368
+ createdAt: comment.created_at,
369
+ updatedAt: comment.updated_at
370
+ };
371
+ }
372
+ async transitionIssue(id, state) {
373
+ await this.updateIssue(id, { state });
374
+ }
375
+ async linkPR(issueId, prUrl) {
376
+ await this.addComment(
377
+ issueId,
378
+ `Linked Pull Request: ${prUrl}`
379
+ );
380
+ }
381
+ normalizeIssue(ghIssue) {
382
+ return {
383
+ id: String(ghIssue.id),
384
+ ref: `#${ghIssue.number}`,
385
+ title: ghIssue.title,
386
+ description: ghIssue.body ?? "",
387
+ state: this.mapStateFromGitHub(ghIssue.state),
388
+ labels: ghIssue.labels.map(
389
+ (l) => typeof l === "string" ? l : l.name
390
+ ),
391
+ assignee: ghIssue.assignee?.login,
392
+ url: ghIssue.html_url,
393
+ tracker: "github",
394
+ priority: void 0,
395
+ // GitHub doesn't have priority
396
+ dueDate: void 0,
397
+ // GitHub doesn't have due dates on issues
398
+ createdAt: ghIssue.created_at,
399
+ updatedAt: ghIssue.updated_at
400
+ };
401
+ }
402
+ mapStateFromGitHub(ghState) {
403
+ return ghState === "closed" ? "closed" : "open";
404
+ }
405
+ mapStateToGitHub(state) {
406
+ if (!state) return "open";
407
+ if (state === "closed") return "closed";
408
+ return "open";
409
+ }
410
+ };
411
+ }
412
+ });
413
+
414
+ // src/lib/tracker/gitlab.ts
415
+ var GitLabTracker;
416
+ var init_gitlab = __esm({
417
+ "src/lib/tracker/gitlab.ts"() {
418
+ "use strict";
419
+ init_esm_shims();
420
+ init_interface();
421
+ GitLabTracker = class {
422
+ constructor(token, projectId) {
423
+ this.token = token;
424
+ this.projectId = projectId;
425
+ }
426
+ name = "gitlab";
427
+ async listIssues(_filters) {
428
+ throw new NotImplementedError(
429
+ "GitLab tracker is not yet implemented. Coming soon!"
430
+ );
431
+ }
432
+ async getIssue(_id) {
433
+ throw new NotImplementedError(
434
+ "GitLab tracker is not yet implemented. Coming soon!"
435
+ );
436
+ }
437
+ async updateIssue(_id, _update) {
438
+ throw new NotImplementedError(
439
+ "GitLab tracker is not yet implemented. Coming soon!"
440
+ );
441
+ }
442
+ async createIssue(_issue) {
443
+ throw new NotImplementedError(
444
+ "GitLab tracker is not yet implemented. Coming soon!"
445
+ );
446
+ }
447
+ async getComments(_issueId) {
448
+ throw new NotImplementedError(
449
+ "GitLab tracker is not yet implemented. Coming soon!"
450
+ );
451
+ }
452
+ async addComment(_issueId, _body) {
453
+ throw new NotImplementedError(
454
+ "GitLab tracker is not yet implemented. Coming soon!"
455
+ );
456
+ }
457
+ async transitionIssue(_id, _state) {
458
+ throw new NotImplementedError(
459
+ "GitLab tracker is not yet implemented. Coming soon!"
460
+ );
461
+ }
462
+ async linkPR(_issueId, _prUrl) {
463
+ throw new NotImplementedError(
464
+ "GitLab tracker is not yet implemented. Coming soon!"
465
+ );
466
+ }
467
+ };
468
+ }
469
+ });
470
+
471
+ // src/lib/tracker/factory.ts
472
+ function getTrackerKeyFromConfig(trackerType) {
473
+ try {
474
+ const { config: yamlConfig } = loadConfig();
475
+ return yamlConfig.trackerKeys[trackerType];
476
+ } catch {
477
+ return void 0;
478
+ }
479
+ }
480
+ function createTracker(config) {
481
+ switch (config.type) {
482
+ case "linear": {
483
+ const configKey = getTrackerKeyFromConfig("linear");
484
+ const envKey = config.apiKeyEnv ? process.env[config.apiKeyEnv] : process.env.LINEAR_API_KEY;
485
+ const apiKey = configKey || envKey;
486
+ if (!apiKey) {
487
+ throw new TrackerAuthError(
488
+ "linear",
489
+ `API key not found. Configure in Settings or set ${config.apiKeyEnv ?? "LINEAR_API_KEY"} environment variable.`
490
+ );
491
+ }
492
+ return new LinearTracker(apiKey, { team: config.team });
493
+ }
494
+ case "github": {
495
+ const configKey = getTrackerKeyFromConfig("github");
496
+ const envToken = config.tokenEnv ? process.env[config.tokenEnv] : process.env.GITHUB_TOKEN;
497
+ const token = configKey || envToken;
498
+ if (!token) {
499
+ throw new TrackerAuthError(
500
+ "github",
501
+ `Token not found. Configure in Settings or set ${config.tokenEnv ?? "GITHUB_TOKEN"} environment variable.`
502
+ );
503
+ }
504
+ if (!config.owner || !config.repo) {
505
+ throw new Error(
506
+ "GitHub tracker requires owner and repo configuration"
507
+ );
508
+ }
509
+ return new GitHubTracker(token, config.owner, config.repo);
510
+ }
511
+ case "gitlab": {
512
+ const configKey = getTrackerKeyFromConfig("gitlab");
513
+ const envToken = config.tokenEnv ? process.env[config.tokenEnv] : process.env.GITLAB_TOKEN;
514
+ const token = configKey || envToken;
515
+ if (!token) {
516
+ throw new TrackerAuthError(
517
+ "gitlab",
518
+ `Token not found. Configure in Settings or set ${config.tokenEnv ?? "GITLAB_TOKEN"} environment variable.`
519
+ );
520
+ }
521
+ if (!config.projectId) {
522
+ throw new Error("GitLab tracker requires projectId configuration");
523
+ }
524
+ return new GitLabTracker(token, config.projectId);
525
+ }
526
+ case "rally": {
527
+ const configKey = getTrackerKeyFromConfig("rally");
528
+ const envKey = config.apiKeyEnv ? process.env[config.apiKeyEnv] : process.env.RALLY_API_KEY;
529
+ const apiKey = configKey || envKey;
530
+ if (!apiKey) {
531
+ throw new TrackerAuthError(
532
+ "rally",
533
+ `API key not found. Configure in Settings or set ${config.apiKeyEnv ?? "RALLY_API_KEY"} environment variable.`
534
+ );
535
+ }
536
+ return new RallyTracker({
537
+ apiKey,
538
+ server: config.server,
539
+ workspace: config.workspace,
540
+ project: config.project
541
+ });
542
+ }
543
+ default:
544
+ throw new Error(`Unknown tracker type: ${config.type}`);
545
+ }
546
+ }
547
+ function createTrackerFromConfig(trackersConfig, trackerType) {
548
+ const config = trackersConfig[trackerType];
549
+ if (!config) {
550
+ throw new Error(
551
+ `No configuration found for tracker: ${trackerType}. Add [trackers.${trackerType}] to config.`
552
+ );
553
+ }
554
+ return createTracker({ ...config, type: trackerType });
555
+ }
556
+ function getPrimaryTracker(trackersConfig) {
557
+ return createTrackerFromConfig(trackersConfig, trackersConfig.primary);
558
+ }
559
+ function getSecondaryTracker(trackersConfig) {
560
+ if (!trackersConfig.secondary) {
561
+ return null;
562
+ }
563
+ return createTrackerFromConfig(trackersConfig, trackersConfig.secondary);
564
+ }
565
+ function getAllTrackers(trackersConfig) {
566
+ const trackers = [getPrimaryTracker(trackersConfig)];
567
+ const secondary = getSecondaryTracker(trackersConfig);
568
+ if (secondary) {
569
+ trackers.push(secondary);
570
+ }
571
+ return trackers;
572
+ }
573
+ var init_factory = __esm({
574
+ "src/lib/tracker/factory.ts"() {
575
+ "use strict";
576
+ init_esm_shims();
577
+ init_interface();
578
+ init_linear();
579
+ init_github();
580
+ init_gitlab();
581
+ init_rally();
582
+ init_config_yaml();
583
+ }
584
+ });
585
+
586
+ export {
587
+ LinearTracker,
588
+ init_linear,
589
+ GitHubTracker,
590
+ init_github,
591
+ GitLabTracker,
592
+ init_gitlab,
593
+ createTracker,
594
+ createTrackerFromConfig,
595
+ getPrimaryTracker,
596
+ getSecondaryTracker,
597
+ getAllTrackers,
598
+ init_factory
599
+ };
600
+ //# sourceMappingURL=chunk-NTO3EDB3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/tracker/linear.ts","../src/lib/tracker/github.ts","../src/lib/tracker/gitlab.ts","../src/lib/tracker/factory.ts"],"sourcesContent":["/**\n * Linear Issue Tracker Adapter\n *\n * Implements IssueTracker interface for Linear.\n */\n\nimport { LinearClient } from '@linear/sdk';\nimport type {\n Issue,\n IssueFilters,\n IssueState,\n IssueTracker,\n IssueUpdate,\n NewIssue,\n Comment,\n TrackerType,\n} from './interface.js';\nimport { IssueNotFoundError, TrackerAuthError } from './interface.js';\n\n// Map Linear state types to our normalized states\nconst STATE_MAP: Record<string, IssueState> = {\n backlog: 'open',\n unstarted: 'open',\n started: 'in_progress',\n completed: 'closed',\n canceled: 'closed',\n};\n\nexport class LinearTracker implements IssueTracker {\n readonly name: TrackerType = 'linear';\n private client: LinearClient;\n private defaultTeam?: string;\n\n constructor(apiKey: string, options?: { team?: string }) {\n if (!apiKey) {\n throw new TrackerAuthError('linear', 'API key is required');\n }\n this.client = new LinearClient({ apiKey });\n this.defaultTeam = options?.team;\n }\n\n async listIssues(filters?: IssueFilters): Promise<Issue[]> {\n const team = filters?.team ?? this.defaultTeam;\n\n const result = await this.client.issues({\n first: filters?.limit ?? 50,\n filter: {\n team: team ? { key: { eq: team } } : undefined,\n state: filters?.state\n ? { type: { eq: this.reverseMapState(filters.state) } }\n : filters?.includeClosed\n ? undefined\n : { type: { neq: 'completed' } },\n labels: filters?.labels?.length\n ? { name: { in: filters.labels } }\n : undefined,\n assignee: filters?.assignee\n ? { name: { containsIgnoreCase: filters.assignee } }\n : undefined,\n },\n });\n\n const issues: Issue[] = [];\n for (const node of result.nodes) {\n issues.push(await this.normalizeIssue(node));\n }\n return issues;\n }\n\n async getIssue(id: string): Promise<Issue> {\n try {\n // Check if it's a UUID (36 chars with hyphens)\n const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id);\n\n if (isUuid) {\n // Fetch directly by UUID\n const issue = await this.client.issue(id);\n if (issue) {\n return this.normalizeIssue(issue);\n }\n } else {\n // Parse identifier (e.g., MIN-630) and search\n const match = id.match(/^([A-Z]+)-(\\d+)$/i);\n if (match) {\n const [, teamKey, number] = match;\n // Use searchIssues which supports identifier matching\n const results = await this.client.searchIssues(id, { first: 1 });\n if (results.nodes.length > 0) {\n return this.normalizeIssue(results.nodes[0]);\n }\n }\n }\n\n throw new IssueNotFoundError(id, 'linear');\n } catch (error) {\n if (error instanceof IssueNotFoundError) throw error;\n throw new IssueNotFoundError(id, 'linear');\n }\n }\n\n async updateIssue(id: string, update: IssueUpdate): Promise<Issue> {\n const issue = await this.getIssue(id);\n\n const updatePayload: Record<string, unknown> = {};\n\n if (update.title !== undefined) {\n updatePayload.title = update.title;\n }\n if (update.description !== undefined) {\n updatePayload.description = update.description;\n }\n if (update.priority !== undefined) {\n updatePayload.priority = update.priority;\n }\n if (update.dueDate !== undefined) {\n updatePayload.dueDate = update.dueDate;\n }\n if (update.state !== undefined) {\n // Need to find the state ID - this is complex in Linear\n // For now, we'll use the transition method\n await this.transitionIssue(id, update.state);\n }\n if (update.labels !== undefined) {\n // Need to look up label IDs - complex operation\n // TODO: Implement label updates\n }\n\n if (Object.keys(updatePayload).length > 0) {\n await this.client.updateIssue(issue.id, updatePayload);\n }\n\n return this.getIssue(id);\n }\n\n async createIssue(newIssue: NewIssue): Promise<Issue> {\n const team = newIssue.team ?? this.defaultTeam;\n\n if (!team) {\n throw new Error('Team is required to create an issue');\n }\n\n // Get team ID from key\n const teams = await this.client.teams({\n filter: { key: { eq: team } },\n });\n\n if (teams.nodes.length === 0) {\n throw new Error(`Team not found: ${team}`);\n }\n\n const teamId = teams.nodes[0].id;\n\n const result = await this.client.createIssue({\n teamId,\n title: newIssue.title,\n description: newIssue.description,\n priority: newIssue.priority,\n dueDate: newIssue.dueDate,\n });\n\n const created = await result.issue;\n if (!created) {\n throw new Error('Failed to create issue');\n }\n\n return this.normalizeIssue(created);\n }\n\n async getComments(issueId: string): Promise<Comment[]> {\n const issue = await this.client.issue(issueId);\n const comments = await issue.comments();\n\n return comments.nodes.map((c) => ({\n id: c.id,\n issueId,\n body: c.body,\n author: c.user?.then((u) => u?.name ?? 'Unknown') as unknown as string, // Simplified\n createdAt: c.createdAt.toISOString(),\n updatedAt: c.updatedAt.toISOString(),\n }));\n }\n\n async addComment(issueId: string, body: string): Promise<Comment> {\n const result = await this.client.createComment({\n issueId,\n body,\n });\n\n const comment = await result.comment;\n if (!comment) {\n throw new Error('Failed to create comment');\n }\n\n return {\n id: comment.id,\n issueId,\n body: comment.body,\n author: 'Panopticon', // Simplified\n createdAt: comment.createdAt.toISOString(),\n updatedAt: comment.updatedAt.toISOString(),\n };\n }\n\n async transitionIssue(id: string, state: IssueState): Promise<void> {\n // Resolve the Linear issue directly (avoid normalizeIssue which may fail on SDK edge cases)\n let linearIssue: any;\n const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id);\n if (isUuid) {\n linearIssue = await this.client.issue(id);\n } else {\n const results = await this.client.searchIssues(id, { first: 1 });\n if (results.nodes.length > 0) {\n linearIssue = results.nodes[0];\n } else {\n throw new IssueNotFoundError(id, 'linear');\n }\n }\n\n // Get workflow states for the issue's team\n const team = await linearIssue.team;\n if (!team) {\n throw new Error('Could not determine issue team');\n }\n\n const states = await team.states();\n const targetStateType = this.reverseMapState(state);\n\n // Find a state matching the target type.\n // Multiple states can share the same type (e.g., \"In Planning\", \"In Progress\", \"In Review\"\n // are all type \"started\"). Prefer the one with the lowest position (most basic/default state\n // for that type), which matches Linear's convention.\n const matchingStates = states.nodes\n .filter((s: any) => s.type === targetStateType)\n .sort((a: any, b: any) => (a.position ?? 0) - (b.position ?? 0));\n const targetState = matchingStates[0];\n if (!targetState) {\n throw new Error(`No state found matching type: ${targetStateType}`);\n }\n\n await this.client.updateIssue(linearIssue.id, {\n stateId: targetState.id,\n });\n }\n\n async linkPR(issueId: string, prUrl: string): Promise<void> {\n const issue = await this.getIssue(issueId);\n\n await this.client.createAttachment({\n issueId: issue.id,\n title: 'Pull Request',\n url: prUrl,\n });\n }\n\n private async normalizeIssue(linearIssue: any): Promise<Issue> {\n const state = await linearIssue.state;\n const assignee = await linearIssue.assignee;\n const labels = await linearIssue.labels();\n\n // Handle dueDate - can be Date, string, or undefined\n let dueDate: string | undefined;\n if (linearIssue.dueDate) {\n dueDate = linearIssue.dueDate instanceof Date\n ? linearIssue.dueDate.toISOString()\n : String(linearIssue.dueDate);\n }\n\n return {\n id: linearIssue.id,\n ref: linearIssue.identifier,\n title: linearIssue.title,\n description: linearIssue.description ?? '',\n state: this.mapState(state?.type ?? 'backlog'),\n labels: labels?.nodes?.map((l: any) => l.name) ?? [],\n assignee: assignee?.name,\n url: linearIssue.url,\n tracker: 'linear',\n priority: linearIssue.priority,\n dueDate,\n createdAt: linearIssue.createdAt instanceof Date\n ? linearIssue.createdAt.toISOString()\n : String(linearIssue.createdAt),\n updatedAt: linearIssue.updatedAt instanceof Date\n ? linearIssue.updatedAt.toISOString()\n : String(linearIssue.updatedAt),\n };\n }\n\n private mapState(linearState: string): IssueState {\n return STATE_MAP[linearState] ?? 'open';\n }\n\n private reverseMapState(state: IssueState): string {\n switch (state) {\n case 'open':\n return 'unstarted';\n case 'in_progress':\n return 'started';\n case 'closed':\n return 'completed';\n default:\n return 'unstarted';\n }\n }\n}\n","/**\n * GitHub Issues Tracker Adapter\n *\n * Implements IssueTracker interface for GitHub Issues.\n */\n\nimport { Octokit } from '@octokit/rest';\nimport type {\n Issue,\n IssueFilters,\n IssueState,\n IssueTracker,\n IssueUpdate,\n NewIssue,\n Comment,\n TrackerType,\n} from './interface.js';\nimport { IssueNotFoundError, TrackerAuthError } from './interface.js';\n\nexport class GitHubTracker implements IssueTracker {\n readonly name: TrackerType = 'github';\n private octokit: Octokit;\n private owner: string;\n private repo: string;\n\n constructor(token: string, owner: string, repo: string) {\n if (!token) {\n throw new TrackerAuthError('github', 'Token is required');\n }\n if (!owner || !repo) {\n throw new Error('GitHub owner and repo are required');\n }\n\n this.octokit = new Octokit({ auth: token });\n this.owner = owner;\n this.repo = repo;\n }\n\n async listIssues(filters?: IssueFilters): Promise<Issue[]> {\n const state = this.mapStateToGitHub(filters?.state);\n\n const response = await this.octokit.issues.listForRepo({\n owner: this.owner,\n repo: this.repo,\n state: filters?.includeClosed ? 'all' : state,\n labels: filters?.labels?.join(',') || undefined,\n assignee: filters?.assignee || undefined,\n per_page: filters?.limit ?? 50,\n });\n\n // Filter out pull requests (GitHub API returns both)\n const issues = response.data.filter((item) => !item.pull_request);\n\n return issues.map((issue) => this.normalizeIssue(issue));\n }\n\n async getIssue(id: string): Promise<Issue> {\n try {\n // Parse the issue number from refs like \"#42\" or just \"42\"\n const issueNumber = parseInt(id.replace(/^#/, ''), 10);\n\n if (isNaN(issueNumber)) {\n throw new IssueNotFoundError(id, 'github');\n }\n\n const { data: issue } = await this.octokit.issues.get({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n });\n\n return this.normalizeIssue(issue);\n } catch (error: any) {\n if (error?.status === 404) {\n throw new IssueNotFoundError(id, 'github');\n }\n throw error;\n }\n }\n\n async updateIssue(id: string, update: IssueUpdate): Promise<Issue> {\n const issueNumber = parseInt(id.replace(/^#/, ''), 10);\n\n const updatePayload: Record<string, unknown> = {};\n\n if (update.title !== undefined) {\n updatePayload.title = update.title;\n }\n if (update.description !== undefined) {\n updatePayload.body = update.description;\n }\n if (update.state !== undefined) {\n updatePayload.state = update.state === 'closed' ? 'closed' : 'open';\n }\n if (update.labels !== undefined) {\n updatePayload.labels = update.labels;\n }\n if (update.assignee !== undefined) {\n updatePayload.assignees = update.assignee ? [update.assignee] : [];\n }\n\n await this.octokit.issues.update({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n ...updatePayload,\n });\n\n return this.getIssue(id);\n }\n\n async createIssue(newIssue: NewIssue): Promise<Issue> {\n const { data: issue } = await this.octokit.issues.create({\n owner: this.owner,\n repo: this.repo,\n title: newIssue.title,\n body: newIssue.description,\n labels: newIssue.labels,\n assignees: newIssue.assignee ? [newIssue.assignee] : undefined,\n });\n\n return this.normalizeIssue(issue);\n }\n\n async getComments(issueId: string): Promise<Comment[]> {\n const issueNumber = parseInt(issueId.replace(/^#/, ''), 10);\n\n const { data: comments } = await this.octokit.issues.listComments({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n });\n\n return comments.map((c) => ({\n id: String(c.id),\n issueId,\n body: c.body ?? '',\n author: c.user?.login ?? 'Unknown',\n createdAt: c.created_at,\n updatedAt: c.updated_at,\n }));\n }\n\n async addComment(issueId: string, body: string): Promise<Comment> {\n const issueNumber = parseInt(issueId.replace(/^#/, ''), 10);\n\n const { data: comment } = await this.octokit.issues.createComment({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n body,\n });\n\n return {\n id: String(comment.id),\n issueId,\n body: comment.body ?? '',\n author: comment.user?.login ?? 'Unknown',\n createdAt: comment.created_at,\n updatedAt: comment.updated_at,\n };\n }\n\n async transitionIssue(id: string, state: IssueState): Promise<void> {\n await this.updateIssue(id, { state });\n }\n\n async linkPR(issueId: string, prUrl: string): Promise<void> {\n // GitHub auto-links PRs that mention issues\n // Add a comment with the PR link\n await this.addComment(\n issueId,\n `Linked Pull Request: ${prUrl}`\n );\n }\n\n private normalizeIssue(ghIssue: any): Issue {\n return {\n id: String(ghIssue.id),\n ref: `#${ghIssue.number}`,\n title: ghIssue.title,\n description: ghIssue.body ?? '',\n state: this.mapStateFromGitHub(ghIssue.state),\n labels: ghIssue.labels.map((l: any) =>\n typeof l === 'string' ? l : l.name\n ),\n assignee: ghIssue.assignee?.login,\n url: ghIssue.html_url,\n tracker: 'github',\n priority: undefined, // GitHub doesn't have priority\n dueDate: undefined, // GitHub doesn't have due dates on issues\n createdAt: ghIssue.created_at,\n updatedAt: ghIssue.updated_at,\n };\n }\n\n private mapStateFromGitHub(ghState: string): IssueState {\n // GitHub only has open and closed states\n // No way to distinguish \"in_progress\" without custom labels\n return ghState === 'closed' ? 'closed' : 'open';\n }\n\n private mapStateToGitHub(\n state?: IssueState\n ): 'open' | 'closed' | 'all' {\n if (!state) return 'open';\n if (state === 'closed') return 'closed';\n return 'open'; // Both 'open' and 'in_progress' map to 'open'\n }\n}\n","/**\n * GitLab Issues Tracker Adapter (Stub)\n *\n * Placeholder implementation for GitLab Issues support.\n * Full implementation will use @gitbeaker/rest.\n */\n\nimport type {\n Issue,\n IssueFilters,\n IssueState,\n IssueTracker,\n IssueUpdate,\n NewIssue,\n Comment,\n TrackerType,\n} from './interface.js';\nimport { NotImplementedError } from './interface.js';\n\nexport class GitLabTracker implements IssueTracker {\n readonly name: TrackerType = 'gitlab';\n\n constructor(\n private token: string,\n private projectId: string\n ) {\n // Stub - will initialize @gitbeaker client when implemented\n }\n\n async listIssues(_filters?: IssueFilters): Promise<Issue[]> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async getIssue(_id: string): Promise<Issue> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async updateIssue(_id: string, _update: IssueUpdate): Promise<Issue> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async createIssue(_issue: NewIssue): Promise<Issue> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async getComments(_issueId: string): Promise<Comment[]> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async addComment(_issueId: string, _body: string): Promise<Comment> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async transitionIssue(_id: string, _state: IssueState): Promise<void> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async linkPR(_issueId: string, _prUrl: string): Promise<void> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n}\n","/**\n * Tracker Factory\n *\n * Creates appropriate tracker instances based on configuration.\n */\n\nimport type { IssueTracker, TrackerType } from './interface.js';\nimport { TrackerAuthError } from './interface.js';\nimport { LinearTracker } from './linear.js';\nimport { GitHubTracker } from './github.js';\nimport { GitLabTracker } from './gitlab.js';\nimport { RallyTracker } from './rally.js';\nimport type { TrackersConfig } from '../config.js';\nimport { loadConfig as loadYamlConfig } from '../config-yaml.js';\n\n// Configuration for a single tracker\nexport interface TrackerConfig {\n type: TrackerType;\n\n // Linear-specific\n apiKeyEnv?: string;\n team?: string;\n\n // GitHub-specific\n tokenEnv?: string;\n owner?: string;\n repo?: string;\n\n // GitLab-specific\n projectId?: string;\n\n // Rally-specific\n server?: string;\n workspace?: string;\n project?: string;\n}\n\n// Multi-tracker configuration (re-exported from config.ts)\n// Note: Use TrackersConfig from config.ts for full type with nested configs\n\n/**\n * Get tracker API key from config.yaml (Settings page).\n * This is checked FIRST — env vars are the fallback, not the other way around.\n */\nfunction getTrackerKeyFromConfig(trackerType: TrackerType): string | undefined {\n try {\n const { config: yamlConfig } = loadYamlConfig();\n return yamlConfig.trackerKeys[trackerType];\n } catch {\n return undefined;\n }\n}\n\n/**\n * Create a tracker instance from configuration.\n * Priority: config.yaml (Settings) > environment variable > custom env var name\n */\nexport function createTracker(config: TrackerConfig): IssueTracker {\n switch (config.type) {\n case 'linear': {\n const configKey = getTrackerKeyFromConfig('linear');\n const envKey = config.apiKeyEnv\n ? process.env[config.apiKeyEnv]\n : process.env.LINEAR_API_KEY;\n const apiKey = configKey || envKey;\n\n if (!apiKey) {\n throw new TrackerAuthError(\n 'linear',\n `API key not found. Configure in Settings or set ${config.apiKeyEnv ?? 'LINEAR_API_KEY'} environment variable.`\n );\n }\n\n return new LinearTracker(apiKey, { team: config.team });\n }\n\n case 'github': {\n const configKey = getTrackerKeyFromConfig('github');\n const envToken = config.tokenEnv\n ? process.env[config.tokenEnv]\n : process.env.GITHUB_TOKEN;\n const token = configKey || envToken;\n\n if (!token) {\n throw new TrackerAuthError(\n 'github',\n `Token not found. Configure in Settings or set ${config.tokenEnv ?? 'GITHUB_TOKEN'} environment variable.`\n );\n }\n\n if (!config.owner || !config.repo) {\n throw new Error(\n 'GitHub tracker requires owner and repo configuration'\n );\n }\n\n return new GitHubTracker(token, config.owner, config.repo);\n }\n\n case 'gitlab': {\n const configKey = getTrackerKeyFromConfig('gitlab');\n const envToken = config.tokenEnv\n ? process.env[config.tokenEnv]\n : process.env.GITLAB_TOKEN;\n const token = configKey || envToken;\n\n if (!token) {\n throw new TrackerAuthError(\n 'gitlab',\n `Token not found. Configure in Settings or set ${config.tokenEnv ?? 'GITLAB_TOKEN'} environment variable.`\n );\n }\n\n if (!config.projectId) {\n throw new Error('GitLab tracker requires projectId configuration');\n }\n\n return new GitLabTracker(token, config.projectId);\n }\n\n case 'rally': {\n const configKey = getTrackerKeyFromConfig('rally');\n const envKey = config.apiKeyEnv\n ? process.env[config.apiKeyEnv]\n : process.env.RALLY_API_KEY;\n const apiKey = configKey || envKey;\n\n if (!apiKey) {\n throw new TrackerAuthError(\n 'rally',\n `API key not found. Configure in Settings or set ${config.apiKeyEnv ?? 'RALLY_API_KEY'} environment variable.`\n );\n }\n\n return new RallyTracker({\n apiKey,\n server: config.server,\n workspace: config.workspace,\n project: config.project,\n });\n }\n\n default:\n throw new Error(`Unknown tracker type: ${config.type}`);\n }\n}\n\n/**\n * Create tracker from trackers configuration section\n */\nexport function createTrackerFromConfig(\n trackersConfig: TrackersConfig,\n trackerType: TrackerType\n): IssueTracker {\n const config = trackersConfig[trackerType];\n\n if (!config) {\n throw new Error(\n `No configuration found for tracker: ${trackerType}. Add [trackers.${trackerType}] to config.`\n );\n }\n\n return createTracker({ ...config, type: trackerType });\n}\n\n/**\n * Get the primary tracker from configuration\n */\nexport function getPrimaryTracker(trackersConfig: TrackersConfig): IssueTracker {\n return createTrackerFromConfig(trackersConfig, trackersConfig.primary);\n}\n\n/**\n * Get the secondary tracker from configuration (if configured)\n */\nexport function getSecondaryTracker(\n trackersConfig: TrackersConfig\n): IssueTracker | null {\n if (!trackersConfig.secondary) {\n return null;\n }\n return createTrackerFromConfig(trackersConfig, trackersConfig.secondary);\n}\n\n/**\n * Get all configured trackers\n */\nexport function getAllTrackers(trackersConfig: TrackersConfig): IssueTracker[] {\n const trackers: IssueTracker[] = [getPrimaryTracker(trackersConfig)];\n\n const secondary = getSecondaryTracker(trackersConfig);\n if (secondary) {\n trackers.push(secondary);\n }\n\n return trackers;\n}\n"],"mappings":"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","names":[]}