claude-autopm 2.7.0 → 2.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) hide show
  1. package/README.md +307 -56
  2. package/autopm/.claude/.env +158 -0
  3. package/autopm/.claude/settings.local.json +9 -0
  4. package/bin/autopm.js +11 -2
  5. package/bin/commands/epic.js +23 -3
  6. package/bin/commands/plugin.js +395 -0
  7. package/bin/commands/team.js +184 -10
  8. package/install/install.js +223 -4
  9. package/lib/cli/commands/issue.js +360 -20
  10. package/lib/plugins/PluginManager.js +1328 -0
  11. package/lib/plugins/PluginManager.old.js +400 -0
  12. package/lib/providers/AzureDevOpsProvider.js +575 -0
  13. package/lib/providers/GitHubProvider.js +475 -0
  14. package/lib/services/EpicService.js +1092 -3
  15. package/lib/services/IssueService.js +991 -0
  16. package/package.json +9 -1
  17. package/scripts/publish-plugins.sh +166 -0
  18. package/autopm/.claude/agents/cloud/README.md +0 -55
  19. package/autopm/.claude/agents/cloud/aws-cloud-architect.md +0 -521
  20. package/autopm/.claude/agents/cloud/azure-cloud-architect.md +0 -436
  21. package/autopm/.claude/agents/cloud/gcp-cloud-architect.md +0 -385
  22. package/autopm/.claude/agents/cloud/gcp-cloud-functions-engineer.md +0 -306
  23. package/autopm/.claude/agents/cloud/gemini-api-expert.md +0 -880
  24. package/autopm/.claude/agents/cloud/kubernetes-orchestrator.md +0 -566
  25. package/autopm/.claude/agents/cloud/openai-python-expert.md +0 -1087
  26. package/autopm/.claude/agents/cloud/terraform-infrastructure-expert.md +0 -454
  27. package/autopm/.claude/agents/core/agent-manager.md +0 -296
  28. package/autopm/.claude/agents/core/code-analyzer.md +0 -131
  29. package/autopm/.claude/agents/core/file-analyzer.md +0 -162
  30. package/autopm/.claude/agents/core/test-runner.md +0 -200
  31. package/autopm/.claude/agents/data/airflow-orchestration-expert.md +0 -52
  32. package/autopm/.claude/agents/data/kedro-pipeline-expert.md +0 -50
  33. package/autopm/.claude/agents/data/langgraph-workflow-expert.md +0 -520
  34. package/autopm/.claude/agents/databases/README.md +0 -50
  35. package/autopm/.claude/agents/databases/bigquery-expert.md +0 -392
  36. package/autopm/.claude/agents/databases/cosmosdb-expert.md +0 -368
  37. package/autopm/.claude/agents/databases/mongodb-expert.md +0 -398
  38. package/autopm/.claude/agents/databases/postgresql-expert.md +0 -321
  39. package/autopm/.claude/agents/databases/redis-expert.md +0 -52
  40. package/autopm/.claude/agents/devops/README.md +0 -52
  41. package/autopm/.claude/agents/devops/azure-devops-specialist.md +0 -308
  42. package/autopm/.claude/agents/devops/docker-containerization-expert.md +0 -298
  43. package/autopm/.claude/agents/devops/github-operations-specialist.md +0 -335
  44. package/autopm/.claude/agents/devops/mcp-context-manager.md +0 -319
  45. package/autopm/.claude/agents/devops/observability-engineer.md +0 -574
  46. package/autopm/.claude/agents/devops/ssh-operations-expert.md +0 -1093
  47. package/autopm/.claude/agents/devops/traefik-proxy-expert.md +0 -444
  48. package/autopm/.claude/agents/frameworks/README.md +0 -64
  49. package/autopm/.claude/agents/frameworks/e2e-test-engineer.md +0 -360
  50. package/autopm/.claude/agents/frameworks/nats-messaging-expert.md +0 -254
  51. package/autopm/.claude/agents/frameworks/react-frontend-engineer.md +0 -217
  52. package/autopm/.claude/agents/frameworks/react-ui-expert.md +0 -226
  53. package/autopm/.claude/agents/frameworks/tailwindcss-expert.md +0 -770
  54. package/autopm/.claude/agents/frameworks/ux-design-expert.md +0 -244
  55. package/autopm/.claude/agents/integration/message-queue-engineer.md +0 -794
  56. package/autopm/.claude/agents/languages/README.md +0 -50
  57. package/autopm/.claude/agents/languages/bash-scripting-expert.md +0 -541
  58. package/autopm/.claude/agents/languages/javascript-frontend-engineer.md +0 -197
  59. package/autopm/.claude/agents/languages/nodejs-backend-engineer.md +0 -226
  60. package/autopm/.claude/agents/languages/python-backend-engineer.md +0 -214
  61. package/autopm/.claude/agents/languages/python-backend-expert.md +0 -289
  62. package/autopm/.claude/agents/testing/frontend-testing-engineer.md +0 -395
  63. package/autopm/.claude/commands/ai/langgraph-workflow.md +0 -65
  64. package/autopm/.claude/commands/ai/openai-chat.md +0 -65
  65. package/autopm/.claude/commands/azure/COMMANDS.md +0 -107
  66. package/autopm/.claude/commands/azure/COMMAND_MAPPING.md +0 -252
  67. package/autopm/.claude/commands/azure/INTEGRATION_FIX.md +0 -103
  68. package/autopm/.claude/commands/azure/README.md +0 -246
  69. package/autopm/.claude/commands/azure/active-work.md +0 -198
  70. package/autopm/.claude/commands/azure/aliases.md +0 -143
  71. package/autopm/.claude/commands/azure/blocked-items.md +0 -287
  72. package/autopm/.claude/commands/azure/clean.md +0 -93
  73. package/autopm/.claude/commands/azure/docs-query.md +0 -48
  74. package/autopm/.claude/commands/azure/feature-decompose.md +0 -380
  75. package/autopm/.claude/commands/azure/feature-list.md +0 -61
  76. package/autopm/.claude/commands/azure/feature-new.md +0 -115
  77. package/autopm/.claude/commands/azure/feature-show.md +0 -205
  78. package/autopm/.claude/commands/azure/feature-start.md +0 -130
  79. package/autopm/.claude/commands/azure/fix-integration-example.md +0 -93
  80. package/autopm/.claude/commands/azure/help.md +0 -150
  81. package/autopm/.claude/commands/azure/import-us.md +0 -269
  82. package/autopm/.claude/commands/azure/init.md +0 -211
  83. package/autopm/.claude/commands/azure/next-task.md +0 -262
  84. package/autopm/.claude/commands/azure/search.md +0 -160
  85. package/autopm/.claude/commands/azure/sprint-status.md +0 -235
  86. package/autopm/.claude/commands/azure/standup.md +0 -260
  87. package/autopm/.claude/commands/azure/sync-all.md +0 -99
  88. package/autopm/.claude/commands/azure/task-analyze.md +0 -186
  89. package/autopm/.claude/commands/azure/task-close.md +0 -329
  90. package/autopm/.claude/commands/azure/task-edit.md +0 -145
  91. package/autopm/.claude/commands/azure/task-list.md +0 -263
  92. package/autopm/.claude/commands/azure/task-new.md +0 -84
  93. package/autopm/.claude/commands/azure/task-reopen.md +0 -79
  94. package/autopm/.claude/commands/azure/task-show.md +0 -126
  95. package/autopm/.claude/commands/azure/task-start.md +0 -301
  96. package/autopm/.claude/commands/azure/task-status.md +0 -65
  97. package/autopm/.claude/commands/azure/task-sync.md +0 -67
  98. package/autopm/.claude/commands/azure/us-edit.md +0 -164
  99. package/autopm/.claude/commands/azure/us-list.md +0 -202
  100. package/autopm/.claude/commands/azure/us-new.md +0 -265
  101. package/autopm/.claude/commands/azure/us-parse.md +0 -253
  102. package/autopm/.claude/commands/azure/us-show.md +0 -188
  103. package/autopm/.claude/commands/azure/us-status.md +0 -320
  104. package/autopm/.claude/commands/azure/validate.md +0 -86
  105. package/autopm/.claude/commands/azure/work-item-sync.md +0 -47
  106. package/autopm/.claude/commands/cloud/infra-deploy.md +0 -38
  107. package/autopm/.claude/commands/github/workflow-create.md +0 -42
  108. package/autopm/.claude/commands/infrastructure/ssh-security.md +0 -65
  109. package/autopm/.claude/commands/infrastructure/traefik-setup.md +0 -65
  110. package/autopm/.claude/commands/kubernetes/deploy.md +0 -37
  111. package/autopm/.claude/commands/playwright/test-scaffold.md +0 -38
  112. package/autopm/.claude/commands/pm/blocked.md +0 -28
  113. package/autopm/.claude/commands/pm/clean.md +0 -119
  114. package/autopm/.claude/commands/pm/context-create.md +0 -136
  115. package/autopm/.claude/commands/pm/context-prime.md +0 -170
  116. package/autopm/.claude/commands/pm/context-update.md +0 -292
  117. package/autopm/.claude/commands/pm/context.md +0 -28
  118. package/autopm/.claude/commands/pm/epic-close.md +0 -86
  119. package/autopm/.claude/commands/pm/epic-decompose.md +0 -370
  120. package/autopm/.claude/commands/pm/epic-edit.md +0 -83
  121. package/autopm/.claude/commands/pm/epic-list.md +0 -30
  122. package/autopm/.claude/commands/pm/epic-merge.md +0 -222
  123. package/autopm/.claude/commands/pm/epic-oneshot.md +0 -119
  124. package/autopm/.claude/commands/pm/epic-refresh.md +0 -119
  125. package/autopm/.claude/commands/pm/epic-show.md +0 -28
  126. package/autopm/.claude/commands/pm/epic-split.md +0 -120
  127. package/autopm/.claude/commands/pm/epic-start.md +0 -195
  128. package/autopm/.claude/commands/pm/epic-status.md +0 -28
  129. package/autopm/.claude/commands/pm/epic-sync-modular.md +0 -338
  130. package/autopm/.claude/commands/pm/epic-sync-original.md +0 -473
  131. package/autopm/.claude/commands/pm/epic-sync.md +0 -486
  132. package/autopm/.claude/commands/pm/help.md +0 -28
  133. package/autopm/.claude/commands/pm/import.md +0 -115
  134. package/autopm/.claude/commands/pm/in-progress.md +0 -28
  135. package/autopm/.claude/commands/pm/init.md +0 -28
  136. package/autopm/.claude/commands/pm/issue-analyze.md +0 -202
  137. package/autopm/.claude/commands/pm/issue-close.md +0 -119
  138. package/autopm/.claude/commands/pm/issue-edit.md +0 -93
  139. package/autopm/.claude/commands/pm/issue-reopen.md +0 -87
  140. package/autopm/.claude/commands/pm/issue-show.md +0 -41
  141. package/autopm/.claude/commands/pm/issue-start.md +0 -234
  142. package/autopm/.claude/commands/pm/issue-status.md +0 -95
  143. package/autopm/.claude/commands/pm/issue-sync.md +0 -411
  144. package/autopm/.claude/commands/pm/next.md +0 -28
  145. package/autopm/.claude/commands/pm/prd-edit.md +0 -82
  146. package/autopm/.claude/commands/pm/prd-list.md +0 -28
  147. package/autopm/.claude/commands/pm/prd-new.md +0 -55
  148. package/autopm/.claude/commands/pm/prd-parse.md +0 -42
  149. package/autopm/.claude/commands/pm/prd-status.md +0 -28
  150. package/autopm/.claude/commands/pm/search.md +0 -28
  151. package/autopm/.claude/commands/pm/standup.md +0 -28
  152. package/autopm/.claude/commands/pm/status.md +0 -28
  153. package/autopm/.claude/commands/pm/sync.md +0 -99
  154. package/autopm/.claude/commands/pm/test-reference-update.md +0 -151
  155. package/autopm/.claude/commands/pm/validate.md +0 -28
  156. package/autopm/.claude/commands/pm/what-next.md +0 -28
  157. package/autopm/.claude/commands/python/api-scaffold.md +0 -50
  158. package/autopm/.claude/commands/python/docs-query.md +0 -48
  159. package/autopm/.claude/commands/react/app-scaffold.md +0 -50
  160. package/autopm/.claude/commands/testing/prime.md +0 -314
  161. package/autopm/.claude/commands/testing/run.md +0 -125
  162. package/autopm/.claude/commands/ui/bootstrap-scaffold.md +0 -65
  163. package/autopm/.claude/commands/ui/tailwind-system.md +0 -64
  164. package/autopm/.claude/rules/ai-integration-patterns.md +0 -219
  165. package/autopm/.claude/rules/ci-cd-kubernetes-strategy.md +0 -25
  166. package/autopm/.claude/rules/database-management-strategy.md +0 -17
  167. package/autopm/.claude/rules/database-pipeline.md +0 -94
  168. package/autopm/.claude/rules/devops-troubleshooting-playbook.md +0 -450
  169. package/autopm/.claude/rules/docker-first-development.md +0 -404
  170. package/autopm/.claude/rules/infrastructure-pipeline.md +0 -128
  171. package/autopm/.claude/rules/performance-guidelines.md +0 -403
  172. package/autopm/.claude/rules/ui-development-standards.md +0 -281
  173. package/autopm/.claude/rules/ui-framework-rules.md +0 -151
  174. package/autopm/.claude/rules/ux-design-rules.md +0 -209
  175. package/autopm/.claude/rules/visual-testing.md +0 -223
  176. package/autopm/.claude/scripts/azure/README.md +0 -192
  177. package/autopm/.claude/scripts/azure/active-work.js +0 -524
  178. package/autopm/.claude/scripts/azure/active-work.sh +0 -20
  179. package/autopm/.claude/scripts/azure/blocked.js +0 -520
  180. package/autopm/.claude/scripts/azure/blocked.sh +0 -20
  181. package/autopm/.claude/scripts/azure/daily.js +0 -533
  182. package/autopm/.claude/scripts/azure/daily.sh +0 -20
  183. package/autopm/.claude/scripts/azure/dashboard.js +0 -970
  184. package/autopm/.claude/scripts/azure/dashboard.sh +0 -20
  185. package/autopm/.claude/scripts/azure/feature-list.js +0 -254
  186. package/autopm/.claude/scripts/azure/feature-list.sh +0 -20
  187. package/autopm/.claude/scripts/azure/feature-show.js +0 -7
  188. package/autopm/.claude/scripts/azure/feature-show.sh +0 -20
  189. package/autopm/.claude/scripts/azure/feature-status.js +0 -604
  190. package/autopm/.claude/scripts/azure/feature-status.sh +0 -20
  191. package/autopm/.claude/scripts/azure/help.js +0 -342
  192. package/autopm/.claude/scripts/azure/help.sh +0 -20
  193. package/autopm/.claude/scripts/azure/next-task.js +0 -508
  194. package/autopm/.claude/scripts/azure/next-task.sh +0 -20
  195. package/autopm/.claude/scripts/azure/search.js +0 -469
  196. package/autopm/.claude/scripts/azure/search.sh +0 -20
  197. package/autopm/.claude/scripts/azure/setup.js +0 -745
  198. package/autopm/.claude/scripts/azure/setup.sh +0 -20
  199. package/autopm/.claude/scripts/azure/sprint-report.js +0 -1012
  200. package/autopm/.claude/scripts/azure/sprint-report.sh +0 -20
  201. package/autopm/.claude/scripts/azure/sync.js +0 -563
  202. package/autopm/.claude/scripts/azure/sync.sh +0 -20
  203. package/autopm/.claude/scripts/azure/us-list.js +0 -210
  204. package/autopm/.claude/scripts/azure/us-list.sh +0 -20
  205. package/autopm/.claude/scripts/azure/us-status.js +0 -238
  206. package/autopm/.claude/scripts/azure/us-status.sh +0 -20
  207. package/autopm/.claude/scripts/azure/validate.js +0 -626
  208. package/autopm/.claude/scripts/azure/validate.sh +0 -20
  209. package/autopm/.claude/scripts/azure/wrapper-template.sh +0 -20
  210. package/autopm/.claude/scripts/github/dependency-tracker.js +0 -554
  211. package/autopm/.claude/scripts/github/dependency-validator.js +0 -545
  212. package/autopm/.claude/scripts/github/dependency-visualizer.js +0 -477
  213. package/autopm/.claude/scripts/pm/analytics.js +0 -425
  214. package/autopm/.claude/scripts/pm/blocked.js +0 -164
  215. package/autopm/.claude/scripts/pm/blocked.sh +0 -78
  216. package/autopm/.claude/scripts/pm/clean.js +0 -464
  217. package/autopm/.claude/scripts/pm/context-create.js +0 -216
  218. package/autopm/.claude/scripts/pm/context-prime.js +0 -335
  219. package/autopm/.claude/scripts/pm/context-update.js +0 -344
  220. package/autopm/.claude/scripts/pm/context.js +0 -338
  221. package/autopm/.claude/scripts/pm/epic-close.js +0 -347
  222. package/autopm/.claude/scripts/pm/epic-edit.js +0 -382
  223. package/autopm/.claude/scripts/pm/epic-list.js +0 -273
  224. package/autopm/.claude/scripts/pm/epic-list.sh +0 -109
  225. package/autopm/.claude/scripts/pm/epic-show.js +0 -291
  226. package/autopm/.claude/scripts/pm/epic-show.sh +0 -105
  227. package/autopm/.claude/scripts/pm/epic-split.js +0 -522
  228. package/autopm/.claude/scripts/pm/epic-start/epic-start.js +0 -183
  229. package/autopm/.claude/scripts/pm/epic-start/epic-start.sh +0 -94
  230. package/autopm/.claude/scripts/pm/epic-status.js +0 -291
  231. package/autopm/.claude/scripts/pm/epic-status.sh +0 -104
  232. package/autopm/.claude/scripts/pm/epic-sync/README.md +0 -208
  233. package/autopm/.claude/scripts/pm/epic-sync/create-epic-issue.sh +0 -77
  234. package/autopm/.claude/scripts/pm/epic-sync/create-task-issues.sh +0 -86
  235. package/autopm/.claude/scripts/pm/epic-sync/update-epic-file.sh +0 -79
  236. package/autopm/.claude/scripts/pm/epic-sync/update-references.sh +0 -89
  237. package/autopm/.claude/scripts/pm/epic-sync.sh +0 -137
  238. package/autopm/.claude/scripts/pm/help.js +0 -92
  239. package/autopm/.claude/scripts/pm/help.sh +0 -90
  240. package/autopm/.claude/scripts/pm/in-progress.js +0 -178
  241. package/autopm/.claude/scripts/pm/in-progress.sh +0 -93
  242. package/autopm/.claude/scripts/pm/init.js +0 -321
  243. package/autopm/.claude/scripts/pm/init.sh +0 -178
  244. package/autopm/.claude/scripts/pm/issue-close.js +0 -232
  245. package/autopm/.claude/scripts/pm/issue-edit.js +0 -310
  246. package/autopm/.claude/scripts/pm/issue-show.js +0 -272
  247. package/autopm/.claude/scripts/pm/issue-start.js +0 -181
  248. package/autopm/.claude/scripts/pm/issue-sync/format-comment.sh +0 -468
  249. package/autopm/.claude/scripts/pm/issue-sync/gather-updates.sh +0 -460
  250. package/autopm/.claude/scripts/pm/issue-sync/post-comment.sh +0 -330
  251. package/autopm/.claude/scripts/pm/issue-sync/preflight-validation.sh +0 -348
  252. package/autopm/.claude/scripts/pm/issue-sync/update-frontmatter.sh +0 -387
  253. package/autopm/.claude/scripts/pm/lib/README.md +0 -85
  254. package/autopm/.claude/scripts/pm/lib/epic-discovery.js +0 -119
  255. package/autopm/.claude/scripts/pm/lib/logger.js +0 -78
  256. package/autopm/.claude/scripts/pm/next.js +0 -189
  257. package/autopm/.claude/scripts/pm/next.sh +0 -72
  258. package/autopm/.claude/scripts/pm/optimize.js +0 -407
  259. package/autopm/.claude/scripts/pm/pr-create.js +0 -337
  260. package/autopm/.claude/scripts/pm/pr-list.js +0 -257
  261. package/autopm/.claude/scripts/pm/prd-list.js +0 -242
  262. package/autopm/.claude/scripts/pm/prd-list.sh +0 -103
  263. package/autopm/.claude/scripts/pm/prd-new.js +0 -684
  264. package/autopm/.claude/scripts/pm/prd-parse.js +0 -547
  265. package/autopm/.claude/scripts/pm/prd-status.js +0 -152
  266. package/autopm/.claude/scripts/pm/prd-status.sh +0 -63
  267. package/autopm/.claude/scripts/pm/release.js +0 -460
  268. package/autopm/.claude/scripts/pm/search.js +0 -192
  269. package/autopm/.claude/scripts/pm/search.sh +0 -89
  270. package/autopm/.claude/scripts/pm/standup.js +0 -362
  271. package/autopm/.claude/scripts/pm/standup.sh +0 -95
  272. package/autopm/.claude/scripts/pm/status.js +0 -148
  273. package/autopm/.claude/scripts/pm/status.sh +0 -59
  274. package/autopm/.claude/scripts/pm/sync-batch.js +0 -337
  275. package/autopm/.claude/scripts/pm/sync.js +0 -343
  276. package/autopm/.claude/scripts/pm/template-list.js +0 -141
  277. package/autopm/.claude/scripts/pm/template-new.js +0 -366
  278. package/autopm/.claude/scripts/pm/validate.js +0 -274
  279. package/autopm/.claude/scripts/pm/validate.sh +0 -106
  280. package/autopm/.claude/scripts/pm/what-next.js +0 -660
  281. package/bin/node/azure-feature-show.js +0 -7
