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.
- package/README.md +307 -56
- package/autopm/.claude/.env +158 -0
- package/autopm/.claude/settings.local.json +9 -0
- package/bin/autopm.js +11 -2
- package/bin/commands/epic.js +23 -3
- package/bin/commands/plugin.js +395 -0
- package/bin/commands/team.js +184 -10
- package/install/install.js +223 -4
- package/lib/cli/commands/issue.js +360 -20
- package/lib/plugins/PluginManager.js +1328 -0
- package/lib/plugins/PluginManager.old.js +400 -0
- package/lib/providers/AzureDevOpsProvider.js +575 -0
- package/lib/providers/GitHubProvider.js +475 -0
- package/lib/services/EpicService.js +1092 -3
- package/lib/services/IssueService.js +991 -0
- package/package.json +9 -1
- package/scripts/publish-plugins.sh +166 -0
- package/autopm/.claude/agents/cloud/README.md +0 -55
- package/autopm/.claude/agents/cloud/aws-cloud-architect.md +0 -521
- package/autopm/.claude/agents/cloud/azure-cloud-architect.md +0 -436
- package/autopm/.claude/agents/cloud/gcp-cloud-architect.md +0 -385
- package/autopm/.claude/agents/cloud/gcp-cloud-functions-engineer.md +0 -306
- package/autopm/.claude/agents/cloud/gemini-api-expert.md +0 -880
- package/autopm/.claude/agents/cloud/kubernetes-orchestrator.md +0 -566
- package/autopm/.claude/agents/cloud/openai-python-expert.md +0 -1087
- package/autopm/.claude/agents/cloud/terraform-infrastructure-expert.md +0 -454
- package/autopm/.claude/agents/core/agent-manager.md +0 -296
- package/autopm/.claude/agents/core/code-analyzer.md +0 -131
- package/autopm/.claude/agents/core/file-analyzer.md +0 -162
- package/autopm/.claude/agents/core/test-runner.md +0 -200
- package/autopm/.claude/agents/data/airflow-orchestration-expert.md +0 -52
- package/autopm/.claude/agents/data/kedro-pipeline-expert.md +0 -50
- package/autopm/.claude/agents/data/langgraph-workflow-expert.md +0 -520
- package/autopm/.claude/agents/databases/README.md +0 -50
- package/autopm/.claude/agents/databases/bigquery-expert.md +0 -392
- package/autopm/.claude/agents/databases/cosmosdb-expert.md +0 -368
- package/autopm/.claude/agents/databases/mongodb-expert.md +0 -398
- package/autopm/.claude/agents/databases/postgresql-expert.md +0 -321
- package/autopm/.claude/agents/databases/redis-expert.md +0 -52
- package/autopm/.claude/agents/devops/README.md +0 -52
- package/autopm/.claude/agents/devops/azure-devops-specialist.md +0 -308
- package/autopm/.claude/agents/devops/docker-containerization-expert.md +0 -298
- package/autopm/.claude/agents/devops/github-operations-specialist.md +0 -335
- package/autopm/.claude/agents/devops/mcp-context-manager.md +0 -319
- package/autopm/.claude/agents/devops/observability-engineer.md +0 -574
- package/autopm/.claude/agents/devops/ssh-operations-expert.md +0 -1093
- package/autopm/.claude/agents/devops/traefik-proxy-expert.md +0 -444
- package/autopm/.claude/agents/frameworks/README.md +0 -64
- package/autopm/.claude/agents/frameworks/e2e-test-engineer.md +0 -360
- package/autopm/.claude/agents/frameworks/nats-messaging-expert.md +0 -254
- package/autopm/.claude/agents/frameworks/react-frontend-engineer.md +0 -217
- package/autopm/.claude/agents/frameworks/react-ui-expert.md +0 -226
- package/autopm/.claude/agents/frameworks/tailwindcss-expert.md +0 -770
- package/autopm/.claude/agents/frameworks/ux-design-expert.md +0 -244
- package/autopm/.claude/agents/integration/message-queue-engineer.md +0 -794
- package/autopm/.claude/agents/languages/README.md +0 -50
- package/autopm/.claude/agents/languages/bash-scripting-expert.md +0 -541
- package/autopm/.claude/agents/languages/javascript-frontend-engineer.md +0 -197
- package/autopm/.claude/agents/languages/nodejs-backend-engineer.md +0 -226
- package/autopm/.claude/agents/languages/python-backend-engineer.md +0 -214
- package/autopm/.claude/agents/languages/python-backend-expert.md +0 -289
- package/autopm/.claude/agents/testing/frontend-testing-engineer.md +0 -395
- package/autopm/.claude/commands/ai/langgraph-workflow.md +0 -65
- package/autopm/.claude/commands/ai/openai-chat.md +0 -65
- package/autopm/.claude/commands/azure/COMMANDS.md +0 -107
- package/autopm/.claude/commands/azure/COMMAND_MAPPING.md +0 -252
- package/autopm/.claude/commands/azure/INTEGRATION_FIX.md +0 -103
- package/autopm/.claude/commands/azure/README.md +0 -246
- package/autopm/.claude/commands/azure/active-work.md +0 -198
- package/autopm/.claude/commands/azure/aliases.md +0 -143
- package/autopm/.claude/commands/azure/blocked-items.md +0 -287
- package/autopm/.claude/commands/azure/clean.md +0 -93
- package/autopm/.claude/commands/azure/docs-query.md +0 -48
- package/autopm/.claude/commands/azure/feature-decompose.md +0 -380
- package/autopm/.claude/commands/azure/feature-list.md +0 -61
- package/autopm/.claude/commands/azure/feature-new.md +0 -115
- package/autopm/.claude/commands/azure/feature-show.md +0 -205
- package/autopm/.claude/commands/azure/feature-start.md +0 -130
- package/autopm/.claude/commands/azure/fix-integration-example.md +0 -93
- package/autopm/.claude/commands/azure/help.md +0 -150
- package/autopm/.claude/commands/azure/import-us.md +0 -269
- package/autopm/.claude/commands/azure/init.md +0 -211
- package/autopm/.claude/commands/azure/next-task.md +0 -262
- package/autopm/.claude/commands/azure/search.md +0 -160
- package/autopm/.claude/commands/azure/sprint-status.md +0 -235
- package/autopm/.claude/commands/azure/standup.md +0 -260
- package/autopm/.claude/commands/azure/sync-all.md +0 -99
- package/autopm/.claude/commands/azure/task-analyze.md +0 -186
- package/autopm/.claude/commands/azure/task-close.md +0 -329
- package/autopm/.claude/commands/azure/task-edit.md +0 -145
- package/autopm/.claude/commands/azure/task-list.md +0 -263
- package/autopm/.claude/commands/azure/task-new.md +0 -84
- package/autopm/.claude/commands/azure/task-reopen.md +0 -79
- package/autopm/.claude/commands/azure/task-show.md +0 -126
- package/autopm/.claude/commands/azure/task-start.md +0 -301
- package/autopm/.claude/commands/azure/task-status.md +0 -65
- package/autopm/.claude/commands/azure/task-sync.md +0 -67
- package/autopm/.claude/commands/azure/us-edit.md +0 -164
- package/autopm/.claude/commands/azure/us-list.md +0 -202
- package/autopm/.claude/commands/azure/us-new.md +0 -265
- package/autopm/.claude/commands/azure/us-parse.md +0 -253
- package/autopm/.claude/commands/azure/us-show.md +0 -188
- package/autopm/.claude/commands/azure/us-status.md +0 -320
- package/autopm/.claude/commands/azure/validate.md +0 -86
- package/autopm/.claude/commands/azure/work-item-sync.md +0 -47
- package/autopm/.claude/commands/cloud/infra-deploy.md +0 -38
- package/autopm/.claude/commands/github/workflow-create.md +0 -42
- package/autopm/.claude/commands/infrastructure/ssh-security.md +0 -65
- package/autopm/.claude/commands/infrastructure/traefik-setup.md +0 -65
- package/autopm/.claude/commands/kubernetes/deploy.md +0 -37
- package/autopm/.claude/commands/playwright/test-scaffold.md +0 -38
- package/autopm/.claude/commands/pm/blocked.md +0 -28
- package/autopm/.claude/commands/pm/clean.md +0 -119
- package/autopm/.claude/commands/pm/context-create.md +0 -136
- package/autopm/.claude/commands/pm/context-prime.md +0 -170
- package/autopm/.claude/commands/pm/context-update.md +0 -292
- package/autopm/.claude/commands/pm/context.md +0 -28
- package/autopm/.claude/commands/pm/epic-close.md +0 -86
- package/autopm/.claude/commands/pm/epic-decompose.md +0 -370
- package/autopm/.claude/commands/pm/epic-edit.md +0 -83
- package/autopm/.claude/commands/pm/epic-list.md +0 -30
- package/autopm/.claude/commands/pm/epic-merge.md +0 -222
- package/autopm/.claude/commands/pm/epic-oneshot.md +0 -119
- package/autopm/.claude/commands/pm/epic-refresh.md +0 -119
- package/autopm/.claude/commands/pm/epic-show.md +0 -28
- package/autopm/.claude/commands/pm/epic-split.md +0 -120
- package/autopm/.claude/commands/pm/epic-start.md +0 -195
- package/autopm/.claude/commands/pm/epic-status.md +0 -28
- package/autopm/.claude/commands/pm/epic-sync-modular.md +0 -338
- package/autopm/.claude/commands/pm/epic-sync-original.md +0 -473
- package/autopm/.claude/commands/pm/epic-sync.md +0 -486
- package/autopm/.claude/commands/pm/help.md +0 -28
- package/autopm/.claude/commands/pm/import.md +0 -115
- package/autopm/.claude/commands/pm/in-progress.md +0 -28
- package/autopm/.claude/commands/pm/init.md +0 -28
- package/autopm/.claude/commands/pm/issue-analyze.md +0 -202
- package/autopm/.claude/commands/pm/issue-close.md +0 -119
- package/autopm/.claude/commands/pm/issue-edit.md +0 -93
- package/autopm/.claude/commands/pm/issue-reopen.md +0 -87
- package/autopm/.claude/commands/pm/issue-show.md +0 -41
- package/autopm/.claude/commands/pm/issue-start.md +0 -234
- package/autopm/.claude/commands/pm/issue-status.md +0 -95
- package/autopm/.claude/commands/pm/issue-sync.md +0 -411
- package/autopm/.claude/commands/pm/next.md +0 -28
- package/autopm/.claude/commands/pm/prd-edit.md +0 -82
- package/autopm/.claude/commands/pm/prd-list.md +0 -28
- package/autopm/.claude/commands/pm/prd-new.md +0 -55
- package/autopm/.claude/commands/pm/prd-parse.md +0 -42
- package/autopm/.claude/commands/pm/prd-status.md +0 -28
- package/autopm/.claude/commands/pm/search.md +0 -28
- package/autopm/.claude/commands/pm/standup.md +0 -28
- package/autopm/.claude/commands/pm/status.md +0 -28
- package/autopm/.claude/commands/pm/sync.md +0 -99
- package/autopm/.claude/commands/pm/test-reference-update.md +0 -151
- package/autopm/.claude/commands/pm/validate.md +0 -28
- package/autopm/.claude/commands/pm/what-next.md +0 -28
- package/autopm/.claude/commands/python/api-scaffold.md +0 -50
- package/autopm/.claude/commands/python/docs-query.md +0 -48
- package/autopm/.claude/commands/react/app-scaffold.md +0 -50
- package/autopm/.claude/commands/testing/prime.md +0 -314
- package/autopm/.claude/commands/testing/run.md +0 -125
- package/autopm/.claude/commands/ui/bootstrap-scaffold.md +0 -65
- package/autopm/.claude/commands/ui/tailwind-system.md +0 -64
- package/autopm/.claude/rules/ai-integration-patterns.md +0 -219
- package/autopm/.claude/rules/ci-cd-kubernetes-strategy.md +0 -25
- package/autopm/.claude/rules/database-management-strategy.md +0 -17
- package/autopm/.claude/rules/database-pipeline.md +0 -94
- package/autopm/.claude/rules/devops-troubleshooting-playbook.md +0 -450
- package/autopm/.claude/rules/docker-first-development.md +0 -404
- package/autopm/.claude/rules/infrastructure-pipeline.md +0 -128
- package/autopm/.claude/rules/performance-guidelines.md +0 -403
- package/autopm/.claude/rules/ui-development-standards.md +0 -281
- package/autopm/.claude/rules/ui-framework-rules.md +0 -151
- package/autopm/.claude/rules/ux-design-rules.md +0 -209
- package/autopm/.claude/rules/visual-testing.md +0 -223
- package/autopm/.claude/scripts/azure/README.md +0 -192
- package/autopm/.claude/scripts/azure/active-work.js +0 -524
- package/autopm/.claude/scripts/azure/active-work.sh +0 -20
- package/autopm/.claude/scripts/azure/blocked.js +0 -520
- package/autopm/.claude/scripts/azure/blocked.sh +0 -20
- package/autopm/.claude/scripts/azure/daily.js +0 -533
- package/autopm/.claude/scripts/azure/daily.sh +0 -20
- package/autopm/.claude/scripts/azure/dashboard.js +0 -970
- package/autopm/.claude/scripts/azure/dashboard.sh +0 -20
- package/autopm/.claude/scripts/azure/feature-list.js +0 -254
- package/autopm/.claude/scripts/azure/feature-list.sh +0 -20
- package/autopm/.claude/scripts/azure/feature-show.js +0 -7
- package/autopm/.claude/scripts/azure/feature-show.sh +0 -20
- package/autopm/.claude/scripts/azure/feature-status.js +0 -604
- package/autopm/.claude/scripts/azure/feature-status.sh +0 -20
- package/autopm/.claude/scripts/azure/help.js +0 -342
- package/autopm/.claude/scripts/azure/help.sh +0 -20
- package/autopm/.claude/scripts/azure/next-task.js +0 -508
- package/autopm/.claude/scripts/azure/next-task.sh +0 -20
- package/autopm/.claude/scripts/azure/search.js +0 -469
- package/autopm/.claude/scripts/azure/search.sh +0 -20
- package/autopm/.claude/scripts/azure/setup.js +0 -745
- package/autopm/.claude/scripts/azure/setup.sh +0 -20
- package/autopm/.claude/scripts/azure/sprint-report.js +0 -1012
- package/autopm/.claude/scripts/azure/sprint-report.sh +0 -20
- package/autopm/.claude/scripts/azure/sync.js +0 -563
- package/autopm/.claude/scripts/azure/sync.sh +0 -20
- package/autopm/.claude/scripts/azure/us-list.js +0 -210
- package/autopm/.claude/scripts/azure/us-list.sh +0 -20
- package/autopm/.claude/scripts/azure/us-status.js +0 -238
- package/autopm/.claude/scripts/azure/us-status.sh +0 -20
- package/autopm/.claude/scripts/azure/validate.js +0 -626
- package/autopm/.claude/scripts/azure/validate.sh +0 -20
- package/autopm/.claude/scripts/azure/wrapper-template.sh +0 -20
- package/autopm/.claude/scripts/github/dependency-tracker.js +0 -554
- package/autopm/.claude/scripts/github/dependency-validator.js +0 -545
- package/autopm/.claude/scripts/github/dependency-visualizer.js +0 -477
- package/autopm/.claude/scripts/pm/analytics.js +0 -425
- package/autopm/.claude/scripts/pm/blocked.js +0 -164
- package/autopm/.claude/scripts/pm/blocked.sh +0 -78
- package/autopm/.claude/scripts/pm/clean.js +0 -464
- package/autopm/.claude/scripts/pm/context-create.js +0 -216
- package/autopm/.claude/scripts/pm/context-prime.js +0 -335
- package/autopm/.claude/scripts/pm/context-update.js +0 -344
- package/autopm/.claude/scripts/pm/context.js +0 -338
- package/autopm/.claude/scripts/pm/epic-close.js +0 -347
- package/autopm/.claude/scripts/pm/epic-edit.js +0 -382
- package/autopm/.claude/scripts/pm/epic-list.js +0 -273
- package/autopm/.claude/scripts/pm/epic-list.sh +0 -109
- package/autopm/.claude/scripts/pm/epic-show.js +0 -291
- package/autopm/.claude/scripts/pm/epic-show.sh +0 -105
- package/autopm/.claude/scripts/pm/epic-split.js +0 -522
- package/autopm/.claude/scripts/pm/epic-start/epic-start.js +0 -183
- package/autopm/.claude/scripts/pm/epic-start/epic-start.sh +0 -94
- package/autopm/.claude/scripts/pm/epic-status.js +0 -291
- package/autopm/.claude/scripts/pm/epic-status.sh +0 -104
- package/autopm/.claude/scripts/pm/epic-sync/README.md +0 -208
- package/autopm/.claude/scripts/pm/epic-sync/create-epic-issue.sh +0 -77
- package/autopm/.claude/scripts/pm/epic-sync/create-task-issues.sh +0 -86
- package/autopm/.claude/scripts/pm/epic-sync/update-epic-file.sh +0 -79
- package/autopm/.claude/scripts/pm/epic-sync/update-references.sh +0 -89
- package/autopm/.claude/scripts/pm/epic-sync.sh +0 -137
- package/autopm/.claude/scripts/pm/help.js +0 -92
- package/autopm/.claude/scripts/pm/help.sh +0 -90
- package/autopm/.claude/scripts/pm/in-progress.js +0 -178
- package/autopm/.claude/scripts/pm/in-progress.sh +0 -93
- package/autopm/.claude/scripts/pm/init.js +0 -321
- package/autopm/.claude/scripts/pm/init.sh +0 -178
- package/autopm/.claude/scripts/pm/issue-close.js +0 -232
- package/autopm/.claude/scripts/pm/issue-edit.js +0 -310
- package/autopm/.claude/scripts/pm/issue-show.js +0 -272
- package/autopm/.claude/scripts/pm/issue-start.js +0 -181
- package/autopm/.claude/scripts/pm/issue-sync/format-comment.sh +0 -468
- package/autopm/.claude/scripts/pm/issue-sync/gather-updates.sh +0 -460
- package/autopm/.claude/scripts/pm/issue-sync/post-comment.sh +0 -330
- package/autopm/.claude/scripts/pm/issue-sync/preflight-validation.sh +0 -348
- package/autopm/.claude/scripts/pm/issue-sync/update-frontmatter.sh +0 -387
- package/autopm/.claude/scripts/pm/lib/README.md +0 -85
- package/autopm/.claude/scripts/pm/lib/epic-discovery.js +0 -119
- package/autopm/.claude/scripts/pm/lib/logger.js +0 -78
- package/autopm/.claude/scripts/pm/next.js +0 -189
- package/autopm/.claude/scripts/pm/next.sh +0 -72
- package/autopm/.claude/scripts/pm/optimize.js +0 -407
- package/autopm/.claude/scripts/pm/pr-create.js +0 -337
- package/autopm/.claude/scripts/pm/pr-list.js +0 -257
- package/autopm/.claude/scripts/pm/prd-list.js +0 -242
- package/autopm/.claude/scripts/pm/prd-list.sh +0 -103
- package/autopm/.claude/scripts/pm/prd-new.js +0 -684
- package/autopm/.claude/scripts/pm/prd-parse.js +0 -547
- package/autopm/.claude/scripts/pm/prd-status.js +0 -152
- package/autopm/.claude/scripts/pm/prd-status.sh +0 -63
- package/autopm/.claude/scripts/pm/release.js +0 -460
- package/autopm/.claude/scripts/pm/search.js +0 -192
- package/autopm/.claude/scripts/pm/search.sh +0 -89
- package/autopm/.claude/scripts/pm/standup.js +0 -362
- package/autopm/.claude/scripts/pm/standup.sh +0 -95
- package/autopm/.claude/scripts/pm/status.js +0 -148
- package/autopm/.claude/scripts/pm/status.sh +0 -59
- package/autopm/.claude/scripts/pm/sync-batch.js +0 -337
- package/autopm/.claude/scripts/pm/sync.js +0 -343
- package/autopm/.claude/scripts/pm/template-list.js +0 -141
- package/autopm/.claude/scripts/pm/template-new.js +0 -366
- package/autopm/.claude/scripts/pm/validate.js +0 -274
- package/autopm/.claude/scripts/pm/validate.sh +0 -106
- package/autopm/.claude/scripts/pm/what-next.js +0 -660
- package/bin/node/azure-feature-show.js +0 -7
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Azure DevOps Provider for ClaudeAutoPM
|
|
3
|
+
*
|
|
4
|
+
* Provides bidirectional synchronization with Azure DevOps Work Items
|
|
5
|
+
* following 2025 best practices
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Full CRUD operations for work items (Epic, Feature, User Story, Task, Bug)
|
|
9
|
+
* - Comment management
|
|
10
|
+
* - Area Path and Iteration Path management
|
|
11
|
+
* - WIQL queries for advanced filtering
|
|
12
|
+
* - Relation management (Parent/Child links)
|
|
13
|
+
* - State mapping (Azure DevOps <-> Local)
|
|
14
|
+
* - Error handling with meaningful messages
|
|
15
|
+
*
|
|
16
|
+
* @module lib/providers/AzureDevOpsProvider
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const azdev = require('azure-devops-node-api');
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Azure DevOps Provider Class
|
|
23
|
+
*
|
|
24
|
+
* Manages integration with Azure DevOps Work Item Tracking API
|
|
25
|
+
*
|
|
26
|
+
* @class AzureDevOpsProvider
|
|
27
|
+
*/
|
|
28
|
+
class AzureDevOpsProvider {
|
|
29
|
+
/**
|
|
30
|
+
* Creates a new Azure DevOps provider instance
|
|
31
|
+
*
|
|
32
|
+
* @param {Object} options - Configuration options
|
|
33
|
+
* @param {string} [options.token] - Personal Access Token (PAT)
|
|
34
|
+
* @param {string} [options.organization] - Azure DevOps organization name
|
|
35
|
+
* @param {string} [options.project] - Project name
|
|
36
|
+
*/
|
|
37
|
+
constructor(options = {}) {
|
|
38
|
+
this.token = options.token || process.env.AZURE_DEVOPS_PAT;
|
|
39
|
+
this.organization = options.organization || process.env.AZURE_DEVOPS_ORG;
|
|
40
|
+
this.project = options.project || process.env.AZURE_DEVOPS_PROJECT;
|
|
41
|
+
|
|
42
|
+
this.connection = null;
|
|
43
|
+
this.witApi = null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Authenticates with Azure DevOps API
|
|
48
|
+
*
|
|
49
|
+
* Creates connection using PAT and verifies project access
|
|
50
|
+
*
|
|
51
|
+
* @async
|
|
52
|
+
* @returns {Promise<Object>} Project object
|
|
53
|
+
* @throws {Error} If token, organization, or project is missing
|
|
54
|
+
* @throws {Error} If project not found or access denied
|
|
55
|
+
*/
|
|
56
|
+
async authenticate() {
|
|
57
|
+
if (!this.token) {
|
|
58
|
+
throw new Error('Azure DevOps PAT token is required');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!this.organization) {
|
|
62
|
+
throw new Error('Azure DevOps organization is required');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!this.project) {
|
|
66
|
+
throw new Error('Azure DevOps project is required');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Create organization URL
|
|
70
|
+
const orgUrl = `https://dev.azure.com/${this.organization}`;
|
|
71
|
+
|
|
72
|
+
// Create auth handler
|
|
73
|
+
const authHandler = azdev.getPersonalAccessTokenHandler(this.token);
|
|
74
|
+
|
|
75
|
+
// Create connection
|
|
76
|
+
this.connection = new azdev.WebApi(orgUrl, authHandler);
|
|
77
|
+
|
|
78
|
+
// Get Work Item Tracking API
|
|
79
|
+
this.witApi = await this.connection.getWorkItemTrackingApi();
|
|
80
|
+
|
|
81
|
+
// Verify project access
|
|
82
|
+
const project = await this.witApi.getProject(this.project);
|
|
83
|
+
if (!project) {
|
|
84
|
+
throw new Error('Project not found or access denied');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return project;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Fetches a single work item by ID
|
|
92
|
+
*
|
|
93
|
+
* @async
|
|
94
|
+
* @param {number} id - Work item ID
|
|
95
|
+
* @param {string} [expand] - Expand option (None, Relations, Fields, Links, All)
|
|
96
|
+
* @returns {Promise<Object>} Work item object
|
|
97
|
+
* @throws {Error} If work item is not found
|
|
98
|
+
*/
|
|
99
|
+
async getWorkItem(id, expand) {
|
|
100
|
+
try {
|
|
101
|
+
return await this._makeRequest(async () => {
|
|
102
|
+
return await this.witApi.getWorkItem(id, expand);
|
|
103
|
+
});
|
|
104
|
+
} catch (error) {
|
|
105
|
+
if (error.statusCode === 404) {
|
|
106
|
+
throw new Error(`Work item not found: ${id}`);
|
|
107
|
+
}
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Lists work items with optional filtering
|
|
114
|
+
*
|
|
115
|
+
* @async
|
|
116
|
+
* @param {Object} [filters={}] - Filter options
|
|
117
|
+
* @param {string} [filters.type] - Work item type (Epic, Feature, User Story, Task, Bug)
|
|
118
|
+
* @param {string} [filters.state] - Work item state (New, Active, Resolved, Closed)
|
|
119
|
+
* @param {string} [filters.areaPath] - Area path filter
|
|
120
|
+
* @param {string} [filters.iterationPath] - Iteration path filter
|
|
121
|
+
* @returns {Promise<Array>} Array of work item objects
|
|
122
|
+
*/
|
|
123
|
+
async listWorkItems(filters = {}) {
|
|
124
|
+
// Build WIQL query
|
|
125
|
+
let wiql = `SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = '${this.project}'`;
|
|
126
|
+
|
|
127
|
+
if (filters.type) {
|
|
128
|
+
wiql += ` AND [System.WorkItemType] = '${filters.type}'`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (filters.state) {
|
|
132
|
+
wiql += ` AND [System.State] = '${filters.state}'`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (filters.areaPath) {
|
|
136
|
+
wiql += ` AND [System.AreaPath] = '${filters.areaPath}'`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (filters.iterationPath) {
|
|
140
|
+
wiql += ` AND [System.IterationPath] = '${filters.iterationPath}'`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Execute query
|
|
144
|
+
const queryResult = await this.witApi.queryByWiql(
|
|
145
|
+
{ query: wiql },
|
|
146
|
+
this.project
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
// Get work item IDs
|
|
150
|
+
const ids = queryResult.workItems ? queryResult.workItems.map(wi => wi.id) : [];
|
|
151
|
+
|
|
152
|
+
if (ids.length === 0) {
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Fetch full work items
|
|
157
|
+
const workItems = await this.witApi.getWorkItems(
|
|
158
|
+
ids,
|
|
159
|
+
undefined,
|
|
160
|
+
undefined,
|
|
161
|
+
'None'
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
return workItems;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Creates a new work item
|
|
169
|
+
*
|
|
170
|
+
* @async
|
|
171
|
+
* @param {string} type - Work item type (Epic, Feature, User Story, Task, Bug)
|
|
172
|
+
* @param {Object} data - Work item data
|
|
173
|
+
* @param {string} data.title - Work item title (required)
|
|
174
|
+
* @param {string} [data.description] - Work item description
|
|
175
|
+
* @param {string} [data.state] - Work item state
|
|
176
|
+
* @param {string} [data.areaPath] - Area path
|
|
177
|
+
* @param {string} [data.iterationPath] - Iteration path
|
|
178
|
+
* @returns {Promise<Object>} Created work item object
|
|
179
|
+
* @throws {Error} If title is missing
|
|
180
|
+
*/
|
|
181
|
+
async createWorkItem(type, data) {
|
|
182
|
+
if (!data.title) {
|
|
183
|
+
throw new Error('Work item title is required');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Build JSON Patch Document
|
|
187
|
+
const patchDoc = [
|
|
188
|
+
{
|
|
189
|
+
op: 'add',
|
|
190
|
+
path: '/fields/System.Title',
|
|
191
|
+
value: data.title
|
|
192
|
+
}
|
|
193
|
+
];
|
|
194
|
+
|
|
195
|
+
if (data.description) {
|
|
196
|
+
patchDoc.push({
|
|
197
|
+
op: 'add',
|
|
198
|
+
path: '/fields/System.Description',
|
|
199
|
+
value: data.description
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (data.state) {
|
|
204
|
+
patchDoc.push({
|
|
205
|
+
op: 'add',
|
|
206
|
+
path: '/fields/System.State',
|
|
207
|
+
value: data.state
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (data.areaPath) {
|
|
212
|
+
patchDoc.push({
|
|
213
|
+
op: 'add',
|
|
214
|
+
path: '/fields/System.AreaPath',
|
|
215
|
+
value: data.areaPath
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (data.iterationPath) {
|
|
220
|
+
patchDoc.push({
|
|
221
|
+
op: 'add',
|
|
222
|
+
path: '/fields/System.IterationPath',
|
|
223
|
+
value: data.iterationPath
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return await this.witApi.createWorkItem(
|
|
228
|
+
null,
|
|
229
|
+
patchDoc,
|
|
230
|
+
this.project,
|
|
231
|
+
type
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Updates an existing work item
|
|
237
|
+
*
|
|
238
|
+
* @async
|
|
239
|
+
* @param {number} id - Work item ID
|
|
240
|
+
* @param {Object} data - Fields to update
|
|
241
|
+
* @param {string} [data.title] - New title
|
|
242
|
+
* @param {string} [data.description] - New description
|
|
243
|
+
* @param {string} [data.state] - New state
|
|
244
|
+
* @param {string} [data.areaPath] - New area path
|
|
245
|
+
* @param {string} [data.iterationPath] - New iteration path
|
|
246
|
+
* @returns {Promise<Object>} Updated work item object
|
|
247
|
+
*/
|
|
248
|
+
async updateWorkItem(id, data) {
|
|
249
|
+
// Build JSON Patch Document
|
|
250
|
+
const patchDoc = [];
|
|
251
|
+
|
|
252
|
+
if (data.title) {
|
|
253
|
+
patchDoc.push({
|
|
254
|
+
op: 'replace',
|
|
255
|
+
path: '/fields/System.Title',
|
|
256
|
+
value: data.title
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (data.description) {
|
|
261
|
+
patchDoc.push({
|
|
262
|
+
op: 'replace',
|
|
263
|
+
path: '/fields/System.Description',
|
|
264
|
+
value: data.description
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (data.state) {
|
|
269
|
+
patchDoc.push({
|
|
270
|
+
op: 'replace',
|
|
271
|
+
path: '/fields/System.State',
|
|
272
|
+
value: data.state
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (data.areaPath) {
|
|
277
|
+
patchDoc.push({
|
|
278
|
+
op: 'replace',
|
|
279
|
+
path: '/fields/System.AreaPath',
|
|
280
|
+
value: data.areaPath
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (data.iterationPath) {
|
|
285
|
+
patchDoc.push({
|
|
286
|
+
op: 'replace',
|
|
287
|
+
path: '/fields/System.IterationPath',
|
|
288
|
+
value: data.iterationPath
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return await this.witApi.updateWorkItem(null, patchDoc, id);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Deletes a work item
|
|
297
|
+
*
|
|
298
|
+
* @async
|
|
299
|
+
* @param {number} id - Work item ID
|
|
300
|
+
* @returns {Promise<Object>} Delete result
|
|
301
|
+
* @throws {Error} If work item not found
|
|
302
|
+
*/
|
|
303
|
+
async deleteWorkItem(id) {
|
|
304
|
+
try {
|
|
305
|
+
return await this._makeRequest(async () => {
|
|
306
|
+
return await this.witApi.deleteWorkItem(id);
|
|
307
|
+
}, { id });
|
|
308
|
+
} catch (error) {
|
|
309
|
+
if (error.statusCode === 404) {
|
|
310
|
+
throw new Error(`Work item not found: ${id}`);
|
|
311
|
+
}
|
|
312
|
+
throw error;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Adds a comment to a work item
|
|
318
|
+
*
|
|
319
|
+
* @async
|
|
320
|
+
* @param {number} workItemId - Work item ID
|
|
321
|
+
* @param {string} text - Comment text
|
|
322
|
+
* @returns {Promise<Object>} Created comment object
|
|
323
|
+
* @throws {Error} If text is empty
|
|
324
|
+
*/
|
|
325
|
+
async addComment(workItemId, text) {
|
|
326
|
+
if (!text || text.trim() === '') {
|
|
327
|
+
throw new Error('Comment text is required');
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return await this.witApi.addComment(
|
|
331
|
+
{ text },
|
|
332
|
+
this.project,
|
|
333
|
+
workItemId
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Gets all comments for a work item
|
|
339
|
+
*
|
|
340
|
+
* @async
|
|
341
|
+
* @param {number} workItemId - Work item ID
|
|
342
|
+
* @returns {Promise<Object>} Comments object with comments array
|
|
343
|
+
*/
|
|
344
|
+
async getComments(workItemId) {
|
|
345
|
+
return await this.witApi.getComments(this.project, workItemId);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Updates a comment
|
|
350
|
+
*
|
|
351
|
+
* @async
|
|
352
|
+
* @param {number} workItemId - Work item ID
|
|
353
|
+
* @param {number} commentId - Comment ID
|
|
354
|
+
* @param {string} text - New comment text
|
|
355
|
+
* @returns {Promise<Object>} Updated comment object
|
|
356
|
+
*/
|
|
357
|
+
async updateComment(workItemId, commentId, text) {
|
|
358
|
+
return await this.witApi.updateComment(
|
|
359
|
+
{ text },
|
|
360
|
+
this.project,
|
|
361
|
+
workItemId,
|
|
362
|
+
commentId
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Deletes a comment
|
|
368
|
+
*
|
|
369
|
+
* @async
|
|
370
|
+
* @param {number} workItemId - Work item ID
|
|
371
|
+
* @param {number} commentId - Comment ID
|
|
372
|
+
* @returns {Promise<void>}
|
|
373
|
+
*/
|
|
374
|
+
async deleteComment(workItemId, commentId) {
|
|
375
|
+
return await this.witApi.deleteComment(
|
|
376
|
+
this.project,
|
|
377
|
+
workItemId,
|
|
378
|
+
commentId
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Sets the area path for a work item
|
|
384
|
+
*
|
|
385
|
+
* @async
|
|
386
|
+
* @param {number} workItemId - Work item ID
|
|
387
|
+
* @param {string} path - Area path (e.g., "project\\Team A")
|
|
388
|
+
* @returns {Promise<Object>} Updated work item object
|
|
389
|
+
*/
|
|
390
|
+
async setAreaPath(workItemId, path) {
|
|
391
|
+
const patchDoc = [
|
|
392
|
+
{
|
|
393
|
+
op: 'replace',
|
|
394
|
+
path: '/fields/System.AreaPath',
|
|
395
|
+
value: path
|
|
396
|
+
}
|
|
397
|
+
];
|
|
398
|
+
|
|
399
|
+
return await this.witApi.updateWorkItem(null, patchDoc, workItemId);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Sets the iteration path for a work item
|
|
404
|
+
*
|
|
405
|
+
* @async
|
|
406
|
+
* @param {number} workItemId - Work item ID
|
|
407
|
+
* @param {string} path - Iteration path (e.g., "project\\Sprint 1")
|
|
408
|
+
* @returns {Promise<Object>} Updated work item object
|
|
409
|
+
*/
|
|
410
|
+
async setIterationPath(workItemId, path) {
|
|
411
|
+
const patchDoc = [
|
|
412
|
+
{
|
|
413
|
+
op: 'replace',
|
|
414
|
+
path: '/fields/System.IterationPath',
|
|
415
|
+
value: path
|
|
416
|
+
}
|
|
417
|
+
];
|
|
418
|
+
|
|
419
|
+
return await this.witApi.updateWorkItem(null, patchDoc, workItemId);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Executes a WIQL query
|
|
424
|
+
*
|
|
425
|
+
* @async
|
|
426
|
+
* @param {string} wiql - WIQL query string
|
|
427
|
+
* @param {Object} [options={}] - Query options
|
|
428
|
+
* @param {string} [options.expand] - Expand option for work items
|
|
429
|
+
* @returns {Promise<Array>} Array of work item objects
|
|
430
|
+
*/
|
|
431
|
+
async queryWorkItems(wiql, options = {}) {
|
|
432
|
+
// Execute query
|
|
433
|
+
const queryResult = await this.witApi.queryByWiql(
|
|
434
|
+
{ query: wiql },
|
|
435
|
+
this.project
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
// Get work item IDs
|
|
439
|
+
const ids = queryResult.workItems ? queryResult.workItems.map(wi => wi.id) : [];
|
|
440
|
+
|
|
441
|
+
if (ids.length === 0 || !ids.length) {
|
|
442
|
+
return [];
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Fetch full work items
|
|
446
|
+
const expand = options.expand || 'None';
|
|
447
|
+
const workItems = await this.witApi.getWorkItems(
|
|
448
|
+
ids,
|
|
449
|
+
undefined,
|
|
450
|
+
undefined,
|
|
451
|
+
expand
|
|
452
|
+
);
|
|
453
|
+
|
|
454
|
+
return workItems;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Adds a relation to a work item
|
|
459
|
+
*
|
|
460
|
+
* @async
|
|
461
|
+
* @param {number} workItemId - Work item ID
|
|
462
|
+
* @param {Object} relation - Relation object
|
|
463
|
+
* @param {string} relation.rel - Relation type (e.g., "System.LinkTypes.Hierarchy-Reverse")
|
|
464
|
+
* @param {string} relation.url - Related work item URL
|
|
465
|
+
* @returns {Promise<Object>} Updated work item object
|
|
466
|
+
*/
|
|
467
|
+
async addRelation(workItemId, relation) {
|
|
468
|
+
const patchDoc = [
|
|
469
|
+
{
|
|
470
|
+
op: 'add',
|
|
471
|
+
path: '/relations/-',
|
|
472
|
+
value: relation
|
|
473
|
+
}
|
|
474
|
+
];
|
|
475
|
+
|
|
476
|
+
return await this.witApi.updateWorkItem(null, patchDoc, workItemId);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Gets all relations for a work item
|
|
481
|
+
*
|
|
482
|
+
* @async
|
|
483
|
+
* @param {number} workItemId - Work item ID
|
|
484
|
+
* @returns {Promise<Array>} Array of relation objects
|
|
485
|
+
*/
|
|
486
|
+
async getRelations(workItemId) {
|
|
487
|
+
const workItem = await this.witApi.getWorkItem(workItemId, 'Relations');
|
|
488
|
+
|
|
489
|
+
return workItem.relations || [];
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Checks rate limit status
|
|
494
|
+
*
|
|
495
|
+
* Azure DevOps does not expose rate limit information via API
|
|
496
|
+
*
|
|
497
|
+
* @async
|
|
498
|
+
* @returns {Promise<Object>} Rate limit information (not available)
|
|
499
|
+
*/
|
|
500
|
+
async checkRateLimit() {
|
|
501
|
+
return {
|
|
502
|
+
available: false,
|
|
503
|
+
message: 'Azure DevOps does not expose rate limit information via API'
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Maps Azure DevOps state to local status
|
|
509
|
+
*
|
|
510
|
+
* @param {string} azureState - Azure DevOps state
|
|
511
|
+
* @returns {string} Local status
|
|
512
|
+
*/
|
|
513
|
+
_mapStateToLocal(azureState) {
|
|
514
|
+
const stateMap = {
|
|
515
|
+
'New': 'open',
|
|
516
|
+
'Active': 'in-progress',
|
|
517
|
+
'Resolved': 'done',
|
|
518
|
+
'Closed': 'closed',
|
|
519
|
+
'Removed': 'closed'
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
return stateMap[azureState] || azureState;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Maps local status to Azure DevOps state
|
|
527
|
+
*
|
|
528
|
+
* @param {string} localStatus - Local status
|
|
529
|
+
* @returns {string} Azure DevOps state
|
|
530
|
+
*/
|
|
531
|
+
_mapLocalStatusToState(localStatus) {
|
|
532
|
+
const statusMap = {
|
|
533
|
+
'open': 'New',
|
|
534
|
+
'in-progress': 'Active',
|
|
535
|
+
'done': 'Resolved',
|
|
536
|
+
'closed': 'Closed'
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
return statusMap[localStatus] || localStatus;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Makes a request with error handling
|
|
544
|
+
*
|
|
545
|
+
* @async
|
|
546
|
+
* @param {Function} requestFn - Function that makes the request
|
|
547
|
+
* @param {Object} [context={}] - Context for error messages
|
|
548
|
+
* @returns {Promise<*>} Response data
|
|
549
|
+
* @throws {Error} If request fails with meaningful error message
|
|
550
|
+
* @private
|
|
551
|
+
*/
|
|
552
|
+
async _makeRequest(requestFn, context = {}) {
|
|
553
|
+
try {
|
|
554
|
+
return await requestFn();
|
|
555
|
+
} catch (error) {
|
|
556
|
+
// Handle specific error codes
|
|
557
|
+
if (error.statusCode === 401) {
|
|
558
|
+
throw new Error('Authentication failed - check AZURE_DEVOPS_PAT');
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
if (error.statusCode === 403) {
|
|
562
|
+
throw new Error('Access denied - check PAT permissions');
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (error.statusCode === 404 && context.id) {
|
|
566
|
+
throw new Error(`Work item not found: ${context.id}`);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// Rethrow other errors
|
|
570
|
+
throw error;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
module.exports = AzureDevOpsProvider;
|