claude-autopm 1.18.0 ā 1.20.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.
- package/README.md +159 -0
- package/autopm/.claude/agents/README.md +1 -1
- package/autopm/.claude/agents/core/mcp-manager.md +1 -1
- package/autopm/.claude/agents/decision-matrices/python-backend-selection.md +25 -25
- package/autopm/.claude/agents/decision-matrices/ui-framework-selection.md +43 -43
- package/autopm/.claude/agents/devops/github-operations-specialist.md +1 -1
- package/autopm/.claude/agents/frameworks/README.md +5 -5
- package/autopm/.claude/agents/frameworks/e2e-test-engineer.md +1 -1
- package/autopm/.claude/agents/frameworks/nats-messaging-expert.md +1 -1
- package/autopm/.claude/agents/frameworks/react-frontend-engineer.md +1 -1
- package/autopm/.claude/agents/frameworks/react-ui-expert.md +3 -3
- package/autopm/.claude/agents/frameworks/tailwindcss-expert.md +3 -3
- package/autopm/.claude/agents/frameworks/ux-design-expert.md +3 -3
- package/autopm/.claude/commands/infrastructure/traefik-setup.md +1 -1
- package/autopm/.claude/commands/playwright/test-scaffold.md +1 -1
- package/autopm/.claude/commands/pm/context.md +11 -0
- package/autopm/.claude/commands/pm/epic-decompose.md +25 -2
- package/autopm/.claude/commands/pm/epic-oneshot.md +13 -0
- package/autopm/.claude/commands/pm/epic-start.md +19 -0
- package/autopm/.claude/commands/pm/epic-sync-modular.md +10 -10
- package/autopm/.claude/commands/pm/epic-sync.md +14 -14
- package/autopm/.claude/commands/pm/issue-start.md +50 -5
- package/autopm/.claude/commands/pm/issue-sync.md +15 -15
- package/autopm/.claude/commands/pm/what-next.md +11 -0
- package/autopm/.claude/commands/ui/bootstrap-scaffold.md +6 -5
- package/autopm/.claude/commands/ui/tailwind-system.md +1 -1
- package/autopm/.claude/examples/mcp/playwright-mcp.md +2 -2
- package/autopm/.claude/examples/mcp-servers.example.json +2 -2
- package/autopm/.claude/hooks/docker-first-enforcement.sh +1 -1
- package/autopm/.claude/mcp/MCP-REGISTRY.md +1 -1
- package/autopm/.claude/mcp/playwright-mcp.md +2 -2
- package/autopm/.claude/rules/agent-coordination.md +26 -24
- package/autopm/.claude/rules/docker-first-development.md +1 -1
- package/autopm/.claude/rules/infrastructure-pipeline.md +1 -1
- package/autopm/.claude/rules/ui-development-standards.md +1 -1
- package/autopm/.claude/rules/visual-testing.md +3 -3
- package/autopm/.claude/scripts/azure/active-work.js +2 -2
- package/autopm/.claude/scripts/azure/blocked.js +13 -13
- package/autopm/.claude/scripts/azure/daily.js +1 -1
- package/autopm/.claude/scripts/azure/dashboard.js +1 -1
- package/autopm/.claude/scripts/azure/feature-list.js +2 -2
- package/autopm/.claude/scripts/azure/feature-status.js +1 -1
- package/autopm/.claude/scripts/azure/next-task.js +1 -1
- package/autopm/.claude/scripts/azure/search.js +1 -1
- package/autopm/.claude/scripts/azure/setup.js +15 -15
- package/autopm/.claude/scripts/azure/sprint-report.js +2 -2
- package/autopm/.claude/scripts/azure/sync.js +1 -1
- package/autopm/.claude/scripts/azure/us-list.js +1 -1
- package/autopm/.claude/scripts/azure/us-status.js +1 -1
- package/autopm/.claude/scripts/azure/validate.js +13 -13
- package/autopm/.claude/scripts/lib/frontmatter-utils.sh +42 -7
- package/autopm/.claude/scripts/lib/logging-utils.sh +20 -16
- package/autopm/.claude/scripts/lib/validation-utils.sh +1 -1
- package/autopm/.claude/scripts/pm/context.js +338 -0
- package/autopm/.claude/scripts/pm/issue-sync/format-comment.sh +3 -3
- package/autopm/.claude/scripts/pm/lib/README.md +85 -0
- package/autopm/.claude/scripts/pm/lib/logger.js +78 -0
- package/autopm/.claude/scripts/pm/next.js +25 -1
- package/autopm/.claude/scripts/pm/what-next.js +660 -0
- package/autopm/.claude/teams.json +3 -5
- package/autopm/.claude/templates/claude-templates/addons/devops-agents.md +2 -2
- package/autopm/.claude/templates/claude-templates/addons/docker-agents.md +4 -4
- package/autopm/.claude/templates/claude-templates/addons/minimal-agents.md +1 -1
- package/autopm/.claude/templates/issue-decomposition/api.yaml +2 -2
- package/autopm/.claude/templates/issue-decomposition/auth.yaml +4 -4
- package/autopm/.claude/templates/issue-decomposition/crud.yaml +3 -3
- package/autopm/.claude/templates/issue-decomposition/default.yaml +1 -1
- package/autopm/.claude/templates/issue-decomposition/ui-feature.yaml +2 -2
- package/bin/autopm.js +25 -0
- package/package.json +1 -2
- package/lib/agentExecutor.js.deprecated +0 -101
- package/lib/azure/cache.js +0 -80
- package/lib/azure/client.js +0 -77
- package/lib/azure/formatter.js +0 -177
- package/lib/commandHelpers.js +0 -177
- package/lib/context/manager.js +0 -290
- package/lib/documentation/manager.js +0 -528
- package/lib/github/workflow-manager.js +0 -546
- package/lib/helpers/azure-batch-api.js +0 -133
- package/lib/helpers/azure-cache-manager.js +0 -287
- package/lib/helpers/azure-parallel-processor.js +0 -158
- package/lib/helpers/azure-work-item-create.js +0 -278
- package/lib/helpers/gh-issue-create.js +0 -250
- package/lib/helpers/interactive-prompt.js +0 -336
- package/lib/helpers/output-manager.js +0 -335
- package/lib/helpers/progress-indicator.js +0 -258
- package/lib/performance/benchmarker.js +0 -429
- package/lib/pm/epic-decomposer.js +0 -273
- package/lib/pm/epic-syncer.js +0 -221
- package/lib/prdMetadata.js +0 -270
- package/lib/providers/azure/index.js +0 -234
- package/lib/providers/factory.js +0 -87
- package/lib/providers/github/index.js +0 -204
- package/lib/providers/interface.js +0 -73
- package/lib/python/scaffold-manager.js +0 -576
- package/lib/react/scaffold-manager.js +0 -745
- package/lib/regression/analyzer.js +0 -578
- package/lib/release/manager.js +0 -324
- package/lib/tailwind/manager.js +0 -486
- package/lib/traefik/manager.js +0 -484
- package/lib/utils/colors.js +0 -126
- package/lib/utils/config.js +0 -317
- package/lib/utils/filesystem.js +0 -316
- package/lib/utils/logger.js +0 -135
- package/lib/utils/prompts.js +0 -294
- package/lib/utils/shell.js +0 -237
- package/lib/validators/email-validator.js +0 -337
- package/lib/workflow/manager.js +0 -449
|
@@ -4,21 +4,21 @@ Use Docker-aware agents for containerized development:
|
|
|
4
4
|
|
|
5
5
|
### Docker Specialists (PRIMARY)
|
|
6
6
|
|
|
7
|
-
#### docker-expert
|
|
7
|
+
#### docker-containerization-expert
|
|
8
8
|
**Use for**: Dockerfile optimization, multi-stage builds, security
|
|
9
9
|
- Container best practices
|
|
10
10
|
- Image size optimization
|
|
11
11
|
- Security scanning
|
|
12
12
|
- Registry management
|
|
13
13
|
|
|
14
|
-
#### docker-
|
|
14
|
+
#### docker-containerization-expert
|
|
15
15
|
**Use for**: Multi-container orchestration, service dependencies
|
|
16
16
|
- Development environment setup
|
|
17
17
|
- Service networking
|
|
18
18
|
- Volume management
|
|
19
19
|
- Environment configuration
|
|
20
20
|
|
|
21
|
-
#### docker-
|
|
21
|
+
#### docker-containerization-expert
|
|
22
22
|
**Use for**: Development workflows, hot reload setup
|
|
23
23
|
- Volume mounting strategies
|
|
24
24
|
- Development vs production configs
|
|
@@ -47,7 +47,7 @@ Use Docker-aware agents for containerized development:
|
|
|
47
47
|
- Build optimization in Docker
|
|
48
48
|
- Environment variable injection
|
|
49
49
|
|
|
50
|
-
####
|
|
50
|
+
#### python-backend-engineer
|
|
51
51
|
- Async Python in containers
|
|
52
52
|
- Uvicorn/Gunicorn configuration
|
|
53
53
|
- Health check endpoints
|
|
@@ -26,7 +26,7 @@ Use appropriate agents for traditional development:
|
|
|
26
26
|
- Component architecture and state management
|
|
27
27
|
- Traditional build tools (webpack, vite)
|
|
28
28
|
|
|
29
|
-
####
|
|
29
|
+
#### frontend-testing-engineer
|
|
30
30
|
- E2E testing with native runners
|
|
31
31
|
- Cross-browser testing
|
|
32
32
|
- Test automation frameworks
|
|
@@ -28,7 +28,7 @@ streams:
|
|
|
28
28
|
|
|
29
29
|
backend:
|
|
30
30
|
name: "API Implementation"
|
|
31
|
-
agent: "python-backend-
|
|
31
|
+
agent: "python-backend-engineer"
|
|
32
32
|
priority: 2
|
|
33
33
|
parameters:
|
|
34
34
|
framework: "fastapi"
|
|
@@ -63,7 +63,7 @@ streams:
|
|
|
63
63
|
|
|
64
64
|
integration:
|
|
65
65
|
name: "Integration Layer"
|
|
66
|
-
agent: "python-backend-
|
|
66
|
+
agent: "python-backend-engineer"
|
|
67
67
|
priority: 4
|
|
68
68
|
dependencies: ["middleware"]
|
|
69
69
|
tasks:
|
|
@@ -30,7 +30,7 @@ streams:
|
|
|
30
30
|
|
|
31
31
|
backend:
|
|
32
32
|
name: "Service Layer"
|
|
33
|
-
agent: "python-backend-
|
|
33
|
+
agent: "python-backend-engineer"
|
|
34
34
|
priority: 2
|
|
35
35
|
parameters:
|
|
36
36
|
framework: "fastapi"
|
|
@@ -49,7 +49,7 @@ streams:
|
|
|
49
49
|
|
|
50
50
|
api:
|
|
51
51
|
name: "API Endpoints"
|
|
52
|
-
agent: "
|
|
52
|
+
agent: "python-backend-engineer"
|
|
53
53
|
priority: 3
|
|
54
54
|
dependencies: ["backend"]
|
|
55
55
|
tasks:
|
|
@@ -68,7 +68,7 @@ streams:
|
|
|
68
68
|
|
|
69
69
|
frontend:
|
|
70
70
|
name: "UI Components"
|
|
71
|
-
agent: "react-
|
|
71
|
+
agent: "react-frontend-engineer"
|
|
72
72
|
priority: 4
|
|
73
73
|
parameters:
|
|
74
74
|
framework: "mui"
|
|
@@ -91,7 +91,7 @@ streams:
|
|
|
91
91
|
|
|
92
92
|
tests:
|
|
93
93
|
name: "Test Suite"
|
|
94
|
-
agent: "
|
|
94
|
+
agent: "frontend-testing-engineer"
|
|
95
95
|
priority: 5
|
|
96
96
|
dependencies: ["frontend", "api"]
|
|
97
97
|
tasks:
|
|
@@ -29,7 +29,7 @@ streams:
|
|
|
29
29
|
|
|
30
30
|
backend:
|
|
31
31
|
name: "Service Layer"
|
|
32
|
-
agent: "python-backend-
|
|
32
|
+
agent: "python-backend-engineer"
|
|
33
33
|
priority: 2
|
|
34
34
|
parameters:
|
|
35
35
|
framework: "fastapi"
|
|
@@ -48,7 +48,7 @@ streams:
|
|
|
48
48
|
|
|
49
49
|
api:
|
|
50
50
|
name: "REST API Endpoints"
|
|
51
|
-
agent: "
|
|
51
|
+
agent: "python-backend-engineer"
|
|
52
52
|
priority: 3
|
|
53
53
|
dependencies: ["backend"]
|
|
54
54
|
tasks:
|
|
@@ -65,7 +65,7 @@ streams:
|
|
|
65
65
|
|
|
66
66
|
frontend:
|
|
67
67
|
name: "UI Components"
|
|
68
|
-
agent: "react-
|
|
68
|
+
agent: "react-frontend-engineer"
|
|
69
69
|
priority: 4
|
|
70
70
|
parameters:
|
|
71
71
|
framework: "mui"
|
|
@@ -30,7 +30,7 @@ streams:
|
|
|
30
30
|
|
|
31
31
|
components:
|
|
32
32
|
name: "Component Development"
|
|
33
|
-
agent: "react-
|
|
33
|
+
agent: "react-frontend-engineer"
|
|
34
34
|
priority: 2
|
|
35
35
|
parameters:
|
|
36
36
|
framework: "mui"
|
|
@@ -83,7 +83,7 @@ streams:
|
|
|
83
83
|
|
|
84
84
|
tests:
|
|
85
85
|
name: "Testing & QA"
|
|
86
|
-
agent: "
|
|
86
|
+
agent: "frontend-testing-engineer"
|
|
87
87
|
priority: 5
|
|
88
88
|
dependencies: ["integration"]
|
|
89
89
|
tasks:
|
package/bin/autopm.js
CHANGED
|
@@ -291,7 +291,9 @@ function main() {
|
|
|
291
291
|
autopm team reset # Reset to default team
|
|
292
292
|
|
|
293
293
|
š” Claude Code PM Commands:
|
|
294
|
+
/pm:what-next # ā Smart suggestions for what to do next
|
|
294
295
|
/pm:status # Project overview and health
|
|
296
|
+
/pm:context # Show current project context and progress
|
|
295
297
|
/pm:validate # Validate configuration
|
|
296
298
|
/pm:prd-new feature-name # Create new Product Requirements Document
|
|
297
299
|
/pm:prd-parse feature-name # Parse PRD into epic structure
|
|
@@ -305,6 +307,29 @@ function main() {
|
|
|
305
307
|
/pm:search keyword # Search across PRDs and epics
|
|
306
308
|
/pm:help # Show all PM commands
|
|
307
309
|
|
|
310
|
+
š PM Workflow Decision Guide:
|
|
311
|
+
|
|
312
|
+
WHEN TO USE ONE EPIC (/pm:epic-decompose):
|
|
313
|
+
ā
Simple feature (1-2 weeks)
|
|
314
|
+
ā
Single component (frontend OR backend)
|
|
315
|
+
ā
One developer
|
|
316
|
+
Examples: "User profile page", "REST API endpoint"
|
|
317
|
+
|
|
318
|
+
WHEN TO USE MULTIPLE EPICS (/pm:epic-split):
|
|
319
|
+
ā
Complex project (2+ months)
|
|
320
|
+
ā
Multiple components (frontend + backend + infra)
|
|
321
|
+
ā
Multiple teams working in parallel
|
|
322
|
+
Examples: "E-commerce platform", "Social dashboard"
|
|
323
|
+
|
|
324
|
+
SIMPLE FEATURE FLOW:
|
|
325
|
+
/pm:prd-new feature ā /pm:prd-parse feature ā /pm:epic-decompose feature
|
|
326
|
+
|
|
327
|
+
COMPLEX PROJECT FLOW:
|
|
328
|
+
/pm:prd-new project ā /pm:prd-parse project ā /pm:epic-split project
|
|
329
|
+
ā /pm:epic-decompose project/01-epic1 ā /pm:epic-decompose project/02-epic2 ...
|
|
330
|
+
|
|
331
|
+
š Full Guide: See PM-WORKFLOW-GUIDE.md
|
|
332
|
+
|
|
308
333
|
š Complete Workflows:
|
|
309
334
|
|
|
310
335
|
=== GITHUB WORKFLOW (PRD ā Epic ā Issues) ===
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-autopm",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.1",
|
|
4
4
|
"description": "Autonomous Project Management Framework for Claude Code - Advanced AI-powered development automation",
|
|
5
5
|
"main": "bin/autopm.js",
|
|
6
6
|
"bin": {
|
|
@@ -129,7 +129,6 @@
|
|
|
129
129
|
"yargs": "^17.7.2"
|
|
130
130
|
},
|
|
131
131
|
"devDependencies": {
|
|
132
|
-
"@babel/preset-env": "^7.28.3",
|
|
133
132
|
"@jest/globals": "^30.1.2",
|
|
134
133
|
"@types/jest": "^30.0.0",
|
|
135
134
|
"axios": "^1.12.2",
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent Executor Module
|
|
3
|
-
* Handles execution of AI agents with prompts
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const fs = require('fs-extra');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
const { spawn } = require('child_process');
|
|
9
|
-
const colors = require('./utils/colors');
|
|
10
|
-
|
|
11
|
-
class AgentExecutor {
|
|
12
|
-
constructor() {
|
|
13
|
-
this.agentsPath = path.join(__dirname, '../autopm/.claude/agents');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Execute an agent with the given prompt
|
|
18
|
-
* @param {string} agentType - The type of agent to execute
|
|
19
|
-
* @param {string} prompt - The prompt to send to the agent
|
|
20
|
-
* @param {Object} context - Additional context for the agent
|
|
21
|
-
* @returns {Promise<Object>} The result of the agent execution
|
|
22
|
-
*/
|
|
23
|
-
async run(agentType, prompt, context = {}) {
|
|
24
|
-
console.log(colors.blue(`š¤ Preparing ${agentType} agent...`));
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
// Replace $ARGUMENTS in prompt with actual arguments
|
|
28
|
-
let finalPrompt = prompt;
|
|
29
|
-
if (context.arguments) {
|
|
30
|
-
finalPrompt = prompt.replace(/\$ARGUMENTS/g, context.arguments);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Check if we're in Claude Code environment
|
|
34
|
-
const isClaudeCode = process.env.CLAUDE_CODE === 'true' ||
|
|
35
|
-
process.env.ANTHROPIC_WORKSPACE === 'true';
|
|
36
|
-
|
|
37
|
-
if (isClaudeCode) {
|
|
38
|
-
// If in Claude Code, use the Task tool
|
|
39
|
-
console.log(colors.cyan('š Executing via Claude Code Task tool...'));
|
|
40
|
-
console.log(colors.gray('Prompt:'), finalPrompt.substring(0, 200) + '...');
|
|
41
|
-
|
|
42
|
-
// Claude Code should handle this through its Task tool
|
|
43
|
-
// This would be invoked by Claude when running the command
|
|
44
|
-
return {
|
|
45
|
-
status: 'success',
|
|
46
|
-
agent: agentType,
|
|
47
|
-
message: 'Agent should be executed via Claude Code Task tool',
|
|
48
|
-
prompt: finalPrompt,
|
|
49
|
-
context: context
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Not in Claude Code - show instructions
|
|
54
|
-
console.log();
|
|
55
|
-
console.log(colors.yellow('ā ļø This command requires Claude Code'));
|
|
56
|
-
console.log();
|
|
57
|
-
console.log(colors.cyan('To use AI-powered commands:'));
|
|
58
|
-
console.log();
|
|
59
|
-
console.log(colors.green('1. Open your project in Claude Code'));
|
|
60
|
-
console.log(colors.gray('2. Run commands directly in chat:'));
|
|
61
|
-
console.log(colors.gray(` /pm:prd-new ${context.arguments || 'feature-name'}`));
|
|
62
|
-
console.log();
|
|
63
|
-
console.log(colors.blue('Why Claude Code?'));
|
|
64
|
-
console.log(colors.gray('⢠Interactive brainstorming sessions'));
|
|
65
|
-
console.log(colors.gray('⢠Intelligent context understanding'));
|
|
66
|
-
console.log(colors.gray('⢠Real-time Q&A during PRD creation'));
|
|
67
|
-
console.log();
|
|
68
|
-
console.log(colors.cyan('š What this command would do:'));
|
|
69
|
-
console.log(colors.gray('ā'.repeat(60)));
|
|
70
|
-
|
|
71
|
-
// Show a summary of the command intent
|
|
72
|
-
if (agentType === 'pm-specialist' && context.arguments) {
|
|
73
|
-
console.log(colors.white(`Create PRD for: ${context.arguments}`));
|
|
74
|
-
console.log();
|
|
75
|
-
console.log('The AI agent would:');
|
|
76
|
-
console.log('1. Ask clarifying questions about the feature');
|
|
77
|
-
console.log('2. Help define user stories and requirements');
|
|
78
|
-
console.log('3. Generate comprehensive PRD document');
|
|
79
|
-
console.log(`4. Save to: .claude/prds/${context.arguments}.md`);
|
|
80
|
-
} else {
|
|
81
|
-
console.log(finalPrompt.substring(0, 300) + '...');
|
|
82
|
-
}
|
|
83
|
-
console.log(colors.gray('ā'.repeat(60)));
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
status: 'claude-required',
|
|
87
|
-
agent: agentType,
|
|
88
|
-
message: 'Claude Code required for AI-powered commands',
|
|
89
|
-
prompt: finalPrompt,
|
|
90
|
-
context: context
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
} catch (error) {
|
|
94
|
-
console.error(colors.red(`ā Agent execution failed: ${error.message}`));
|
|
95
|
-
throw error;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
module.exports = new AgentExecutor();
|
package/lib/azure/cache.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Simple cache implementation for Azure DevOps API responses
|
|
3
|
-
* Uses LRU (Least Recently Used) eviction policy
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
class AzureCache {
|
|
7
|
-
constructor(options = {}) {
|
|
8
|
-
this.ttl = options.ttl || 5 * 60 * 1000; // 5 minutes default
|
|
9
|
-
this.maxSize = options.maxSize || 100;
|
|
10
|
-
this.cache = new Map();
|
|
11
|
-
this.stats = { hits: 0, misses: 0 };
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
get(key) {
|
|
15
|
-
const item = this.cache.get(key);
|
|
16
|
-
|
|
17
|
-
if (!item) {
|
|
18
|
-
this.stats.misses++;
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (this.isExpired(item)) {
|
|
23
|
-
this.cache.delete(key);
|
|
24
|
-
this.stats.misses++;
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Move to end (most recently used)
|
|
29
|
-
this.cache.delete(key);
|
|
30
|
-
this.cache.set(key, item);
|
|
31
|
-
|
|
32
|
-
this.stats.hits++;
|
|
33
|
-
return item.value;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
set(key, value) {
|
|
37
|
-
// Remove oldest item if at capacity
|
|
38
|
-
if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
|
|
39
|
-
const firstKey = this.cache.keys().next().value;
|
|
40
|
-
this.cache.delete(firstKey);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
this.cache.set(key, {
|
|
44
|
-
value,
|
|
45
|
-
timestamp: Date.now()
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
isExpired(item) {
|
|
50
|
-
return Date.now() - item.timestamp > this.ttl;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
clear() {
|
|
54
|
-
this.cache.clear();
|
|
55
|
-
this.stats = { hits: 0, misses: 0 };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
getStats() {
|
|
59
|
-
const total = this.stats.hits + this.stats.misses;
|
|
60
|
-
const hitRate = total > 0 ? (this.stats.hits / total * 100).toFixed(2) : 0;
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
...this.stats,
|
|
64
|
-
hitRate: `${hitRate}%`,
|
|
65
|
-
size: this.cache.size,
|
|
66
|
-
maxSize: this.maxSize
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Clean up expired entries
|
|
71
|
-
cleanup() {
|
|
72
|
-
for (const [key, item] of this.cache.entries()) {
|
|
73
|
-
if (this.isExpired(item)) {
|
|
74
|
-
this.cache.delete(key);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
module.exports = AzureCache;
|
package/lib/azure/client.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Azure DevOps Client
|
|
5
|
-
* Wrapper for Azure DevOps REST API
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
class AzureDevOpsClient {
|
|
9
|
-
constructor(options = {}) {
|
|
10
|
-
this.organization = options.organization;
|
|
11
|
-
this.project = options.project;
|
|
12
|
-
this.token = options.token;
|
|
13
|
-
this.baseUrl = `https://dev.azure.com/${this.organization}`;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Create work item
|
|
18
|
-
*/
|
|
19
|
-
async createWorkItem(options) {
|
|
20
|
-
// This would make actual API call
|
|
21
|
-
console.log(`Creating ${options.type} work item`);
|
|
22
|
-
return {
|
|
23
|
-
id: Math.floor(Math.random() * 10000),
|
|
24
|
-
fields: options.fields,
|
|
25
|
-
url: `${this.baseUrl}/${this.project}/_workitems/edit/${Math.floor(Math.random() * 10000)}`
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Update work item
|
|
31
|
-
*/
|
|
32
|
-
async updateWorkItem(options) {
|
|
33
|
-
console.log(`Updating work item ${options.id}`);
|
|
34
|
-
return {
|
|
35
|
-
id: options.id,
|
|
36
|
-
fields: options.fields
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Get work item
|
|
42
|
-
*/
|
|
43
|
-
async getWorkItem(options) {
|
|
44
|
-
console.log(`Getting work item ${options.id}`);
|
|
45
|
-
return {
|
|
46
|
-
id: options.id,
|
|
47
|
-
fields: {
|
|
48
|
-
'System.Title': 'Work Item',
|
|
49
|
-
'System.State': 'Active'
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Create client instance
|
|
57
|
-
*/
|
|
58
|
-
function createClient(options) {
|
|
59
|
-
return new AzureDevOpsClient(options);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Get default client
|
|
64
|
-
*/
|
|
65
|
-
function getClient() {
|
|
66
|
-
return createClient({
|
|
67
|
-
organization: process.env.AZURE_DEVOPS_ORG,
|
|
68
|
-
project: process.env.AZURE_DEVOPS_PROJECT,
|
|
69
|
-
token: process.env.AZURE_DEVOPS_PAT
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
module.exports = {
|
|
74
|
-
AzureDevOpsClient,
|
|
75
|
-
createClient,
|
|
76
|
-
getClient
|
|
77
|
-
};
|
package/lib/azure/formatter.js
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Azure DevOps Output Formatter
|
|
3
|
-
* Formats work items and sprint data for console display
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const Table = require('table').table;
|
|
7
|
-
const chalk = require('chalk');
|
|
8
|
-
|
|
9
|
-
class AzureFormatter {
|
|
10
|
-
static formatWorkItems(items, options = {}) {
|
|
11
|
-
if (!items || items.length === 0) {
|
|
12
|
-
return chalk.yellow('No work items found.');
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const headers = this.getHeaders(options);
|
|
16
|
-
const rows = items.map(item => this.formatWorkItem(item, options));
|
|
17
|
-
|
|
18
|
-
const tableConfig = {
|
|
19
|
-
header: {
|
|
20
|
-
alignment: 'center',
|
|
21
|
-
content: chalk.cyan.bold('Work Items')
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
return Table([headers, ...rows], tableConfig);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
static getHeaders(options) {
|
|
29
|
-
const headers = [
|
|
30
|
-
chalk.bold('ID'),
|
|
31
|
-
chalk.bold('Type'),
|
|
32
|
-
chalk.bold('Title'),
|
|
33
|
-
chalk.bold('State'),
|
|
34
|
-
chalk.bold('Assigned To')
|
|
35
|
-
];
|
|
36
|
-
|
|
37
|
-
if (options.showRemaining) {
|
|
38
|
-
headers.push(chalk.bold('Remaining'));
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (options.showPriority) {
|
|
42
|
-
headers.push(chalk.bold('Priority'));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return headers;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
static formatWorkItem(item, options) {
|
|
49
|
-
const fields = item.fields || {};
|
|
50
|
-
const row = [
|
|
51
|
-
chalk.blue(item.id),
|
|
52
|
-
this.getTypeIcon(fields['System.WorkItemType']),
|
|
53
|
-
this.truncate(fields['System.Title'], 50),
|
|
54
|
-
this.getStateColor(fields['System.State']),
|
|
55
|
-
this.getAssignedTo(fields['System.AssignedTo'])
|
|
56
|
-
];
|
|
57
|
-
|
|
58
|
-
if (options.showRemaining) {
|
|
59
|
-
row.push(fields['Microsoft.VSTS.Scheduling.RemainingWork'] || '-');
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (options.showPriority) {
|
|
63
|
-
row.push(fields['Microsoft.VSTS.Common.Priority'] || '-');
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return row;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
static getTypeIcon(type) {
|
|
70
|
-
const icons = {
|
|
71
|
-
'Task': 'š Task',
|
|
72
|
-
'Bug': 'š Bug',
|
|
73
|
-
'User Story': 'š Story',
|
|
74
|
-
'Feature': 'šÆ Feature',
|
|
75
|
-
'Epic': 'šļø Epic'
|
|
76
|
-
};
|
|
77
|
-
return icons[type] || type;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
static getStateColor(state) {
|
|
81
|
-
const colors = {
|
|
82
|
-
'New': chalk.gray(state),
|
|
83
|
-
'Active': chalk.blue(state),
|
|
84
|
-
'In Progress': chalk.yellow(state),
|
|
85
|
-
'Resolved': chalk.green(state),
|
|
86
|
-
'Closed': chalk.dim(state),
|
|
87
|
-
'Done': chalk.green(state),
|
|
88
|
-
'Removed': chalk.strikethrough(state)
|
|
89
|
-
};
|
|
90
|
-
return colors[state] || state;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
static getAssignedTo(assignedTo) {
|
|
94
|
-
if (!assignedTo) return chalk.gray('Unassigned');
|
|
95
|
-
const name = assignedTo.displayName || assignedTo.uniqueName || assignedTo;
|
|
96
|
-
return this.truncate(name, 20);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
static truncate(text, length) {
|
|
100
|
-
if (!text) return '';
|
|
101
|
-
if (text.length <= length) return text;
|
|
102
|
-
return text.substring(0, length - 3) + '...';
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
static formatSummary(items) {
|
|
106
|
-
if (!items || items.length === 0) {
|
|
107
|
-
return '';
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const states = {};
|
|
111
|
-
const types = {};
|
|
112
|
-
let totalRemaining = 0;
|
|
113
|
-
|
|
114
|
-
items.forEach(item => {
|
|
115
|
-
const fields = item.fields || {};
|
|
116
|
-
const state = fields['System.State'];
|
|
117
|
-
const type = fields['System.WorkItemType'];
|
|
118
|
-
const remaining = fields['Microsoft.VSTS.Scheduling.RemainingWork'] || 0;
|
|
119
|
-
|
|
120
|
-
states[state] = (states[state] || 0) + 1;
|
|
121
|
-
types[type] = (types[type] || 0) + 1;
|
|
122
|
-
totalRemaining += remaining;
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
const lines = [];
|
|
126
|
-
lines.push(chalk.bold('\nš Summary:'));
|
|
127
|
-
lines.push(`Total items: ${chalk.cyan(items.length)}`);
|
|
128
|
-
|
|
129
|
-
if (Object.keys(types).length > 0) {
|
|
130
|
-
lines.push('\nBy Type:');
|
|
131
|
-
Object.entries(types).forEach(([type, count]) => {
|
|
132
|
-
lines.push(` ${this.getTypeIcon(type)}: ${count}`);
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (Object.keys(states).length > 0) {
|
|
137
|
-
lines.push('\nBy State:');
|
|
138
|
-
Object.entries(states).forEach(([state, count]) => {
|
|
139
|
-
lines.push(` ${this.getStateColor(state)}: ${count}`);
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (totalRemaining > 0) {
|
|
144
|
-
lines.push(`\nTotal Remaining Work: ${chalk.yellow(totalRemaining + ' hours')}`);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return lines.join('\n');
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
static formatSprintInfo(sprint) {
|
|
151
|
-
if (!sprint) {
|
|
152
|
-
return chalk.yellow('No active sprint found.');
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const attributes = sprint.attributes || {};
|
|
156
|
-
const startDate = attributes.startDate ? new Date(attributes.startDate).toLocaleDateString() : 'N/A';
|
|
157
|
-
const endDate = attributes.finishDate ? new Date(attributes.finishDate).toLocaleDateString() : 'N/A';
|
|
158
|
-
|
|
159
|
-
return chalk.cyan.bold(`\nš Current Sprint: ${sprint.name}\n`) +
|
|
160
|
-
` Start: ${startDate}\n` +
|
|
161
|
-
` End: ${endDate}\n`;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
static formatError(error) {
|
|
165
|
-
return chalk.red(`\nā Error: ${error.message}\n`);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
static formatSuccess(message) {
|
|
169
|
-
return chalk.green(`\nā
${message}\n`);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
static formatWarning(message) {
|
|
173
|
-
return chalk.yellow(`\nā ļø ${message}\n`);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
module.exports = AzureFormatter;
|