claude-autopm 2.8.1 → 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 +116 -8
- package/bin/autopm.js +2 -0
- package/bin/commands/plugin.js +395 -0
- package/bin/commands/team.js +184 -10
- package/install/install.js +223 -4
- package/lib/plugins/PluginManager.js +1328 -0
- package/lib/plugins/PluginManager.old.js +400 -0
- package/package.json +4 -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,547 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* PRD Parse - Convert PRD to technical implementation epic
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
|
|
9
|
-
class PrdParser {
|
|
10
|
-
constructor() {
|
|
11
|
-
this.prdsDir = path.join('.claude', 'prds');
|
|
12
|
-
this.epicsDir = path.join('.claude', 'epics');
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
parseFrontmatter(content) {
|
|
16
|
-
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
17
|
-
if (!frontmatterMatch) return null;
|
|
18
|
-
|
|
19
|
-
const frontmatter = {};
|
|
20
|
-
const lines = frontmatterMatch[1].split('\n');
|
|
21
|
-
|
|
22
|
-
lines.forEach(line => {
|
|
23
|
-
const [key, ...valueParts] = line.split(':');
|
|
24
|
-
if (key && valueParts.length) {
|
|
25
|
-
frontmatter[key.trim()] = valueParts.join(':').trim();
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
return frontmatter;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
extractPrdContent(content) {
|
|
33
|
-
// Remove frontmatter
|
|
34
|
-
const contentWithoutFrontmatter = content.replace(/^---\n[\s\S]*?\n---\n/, '');
|
|
35
|
-
|
|
36
|
-
const sections = {
|
|
37
|
-
vision: '',
|
|
38
|
-
problem: '',
|
|
39
|
-
users: '',
|
|
40
|
-
features: [],
|
|
41
|
-
requirements: [],
|
|
42
|
-
metrics: '',
|
|
43
|
-
technical: '',
|
|
44
|
-
timeline: ''
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
// Extract sections
|
|
48
|
-
const lines = contentWithoutFrontmatter.split('\n');
|
|
49
|
-
let currentSection = '';
|
|
50
|
-
let sectionContent = [];
|
|
51
|
-
|
|
52
|
-
lines.forEach(line => {
|
|
53
|
-
if (line.startsWith('## ')) {
|
|
54
|
-
// Save previous section
|
|
55
|
-
if (currentSection && sectionContent.length > 0) {
|
|
56
|
-
this.saveSection(sections, currentSection, sectionContent);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
currentSection = line.replace('## ', '').toLowerCase();
|
|
60
|
-
sectionContent = [];
|
|
61
|
-
} else {
|
|
62
|
-
sectionContent.push(line);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// Save last section
|
|
67
|
-
if (currentSection && sectionContent.length > 0) {
|
|
68
|
-
this.saveSection(sections, currentSection, sectionContent);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return sections;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
saveSection(sections, sectionName, content) {
|
|
75
|
-
const contentStr = content.join('\n').trim();
|
|
76
|
-
|
|
77
|
-
if (sectionName.includes('vision') || sectionName.includes('summary')) {
|
|
78
|
-
sections.vision = contentStr;
|
|
79
|
-
} else if (sectionName.includes('problem')) {
|
|
80
|
-
sections.problem = contentStr;
|
|
81
|
-
} else if (sectionName.includes('user') || sectionName.includes('target')) {
|
|
82
|
-
sections.users = contentStr;
|
|
83
|
-
} else if (sectionName.includes('feature')) {
|
|
84
|
-
// Extract feature list
|
|
85
|
-
sections.features = content
|
|
86
|
-
.filter(line => line.match(/^[\-\*•]\s/) || line.match(/^\d+\./))
|
|
87
|
-
.map(line => line.replace(/^[\-\*•\d\.]\s+/, '').trim());
|
|
88
|
-
} else if (sectionName.includes('requirement')) {
|
|
89
|
-
sections.requirements = content
|
|
90
|
-
.filter(line => line.match(/^[\-\*•]\s/) || line.match(/^\d+\./))
|
|
91
|
-
.map(line => line.replace(/^[\-\*•\d\.]\s+/, '').trim());
|
|
92
|
-
} else if (sectionName.includes('metric') || sectionName.includes('success')) {
|
|
93
|
-
sections.metrics = contentStr;
|
|
94
|
-
} else if (sectionName.includes('technical') || sectionName.includes('architecture')) {
|
|
95
|
-
sections.technical = contentStr;
|
|
96
|
-
} else if (sectionName.includes('timeline') || sectionName.includes('schedule')) {
|
|
97
|
-
sections.timeline = contentStr;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
generateTechnicalApproach(prdSections) {
|
|
102
|
-
const approach = {
|
|
103
|
-
frontend: [],
|
|
104
|
-
backend: [],
|
|
105
|
-
infrastructure: [],
|
|
106
|
-
data: [],
|
|
107
|
-
security: []
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
// Analyze features to determine technical needs
|
|
111
|
-
prdSections.features.forEach(feature => {
|
|
112
|
-
const featureLower = feature.toLowerCase();
|
|
113
|
-
|
|
114
|
-
// Frontend detection
|
|
115
|
-
if (featureLower.includes('ui') || featureLower.includes('interface') ||
|
|
116
|
-
featureLower.includes('display') || featureLower.includes('view')) {
|
|
117
|
-
approach.frontend.push(`Component for: ${feature}`);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Backend detection
|
|
121
|
-
if (featureLower.includes('api') || featureLower.includes('process') ||
|
|
122
|
-
featureLower.includes('calculate') || featureLower.includes('service')) {
|
|
123
|
-
approach.backend.push(`Service for: ${feature}`);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Data detection
|
|
127
|
-
if (featureLower.includes('data') || featureLower.includes('store') ||
|
|
128
|
-
featureLower.includes('database') || featureLower.includes('persist')) {
|
|
129
|
-
approach.data.push(`Storage for: ${feature}`);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Security detection
|
|
133
|
-
if (featureLower.includes('auth') || featureLower.includes('secure') ||
|
|
134
|
-
featureLower.includes('permission') || featureLower.includes('access')) {
|
|
135
|
-
approach.security.push(`Security for: ${feature}`);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
// Add defaults if empty
|
|
140
|
-
if (approach.frontend.length === 0) approach.frontend.push('User interface components');
|
|
141
|
-
if (approach.backend.length === 0) approach.backend.push('API endpoints and business logic');
|
|
142
|
-
if (approach.data.length === 0) approach.data.push('Data persistence layer');
|
|
143
|
-
|
|
144
|
-
return approach;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
generateTasks(prdSections, technicalApproach) {
|
|
148
|
-
const tasks = [];
|
|
149
|
-
let taskId = 1;
|
|
150
|
-
|
|
151
|
-
// Setup tasks
|
|
152
|
-
tasks.push({
|
|
153
|
-
id: `TASK-${taskId++}`,
|
|
154
|
-
title: 'Project setup and configuration',
|
|
155
|
-
type: 'setup',
|
|
156
|
-
effort: '2h'
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
// Frontend tasks
|
|
160
|
-
if (technicalApproach.frontend.length > 0) {
|
|
161
|
-
tasks.push({
|
|
162
|
-
id: `TASK-${taskId++}`,
|
|
163
|
-
title: 'Implement UI components',
|
|
164
|
-
type: 'frontend',
|
|
165
|
-
effort: '1d'
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Backend tasks
|
|
170
|
-
if (technicalApproach.backend.length > 0) {
|
|
171
|
-
tasks.push({
|
|
172
|
-
id: `TASK-${taskId++}`,
|
|
173
|
-
title: 'Implement backend services',
|
|
174
|
-
type: 'backend',
|
|
175
|
-
effort: '2d'
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Data tasks
|
|
180
|
-
if (technicalApproach.data.length > 0) {
|
|
181
|
-
tasks.push({
|
|
182
|
-
id: `TASK-${taskId++}`,
|
|
183
|
-
title: 'Set up data models and persistence',
|
|
184
|
-
type: 'backend',
|
|
185
|
-
effort: '1d'
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Integration
|
|
190
|
-
tasks.push({
|
|
191
|
-
id: `TASK-${taskId++}`,
|
|
192
|
-
title: 'Integration and API connections',
|
|
193
|
-
type: 'integration',
|
|
194
|
-
effort: '1d'
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
// Testing
|
|
198
|
-
tasks.push({
|
|
199
|
-
id: `TASK-${taskId++}`,
|
|
200
|
-
title: 'Write tests and documentation',
|
|
201
|
-
type: 'testing',
|
|
202
|
-
effort: '1d'
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
// Deployment
|
|
206
|
-
tasks.push({
|
|
207
|
-
id: `TASK-${taskId++}`,
|
|
208
|
-
title: 'Deployment and release preparation',
|
|
209
|
-
type: 'deployment',
|
|
210
|
-
effort: '4h'
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
return tasks;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
async parsePrd(featureName, options = {}) {
|
|
217
|
-
console.log(`\n🔄 Parsing PRD: ${featureName}`);
|
|
218
|
-
console.log(`${'═'.repeat(50)}\n`);
|
|
219
|
-
|
|
220
|
-
// Check if PRD exists
|
|
221
|
-
const prdFile = path.join(this.prdsDir, `${featureName}.md`);
|
|
222
|
-
if (!fs.existsSync(prdFile)) {
|
|
223
|
-
console.error(`❌ PRD not found: ${featureName}`);
|
|
224
|
-
console.log(`💡 First create it with: /pm:prd-new ${featureName}`);
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// Check for existing epic
|
|
229
|
-
const epicDir = path.join(this.epicsDir, featureName);
|
|
230
|
-
const epicFile = path.join(epicDir, 'epic.md');
|
|
231
|
-
|
|
232
|
-
if (fs.existsSync(epicFile) && !options.overwrite) {
|
|
233
|
-
console.error(`⚠️ Epic '${featureName}' already exists.`);
|
|
234
|
-
console.log(`💡 Use --overwrite to replace it`);
|
|
235
|
-
console.log(`💡 Or view it with: /pm:epic-show ${featureName}`);
|
|
236
|
-
return false;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Read and parse PRD
|
|
240
|
-
console.log('📖 Reading PRD...');
|
|
241
|
-
const prdContent = fs.readFileSync(prdFile, 'utf8');
|
|
242
|
-
const frontmatter = this.parseFrontmatter(prdContent);
|
|
243
|
-
const prdSections = this.extractPrdContent(prdContent);
|
|
244
|
-
|
|
245
|
-
if (!frontmatter) {
|
|
246
|
-
console.error('❌ Invalid PRD frontmatter');
|
|
247
|
-
return false;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Analyze and generate technical approach
|
|
251
|
-
console.log('🔍 Analyzing requirements...');
|
|
252
|
-
const technicalApproach = this.generateTechnicalApproach(prdSections);
|
|
253
|
-
|
|
254
|
-
// Generate tasks
|
|
255
|
-
console.log('📝 Generating implementation tasks...');
|
|
256
|
-
const tasks = this.generateTasks(prdSections, technicalApproach);
|
|
257
|
-
|
|
258
|
-
// Create epic
|
|
259
|
-
console.log('🚀 Creating implementation epic...');
|
|
260
|
-
const epicContent = this.generateEpicContent(
|
|
261
|
-
featureName,
|
|
262
|
-
frontmatter,
|
|
263
|
-
prdSections,
|
|
264
|
-
technicalApproach,
|
|
265
|
-
tasks
|
|
266
|
-
);
|
|
267
|
-
|
|
268
|
-
// Ensure epic directory exists
|
|
269
|
-
if (!fs.existsSync(epicDir)) {
|
|
270
|
-
fs.mkdirSync(epicDir, { recursive: true });
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// Write epic file
|
|
274
|
-
fs.writeFileSync(epicFile, epicContent);
|
|
275
|
-
|
|
276
|
-
// Display summary
|
|
277
|
-
console.log('\n✅ Epic created successfully!');
|
|
278
|
-
console.log(`\n📋 Implementation Summary:`);
|
|
279
|
-
console.log(`${'─'.repeat(50)}`);
|
|
280
|
-
console.log(`📄 Epic: ${epicFile}`);
|
|
281
|
-
console.log(`📊 Tasks: ${tasks.length}`);
|
|
282
|
-
console.log(`⏱️ Estimated effort: ${this.calculateTotalEffort(tasks)}`);
|
|
283
|
-
|
|
284
|
-
console.log(`\n🔧 Technical Components:`);
|
|
285
|
-
if (technicalApproach.frontend.length > 0) {
|
|
286
|
-
console.log(` • Frontend: ${technicalApproach.frontend.length} components`);
|
|
287
|
-
}
|
|
288
|
-
if (technicalApproach.backend.length > 0) {
|
|
289
|
-
console.log(` • Backend: ${technicalApproach.backend.length} services`);
|
|
290
|
-
}
|
|
291
|
-
if (technicalApproach.data.length > 0) {
|
|
292
|
-
console.log(` • Data: ${technicalApproach.data.length} models`);
|
|
293
|
-
}
|
|
294
|
-
if (technicalApproach.security.length > 0) {
|
|
295
|
-
console.log(` • Security: ${technicalApproach.security.length} controls`);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Determine if PRD is complex enough to suggest splitting
|
|
299
|
-
const componentCount =
|
|
300
|
-
(technicalApproach.frontend.length > 0 ? 1 : 0) +
|
|
301
|
-
(technicalApproach.backend.length > 0 ? 1 : 0) +
|
|
302
|
-
(technicalApproach.data.length > 0 ? 1 : 0) +
|
|
303
|
-
(technicalApproach.security.length > 0 ? 1 : 0);
|
|
304
|
-
|
|
305
|
-
const isComplexPrd = componentCount >= 3 || tasks.length > 10;
|
|
306
|
-
|
|
307
|
-
console.log(`\n💡 Next Steps:`);
|
|
308
|
-
console.log(` 1. Review epic: /pm:epic-show ${featureName}`);
|
|
309
|
-
|
|
310
|
-
if (isComplexPrd) {
|
|
311
|
-
console.log(` 2. Consider splitting into epics: /pm:epic-split ${featureName}`);
|
|
312
|
-
console.log(` (Complex PRD detected - ${componentCount} components, ${tasks.length} tasks)`);
|
|
313
|
-
console.log(` OR decompose as single epic: /pm:epic-decompose ${featureName}`);
|
|
314
|
-
} else {
|
|
315
|
-
console.log(` 2. Decompose into tasks: /pm:epic-decompose ${featureName}`);
|
|
316
|
-
console.log(` (For complex PRDs, consider: /pm:epic-split ${featureName})`);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
console.log(` 3. Sync to GitHub: /pm:epic-sync ${featureName}`);
|
|
320
|
-
console.log(` 4. Start implementation: /pm:issue-start TASK-1`);
|
|
321
|
-
|
|
322
|
-
return true;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
generateEpicContent(featureName, frontmatter, prdSections, technicalApproach, tasks) {
|
|
326
|
-
const now = new Date().toISOString();
|
|
327
|
-
const description = frontmatter.description || prdSections.vision.substring(0, 200);
|
|
328
|
-
|
|
329
|
-
return `---
|
|
330
|
-
name: ${featureName}
|
|
331
|
-
status: backlog
|
|
332
|
-
created: ${now}
|
|
333
|
-
progress: 0%
|
|
334
|
-
prd: .claude/prds/${featureName}.md
|
|
335
|
-
github: [Will be updated when synced to GitHub]
|
|
336
|
-
priority: ${frontmatter.priority || 'P2'}
|
|
337
|
-
---
|
|
338
|
-
|
|
339
|
-
# Epic: ${featureName}
|
|
340
|
-
|
|
341
|
-
## Overview
|
|
342
|
-
${description}
|
|
343
|
-
|
|
344
|
-
${prdSections.vision ? `### Vision\n${prdSections.vision}\n` : ''}
|
|
345
|
-
|
|
346
|
-
## Architecture Decisions
|
|
347
|
-
|
|
348
|
-
### Technology Stack
|
|
349
|
-
- **Frontend**: Modern component-based UI
|
|
350
|
-
- **Backend**: RESTful API services
|
|
351
|
-
- **Data**: Persistent storage with appropriate database
|
|
352
|
-
- **Infrastructure**: Cloud-native deployment
|
|
353
|
-
|
|
354
|
-
### Design Patterns
|
|
355
|
-
- Separation of concerns
|
|
356
|
-
- API-first development
|
|
357
|
-
- Test-driven development
|
|
358
|
-
- Progressive enhancement
|
|
359
|
-
|
|
360
|
-
## Technical Approach
|
|
361
|
-
|
|
362
|
-
### Frontend Components
|
|
363
|
-
${technicalApproach.frontend.map(c => `- ${c}`).join('\n')}
|
|
364
|
-
|
|
365
|
-
### Backend Services
|
|
366
|
-
${technicalApproach.backend.map(s => `- ${s}`).join('\n')}
|
|
367
|
-
|
|
368
|
-
### Data Models
|
|
369
|
-
${technicalApproach.data.map(d => `- ${d}`).join('\n')}
|
|
370
|
-
|
|
371
|
-
${technicalApproach.security.length > 0 ? `### Security Controls\n${technicalApproach.security.map(s => `- ${s}`).join('\n')}\n` : ''}
|
|
372
|
-
|
|
373
|
-
### Infrastructure
|
|
374
|
-
- Development environment setup
|
|
375
|
-
- Testing infrastructure
|
|
376
|
-
- Deployment pipeline
|
|
377
|
-
- Monitoring and logging
|
|
378
|
-
|
|
379
|
-
## Implementation Strategy
|
|
380
|
-
|
|
381
|
-
### Phase 1: Foundation
|
|
382
|
-
- Set up project structure
|
|
383
|
-
- Configure development environment
|
|
384
|
-
- Establish CI/CD pipeline
|
|
385
|
-
|
|
386
|
-
### Phase 2: Core Implementation
|
|
387
|
-
- Build core functionality
|
|
388
|
-
- Implement data models
|
|
389
|
-
- Create API endpoints
|
|
390
|
-
|
|
391
|
-
### Phase 3: Integration
|
|
392
|
-
- Connect frontend and backend
|
|
393
|
-
- Implement authentication
|
|
394
|
-
- Add error handling
|
|
395
|
-
|
|
396
|
-
### Phase 4: Polish
|
|
397
|
-
- Performance optimization
|
|
398
|
-
- Security hardening
|
|
399
|
-
- Documentation
|
|
400
|
-
|
|
401
|
-
## Task Breakdown
|
|
402
|
-
|
|
403
|
-
${tasks.map(task => `### ${task.id}: ${task.title}
|
|
404
|
-
- **Type**: ${task.type}
|
|
405
|
-
- **Effort**: ${task.effort}
|
|
406
|
-
- **Status**: Not Started`).join('\n\n')}
|
|
407
|
-
|
|
408
|
-
## Dependencies
|
|
409
|
-
|
|
410
|
-
### External Dependencies
|
|
411
|
-
- Framework libraries
|
|
412
|
-
- Database system
|
|
413
|
-
- Authentication service
|
|
414
|
-
|
|
415
|
-
### Internal Dependencies
|
|
416
|
-
- Shared components
|
|
417
|
-
- Common utilities
|
|
418
|
-
- API contracts
|
|
419
|
-
|
|
420
|
-
## Success Criteria
|
|
421
|
-
|
|
422
|
-
${prdSections.metrics || '- All functional requirements met\n- Performance targets achieved\n- Security requirements satisfied\n- Documentation complete'}
|
|
423
|
-
|
|
424
|
-
## Estimated Effort
|
|
425
|
-
|
|
426
|
-
**Total**: ${this.calculateTotalEffort(tasks)}
|
|
427
|
-
|
|
428
|
-
### Breakdown by Type:
|
|
429
|
-
- Setup: ${this.calculateEffortByType(tasks, 'setup')}
|
|
430
|
-
- Frontend: ${this.calculateEffortByType(tasks, 'frontend')}
|
|
431
|
-
- Backend: ${this.calculateEffortByType(tasks, 'backend')}
|
|
432
|
-
- Integration: ${this.calculateEffortByType(tasks, 'integration')}
|
|
433
|
-
- Testing: ${this.calculateEffortByType(tasks, 'testing')}
|
|
434
|
-
- Deployment: ${this.calculateEffortByType(tasks, 'deployment')}
|
|
435
|
-
|
|
436
|
-
## Notes
|
|
437
|
-
|
|
438
|
-
- This epic was automatically generated from the PRD
|
|
439
|
-
- Review and adjust estimates based on team capacity
|
|
440
|
-
- Consider breaking down large tasks further
|
|
441
|
-
- Update progress as tasks are completed
|
|
442
|
-
|
|
443
|
-
---
|
|
444
|
-
|
|
445
|
-
*Generated on ${now} by PM System*`;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
calculateTotalEffort(tasks) {
|
|
449
|
-
let totalHours = 0;
|
|
450
|
-
|
|
451
|
-
tasks.forEach(task => {
|
|
452
|
-
totalHours += this.parseEffort(task.effort);
|
|
453
|
-
});
|
|
454
|
-
|
|
455
|
-
return this.formatEffort(totalHours);
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
calculateEffortByType(tasks, type) {
|
|
459
|
-
const typeTasks = tasks.filter(t => t.type === type);
|
|
460
|
-
let totalHours = 0;
|
|
461
|
-
|
|
462
|
-
typeTasks.forEach(task => {
|
|
463
|
-
totalHours += this.parseEffort(task.effort);
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
return this.formatEffort(totalHours);
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
parseEffort(effort) {
|
|
470
|
-
if (!effort || typeof effort !== 'string') {
|
|
471
|
-
return 8; // Default to 1 day
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
const numericValue = parseInt(effort);
|
|
475
|
-
if (isNaN(numericValue)) {
|
|
476
|
-
return 8; // Default to 1 day for invalid input
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
if (effort.includes('d')) {
|
|
480
|
-
return numericValue * 8;
|
|
481
|
-
} else if (effort.includes('h')) {
|
|
482
|
-
return numericValue;
|
|
483
|
-
} else if (effort.includes('w')) {
|
|
484
|
-
return numericValue * 40;
|
|
485
|
-
}
|
|
486
|
-
return 8; // Default to 1 day
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
formatEffort(hours) {
|
|
490
|
-
if (hours >= 40) {
|
|
491
|
-
const weeks = Math.floor(hours / 40);
|
|
492
|
-
const days = Math.floor((hours % 40) / 8);
|
|
493
|
-
return `${weeks}w ${days}d`;
|
|
494
|
-
} else if (hours >= 8) {
|
|
495
|
-
const days = Math.floor(hours / 8);
|
|
496
|
-
const remainingHours = hours % 8;
|
|
497
|
-
return remainingHours > 0 ? `${days}d ${remainingHours}h` : `${days}d`;
|
|
498
|
-
}
|
|
499
|
-
return `${hours}h`;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
async run(args) {
|
|
503
|
-
const featureName = args[0];
|
|
504
|
-
|
|
505
|
-
if (!featureName) {
|
|
506
|
-
console.error('❌ Error: Feature name required');
|
|
507
|
-
console.error('Usage: /pm:prd-parse <feature-name> [--overwrite]');
|
|
508
|
-
|
|
509
|
-
// List available PRDs
|
|
510
|
-
if (fs.existsSync(this.prdsDir)) {
|
|
511
|
-
const prds = fs.readdirSync(this.prdsDir)
|
|
512
|
-
.filter(f => f.endsWith('.md'))
|
|
513
|
-
.map(f => f.replace('.md', ''));
|
|
514
|
-
|
|
515
|
-
if (prds.length > 0) {
|
|
516
|
-
console.log('\n📋 Available PRDs:');
|
|
517
|
-
prds.forEach(prd => {
|
|
518
|
-
console.log(` • ${prd}`);
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
process.exit(1);
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
const options = {};
|
|
527
|
-
args.slice(1).forEach(arg => {
|
|
528
|
-
if (arg === '--overwrite') {
|
|
529
|
-
options.overwrite = true;
|
|
530
|
-
}
|
|
531
|
-
});
|
|
532
|
-
|
|
533
|
-
const success = await this.parsePrd(featureName, options);
|
|
534
|
-
process.exit(success ? 0 : 1);
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
// Main execution
|
|
539
|
-
if (require.main === module) {
|
|
540
|
-
const parser = new PrdParser();
|
|
541
|
-
parser.run(process.argv.slice(2)).catch(error => {
|
|
542
|
-
console.error('❌ Error:', error.message);
|
|
543
|
-
process.exit(1);
|
|
544
|
-
});
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
module.exports = PrdParser;
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* PRD Status Script - Node.js Implementation
|
|
5
|
-
* Displays status report for all PRDs in the project
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const fs = require('fs');
|
|
9
|
-
const path = require('path');
|
|
10
|
-
|
|
11
|
-
class PRDStatus {
|
|
12
|
-
constructor() {
|
|
13
|
-
this.prdsDir = path.join(process.cwd(), '.claude', 'prds');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
getPRDFiles() {
|
|
17
|
-
if (!fs.existsSync(this.prdsDir)) {
|
|
18
|
-
return [];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return fs.readdirSync(this.prdsDir)
|
|
22
|
-
.filter(file => file.endsWith('.md'))
|
|
23
|
-
.map(file => path.join(this.prdsDir, file));
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
extractStatus(filePath) {
|
|
27
|
-
try {
|
|
28
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
29
|
-
const statusMatch = content.match(/^status:\s*(.+)$/m);
|
|
30
|
-
return statusMatch ? statusMatch[1].trim() : 'backlog';
|
|
31
|
-
} catch {
|
|
32
|
-
return 'backlog';
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
extractName(filePath) {
|
|
37
|
-
try {
|
|
38
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
39
|
-
const nameMatch = content.match(/^name:\s*(.+)$/m);
|
|
40
|
-
return nameMatch ? nameMatch[1].trim() : path.basename(filePath, '.md');
|
|
41
|
-
} catch {
|
|
42
|
-
return path.basename(filePath, '.md');
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
categorizeStatus(status) {
|
|
47
|
-
const statusLower = status.toLowerCase();
|
|
48
|
-
if (['backlog', 'draft', ''].includes(statusLower)) {
|
|
49
|
-
return 'backlog';
|
|
50
|
-
} else if (['in-progress', 'active'].includes(statusLower)) {
|
|
51
|
-
return 'in_progress';
|
|
52
|
-
} else if (['implemented', 'completed', 'done'].includes(statusLower)) {
|
|
53
|
-
return 'implemented';
|
|
54
|
-
}
|
|
55
|
-
return 'backlog';
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
drawBar(count, total, maxWidth = 20) {
|
|
59
|
-
if (total === 0) return '';
|
|
60
|
-
const barLength = Math.round((count / total) * maxWidth);
|
|
61
|
-
return '█'.repeat(barLength);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
run() {
|
|
65
|
-
console.log('📄 PRD Status Report');
|
|
66
|
-
console.log('====================');
|
|
67
|
-
console.log('');
|
|
68
|
-
|
|
69
|
-
const prdFiles = this.getPRDFiles();
|
|
70
|
-
|
|
71
|
-
if (prdFiles.length === 0) {
|
|
72
|
-
if (!fs.existsSync(this.prdsDir)) {
|
|
73
|
-
console.log('No PRD directory found.');
|
|
74
|
-
} else {
|
|
75
|
-
console.log('No PRDs found.');
|
|
76
|
-
}
|
|
77
|
-
process.exit(0);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Count by status
|
|
81
|
-
const counts = {
|
|
82
|
-
backlog: 0,
|
|
83
|
-
in_progress: 0,
|
|
84
|
-
implemented: 0
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const prds = prdFiles.map(file => {
|
|
88
|
-
const status = this.extractStatus(file);
|
|
89
|
-
const category = this.categorizeStatus(status);
|
|
90
|
-
counts[category]++;
|
|
91
|
-
|
|
92
|
-
return {
|
|
93
|
-
path: file,
|
|
94
|
-
name: this.extractName(file),
|
|
95
|
-
status: status,
|
|
96
|
-
category: category,
|
|
97
|
-
mtime: fs.statSync(file).mtime
|
|
98
|
-
};
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
const total = prdFiles.length;
|
|
102
|
-
|
|
103
|
-
console.log('Getting status...');
|
|
104
|
-
console.log('');
|
|
105
|
-
console.log('');
|
|
106
|
-
|
|
107
|
-
// Display chart
|
|
108
|
-
console.log('📊 Distribution:');
|
|
109
|
-
console.log('================');
|
|
110
|
-
console.log('');
|
|
111
|
-
|
|
112
|
-
console.log(` Backlog: ${counts.backlog.toString().padEnd(3)} [${this.drawBar(counts.backlog, total)}]`);
|
|
113
|
-
console.log(` In Progress: ${counts.in_progress.toString().padEnd(3)} [${this.drawBar(counts.in_progress, total)}]`);
|
|
114
|
-
console.log(` Implemented: ${counts.implemented.toString().padEnd(3)} [${this.drawBar(counts.implemented, total)}]`);
|
|
115
|
-
console.log('');
|
|
116
|
-
console.log(` Total PRDs: ${total}`);
|
|
117
|
-
|
|
118
|
-
// Recent activity
|
|
119
|
-
console.log('');
|
|
120
|
-
console.log('📅 Recent PRDs (last 5 modified):');
|
|
121
|
-
|
|
122
|
-
prds.sort((a, b) => b.mtime - a.mtime)
|
|
123
|
-
.slice(0, 5)
|
|
124
|
-
.forEach(prd => {
|
|
125
|
-
console.log(` • ${prd.name}`);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// Suggestions
|
|
129
|
-
console.log('');
|
|
130
|
-
console.log('💡 Next Actions:');
|
|
131
|
-
|
|
132
|
-
if (counts.backlog > 0) {
|
|
133
|
-
console.log(' • Parse backlog PRDs to epics: /pm:prd-parse <name>');
|
|
134
|
-
}
|
|
135
|
-
if (counts.in_progress > 0) {
|
|
136
|
-
console.log(' • Check progress on active PRDs: /pm:epic-status <name>');
|
|
137
|
-
}
|
|
138
|
-
if (total === 0) {
|
|
139
|
-
console.log(' • Create your first PRD: /pm:prd-new <name>');
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
process.exit(0);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Main execution
|
|
147
|
-
if (require.main === module) {
|
|
148
|
-
const status = new PRDStatus();
|
|
149
|
-
status.run();
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
module.exports = PRDStatus;
|