specweave 0.6.8 → 0.7.1

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 (255) hide show
  1. package/.claude-plugin/README.md +1 -1
  2. package/CLAUDE.md +903 -99
  3. package/README.md +143 -207
  4. package/bin/specweave.js +67 -0
  5. package/dist/cli/commands/abandon.d.ts +13 -0
  6. package/dist/cli/commands/abandon.d.ts.map +1 -0
  7. package/dist/cli/commands/abandon.js +15 -0
  8. package/dist/cli/commands/abandon.js.map +1 -0
  9. package/dist/cli/commands/init.d.ts.map +1 -1
  10. package/dist/cli/commands/init.js +94 -18
  11. package/dist/cli/commands/init.js.map +1 -1
  12. package/dist/cli/commands/pause.d.ts +13 -0
  13. package/dist/cli/commands/pause.d.ts.map +1 -0
  14. package/dist/cli/commands/pause.js +15 -0
  15. package/dist/cli/commands/pause.js.map +1 -0
  16. package/dist/cli/commands/qa.d.ts +54 -0
  17. package/dist/cli/commands/qa.d.ts.map +1 -0
  18. package/dist/cli/commands/qa.js +98 -0
  19. package/dist/cli/commands/qa.js.map +1 -0
  20. package/dist/cli/commands/resume.d.ts +12 -0
  21. package/dist/cli/commands/resume.d.ts.map +1 -0
  22. package/dist/cli/commands/resume.js +14 -0
  23. package/dist/cli/commands/resume.js.map +1 -0
  24. package/dist/cli/commands/status.d.ts +12 -0
  25. package/dist/cli/commands/status.d.ts.map +1 -0
  26. package/dist/cli/commands/status.js +23 -0
  27. package/dist/cli/commands/status.js.map +1 -0
  28. package/dist/cli/helpers/issue-tracker/ado.d.ts +57 -0
  29. package/dist/cli/helpers/issue-tracker/ado.d.ts.map +1 -0
  30. package/dist/cli/helpers/issue-tracker/ado.js +223 -0
  31. package/dist/cli/helpers/issue-tracker/ado.js.map +1 -0
  32. package/dist/cli/helpers/issue-tracker/github.d.ts +65 -0
  33. package/dist/cli/helpers/issue-tracker/github.d.ts.map +1 -0
  34. package/dist/cli/helpers/issue-tracker/github.js +284 -0
  35. package/dist/cli/helpers/issue-tracker/github.js.map +1 -0
  36. package/dist/cli/helpers/issue-tracker/index.d.ts +22 -0
  37. package/dist/cli/helpers/issue-tracker/index.d.ts.map +1 -0
  38. package/dist/cli/helpers/issue-tracker/index.js +270 -0
  39. package/dist/cli/helpers/issue-tracker/index.js.map +1 -0
  40. package/dist/cli/helpers/issue-tracker/jira.d.ts +61 -0
  41. package/dist/cli/helpers/issue-tracker/jira.d.ts.map +1 -0
  42. package/dist/cli/helpers/issue-tracker/jira.js +265 -0
  43. package/dist/cli/helpers/issue-tracker/jira.js.map +1 -0
  44. package/dist/cli/helpers/issue-tracker/types.d.ts +86 -0
  45. package/dist/cli/helpers/issue-tracker/types.d.ts.map +1 -0
  46. package/dist/cli/helpers/issue-tracker/types.js +16 -0
  47. package/dist/cli/helpers/issue-tracker/types.js.map +1 -0
  48. package/dist/cli/helpers/issue-tracker/utils.d.ts +103 -0
  49. package/dist/cli/helpers/issue-tracker/utils.d.ts.map +1 -0
  50. package/dist/cli/helpers/issue-tracker/utils.js +240 -0
  51. package/dist/cli/helpers/issue-tracker/utils.js.map +1 -0
  52. package/dist/core/increment/limits.d.ts +68 -0
  53. package/dist/core/increment/limits.d.ts.map +1 -0
  54. package/dist/core/increment/limits.js +224 -0
  55. package/dist/core/increment/limits.js.map +1 -0
  56. package/dist/core/increment/metadata-manager.d.ts +114 -0
  57. package/dist/core/increment/metadata-manager.d.ts.map +1 -0
  58. package/dist/core/increment/metadata-manager.js +320 -0
  59. package/dist/core/increment/metadata-manager.js.map +1 -0
  60. package/dist/core/increment/status-commands.d.ts +43 -0
  61. package/dist/core/increment/status-commands.d.ts.map +1 -0
  62. package/dist/core/increment/status-commands.js +277 -0
  63. package/dist/core/increment/status-commands.js.map +1 -0
  64. package/dist/core/plugin-detector.d.ts +1 -0
  65. package/dist/core/plugin-detector.d.ts.map +1 -1
  66. package/dist/core/plugin-detector.js +25 -0
  67. package/dist/core/plugin-detector.js.map +1 -1
  68. package/dist/core/qa/qa-runner.d.ts +16 -0
  69. package/dist/core/qa/qa-runner.d.ts.map +1 -0
  70. package/dist/core/qa/qa-runner.js +404 -0
  71. package/dist/core/qa/qa-runner.js.map +1 -0
  72. package/dist/core/qa/quality-gate-decider.d.ts +53 -0
  73. package/dist/core/qa/quality-gate-decider.d.ts.map +1 -0
  74. package/dist/core/qa/quality-gate-decider.js +268 -0
  75. package/dist/core/qa/quality-gate-decider.js.map +1 -0
  76. package/dist/core/qa/risk-calculator.d.ts +126 -0
  77. package/dist/core/qa/risk-calculator.d.ts.map +1 -0
  78. package/dist/core/qa/risk-calculator.js +247 -0
  79. package/dist/core/qa/risk-calculator.js.map +1 -0
  80. package/dist/core/qa/types.d.ts +315 -0
  81. package/dist/core/qa/types.d.ts.map +1 -0
  82. package/dist/core/qa/types.js +8 -0
  83. package/dist/core/qa/types.js.map +1 -0
  84. package/dist/core/types/config.d.ts +35 -0
  85. package/dist/core/types/config.d.ts.map +1 -1
  86. package/dist/core/types/config.js +16 -0
  87. package/dist/core/types/config.js.map +1 -1
  88. package/dist/core/types/increment-metadata.d.ts +120 -0
  89. package/dist/core/types/increment-metadata.d.ts.map +1 -0
  90. package/dist/core/types/increment-metadata.js +138 -0
  91. package/dist/core/types/increment-metadata.js.map +1 -0
  92. package/dist/hooks/lib/invoke-translator-skill.d.ts +60 -0
  93. package/dist/hooks/lib/invoke-translator-skill.d.ts.map +1 -0
  94. package/dist/hooks/lib/invoke-translator-skill.js +201 -0
  95. package/dist/hooks/lib/invoke-translator-skill.js.map +1 -0
  96. package/dist/hooks/lib/translate-file.d.ts +59 -0
  97. package/dist/hooks/lib/translate-file.d.ts.map +1 -0
  98. package/dist/hooks/lib/translate-file.js +350 -0
  99. package/dist/hooks/lib/translate-file.js.map +1 -0
  100. package/dist/locales/en/cli.json +3 -1
  101. package/dist/metrics/calculators/change-failure-rate.d.ts +22 -0
  102. package/dist/metrics/calculators/change-failure-rate.d.ts.map +1 -0
  103. package/dist/metrics/calculators/change-failure-rate.js +70 -0
  104. package/dist/metrics/calculators/change-failure-rate.js.map +1 -0
  105. package/dist/metrics/calculators/deployment-frequency.d.ts +20 -0
  106. package/dist/metrics/calculators/deployment-frequency.d.ts.map +1 -0
  107. package/dist/metrics/calculators/deployment-frequency.js +61 -0
  108. package/dist/metrics/calculators/deployment-frequency.js.map +1 -0
  109. package/dist/metrics/calculators/lead-time.d.ts +22 -0
  110. package/dist/metrics/calculators/lead-time.d.ts.map +1 -0
  111. package/dist/metrics/calculators/lead-time.js +82 -0
  112. package/dist/metrics/calculators/lead-time.js.map +1 -0
  113. package/dist/metrics/calculators/mttr.d.ts +21 -0
  114. package/dist/metrics/calculators/mttr.d.ts.map +1 -0
  115. package/dist/metrics/calculators/mttr.js +60 -0
  116. package/dist/metrics/calculators/mttr.js.map +1 -0
  117. package/dist/metrics/dora-calculator.d.ts +24 -0
  118. package/dist/metrics/dora-calculator.d.ts.map +1 -0
  119. package/dist/metrics/dora-calculator.js +104 -0
  120. package/dist/metrics/dora-calculator.js.map +1 -0
  121. package/dist/metrics/github-client.d.ts +51 -0
  122. package/dist/metrics/github-client.d.ts.map +1 -0
  123. package/dist/metrics/github-client.js +133 -0
  124. package/dist/metrics/github-client.js.map +1 -0
  125. package/dist/metrics/types.d.ts +112 -0
  126. package/dist/metrics/types.d.ts.map +1 -0
  127. package/dist/metrics/types.js +10 -0
  128. package/dist/metrics/types.js.map +1 -0
  129. package/dist/metrics/utils/percentile.d.ts +25 -0
  130. package/dist/metrics/utils/percentile.d.ts.map +1 -0
  131. package/dist/metrics/utils/percentile.js +46 -0
  132. package/dist/metrics/utils/percentile.js.map +1 -0
  133. package/dist/metrics/utils/tier-classifier.d.ts +61 -0
  134. package/dist/metrics/utils/tier-classifier.d.ts.map +1 -0
  135. package/dist/metrics/utils/tier-classifier.js +100 -0
  136. package/dist/metrics/utils/tier-classifier.js.map +1 -0
  137. package/dist/utils/auth-helpers.d.ts +58 -0
  138. package/dist/utils/auth-helpers.d.ts.map +1 -0
  139. package/dist/utils/auth-helpers.js +108 -0
  140. package/dist/utils/auth-helpers.js.map +1 -0
  141. package/dist/utils/env-file.d.ts +88 -0
  142. package/dist/utils/env-file.d.ts.map +1 -0
  143. package/dist/utils/env-file.js +180 -0
  144. package/dist/utils/env-file.js.map +1 -0
  145. package/dist/utils/plugin-detection.d.ts +50 -0
  146. package/dist/utils/plugin-detection.d.ts.map +1 -0
  147. package/dist/utils/plugin-detection.js +229 -0
  148. package/dist/utils/plugin-detection.js.map +1 -0
  149. package/dist/utils/secrets-loader.d.ts +88 -0
  150. package/dist/utils/secrets-loader.d.ts.map +1 -0
  151. package/dist/utils/secrets-loader.js +271 -0
  152. package/dist/utils/secrets-loader.js.map +1 -0
  153. package/dist/utils/translation.d.ts +187 -0
  154. package/dist/utils/translation.d.ts.map +1 -0
  155. package/dist/utils/translation.js +414 -0
  156. package/dist/utils/translation.js.map +1 -0
  157. package/package.json +28 -44
  158. package/plugins/specweave/.claude-plugin/plugin.json +3 -3
  159. package/plugins/specweave/agents/pm/AGENT.md +330 -54
  160. package/plugins/specweave/agents/test-aware-planner/AGENT.md +1035 -0
  161. package/plugins/specweave/agents/test-aware-planner/templates/README.md +118 -0
  162. package/plugins/specweave/agents/test-aware-planner/templates/task-non-testable.md.template +24 -0
  163. package/plugins/specweave/agents/test-aware-planner/templates/task-testable.md.template +53 -0
  164. package/plugins/specweave/agents/test-aware-planner/templates/tasks-frontmatter.md.template +11 -0
  165. package/plugins/specweave/commands/README.md +88 -163
  166. package/plugins/specweave/commands/specweave-abandon.md +314 -0
  167. package/plugins/specweave/commands/specweave-check-tests.md +546 -0
  168. package/plugins/specweave/commands/{do.md → specweave-do.md} +5 -7
  169. package/plugins/specweave/commands/{increment.md → specweave-increment.md} +231 -4
  170. package/plugins/specweave/commands/specweave-pause.md +189 -0
  171. package/plugins/specweave/commands/specweave-qa.md +245 -0
  172. package/plugins/specweave/commands/specweave-resume.md +216 -0
  173. package/plugins/specweave/commands/specweave-status.md +397 -0
  174. package/plugins/specweave/commands/specweave-sync-tasks.md +256 -0
  175. package/plugins/specweave/commands/{translate.md → specweave-translate.md} +3 -3
  176. package/plugins/specweave/commands/specweave-update-scope.md +351 -0
  177. package/plugins/specweave/commands/specweave.md +21 -21
  178. package/plugins/specweave/hooks/post-increment-planning.sh +335 -0
  179. package/plugins/specweave/hooks/post-task-completion.sh +141 -0
  180. package/plugins/specweave/skills/SKILLS-INDEX.md +1 -1
  181. package/plugins/specweave/skills/brownfield-analyzer/SKILL.md +9 -9
  182. package/plugins/specweave/skills/increment-planner/SKILL.md +400 -212
  183. package/plugins/specweave/skills/increment-quality-judge-v2/SKILL.md +499 -0
  184. package/plugins/specweave/skills/plugin-detector/SKILL.md +114 -1
  185. package/plugins/specweave/skills/project-kickstarter/SKILL.md +74 -1
  186. package/plugins/specweave/skills/{rfc-generator → spec-generator}/SKILL.md +22 -29
  187. package/plugins/specweave/skills/specweave-detector/SKILL.md +3 -3
  188. package/plugins/specweave/skills/specweave-framework/SKILL.md +2 -2
  189. package/plugins/specweave-ado/.claude-plugin/plugin.json +18 -4
  190. package/plugins/specweave-ado/agents/ado-manager/AGENT.md +426 -0
  191. package/plugins/specweave-ado/commands/close-workitem.md +52 -0
  192. package/plugins/specweave-ado/commands/create-workitem.md +53 -0
  193. package/plugins/specweave-ado/commands/status.md +53 -0
  194. package/plugins/specweave-ado/commands/sync.md +55 -0
  195. package/plugins/specweave-ado/lib/ado-client.ts +361 -0
  196. package/plugins/specweave-ado/reference/ado-specweave-mapping.md +552 -0
  197. package/plugins/specweave-ado/skills/ado-sync/SKILL.md +344 -193
  198. package/plugins/specweave-docs/skills/docusaurus/SKILL.md +73 -0
  199. package/plugins/specweave-github/agents/github-manager/AGENT.md +49 -0
  200. package/plugins/specweave-github/commands/{github-close-issue.md → close-issue.md} +1 -1
  201. package/plugins/specweave-github/commands/{github-create-issue.md → create-issue.md} +1 -1
  202. package/plugins/specweave-github/commands/{github-status.md → status.md} +1 -1
  203. package/plugins/specweave-github/commands/{github-sync-tasks.md → sync-tasks.md} +1 -1
  204. package/plugins/specweave-github/commands/{github-sync.md → sync.md} +1 -1
  205. package/plugins/specweave-github/reference/github-specweave-mapping.md +377 -0
  206. package/plugins/specweave-github/skills/github-sync/SKILL.md +11 -3
  207. package/plugins/specweave-infrastructure/commands/{specweave.monitor-setup.md → monitor-setup.md} +5 -0
  208. package/plugins/specweave-infrastructure/commands/{specweave.slo-implement.md → slo-implement.md} +5 -0
  209. package/plugins/specweave-jira/agents/jira-manager/AGENT.md +380 -0
  210. package/plugins/specweave-jira/commands/{specweave.sync-jira.md → sync.md} +1 -1
  211. package/plugins/specweave-jira/reference/jira-specweave-mapping.md +508 -0
  212. package/plugins/specweave-ml/commands/ml-deploy.md +1 -1
  213. package/plugins/specweave-ml/commands/ml-evaluate.md +1 -1
  214. package/plugins/specweave-ml/commands/ml-explain.md +1 -1
  215. package/plugins/specweave-ml/commands/{specweave.ml-pipeline.md → ml-pipeline.md} +5 -0
  216. package/src/templates/AGENTS.md.template +331 -31
  217. package/src/templates/CLAUDE.md.template +36 -21
  218. package/src/templates/COMPLETION-REPORT.template.md +128 -0
  219. package/src/templates/README.md.template +17 -16
  220. package/src/templates/docs/README.md +11 -9
  221. package/src/templates/docs/spec-template.md +229 -0
  222. package/plugins/specweave/commands/inc.md +0 -85
  223. package/plugins/specweave/commands/list-increments.md +0 -180
  224. package/src/adapters/README.md +0 -275
  225. package/src/adapters/adapter-base.ts +0 -182
  226. package/src/adapters/adapter-interface.ts +0 -166
  227. package/src/adapters/adapter-loader.ts +0 -256
  228. package/src/adapters/agents-md-generator.ts +0 -228
  229. package/src/adapters/claude/README.md +0 -233
  230. package/src/adapters/claude/adapter.ts +0 -468
  231. package/src/adapters/claude-md-generator.ts +0 -377
  232. package/src/adapters/codex/README.md +0 -105
  233. package/src/adapters/codex/adapter.ts +0 -333
  234. package/src/adapters/cursor/.cursor/context/docs-context.md +0 -62
  235. package/src/adapters/cursor/.cursor/context/increments-context.md +0 -71
  236. package/src/adapters/cursor/.cursor/context/strategy-context.md +0 -73
  237. package/src/adapters/cursor/.cursor/context/tests-context.md +0 -89
  238. package/src/adapters/cursor/README.md +0 -283
  239. package/src/adapters/cursor/adapter.ts +0 -451
  240. package/src/adapters/doc-generator.ts +0 -331
  241. package/src/adapters/gemini/README.md +0 -97
  242. package/src/adapters/gemini/adapter.ts +0 -298
  243. package/src/adapters/generic/README.md +0 -277
  244. package/src/adapters/generic/adapter.ts +0 -378
  245. package/src/adapters/registry.yaml +0 -187
  246. /package/plugins/specweave/commands/{costs.md → specweave-costs.md} +0 -0
  247. /package/plugins/specweave/commands/{done.md → specweave-done.md} +0 -0
  248. /package/plugins/specweave/commands/{next.md → specweave-next.md} +0 -0
  249. /package/plugins/specweave/commands/{progress.md → specweave-progress.md} +0 -0
  250. /package/plugins/specweave/commands/{sync-docs.md → specweave-sync-docs.md} +0 -0
  251. /package/plugins/specweave/commands/{tdd-cycle.md → specweave-tdd-cycle.md} +0 -0
  252. /package/plugins/specweave/commands/{tdd-green.md → specweave-tdd-green.md} +0 -0
  253. /package/plugins/specweave/commands/{tdd-red.md → specweave-tdd-red.md} +0 -0
  254. /package/plugins/specweave/commands/{tdd-refactor.md → specweave-tdd-refactor.md} +0 -0
  255. /package/plugins/specweave/commands/{validate.md → specweave-validate.md} +0 -0