@@ -0,0 +1,475 @@
1
+ /**
2
+ * GitHub Provider for ClaudeAutoPM
3
+ *
4
+ * Provides bidirectional synchronization with GitHub Issues following 2025 best practices
5
+ *
6
+ * Features:
7
+ * - Full CRUD operations for issues
8
+ * - Comment management
9
+ * - Label management
10
+ * - Advanced search
11
+ * - Rate limiting with exponential backoff
12
+ * - Retry logic for transient failures
13
+ * - GitHub Enterprise support
14
+ *
15
+ * @module lib/providers/GitHubProvider
16
+ */
17
+
18
+ const { Octokit } = require('@octokit/rest');
19
+
20
+ /**
21
+ * GitHub Provider Class
22
+ *
23
+ * Manages integration with GitHub Issues API using Octokit
24
+ *
25
+ * @class GitHubProvider
26
+ */
27
+ class GitHubProvider {
28
+ /**
29
+ * Creates a new GitHub provider instance
30
+ *
31
+ * @param {Object} options - Configuration options
32
+ * @param {string} [options.token] - GitHub Personal Access Token
33
+ * @param {string} [options.owner] - Repository owner
34
+ * @param {string} [options.repo] - Repository name
35
+ * @param {string} [options.baseUrl] - Custom GitHub API URL (for Enterprise)
36
+ * @param {number} [options.timeout=30000] - Request timeout in milliseconds
37
+ * @param {number} [options.maxRetries=3] - Maximum retry attempts
38
+ */
39
+ constructor(options = {}) {
40
+ this.token = options.token || process.env.GITHUB_TOKEN;
41
+ this.owner = options.owner || process.env.GITHUB_OWNER;
42
+ this.repo = options.repo || process.env.GITHUB_REPO;
43
+ this.baseUrl = options.baseUrl;
44
+ this.timeout = options.timeout || 30000;
45
+ this.maxRetries = options.maxRetries || 3;
46
+
47
+ this.octokit = null;
48
+ this.rateLimitRemaining = null;
49
+ this.rateLimitReset = null;
50
+ }
51
+
52
+ /**
53
+ * Authenticates with GitHub API
54
+ *
55
+ * Creates Octokit instance and verifies authentication
56
+ * by fetching the authenticated user's info
57
+ *
58
+ * @async
59
+ * @returns {Promise<Object>} Authenticated user object
60
+ * @throws {Error} If token is missing or authentication fails
61
+ */
62
+ async authenticate() {
63
+ if (!this.token) {
64
+ throw new Error('GitHub token is required');
65
+ }
66
+
67
+ const options = {
68
+ auth: this.token,
69
+ timeout: this.timeout
70
+ };
71
+
72
+ if (this.baseUrl) {
73
+ options.baseUrl = this.baseUrl;
74
+ }
75
+
76
+ this.octokit = new Octokit(options);
77
+
78
+ // Verify authentication
79
+ const { data: user } = await this.octokit.users.getAuthenticated();
80
+
81
+ return user;
82
+ }
83
+
84
+ /**
85
+ * Fetches a single issue by number
86
+ *
87
+ * @async
88
+ * @param {number} number - Issue number
89
+ * @returns {Promise<Object>} Issue object
90
+ * @throws {Error} If issue is not found or request fails
91
+ */
92
+ async getIssue(number) {
93
+ await this._checkRateLimit();
94
+
95
+ const { data } = await this.octokit.rest.issues.get({
96
+ owner: this.owner,
97
+ repo: this.repo,
98
+ issue_number: number
99
+ });
100
+
101
+ return data;
102
+ }
103
+
104
+ /**
105
+ * Lists issues with optional filtering
106
+ *
107
+ * @async
108
+ * @param {Object} [filters={}] - Filter options
109
+ * @param {string} [filters.state] - Issue state (open, closed, all)
110
+ * @param {Array<string>} [filters.labels] - Filter by labels
111
+ * @param {string} [filters.assignee] - Filter by assignee
112
+ * @param {number} [filters.page=1] - Page number
113
+ * @param {number} [filters.perPage=100] - Results per page
114
+ * @returns {Promise<Array>} Array of issue objects
115
+ */
116
+ async listIssues(filters = {}) {
117
+ await this._checkRateLimit();
118
+
119
+ const params = {
120
+ owner: this.owner,
121
+ repo: this.repo,
122
+ per_page: filters.perPage || 100
123
+ };
124
+
125
+ if (filters.state) {
126
+ params.state = filters.state;
127
+ }
128
+
129
+ if (filters.labels && filters.labels.length > 0) {
130
+ params.labels = filters.labels.join(',');
131
+ }
132
+
133
+ if (filters.assignee) {
134
+ params.assignee = filters.assignee;
135
+ }
136
+
137
+ if (filters.page) {
138
+ params.page = filters.page;
139
+ }
140
+
141
+ const { data } = await this.octokit.rest.issues.list(params);
142
+
143
+ return data;
144
+ }
145
+
146
+ /**
147
+ * Creates a new issue
148
+ *
149
+ * @async
150
+ * @param {Object} data - Issue data
151
+ * @param {string} data.title - Issue title (required)
152
+ * @param {string} [data.body] - Issue description
153
+ * @param {Array<string>} [data.labels] - Labels to add
154
+ * @param {Array<string>} [data.assignees] - Assignees
155
+ * @returns {Promise<Object>} Created issue object
156
+ * @throws {Error} If title is missing or creation fails
157
+ */
158
+ async createIssue(data) {
159
+ if (!data.title) {
160
+ throw new Error('Issue title is required');
161
+ }
162
+
163
+ await this._checkRateLimit();
164
+
165
+ const params = {
166
+ owner: this.owner,
167
+ repo: this.repo,
168
+ title: data.title
169
+ };
170
+
171
+ if (data.body) {
172
+ params.body = data.body;
173
+ }
174
+
175
+ if (data.labels) {
176
+ params.labels = data.labels;
177
+ }
178
+
179
+ if (data.assignees) {
180
+ params.assignees = data.assignees;
181
+ }
182
+
183
+ const { data: issue } = await this.octokit.rest.issues.create(params);
184
+
185
+ return issue;
186
+ }
187
+
188
+ /**
189
+ * Updates an existing issue
190
+ *
191
+ * @async
192
+ * @param {number} number - Issue number
193
+ * @param {Object} data - Fields to update
194
+ * @param {string} [data.title] - New title
195
+ * @param {string} [data.body] - New body
196
+ * @param {string} [data.state] - New state (open, closed)
197
+ * @param {Array<string>} [data.labels] - New labels
198
+ * @returns {Promise<Object>} Updated issue object
199
+ */
200
+ async updateIssue(number, data) {
201
+ await this._checkRateLimit();
202
+
203
+ const params = {
204
+ owner: this.owner,
205
+ repo: this.repo,
206
+ issue_number: number,
207
+ ...data
208
+ };
209
+
210
+ const { data: issue } = await this.octokit.rest.issues.update(params);
211
+
212
+ return issue;
213
+ }
214
+
215
+ /**
216
+ * Closes an issue
217
+ *
218
+ * @async
219
+ * @param {number} number - Issue number
220
+ * @param {string} [comment] - Optional closing comment
221
+ * @returns {Promise<Object>} Closed issue object
222
+ */
223
+ async closeIssue(number, comment) {
224
+ if (comment) {
225
+ await this.createComment(number, comment);
226
+ }
227
+
228
+ return await this.updateIssue(number, { state: 'closed' });
229
+ }
230
+
231
+ /**
232
+ * Creates a comment on an issue
233
+ *
234
+ * @async
235
+ * @param {number} number - Issue number
236
+ * @param {string} body - Comment body
237
+ * @returns {Promise<Object>} Created comment object
238
+ * @throws {Error} If body is empty
239
+ */
240
+ async createComment(number, body) {
241
+ if (!body || body.trim() === '') {
242
+ throw new Error('Comment body is required');
243
+ }
244
+
245
+ await this._checkRateLimit();
246
+
247
+ const { data } = await this.octokit.rest.issues.createComment({
248
+ owner: this.owner,
249
+ repo: this.repo,
250
+ issue_number: number,
251
+ body
252
+ });
253
+
254
+ return data;
255
+ }
256
+
257
+ /**
258
+ * Lists comments for an issue
259
+ *
260
+ * @async
261
+ * @param {number} number - Issue number
262
+ * @param {Object} [options={}] - Pagination options
263
+ * @param {number} [options.page] - Page number
264
+ * @param {number} [options.perPage=100] - Results per page
265
+ * @returns {Promise<Array>} Array of comment objects
266
+ */
267
+ async listComments(number, options = {}) {
268
+ await this._checkRateLimit();
269
+
270
+ const params = {
271
+ owner: this.owner,
272
+ repo: this.repo,
273
+ issue_number: number,
274
+ per_page: options.perPage || 100
275
+ };
276
+
277
+ if (options.page) {
278
+ params.page = options.page;
279
+ }
280
+
281
+ const { data } = await this.octokit.rest.issues.listComments(params);
282
+
283
+ return data;
284
+ }
285
+
286
+ /**
287
+ * Adds labels to an issue
288
+ *
289
+ * @async
290
+ * @param {number} number - Issue number
291
+ * @param {Array<string>} labels - Labels to add
292
+ * @returns {Promise<Array>} Array of label objects
293
+ * @throws {Error} If labels array is empty
294
+ */
295
+ async addLabels(number, labels) {
296
+ if (!labels || labels.length === 0) {
297
+ throw new Error('At least one label is required');
298
+ }
299
+
300
+ await this._checkRateLimit();
301
+
302
+ const { data } = await this.octokit.rest.issues.addLabels({
303
+ owner: this.owner,
304
+ repo: this.repo,
305
+ issue_number: number,
306
+ labels
307
+ });
308
+
309
+ return data;
310
+ }
311
+
312
+ /**
313
+ * Searches issues using GitHub search syntax
314
+ *
315
+ * @async
316
+ * @param {string} query - Search query
317
+ * @param {Object} [options={}] - Additional options
318
+ * @param {Array<string>} [options.labels] - Filter by labels
319
+ * @param {string} [options.state] - Filter by state
320
+ * @param {number} [options.page] - Page number
321
+ * @param {number} [options.perPage=100] - Results per page
322
+ * @returns {Promise<Object>} Search results with total_count and items
323
+ */
324
+ async searchIssues(query, options = {}) {
325
+ await this._checkRateLimit();
326
+
327
+ let searchQuery = query;
328
+
329
+ // Build query with filters
330
+ if (options.labels && options.labels.length > 0) {
331
+ searchQuery += ` label:${options.labels[0]}`;
332
+ }
333
+
334
+ if (options.state) {
335
+ searchQuery += ` state:${options.state}`;
336
+ }
337
+
338
+ // Always scope to current repo
339
+ searchQuery += ` repo:${this.owner}/${this.repo}`;
340
+
341
+ const params = {
342
+ q: searchQuery,
343
+ per_page: options.perPage || 100
344
+ };
345
+
346
+ if (options.page) {
347
+ params.page = options.page;
348
+ }
349
+
350
+ const { data } = await this.octokit.rest.search.issuesAndPullRequests(params);
351
+
352
+ return data;
353
+ }
354
+
355
+ /**
356
+ * Checks current rate limit status
357
+ *
358
+ * @async
359
+ * @returns {Promise<Object>} Rate limit information
360
+ */
361
+ async checkRateLimit() {
362
+ const { data } = await this.octokit.rest.rateLimit.get();
363
+
364
+ this.rateLimitRemaining = data.resources.core.remaining;
365
+ this.rateLimitReset = data.resources.core.reset;
366
+
367
+ return data.resources;
368
+ }
369
+
370
+ /**
371
+ * Handles rate limit errors with exponential backoff
372
+ *
373
+ * @async
374
+ * @param {Error} error - Rate limit error
375
+ * @param {number} retryCount - Current retry attempt
376
+ * @returns {Promise<number>} Wait time in milliseconds
377
+ * @throws {Error} If max retries exceeded
378
+ * @private
379
+ */
380
+ async handleRateLimitError(error, retryCount) {
381
+ if (retryCount >= this.maxRetries) {
382
+ throw new Error('Maximum retry attempts exceeded');
383
+ }
384
+
385
+ let waitTime;
386
+
387
+ // Check if we have reset time from headers
388
+ if (error.response && error.response.headers) {
389
+ const resetTime = error.response.headers['x-ratelimit-reset'];
390
+ if (resetTime) {
391
+ const now = Math.floor(Date.now() / 1000);
392
+ const resetTimestamp = parseInt(resetTime, 10);
393
+ waitTime = Math.max(0, (resetTimestamp - now) * 1000);
394
+ }
395
+ }
396
+
397
+ // Fallback to exponential backoff
398
+ if (!waitTime || waitTime === 0) {
399
+ // 2^retryCount * 1000ms (1s, 2s, 4s, 8s...)
400
+ waitTime = Math.pow(2, retryCount) * 1000;
401
+ }
402
+
403
+ return waitTime;
404
+ }
405
+
406
+ /**
407
+ * Makes a request with retry logic
408
+ *
409
+ * @async
410
+ * @param {Function} requestFn - Function that makes the request
411
+ * @param {Object} [options={}] - Options
412
+ * @param {number} [options.maxRetries] - Override max retries
413
+ * @returns {Promise<*>} Response data
414
+ * @throws {Error} If request fails permanently
415
+ * @private
416
+ */
417
+ async _makeRequest(requestFn, options = {}) {
418
+ const maxRetries = options.maxRetries !== undefined ? options.maxRetries : this.maxRetries;
419
+ let lastError;
420
+
421
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
422
+ try {
423
+ const { data } = await requestFn();
424
+ return data;
425
+ } catch (error) {
426
+ lastError = error;
427
+
428
+ // Check if error is rate limit
429
+ if (error.status === 403 && error.message && error.message.includes('rate limit')) {
430
+ const waitTime = await this.handleRateLimitError(error, attempt);
431
+ await new Promise(resolve => setTimeout(resolve, waitTime));
432
+ continue;
433
+ }
434
+
435
+ // Check if error is transient (5xx)
436
+ if (error.status >= 500 && error.status < 600) {
437
+ if (attempt < maxRetries) {
438
+ const waitTime = Math.pow(2, attempt) * 1000;
439
+ await new Promise(resolve => setTimeout(resolve, waitTime));
440
+ continue;
441
+ }
442
+ }
443
+
444
+ // Non-retryable error
445
+ throw error;
446
+ }
447
+ }
448
+
449
+ throw lastError;
450
+ }
451
+
452
+ /**
453
+ * Checks rate limit before making requests
454
+ *
455
+ * @async
456
+ * @private
457
+ */
458
+ async _checkRateLimit() {
459
+ if (!this.octokit) {
460
+ throw new Error('Not authenticated. Call authenticate() first.');
461
+ }
462
+
463
+ // Only check if we haven't checked recently
464
+ if (this.rateLimitRemaining === null) {
465
+ await this.checkRateLimit();
466
+ }
467
+
468
+ // Warn if rate limit is low
469
+ if (this.rateLimitRemaining !== null && this.rateLimitRemaining < 100) {
470
+ console.warn(`GitHub API rate limit low: ${this.rateLimitRemaining} requests remaining`);
471
+ }
472
+ }
473
+ }
474
+
475
+ module.exports = GitHubProvider;