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
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
# Azure DevOps Shell Scripts
|
|
2
|
-
|
|
3
|
-
Automation scripts for Azure DevOps integration.
|
|
4
|
-
|
|
5
|
-
## Available Scripts
|
|
6
|
-
|
|
7
|
-
### setup.sh
|
|
8
|
-
**Initial setup and configuration**
|
|
9
|
-
```bash
|
|
10
|
-
./setup.sh
|
|
11
|
-
```
|
|
12
|
-
- Configures Azure DevOps credentials
|
|
13
|
-
- Tests connection
|
|
14
|
-
- Creates directory structure
|
|
15
|
-
- Generates configuration files
|
|
16
|
-
|
|
17
|
-
### daily.sh
|
|
18
|
-
**Daily workflow automation**
|
|
19
|
-
```bash
|
|
20
|
-
./daily.sh
|
|
21
|
-
```
|
|
22
|
-
- Shows standup summary
|
|
23
|
-
- Lists active work
|
|
24
|
-
- Checks for blockers
|
|
25
|
-
- Suggests next task
|
|
26
|
-
|
|
27
|
-
### sprint-report.sh
|
|
28
|
-
**Generate sprint reports**
|
|
29
|
-
```bash
|
|
30
|
-
./sprint-report.sh [sprint-name]
|
|
31
|
-
./sprint-report.sh current
|
|
32
|
-
./sprint-report.sh "Sprint 2"
|
|
33
|
-
```
|
|
34
|
-
- Sprint progress and metrics
|
|
35
|
-
- Burndown analysis
|
|
36
|
-
- Team performance
|
|
37
|
-
- Risk assessment
|
|
38
|
-
|
|
39
|
-
### sync.sh
|
|
40
|
-
**Synchronize with Azure DevOps**
|
|
41
|
-
```bash
|
|
42
|
-
./sync.sh --quick # Recent changes only
|
|
43
|
-
./sync.sh --full # Full synchronization
|
|
44
|
-
```
|
|
45
|
-
- Syncs work items to local cache
|
|
46
|
-
- Detects conflicts
|
|
47
|
-
- Cleans old cache files
|
|
48
|
-
|
|
49
|
-
## Usage Examples
|
|
50
|
-
|
|
51
|
-
### Morning Routine
|
|
52
|
-
```bash
|
|
53
|
-
# Start your day
|
|
54
|
-
./daily.sh
|
|
55
|
-
|
|
56
|
-
# Get detailed sprint status
|
|
57
|
-
./sprint-report.sh current
|
|
58
|
-
|
|
59
|
-
# Sync recent changes
|
|
60
|
-
./sync.sh --quick
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
### Weekly Tasks
|
|
64
|
-
```bash
|
|
65
|
-
# Full sync on Monday
|
|
66
|
-
./sync.sh --full
|
|
67
|
-
|
|
68
|
-
# Generate sprint report
|
|
69
|
-
./sprint-report.sh > reports/week-$(date +%U).txt
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### First Time Setup
|
|
73
|
-
```bash
|
|
74
|
-
# Run setup wizard
|
|
75
|
-
./setup.sh
|
|
76
|
-
|
|
77
|
-
# Verify connection
|
|
78
|
-
./daily.sh
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## Environment Variables
|
|
82
|
-
|
|
83
|
-
Required in `.claude/.env`:
|
|
84
|
-
```bash
|
|
85
|
-
AZURE_DEVOPS_PAT=your_personal_access_token
|
|
86
|
-
AZURE_DEVOPS_ORG=your_organization
|
|
87
|
-
AZURE_DEVOPS_PROJECT=your_project
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## Automation
|
|
91
|
-
|
|
92
|
-
### Cron Jobs
|
|
93
|
-
Add to crontab for automation:
|
|
94
|
-
```bash
|
|
95
|
-
# Daily standup at 9 AM
|
|
96
|
-
0 9 * * 1-5 cd /path/to/project && ./claude/scripts/azure/daily.sh
|
|
97
|
-
|
|
98
|
-
# Sync every hour during work hours
|
|
99
|
-
0 9-18 * * 1-5 cd /path/to/project && ./claude/scripts/azure/sync.sh --quick
|
|
100
|
-
|
|
101
|
-
# Weekly sprint report on Friday
|
|
102
|
-
0 16 * * 5 cd /path/to/project && ./claude/scripts/azure/sprint-report.sh
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Git Hooks
|
|
106
|
-
Link to git hooks for automation:
|
|
107
|
-
```bash
|
|
108
|
-
# .git/hooks/pre-commit
|
|
109
|
-
#!/bin/bash
|
|
110
|
-
# Sync before commit
|
|
111
|
-
.claude/scripts/azure/sync.sh --quick
|
|
112
|
-
|
|
113
|
-
# .git/hooks/post-commit
|
|
114
|
-
#!/bin/bash
|
|
115
|
-
# Link commit to Azure DevOps
|
|
116
|
-
# (Add work item ID detection logic)
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Troubleshooting
|
|
120
|
-
|
|
121
|
-
### Connection Issues
|
|
122
|
-
```bash
|
|
123
|
-
# Test API connection
|
|
124
|
-
curl -u ":$AZURE_DEVOPS_PAT" \
|
|
125
|
-
"https://dev.azure.com/$AZURE_DEVOPS_ORG/_apis/projects?api-version=7.0"
|
|
126
|
-
|
|
127
|
-
# Check credentials
|
|
128
|
-
echo $AZURE_DEVOPS_PAT | head -c 10
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
### Permission Errors
|
|
132
|
-
```bash
|
|
133
|
-
# Make scripts executable
|
|
134
|
-
chmod +x .claude/scripts/azure/*.sh
|
|
135
|
-
|
|
136
|
-
# Check file permissions
|
|
137
|
-
ls -la .claude/scripts/azure/
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
### Cache Issues
|
|
141
|
-
```bash
|
|
142
|
-
# Clear cache
|
|
143
|
-
rm -rf .claude/azure/cache/*
|
|
144
|
-
|
|
145
|
-
# Rebuild cache
|
|
146
|
-
./sync.sh --full
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
## Advanced Usage
|
|
150
|
-
|
|
151
|
-
### Custom Queries
|
|
152
|
-
Edit scripts to add custom WIQL queries:
|
|
153
|
-
```bash
|
|
154
|
-
# Example: Find high priority bugs
|
|
155
|
-
query='SELECT [System.Id] FROM workitems
|
|
156
|
-
WHERE [System.WorkItemType] = "Bug"
|
|
157
|
-
AND [Microsoft.VSTS.Common.Priority] = 1'
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### Export Formats
|
|
161
|
-
Scripts support various output formats:
|
|
162
|
-
```bash
|
|
163
|
-
# JSON output
|
|
164
|
-
./sprint-report.sh --json > report.json
|
|
165
|
-
|
|
166
|
-
# CSV export
|
|
167
|
-
./daily.sh --csv > daily.csv
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### Integration with CI/CD
|
|
171
|
-
Use in CI/CD pipelines:
|
|
172
|
-
```yaml
|
|
173
|
-
# Azure Pipelines example
|
|
174
|
-
- script: |
|
|
175
|
-
./claude/scripts/azure/sync.sh --full
|
|
176
|
-
./claude/scripts/azure/sprint-report.sh
|
|
177
|
-
displayName: 'Sync and Report'
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
## Contributing
|
|
181
|
-
|
|
182
|
-
To add new scripts:
|
|
183
|
-
1. Create script in `.claude/scripts/azure/`
|
|
184
|
-
2. Make executable: `chmod +x script.sh`
|
|
185
|
-
3. Add documentation here
|
|
186
|
-
4. Test thoroughly
|
|
187
|
-
|
|
188
|
-
## Support
|
|
189
|
-
|
|
190
|
-
- Azure DevOps API: https://docs.microsoft.com/en-us/rest/api/azure/devops/
|
|
191
|
-
- Script issues: Create issue in project repository
|
|
192
|
-
- Command help: `/azure:help`
|
|
@@ -1,524 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Azure DevOps Active Work Viewer
|
|
5
|
-
* Shows all active work items across the team with full API integration
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const path = require('path');
|
|
9
|
-
const fs = require('fs');
|
|
10
|
-
const chalk = require('chalk');
|
|
11
|
-
const AzureDevOpsClient = require('../../providers/azure/lib/client');
|
|
12
|
-
const AzureFormatter = require('../../providers/azure/lib/formatter');
|
|
13
|
-
const { table } = require('table');
|
|
14
|
-
|
|
15
|
-
class AzureActiveWork {
|
|
16
|
-
constructor(options = {}) {
|
|
17
|
-
this.silent = options.silent || false;
|
|
18
|
-
this.format = options.format || 'table'; // table, json, csv
|
|
19
|
-
this.groupBy = options.groupBy || 'assignee'; // assignee, state, type, priority
|
|
20
|
-
this.includeUnassigned = options.includeUnassigned !== false;
|
|
21
|
-
this.user = options.user || null; // Filter by specific user or 'me'
|
|
22
|
-
this.state = options.state || null; // Filter by specific states
|
|
23
|
-
this.type = options.type || null; // Filter by work item types
|
|
24
|
-
this.testMode = options.testMode || false;
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
// Load environment variables from .env file if it exists
|
|
28
|
-
const envPath = path.join(process.cwd(), '.env');
|
|
29
|
-
if (fs.existsSync(envPath)) {
|
|
30
|
-
require('dotenv').config({ path: envPath });
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Also check .claude/.env
|
|
34
|
-
const claudeEnvPath = path.join(process.cwd(), '.claude', '.env');
|
|
35
|
-
if (fs.existsSync(claudeEnvPath)) {
|
|
36
|
-
require('dotenv').config({ path: claudeEnvPath });
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Initialize Azure DevOps client
|
|
40
|
-
this.client = new AzureDevOpsClient();
|
|
41
|
-
} catch (error) {
|
|
42
|
-
this.handleInitError(error);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
handleInitError(error) {
|
|
47
|
-
if (error.message.includes('Missing required environment variables')) {
|
|
48
|
-
// Check if we should throw the error (for tests that expect it)
|
|
49
|
-
const hasNoEnvVars = !process.env.AZURE_DEVOPS_PAT &&
|
|
50
|
-
!process.env.AZURE_DEVOPS_ORG &&
|
|
51
|
-
!process.env.AZURE_DEVOPS_PROJECT;
|
|
52
|
-
|
|
53
|
-
if (hasNoEnvVars && !this.testMode) {
|
|
54
|
-
throw error; // Re-throw for tests that expect it
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// In production mode when run directly, show error and exit
|
|
58
|
-
if (require.main === module) {
|
|
59
|
-
console.error('❌ Azure DevOps configuration missing!\n');
|
|
60
|
-
console.error('Please set the following environment variables:');
|
|
61
|
-
console.error(' - AZURE_DEVOPS_ORG: Your Azure DevOps organization');
|
|
62
|
-
console.error(' - AZURE_DEVOPS_PROJECT: Your project name');
|
|
63
|
-
console.error(' - AZURE_DEVOPS_PAT: Your Personal Access Token\n');
|
|
64
|
-
console.error('You can set these in .env or .claude/.env file\n');
|
|
65
|
-
process.exit(1);
|
|
66
|
-
}
|
|
67
|
-
// Set client to null for test mode
|
|
68
|
-
this.client = null;
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
throw error;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async getActiveWork() {
|
|
75
|
-
try {
|
|
76
|
-
if (!this.silent && this.format !== "json") {
|
|
77
|
-
console.log(chalk.cyan.bold('\n💼 Fetching Active Work Items...\n'));
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Build WIQL query for active work items
|
|
81
|
-
const states = this.state ?
|
|
82
|
-
this.state.split(',').map(s => `'${s.trim()}'`).join(', ') :
|
|
83
|
-
"'New', 'Active', 'In Progress', 'Committed'";
|
|
84
|
-
|
|
85
|
-
const types = this.type ?
|
|
86
|
-
this.type.split(',').map(t => `'${t.trim()}'`).join(', ') :
|
|
87
|
-
"'Task', 'Bug', 'User Story', 'Feature'";
|
|
88
|
-
|
|
89
|
-
let query = `
|
|
90
|
-
SELECT [System.Id],
|
|
91
|
-
[System.Title],
|
|
92
|
-
[System.State],
|
|
93
|
-
[System.WorkItemType],
|
|
94
|
-
[System.AssignedTo],
|
|
95
|
-
[Microsoft.VSTS.Scheduling.RemainingWork],
|
|
96
|
-
[Microsoft.VSTS.Common.Priority],
|
|
97
|
-
[System.CreatedDate],
|
|
98
|
-
[System.ChangedDate],
|
|
99
|
-
[System.Tags],
|
|
100
|
-
[System.IterationPath]
|
|
101
|
-
FROM workitems
|
|
102
|
-
WHERE [System.State] IN (${states})
|
|
103
|
-
AND [System.WorkItemType] IN (${types})
|
|
104
|
-
AND [System.TeamProject] = '${this.client?.project || 'TestProject'}'
|
|
105
|
-
`;
|
|
106
|
-
|
|
107
|
-
// Add user filter if specified
|
|
108
|
-
if (this.user) {
|
|
109
|
-
const userEmail = this.user === 'me' ? '@Me' : this.user;
|
|
110
|
-
query += ` AND [System.AssignedTo] = '${userEmail}'`;
|
|
111
|
-
} else if (!this.includeUnassigned) {
|
|
112
|
-
query += ` AND [System.AssignedTo] <> ''`;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
query += ` ORDER BY [Microsoft.VSTS.Common.Priority] ASC, [System.ChangedDate] DESC`;
|
|
116
|
-
|
|
117
|
-
// Execute query
|
|
118
|
-
if (!this.client) {
|
|
119
|
-
// Return mock data for testing
|
|
120
|
-
return this.getMockActiveWork();
|
|
121
|
-
}
|
|
122
|
-
const queryResult = await this.client.executeWiql(query);
|
|
123
|
-
|
|
124
|
-
if (!queryResult || !queryResult.workItems || queryResult.workItems.length === 0) {
|
|
125
|
-
if (!this.silent) {
|
|
126
|
-
console.log(chalk.yellow('No active work items found.'));
|
|
127
|
-
}
|
|
128
|
-
return { summary: { total: 0 }, items: [] };
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Get full work item details
|
|
132
|
-
const ids = queryResult.workItems.map(item => item.id);
|
|
133
|
-
const workItems = await this.client.getWorkItems(ids);
|
|
134
|
-
|
|
135
|
-
// Get current sprint info
|
|
136
|
-
const currentSprint = await this.client.getCurrentSprint();
|
|
137
|
-
|
|
138
|
-
// Process and organize work items
|
|
139
|
-
const processedData = this.processWorkItems(workItems, currentSprint);
|
|
140
|
-
|
|
141
|
-
// Mock data structure for compatibility - will be replaced with real data
|
|
142
|
-
const activeWorkData = {
|
|
143
|
-
...processedData,
|
|
144
|
-
rawItems: workItems
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
if (!this.silent && this.format !== "json") {
|
|
148
|
-
this.displayActiveWork(activeWorkData);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return activeWorkData;
|
|
152
|
-
} catch (error) {
|
|
153
|
-
console.error('Error:', error.message);
|
|
154
|
-
process.exit(1);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
displayActiveWork(data) {
|
|
159
|
-
switch (this.format) {
|
|
160
|
-
case 'json':
|
|
161
|
-
console.log(JSON.stringify(data, null, 2));
|
|
162
|
-
break;
|
|
163
|
-
case 'csv':
|
|
164
|
-
this.displayCSV(data);
|
|
165
|
-
break;
|
|
166
|
-
default:
|
|
167
|
-
this.displayTable(data);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
displayTable(data) {
|
|
172
|
-
// Display summary
|
|
173
|
-
console.log(chalk.cyan.bold('📊 Summary'));
|
|
174
|
-
const summary = data.summary;
|
|
175
|
-
console.log(`Sprint: ${chalk.blue(summary.sprint)}`);
|
|
176
|
-
console.log(`Total Active Items: ${chalk.green(summary.total)}`);
|
|
177
|
-
console.log(`In Progress: ${chalk.yellow(summary.inProgress)} | Active: ${chalk.blue(summary.active)} | New: ${chalk.gray(summary.new)}`);
|
|
178
|
-
console.log(`Average Days in Progress: ${summary.avgDaysInProgress}`);
|
|
179
|
-
if (summary.totalRemaining > 0) {
|
|
180
|
-
console.log(`Total Remaining Work: ${chalk.yellow(summary.totalRemaining + 'h')}`);
|
|
181
|
-
}
|
|
182
|
-
console.log('');
|
|
183
|
-
|
|
184
|
-
// Display by group
|
|
185
|
-
if (this.groupBy === 'assignee') {
|
|
186
|
-
this.displayByAssignee(data.byAssignee);
|
|
187
|
-
} else if (this.groupBy === 'state') {
|
|
188
|
-
this.displayByState(data.byState, data.byAssignee);
|
|
189
|
-
} else if (this.groupBy === 'type') {
|
|
190
|
-
this.displayByType(data.byType, data.byAssignee);
|
|
191
|
-
} else if (this.groupBy === 'priority') {
|
|
192
|
-
this.displayByPriority(data.byPriority);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Display blocked items
|
|
196
|
-
if (data.blockedItems && data.blockedItems.length > 0) {
|
|
197
|
-
console.log(chalk.red.bold('\n🚫 Blocked Items'));
|
|
198
|
-
data.blockedItems.forEach(item => {
|
|
199
|
-
console.log(` [${chalk.red(item.id)}] ${item.title}`);
|
|
200
|
-
console.log(` Assigned to: ${item.assignedTo}`);
|
|
201
|
-
console.log(` Tags/Reason: ${chalk.yellow(item.blockedBy)}`);
|
|
202
|
-
console.log(` Days blocked: ${chalk.red(item.daysBlocked)}`);
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
getMockActiveWork() {
|
|
208
|
-
// Return mock data for testing
|
|
209
|
-
return {
|
|
210
|
-
items: [
|
|
211
|
-
{
|
|
212
|
-
id: 101,
|
|
213
|
-
fields: {
|
|
214
|
-
'System.Title': 'Test Task 1',
|
|
215
|
-
'System.WorkItemType': 'Task',
|
|
216
|
-
'System.State': 'Active',
|
|
217
|
-
'System.AssignedTo': { displayName: 'John Doe' },
|
|
218
|
-
'Microsoft.VSTS.Scheduling.RemainingWork': 8,
|
|
219
|
-
'Microsoft.VSTS.Common.Priority': 1,
|
|
220
|
-
'System.ChangedDate': new Date().toISOString()
|
|
221
|
-
}
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
id: 102,
|
|
225
|
-
fields: {
|
|
226
|
-
'System.Title': 'Test Bug 1',
|
|
227
|
-
'System.WorkItemType': 'Bug',
|
|
228
|
-
'System.State': 'In Progress',
|
|
229
|
-
'System.AssignedTo': { displayName: 'Jane Smith' },
|
|
230
|
-
'Microsoft.VSTS.Scheduling.RemainingWork': 4,
|
|
231
|
-
'Microsoft.VSTS.Common.Priority': 2,
|
|
232
|
-
'System.ChangedDate': new Date().toISOString()
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
],
|
|
236
|
-
summary: {
|
|
237
|
-
total: 2,
|
|
238
|
-
totalRemaining: 12
|
|
239
|
-
},
|
|
240
|
-
byState: { 'Active': 1, 'In Progress': 1 },
|
|
241
|
-
byType: { 'Task': 1, 'Bug': 1 },
|
|
242
|
-
byAssignee: {
|
|
243
|
-
'John Doe': [{ id: 101 }],
|
|
244
|
-
'Jane Smith': [{ id: 102 }]
|
|
245
|
-
},
|
|
246
|
-
byPriority: { 1: [{ id: 101 }], 2: [{ id: 102 }] },
|
|
247
|
-
blockedItems: []
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
processWorkItems(workItems, currentSprint) {
|
|
252
|
-
const byAssignee = {};
|
|
253
|
-
const byState = {};
|
|
254
|
-
const byType = {};
|
|
255
|
-
const byPriority = {};
|
|
256
|
-
const blockedItems = [];
|
|
257
|
-
let totalRemaining = 0;
|
|
258
|
-
let totalItems = 0;
|
|
259
|
-
let totalDaysInProgress = 0;
|
|
260
|
-
let inProgressCount = 0;
|
|
261
|
-
|
|
262
|
-
workItems.forEach(item => {
|
|
263
|
-
const fields = item.fields || {};
|
|
264
|
-
const assignedTo = fields['System.AssignedTo'] ?
|
|
265
|
-
(fields['System.AssignedTo'].displayName || fields['System.AssignedTo'].uniqueName || 'Unknown') :
|
|
266
|
-
'Unassigned';
|
|
267
|
-
const state = fields['System.State'] || 'Unknown';
|
|
268
|
-
const type = fields['System.WorkItemType'] || 'Unknown';
|
|
269
|
-
const priority = fields['Microsoft.VSTS.Common.Priority'] || 999;
|
|
270
|
-
const remainingWork = fields['Microsoft.VSTS.Scheduling.RemainingWork'] || 0;
|
|
271
|
-
const tags = fields['System.Tags'] || '';
|
|
272
|
-
|
|
273
|
-
// Calculate days in current state
|
|
274
|
-
const changedDate = new Date(fields['System.ChangedDate']);
|
|
275
|
-
const now = new Date();
|
|
276
|
-
const daysInState = Math.floor((now - changedDate) / (1000 * 60 * 60 * 24));
|
|
277
|
-
|
|
278
|
-
// Check if item is blocked
|
|
279
|
-
const isBlocked = tags.toLowerCase().includes('blocked') ||
|
|
280
|
-
tags.toLowerCase().includes('waiting');
|
|
281
|
-
|
|
282
|
-
const workItemData = {
|
|
283
|
-
id: item.id,
|
|
284
|
-
title: fields['System.Title'],
|
|
285
|
-
type: type,
|
|
286
|
-
state: state,
|
|
287
|
-
priority: priority,
|
|
288
|
-
daysInState: daysInState,
|
|
289
|
-
remainingWork: remainingWork,
|
|
290
|
-
tags: tags,
|
|
291
|
-
iteration: fields['System.IterationPath']
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
// Group by assignee
|
|
295
|
-
if (!byAssignee[assignedTo]) byAssignee[assignedTo] = [];
|
|
296
|
-
byAssignee[assignedTo].push(workItemData);
|
|
297
|
-
|
|
298
|
-
// Group by state
|
|
299
|
-
byState[state] = (byState[state] || 0) + 1;
|
|
300
|
-
|
|
301
|
-
// Group by type
|
|
302
|
-
byType[type] = (byType[type] || 0) + 1;
|
|
303
|
-
|
|
304
|
-
// Group by priority
|
|
305
|
-
if (!byPriority[priority]) byPriority[priority] = [];
|
|
306
|
-
byPriority[priority].push(workItemData);
|
|
307
|
-
|
|
308
|
-
// Track blocked items
|
|
309
|
-
if (isBlocked) {
|
|
310
|
-
blockedItems.push({
|
|
311
|
-
...workItemData,
|
|
312
|
-
assignedTo: assignedTo,
|
|
313
|
-
blockedBy: tags,
|
|
314
|
-
daysBlocked: daysInState
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// Calculate stats
|
|
319
|
-
totalRemaining += remainingWork;
|
|
320
|
-
totalItems++;
|
|
321
|
-
if (state === 'In Progress' || state === 'Active') {
|
|
322
|
-
totalDaysInProgress += daysInState;
|
|
323
|
-
inProgressCount++;
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
const avgDaysInProgress = inProgressCount > 0 ?
|
|
328
|
-
(totalDaysInProgress / inProgressCount).toFixed(1) : 0;
|
|
329
|
-
|
|
330
|
-
return {
|
|
331
|
-
summary: {
|
|
332
|
-
total: totalItems,
|
|
333
|
-
inProgress: byState['In Progress'] || 0,
|
|
334
|
-
active: byState['Active'] || 0,
|
|
335
|
-
new: byState['New'] || 0,
|
|
336
|
-
avgDaysInProgress: parseFloat(avgDaysInProgress),
|
|
337
|
-
totalRemaining: totalRemaining,
|
|
338
|
-
sprint: currentSprint ? currentSprint.name : 'No active sprint'
|
|
339
|
-
},
|
|
340
|
-
byAssignee: byAssignee,
|
|
341
|
-
byState: byState,
|
|
342
|
-
byType: byType,
|
|
343
|
-
byPriority: byPriority,
|
|
344
|
-
blockedItems: blockedItems
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
displayByAssignee(byAssignee) {
|
|
349
|
-
console.log(chalk.green.bold('👥 Work by Assignee\n'));
|
|
350
|
-
|
|
351
|
-
// Sort assignees with Unassigned last
|
|
352
|
-
const sortedAssignees = Object.keys(byAssignee).sort((a, b) => {
|
|
353
|
-
if (a === 'Unassigned') return 1;
|
|
354
|
-
if (b === 'Unassigned') return -1;
|
|
355
|
-
return a.localeCompare(b);
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
sortedAssignees.forEach(assignee => {
|
|
359
|
-
const items = byAssignee[assignee];
|
|
360
|
-
if (items.length === 0) return;
|
|
361
|
-
|
|
362
|
-
const totalRemaining = items.reduce((sum, item) => sum + (item.remainingWork || 0), 0);
|
|
363
|
-
console.log(chalk.yellow.bold(`${assignee} (${items.length} items, ${totalRemaining}h remaining):`));
|
|
364
|
-
|
|
365
|
-
// Sort items by priority
|
|
366
|
-
items.sort((a, b) => a.priority - b.priority);
|
|
367
|
-
|
|
368
|
-
items.forEach(item => {
|
|
369
|
-
const stateColor = this.getStateColor(item.state);
|
|
370
|
-
const priorityLabel = item.priority <= 3 ? chalk.red(`P${item.priority}`) : `P${item.priority}`;
|
|
371
|
-
console.log(` [${chalk.blue(item.id)}] ${item.title}`);
|
|
372
|
-
console.log(` Type: ${item.type} | State: ${stateColor} | Priority: ${priorityLabel}`);
|
|
373
|
-
console.log(` Days in state: ${item.daysInState} | Remaining: ${item.remainingWork || 0}h`);
|
|
374
|
-
if (item.tags) {
|
|
375
|
-
console.log(` Tags: ${chalk.dim(item.tags)}`);
|
|
376
|
-
}
|
|
377
|
-
});
|
|
378
|
-
console.log('');
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
displayByState(byState, byAssignee) {
|
|
383
|
-
console.log(chalk.green.bold('📋 Work by State\n'));
|
|
384
|
-
|
|
385
|
-
Object.entries(byState).forEach(([state, count]) => {
|
|
386
|
-
const stateColor = this.getStateColor(state);
|
|
387
|
-
console.log(`${stateColor}: ${count} items`);
|
|
388
|
-
});
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
displayByType(byType) {
|
|
392
|
-
console.log(chalk.green.bold('📝 Work by Type\n'));
|
|
393
|
-
|
|
394
|
-
Object.entries(byType).forEach(([type, count]) => {
|
|
395
|
-
console.log(`${type}: ${count} items`);
|
|
396
|
-
});
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
displayByPriority(byPriority) {
|
|
400
|
-
console.log(chalk.green.bold('⚡ Work by Priority\n'));
|
|
401
|
-
|
|
402
|
-
const priorities = Object.keys(byPriority).sort((a, b) => parseInt(a) - parseInt(b));
|
|
403
|
-
|
|
404
|
-
priorities.forEach(priority => {
|
|
405
|
-
const items = byPriority[priority];
|
|
406
|
-
if (!items || items.length === 0) return;
|
|
407
|
-
|
|
408
|
-
const priorityLabel = priority <= 3 ?
|
|
409
|
-
chalk.red.bold(`Priority ${priority} (High)`) :
|
|
410
|
-
chalk.yellow.bold(`Priority ${priority}`);
|
|
411
|
-
|
|
412
|
-
console.log(`\n${priorityLabel}:`);
|
|
413
|
-
items.forEach(item => {
|
|
414
|
-
const stateColor = this.getStateColor(item.state);
|
|
415
|
-
console.log(` [${chalk.blue(item.id)}] ${item.title}`);
|
|
416
|
-
console.log(` ${item.type} | ${stateColor} | ${item.remainingWork || 0}h remaining`);
|
|
417
|
-
});
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
displayCSV(data) {
|
|
422
|
-
console.log('ID,Title,Type,State,Priority,Assigned To,Days in State,Remaining Work');
|
|
423
|
-
|
|
424
|
-
Object.entries(data.byAssignee).forEach(([assignee, items]) => {
|
|
425
|
-
items.forEach(item => {
|
|
426
|
-
console.log(`${item.id},"${item.title}",${item.type},${item.state},${item.priority},"${assignee}",${item.daysInState},${item.remainingWork}`);
|
|
427
|
-
});
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
getStateColor(state) {
|
|
432
|
-
const colors = {
|
|
433
|
-
'New': chalk.blue(state),
|
|
434
|
-
'Active': chalk.yellow(state),
|
|
435
|
-
'In Progress': chalk.cyan(state),
|
|
436
|
-
'Resolved': chalk.green(state),
|
|
437
|
-
'Closed': chalk.gray(state),
|
|
438
|
-
'Done': chalk.green(state)
|
|
439
|
-
};
|
|
440
|
-
return colors[state] || chalk.white(state);
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
static parseArguments(args = process.argv) {
|
|
444
|
-
const options = {};
|
|
445
|
-
|
|
446
|
-
args.forEach((arg, index) => {
|
|
447
|
-
if (arg === '--group-by' && args[index + 1]) {
|
|
448
|
-
options.groupBy = args[index + 1];
|
|
449
|
-
} else if (arg === '--format' && args[index + 1]) {
|
|
450
|
-
options.format = args[index + 1];
|
|
451
|
-
} else if (arg === '--user' && args[index + 1]) {
|
|
452
|
-
options.user = args[index + 1];
|
|
453
|
-
} else if (arg === '--state' && args[index + 1]) {
|
|
454
|
-
options.state = args[index + 1];
|
|
455
|
-
} else if (arg === '--type' && args[index + 1]) {
|
|
456
|
-
options.type = args[index + 1];
|
|
457
|
-
} else if (arg === '--no-unassigned') {
|
|
458
|
-
options.includeUnassigned = false;
|
|
459
|
-
} else if (arg === '--json') {
|
|
460
|
-
options.format = 'json';
|
|
461
|
-
} else if (arg === '--csv') {
|
|
462
|
-
options.format = 'csv';
|
|
463
|
-
} else if (arg === '--silent' || arg === '-s') {
|
|
464
|
-
options.silent = true;
|
|
465
|
-
} else if (arg === '--help' || arg === '-h') {
|
|
466
|
-
console.log(chalk.cyan.bold('\nAzure DevOps Active Work Viewer\n'));
|
|
467
|
-
console.log('Usage: azure-active-work [options]\n');
|
|
468
|
-
console.log('Options:');
|
|
469
|
-
console.log(' --user <email|me> Filter by user (use "me" for current user)');
|
|
470
|
-
console.log(' --state <states> Filter by states (comma-separated)');
|
|
471
|
-
console.log(' --type <types> Filter by work item types (comma-separated)');
|
|
472
|
-
console.log(' --group-by <field> Group results by: assignee, state, type, priority');
|
|
473
|
-
console.log(' --format <format> Output format: table, json, csv');
|
|
474
|
-
console.log(' --no-unassigned Exclude unassigned items');
|
|
475
|
-
console.log(' --json Output as JSON');
|
|
476
|
-
console.log(' --csv Output as CSV');
|
|
477
|
-
console.log(' --silent, -s Silent mode (suppress non-data output)');
|
|
478
|
-
console.log(' --help, -h Show this help\n');
|
|
479
|
-
console.log('Examples:');
|
|
480
|
-
console.log(' azure-active-work --user me');
|
|
481
|
-
console.log(' azure-active-work --state "Active,In Progress" --type Task');
|
|
482
|
-
console.log(' azure-active-work --group-by priority --json');
|
|
483
|
-
process.exit(0);
|
|
484
|
-
}
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
return options;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
// Run if called directly
|
|
492
|
-
if (require.main === module) {
|
|
493
|
-
const options = AzureActiveWork.parseArguments();
|
|
494
|
-
const activeWork = new AzureActiveWork(options);
|
|
495
|
-
|
|
496
|
-
activeWork.getActiveWork()
|
|
497
|
-
.then(() => {
|
|
498
|
-
if (activeWork.client) {
|
|
499
|
-
const stats = activeWork.client.getCacheStats();
|
|
500
|
-
if (!options.silent && process.env.DEBUG) {
|
|
501
|
-
console.log(chalk.dim(`\nCache stats: ${JSON.stringify(stats)}`));
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
})
|
|
505
|
-
.catch(error => {
|
|
506
|
-
console.error('Error:', error.message);
|
|
507
|
-
process.exit(1);
|
|
508
|
-
});
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
// Export class and helper functions for testing
|
|
512
|
-
module.exports = {
|
|
513
|
-
AzureActiveWork,
|
|
514
|
-
parseArguments: AzureActiveWork.parseArguments,
|
|
515
|
-
getStateColor: (state) => new AzureActiveWork().getStateColor(state),
|
|
516
|
-
getMockActiveWork: () => new AzureActiveWork().getMockActiveWork(),
|
|
517
|
-
processWorkItems: (workItems, currentSprint) => new AzureActiveWork().processWorkItems(workItems, currentSprint),
|
|
518
|
-
displayTable: (data) => new AzureActiveWork().displayTable(data),
|
|
519
|
-
displayByAssignee: (byAssignee) => new AzureActiveWork().displayByAssignee(byAssignee),
|
|
520
|
-
displayByState: (byState, byAssignee) => new AzureActiveWork().displayByState(byState, byAssignee),
|
|
521
|
-
displayByType: (byType) => new AzureActiveWork().displayByType(byType),
|
|
522
|
-
displayByPriority: (byPriority) => new AzureActiveWork().displayByPriority(byPriority),
|
|
523
|
-
displayCSV: (data) => new AzureActiveWork().displayCSV(data)
|
|
524
|
-
};
|