@@ -0,0 +1,361 @@
1
+ /**
2
+ * Azure DevOps REST API Client
3
+ *
4
+ * Provides TypeScript interface to Azure DevOps REST API v7.1
5
+ * for work item management and SpecWeave integration.
6
+ *
7
+ * @see https://learn.microsoft.com/en-us/rest/api/azure/devops/
8
+ */
9
+
10
+ import https from 'https';
11
+
12
+ // ============================================================================
13
+ // Types
14
+ // ============================================================================
15
+
16
+ export interface AdoConfig {
17
+ organization: string;
18
+ project: string;
19
+ personalAccessToken: string;
20
+ workItemType?: 'Epic' | 'Feature' | 'User Story';
21
+ areaPath?: string;
22
+ iterationPath?: string;
23
+ }
24
+
25
+ export interface WorkItem {
26
+ id: number;
27
+ rev: number;
28
+ fields: {
29
+ 'System.Title': string;
30
+ 'System.Description'?: string;
31
+ 'System.State': string;
32
+ 'System.AreaPath'?: string;
33
+ 'System.IterationPath'?: string;
34
+ 'System.Tags'?: string;
35
+ [key: string]: any;
36
+ };
37
+ _links: {
38
+ html: { href: string };
39
+ };
40
+ url: string;
41
+ }
42
+
43
+ export interface WorkItemComment {
44
+ id: number;
45
+ text: string;
46
+ createdBy: { displayName: string };
47
+ createdDate: string;
48
+ }
49
+
50
+ export interface CreateWorkItemRequest {
51
+ title: string;
52
+ description?: string;
53
+ areaPath?: string;
54
+ iterationPath?: string;
55
+ tags?: string[];
56
+ }
57
+
58
+ export interface UpdateWorkItemRequest {
59
+ state?: string;
60
+ title?: string;
61
+ description?: string;
62
+ tags?: string[];
63
+ }
64
+
65
+ // ============================================================================
66
+ // Azure DevOps Client
67
+ // ============================================================================
68
+
69
+ export class AdoClient {
70
+ private config: AdoConfig;
71
+ private baseUrl: string;
72
+ private authHeader: string;
73
+
74
+ constructor(config: AdoConfig) {
75
+ this.config = config;
76
+ this.baseUrl = `https://dev.azure.com/${config.organization}/${config.project}`;
77
+
78
+ // Basic Auth: base64(":PAT")
79
+ this.authHeader = 'Basic ' + Buffer.from(`:${config.personalAccessToken}`).toString('base64');
80
+ }
81
+
82
+ // ==========================================================================
83
+ // Work Item Operations
84
+ // ==========================================================================
85
+
86
+ /**
87
+ * Create a new work item
88
+ *
89
+ * @see https://learn.microsoft.com/en-us/rest/api/azure/devops/wit/work-items/create
90
+ */
91
+ async createWorkItem(request: CreateWorkItemRequest): Promise<WorkItem> {
92
+ const workItemType = this.config.workItemType || 'Epic';
93
+ const url = `${this.baseUrl}/_apis/wit/workitems/$${workItemType}?api-version=7.1`;
94
+
95
+ // Build JSON Patch document
96
+ const operations: any[] = [
97
+ {
98
+ op: 'add',
99
+ path: '/fields/System.Title',
100
+ value: request.title,
101
+ },
102
+ ];
103
+
104
+ if (request.description) {
105
+ operations.push({
106
+ op: 'add',
107
+ path: '/fields/System.Description',
108
+ value: `<pre>${request.description}</pre>`,
109
+ });
110
+ }
111
+
112
+ if (request.areaPath || this.config.areaPath) {
113
+ operations.push({
114
+ op: 'add',
115
+ path: '/fields/System.AreaPath',
116
+ value: request.areaPath || this.config.areaPath,
117
+ });
118
+ }
119
+
120
+ if (request.iterationPath || this.config.iterationPath) {
121
+ operations.push({
122
+ op: 'add',
123
+ path: '/fields/System.IterationPath',
124
+ value: request.iterationPath || this.config.iterationPath,
125
+ });
126
+ }
127
+
128
+ if (request.tags && request.tags.length > 0) {
129
+ operations.push({
130
+ op: 'add',
131
+ path: '/fields/System.Tags',
132
+ value: request.tags.join('; '),
133
+ });
134
+ }
135
+
136
+ const response = await this.request<WorkItem>('POST', url, operations, {
137
+ 'Content-Type': 'application/json-patch+json',
138
+ });
139
+
140
+ return response;
141
+ }
142
+
143
+ /**
144
+ * Get work item by ID
145
+ *
146
+ * @see https://learn.microsoft.com/en-us/rest/api/azure/devops/wit/work-items/get-work-item
147
+ */
148
+ async getWorkItem(id: number): Promise<WorkItem> {
149
+ const url = `${this.baseUrl}/_apis/wit/workitems/${id}?api-version=7.1`;
150
+ return this.request<WorkItem>('GET', url);
151
+ }
152
+
153
+ /**
154
+ * Update work item
155
+ *
156
+ * @see https://learn.microsoft.com/en-us/rest/api/azure/devops/wit/work-items/update
157
+ */
158
+ async updateWorkItem(id: number, request: UpdateWorkItemRequest): Promise<WorkItem> {
159
+ const url = `${this.baseUrl}/_apis/wit/workitems/${id}?api-version=7.1`;
160
+
161
+ const operations: any[] = [];
162
+
163
+ if (request.state) {
164
+ operations.push({
165
+ op: 'add',
166
+ path: '/fields/System.State',
167
+ value: request.state,
168
+ });
169
+ }
170
+
171
+ if (request.title) {
172
+ operations.push({
173
+ op: 'add',
174
+ path: '/fields/System.Title',
175
+ value: request.title,
176
+ });
177
+ }
178
+
179
+ if (request.description) {
180
+ operations.push({
181
+ op: 'add',
182
+ path: '/fields/System.Description',
183
+ value: `<pre>${request.description}</pre>`,
184
+ });
185
+ }
186
+
187
+ if (request.tags) {
188
+ operations.push({
189
+ op: 'add',
190
+ path: '/fields/System.Tags',
191
+ value: request.tags.join('; '),
192
+ });
193
+ }
194
+
195
+ return this.request<WorkItem>('PATCH', url, operations, {
196
+ 'Content-Type': 'application/json-patch+json',
197
+ });
198
+ }
199
+
200
+ /**
201
+ * Delete work item (move to Recycle Bin)
202
+ *
203
+ * @see https://learn.microsoft.com/en-us/rest/api/azure/devops/wit/work-items/delete
204
+ */
205
+ async deleteWorkItem(id: number): Promise<void> {
206
+ const url = `${this.baseUrl}/_apis/wit/workitems/${id}?api-version=7.1`;
207
+ await this.request('DELETE', url);
208
+ }
209
+
210
+ // ==========================================================================
211
+ // Comment Operations
212
+ // ==========================================================================
213
+
214
+ /**
215
+ * Add comment to work item
216
+ *
217
+ * @see https://learn.microsoft.com/en-us/rest/api/azure/devops/wit/comments/add
218
+ */
219
+ async addComment(workItemId: number, text: string): Promise<WorkItemComment> {
220
+ const url = `${this.baseUrl}/_apis/wit/workitems/${workItemId}/comments?api-version=7.1`;
221
+
222
+ const response = await this.request<WorkItemComment>('POST', url, { text });
223
+
224
+ return response;
225
+ }
226
+
227
+ /**
228
+ * Get comments for work item
229
+ *
230
+ * @see https://learn.microsoft.com/en-us/rest/api/azure/devops/wit/comments/list
231
+ */
232
+ async getComments(workItemId: number): Promise<WorkItemComment[]> {
233
+ const url = `${this.baseUrl}/_apis/wit/workitems/${workItemId}/comments?api-version=7.1`;
234
+
235
+ const response = await this.request<{ comments: WorkItemComment[] }>('GET', url);
236
+
237
+ return response.comments || [];
238
+ }
239
+
240
+ // ==========================================================================
241
+ // Helper Methods
242
+ // ==========================================================================
243
+
244
+ /**
245
+ * Make HTTP request to ADO API
246
+ */
247
+ private async request<T>(
248
+ method: string,
249
+ url: string,
250
+ body?: any,
251
+ additionalHeaders?: Record<string, string>
252
+ ): Promise<T> {
253
+ return new Promise((resolve, reject) => {
254
+ const urlObj = new URL(url);
255
+
256
+ const options: https.RequestOptions = {
257
+ hostname: urlObj.hostname,
258
+ port: 443,
259
+ path: urlObj.pathname + urlObj.search,
260
+ method,
261
+ headers: {
262
+ 'Authorization': this.authHeader,
263
+ 'Accept': 'application/json',
264
+ ...additionalHeaders,
265
+ },
266
+ };
267
+
268
+ const req = https.request(options, (res) => {
269
+ let data = '';
270
+
271
+ res.on('data', (chunk) => {
272
+ data += chunk;
273
+ });
274
+
275
+ res.on('end', () => {
276
+ if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
277
+ try {
278
+ const parsed = data ? JSON.parse(data) : {};
279
+ resolve(parsed as T);
280
+ } catch (error) {
281
+ reject(new Error(`Failed to parse JSON response: ${error}`));
282
+ }
283
+ } else {
284
+ let errorMessage = `ADO API error: ${res.statusCode} ${res.statusMessage}`;
285
+ try {
286
+ const errorData = JSON.parse(data);
287
+ if (errorData.message) {
288
+ errorMessage += ` - ${errorData.message}`;
289
+ }
290
+ } catch {
291
+ // Ignore JSON parse errors for error responses
292
+ }
293
+ reject(new Error(errorMessage));
294
+ }
295
+ });
296
+ });
297
+
298
+ req.on('error', (error) => {
299
+ reject(new Error(`HTTP request failed: ${error.message}`));
300
+ });
301
+
302
+ if (body) {
303
+ req.write(JSON.stringify(body));
304
+ }
305
+
306
+ req.end();
307
+ });
308
+ }
309
+
310
+ /**
311
+ * Test connection to ADO
312
+ */
313
+ async testConnection(): Promise<boolean> {
314
+ try {
315
+ // Simple test: list work item types
316
+ const url = `${this.baseUrl}/_apis/wit/workitemtypes?api-version=7.1`;
317
+ await this.request('GET', url);
318
+ return true;
319
+ } catch (error) {
320
+ return false;
321
+ }
322
+ }
323
+ }
324
+
325
+ // ============================================================================
326
+ // Factory Function
327
+ // ============================================================================
328
+
329
+ /**
330
+ * Create ADO client from environment variables and config
331
+ */
332
+ export function createAdoClient(config: Partial<AdoConfig> = {}): AdoClient {
333
+ const fullConfig: AdoConfig = {
334
+ organization: config.organization || process.env.AZURE_DEVOPS_ORG || '',
335
+ project: config.project || process.env.AZURE_DEVOPS_PROJECT || '',
336
+ personalAccessToken: config.personalAccessToken || process.env.AZURE_DEVOPS_PAT || '',
337
+ workItemType: config.workItemType,
338
+ areaPath: config.areaPath,
339
+ iterationPath: config.iterationPath,
340
+ };
341
+
342
+ if (!fullConfig.organization) {
343
+ throw new Error('ADO organization not configured');
344
+ }
345
+
346
+ if (!fullConfig.project) {
347
+ throw new Error('ADO project not configured');
348
+ }
349
+
350
+ if (!fullConfig.personalAccessToken) {
351
+ throw new Error('AZURE_DEVOPS_PAT not set');
352
+ }
353
+
354
+ return new AdoClient(fullConfig);
355
+ }
356
+
357
+ // ============================================================================
358
+ // Exports
359
+ // ============================================================================
360
+
361
+ export default AdoClient;