den-github-manager 1.0.0
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/CHANGELOG.md +41 -0
- package/CONTRIBUTING.md +91 -0
- package/LICENSE +21 -0
- package/PRE_PUBLISH_CHECKLIST.md +165 -0
- package/README.md +307 -0
- package/bin/den.js +69 -0
- package/docs/backlog.md +78 -0
- package/package.json +59 -0
- package/scripts/pre-publish-test.sh +122 -0
- package/src/commands/analyze.js +35 -0
- package/src/commands/config.js +42 -0
- package/src/commands/init.js +224 -0
- package/src/commands/templates.js +71 -0
- package/src/core/analyzer.js +266 -0
- package/src/core/generator.js +199 -0
- package/src/core/github-client.js +246 -0
- package/src/core/template-manager.js +23 -0
- package/src/index.js +6 -0
- package/src/utils/config.js +57 -0
- package/src/utils/logger.js +49 -0
package/docs/backlog.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Product Backlog
|
|
2
|
+
|
|
3
|
+
Generated: 2026-02-06
|
|
4
|
+
|
|
5
|
+
## Milestones
|
|
6
|
+
|
|
7
|
+
| ID | Milestone | Objective | State |
|
|
8
|
+
|----|-----------|-----------|-------|
|
|
9
|
+
| M0 | Foundation | Setup and initial configuration | ✅ closed |
|
|
10
|
+
| M1 | Core Features | Main functionality | ⬜ open |
|
|
11
|
+
| M2 | Polish | Testing and refinement | ⬜ open |
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Epics
|
|
16
|
+
|
|
17
|
+
| ID | Epic | Description | Milestone |
|
|
18
|
+
|----|------|-------------|-----------||
|
|
19
|
+
| E1 | Setup & Configuration | | M0 |
|
|
20
|
+
| E2 | Core Functionality | | M1 |
|
|
21
|
+
| E3 | User Interface | | M1 |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## User Stories
|
|
26
|
+
|
|
27
|
+
### US-E1-01: Setup repository
|
|
28
|
+
|
|
29
|
+
**Priority**: P0 | **Points**: 3 | **Status**: ✅ completed
|
|
30
|
+
|
|
31
|
+
**Epic**: E1 | **Milestone**: M0
|
|
32
|
+
|
|
33
|
+
**Criterios de Aceptación**:
|
|
34
|
+
- [ ] Implement functionality
|
|
35
|
+
- [ ] Add tests
|
|
36
|
+
- [ ] Update documentation
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
### US-E1-02: Configure development environment
|
|
41
|
+
|
|
42
|
+
**Priority**: P0 | **Points**: 5 | **Status**: ✅ completed
|
|
43
|
+
|
|
44
|
+
**Epic**: E1 | **Milestone**: M0
|
|
45
|
+
|
|
46
|
+
**Criterios de Aceptación**:
|
|
47
|
+
- [ ] Implement functionality
|
|
48
|
+
- [ ] Add tests
|
|
49
|
+
- [ ] Update documentation
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
### US-E2-01: Implement core logic
|
|
54
|
+
|
|
55
|
+
**Priority**: P0 | **Points**: 8 | **Status**: ⬜ pending
|
|
56
|
+
|
|
57
|
+
**Epic**: E2 | **Milestone**: M1
|
|
58
|
+
|
|
59
|
+
**Criterios de Aceptación**:
|
|
60
|
+
- [ ] Implement functionality
|
|
61
|
+
- [ ] Add tests
|
|
62
|
+
- [ ] Update documentation
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### US-E3-01: Create main UI components
|
|
67
|
+
|
|
68
|
+
**Priority**: P1 | **Points**: 5 | **Status**: ⬜ pending
|
|
69
|
+
|
|
70
|
+
**Epic**: E3 | **Milestone**: M1
|
|
71
|
+
|
|
72
|
+
**Criterios de Aceptación**:
|
|
73
|
+
- [ ] Implement functionality
|
|
74
|
+
- [ ] Add tests
|
|
75
|
+
- [ ] Update documentation
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "den-github-manager",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI tool to setup GitHub Projects automatically - Analyze, generate backlog, and configure milestones, issues, and project boards in minutes",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"den": "./bin/den.js",
|
|
9
|
+
"den-github-manager": "./bin/den.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"start": "node bin/den.js",
|
|
13
|
+
"test": "jest",
|
|
14
|
+
"lint": "eslint src/",
|
|
15
|
+
"format": "prettier --write \"src/**/*.js\"",
|
|
16
|
+
"prepare": "chmod +x bin/den.js"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"github",
|
|
20
|
+
"project-management",
|
|
21
|
+
"cli",
|
|
22
|
+
"automation",
|
|
23
|
+
"kanban",
|
|
24
|
+
"agile",
|
|
25
|
+
"scrum",
|
|
26
|
+
"milestones",
|
|
27
|
+
"issues",
|
|
28
|
+
"project-board",
|
|
29
|
+
"backlog",
|
|
30
|
+
"devtools"
|
|
31
|
+
],
|
|
32
|
+
"author": "wolfcito <@akawolfcito>",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/wolfcito/den-github-manager.git"
|
|
37
|
+
},
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/wolfcito/den-github-manager/issues"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/wolfcito/den-github-manager#readme",
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=18.0.0"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"chalk": "^5.3.0",
|
|
47
|
+
"commander": "^11.1.0",
|
|
48
|
+
"inquirer": "^9.2.12",
|
|
49
|
+
"ora": "^7.0.1",
|
|
50
|
+
"@octokit/rest": "^20.0.2",
|
|
51
|
+
"js-yaml": "^4.1.0",
|
|
52
|
+
"marked": "^11.1.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"eslint": "^8.55.0",
|
|
56
|
+
"jest": "^29.7.0",
|
|
57
|
+
"prettier": "^3.1.1"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Pre-publish test script
|
|
4
|
+
# Run this before publishing to npm
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
echo "🧪 Pre-Publish Testing"
|
|
9
|
+
echo "======================"
|
|
10
|
+
echo ""
|
|
11
|
+
|
|
12
|
+
# 1. Syntax check
|
|
13
|
+
echo "1️⃣ Checking syntax..."
|
|
14
|
+
node --check bin/den.js
|
|
15
|
+
echo "✅ Syntax OK"
|
|
16
|
+
echo ""
|
|
17
|
+
|
|
18
|
+
# 2. Check permissions
|
|
19
|
+
echo "2️⃣ Checking permissions..."
|
|
20
|
+
if [ -x "bin/den.js" ]; then
|
|
21
|
+
echo "✅ bin/den.js is executable"
|
|
22
|
+
else
|
|
23
|
+
echo "❌ bin/den.js is not executable"
|
|
24
|
+
echo "Run: chmod +x bin/den.js"
|
|
25
|
+
exit 1
|
|
26
|
+
fi
|
|
27
|
+
echo ""
|
|
28
|
+
|
|
29
|
+
# 3. Install dependencies
|
|
30
|
+
echo "3️⃣ Installing dependencies..."
|
|
31
|
+
npm ci > /dev/null 2>&1
|
|
32
|
+
echo "✅ Dependencies installed"
|
|
33
|
+
echo ""
|
|
34
|
+
|
|
35
|
+
# 4. Test basic commands
|
|
36
|
+
echo "4️⃣ Testing CLI commands..."
|
|
37
|
+
./bin/den.js --version > /dev/null
|
|
38
|
+
echo "✅ Version command works"
|
|
39
|
+
|
|
40
|
+
./bin/den.js --help > /dev/null
|
|
41
|
+
echo "✅ Help command works"
|
|
42
|
+
|
|
43
|
+
./bin/den.js templates --list > /dev/null
|
|
44
|
+
echo "✅ Templates command works"
|
|
45
|
+
|
|
46
|
+
./bin/den.js analyze > /dev/null 2>&1 || true
|
|
47
|
+
echo "✅ Analyze command works"
|
|
48
|
+
|
|
49
|
+
./bin/den.js init --template simple --auto --dry-run > /dev/null 2>&1
|
|
50
|
+
echo "✅ Init command works (dry-run)"
|
|
51
|
+
echo ""
|
|
52
|
+
|
|
53
|
+
# 5. Check package
|
|
54
|
+
echo "5️⃣ Checking package contents..."
|
|
55
|
+
npm pack --dry-run > /tmp/pack-contents.txt 2>&1
|
|
56
|
+
|
|
57
|
+
EXPECTED_FILES=(
|
|
58
|
+
"package.json"
|
|
59
|
+
"README.md"
|
|
60
|
+
"LICENSE"
|
|
61
|
+
"bin/den.js"
|
|
62
|
+
"src/"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
for file in "${EXPECTED_FILES[@]}"; do
|
|
66
|
+
if grep -q "$file" /tmp/pack-contents.txt; then
|
|
67
|
+
echo "✅ $file included"
|
|
68
|
+
else
|
|
69
|
+
echo "⚠️ $file might be missing"
|
|
70
|
+
fi
|
|
71
|
+
done
|
|
72
|
+
|
|
73
|
+
echo ""
|
|
74
|
+
|
|
75
|
+
# 6. Check package.json
|
|
76
|
+
echo "6️⃣ Validating package.json..."
|
|
77
|
+
required_fields=("name" "version" "description" "main" "bin" "author" "license")
|
|
78
|
+
|
|
79
|
+
for field in "${required_fields[@]}"; do
|
|
80
|
+
if grep -q "\"$field\"" package.json; then
|
|
81
|
+
echo "✅ $field present"
|
|
82
|
+
else
|
|
83
|
+
echo "❌ $field missing"
|
|
84
|
+
exit 1
|
|
85
|
+
fi
|
|
86
|
+
done
|
|
87
|
+
|
|
88
|
+
echo ""
|
|
89
|
+
|
|
90
|
+
# 7. Size check
|
|
91
|
+
echo "7️⃣ Package size check..."
|
|
92
|
+
npm pack --quiet > /dev/null
|
|
93
|
+
TARBALL=$(ls -1 den-github-manager-*.tgz 2>/dev/null | head -1)
|
|
94
|
+
|
|
95
|
+
if [ -f "$TARBALL" ]; then
|
|
96
|
+
SIZE=$(du -h "$TARBALL" | cut -f1)
|
|
97
|
+
echo "📦 Package size: $SIZE"
|
|
98
|
+
|
|
99
|
+
# Clean up
|
|
100
|
+
rm "$TARBALL"
|
|
101
|
+
|
|
102
|
+
# Warn if > 1MB
|
|
103
|
+
SIZE_KB=$(du -k "$TARBALL" 2>/dev/null | cut -f1 || echo 0)
|
|
104
|
+
if [ $SIZE_KB -gt 1024 ]; then
|
|
105
|
+
echo "⚠️ Package is larger than 1MB"
|
|
106
|
+
fi
|
|
107
|
+
else
|
|
108
|
+
echo "⚠️ Could not determine package size"
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
echo ""
|
|
112
|
+
|
|
113
|
+
# Summary
|
|
114
|
+
echo "✅ All pre-publish tests passed!"
|
|
115
|
+
echo ""
|
|
116
|
+
echo "📋 Next steps:"
|
|
117
|
+
echo " 1. Commit all changes: git add . && git commit"
|
|
118
|
+
echo " 2. Push to GitHub: git push"
|
|
119
|
+
echo " 3. Login to npm: npm login"
|
|
120
|
+
echo " 4. Publish: npm publish"
|
|
121
|
+
echo " 5. Create release: gh release create v1.0.0"
|
|
122
|
+
echo ""
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Analyzer } from '../core/analyzer.js';
|
|
2
|
+
import { Logger } from '../utils/logger.js';
|
|
3
|
+
|
|
4
|
+
export async function analyzeCommand(options) {
|
|
5
|
+
const logger = new Logger();
|
|
6
|
+
const analyzer = new Analyzer();
|
|
7
|
+
|
|
8
|
+
logger.info('Analyzing project...');
|
|
9
|
+
|
|
10
|
+
const analysis = await analyzer.analyze();
|
|
11
|
+
|
|
12
|
+
if (options.json) {
|
|
13
|
+
logger.json(analysis);
|
|
14
|
+
} else {
|
|
15
|
+
analyzer.generateReport(analysis);
|
|
16
|
+
|
|
17
|
+
// Additional insights
|
|
18
|
+
logger.newline();
|
|
19
|
+
logger.section('💡 Recommendations');
|
|
20
|
+
|
|
21
|
+
if (!analysis.hasBacklog.exists) {
|
|
22
|
+
logger.info('Consider creating a backlog with: den init');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!analysis.hasDocumentation.exists) {
|
|
26
|
+
logger.info('Consider adding documentation in docs/');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (analysis.phase === 'new') {
|
|
30
|
+
logger.info('Perfect time to set up project management!');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
logger.newline();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Config } from '../utils/config.js';
|
|
2
|
+
import { Logger } from '../utils/logger.js';
|
|
3
|
+
|
|
4
|
+
export async function configCommand(options) {
|
|
5
|
+
const logger = new Logger();
|
|
6
|
+
const config = new Config();
|
|
7
|
+
|
|
8
|
+
await config.load();
|
|
9
|
+
|
|
10
|
+
if (options.set) {
|
|
11
|
+
const [key, value] = options.set.split('=');
|
|
12
|
+
|
|
13
|
+
if (!key || !value) {
|
|
14
|
+
logger.error('Invalid format. Use: --set key=value');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
config.set(key, value);
|
|
19
|
+
await config.save();
|
|
20
|
+
logger.success(`Set ${key} = ${value}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (options.get) {
|
|
24
|
+
const value = config.get(options.get);
|
|
25
|
+
console.log(value);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (options.list || (!options.set && !options.get)) {
|
|
29
|
+
logger.section('⚙️ Configuration');
|
|
30
|
+
logger.newline();
|
|
31
|
+
|
|
32
|
+
const allConfig = config.getAll();
|
|
33
|
+
|
|
34
|
+
for (const [key, value] of Object.entries(allConfig)) {
|
|
35
|
+
logger.info(`${key}: ${JSON.stringify(value)}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
logger.newline();
|
|
39
|
+
logger.dim('Config file: ~/.den-github-manager/config.json');
|
|
40
|
+
logger.newline();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import fs from 'fs/promises';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { Analyzer } from '../core/analyzer.js';
|
|
6
|
+
import { Generator } from '../core/generator.js';
|
|
7
|
+
import { GitHubClient } from '../core/github-client.js';
|
|
8
|
+
import { Logger } from '../utils/logger.js';
|
|
9
|
+
|
|
10
|
+
export async function initCommand(options) {
|
|
11
|
+
const logger = new Logger();
|
|
12
|
+
|
|
13
|
+
logger.section('🦁 Den GitHub Manager - Project Setup');
|
|
14
|
+
|
|
15
|
+
// Step 1: Analyze project
|
|
16
|
+
const analyzer = new Analyzer();
|
|
17
|
+
const spinner = ora('Analyzing project...').start();
|
|
18
|
+
|
|
19
|
+
let analysis;
|
|
20
|
+
try {
|
|
21
|
+
analysis = await analyzer.analyze();
|
|
22
|
+
spinner.succeed('Project analyzed');
|
|
23
|
+
} catch (error) {
|
|
24
|
+
spinner.fail('Analysis failed');
|
|
25
|
+
logger.error(error.message);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Show analysis report
|
|
30
|
+
if (!options.auto) {
|
|
31
|
+
logger.newline();
|
|
32
|
+
analyzer.generateReport(analysis);
|
|
33
|
+
logger.newline();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Step 2: Determine backlog strategy
|
|
37
|
+
let backlogContent;
|
|
38
|
+
let template = options.template || 'simple';
|
|
39
|
+
|
|
40
|
+
if (analysis.hasBacklog.exists) {
|
|
41
|
+
logger.success(`Found existing backlog: ${analysis.hasBacklog.path}`);
|
|
42
|
+
|
|
43
|
+
if (!options.auto) {
|
|
44
|
+
const { useExisting } = await inquirer.prompt([{
|
|
45
|
+
type: 'confirm',
|
|
46
|
+
name: 'useExisting',
|
|
47
|
+
message: 'Use existing backlog?',
|
|
48
|
+
default: true
|
|
49
|
+
}]);
|
|
50
|
+
|
|
51
|
+
if (!useExisting) {
|
|
52
|
+
template = await selectTemplate();
|
|
53
|
+
} else {
|
|
54
|
+
// Read existing backlog
|
|
55
|
+
const backlogPath = path.join(process.cwd(), analysis.hasBacklog.path);
|
|
56
|
+
backlogContent = await fs.readFile(backlogPath, 'utf-8');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
logger.warn('No backlog found');
|
|
61
|
+
|
|
62
|
+
if (!options.auto) {
|
|
63
|
+
const { action } = await inquirer.prompt([{
|
|
64
|
+
type: 'list',
|
|
65
|
+
name: 'action',
|
|
66
|
+
message: 'How would you like to proceed?',
|
|
67
|
+
choices: [
|
|
68
|
+
{ name: '📋 Use a template (recommended)', value: 'template' },
|
|
69
|
+
{ name: '🤖 Generate from project structure', value: 'generate' },
|
|
70
|
+
{ name: '✍️ Create manually later', value: 'skip' }
|
|
71
|
+
]
|
|
72
|
+
}]);
|
|
73
|
+
|
|
74
|
+
if (action === 'template') {
|
|
75
|
+
template = await selectTemplate();
|
|
76
|
+
} else if (action === 'skip') {
|
|
77
|
+
logger.info('Skipping backlog generation. You can create it manually later.');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Step 3: Generate or parse backlog
|
|
84
|
+
const generator = new Generator();
|
|
85
|
+
|
|
86
|
+
if (!backlogContent) {
|
|
87
|
+
spinner.start('Generating backlog...');
|
|
88
|
+
backlogContent = await generator.generateBacklog(analysis, template);
|
|
89
|
+
spinner.succeed(`Backlog generated using "${template}" template`);
|
|
90
|
+
|
|
91
|
+
// Save backlog
|
|
92
|
+
const backlogPath = path.join(process.cwd(), 'docs', 'backlog.md');
|
|
93
|
+
await fs.mkdir(path.dirname(backlogPath), { recursive: true });
|
|
94
|
+
await fs.writeFile(backlogPath, backlogContent);
|
|
95
|
+
logger.success(`Saved to: docs/backlog.md`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Step 4: Parse backlog to extract structure
|
|
99
|
+
const backlog = {
|
|
100
|
+
milestones: generator.generateMilestones(analysis, template),
|
|
101
|
+
stories: generator.generateStories(analysis, template)
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// Step 5: Confirm before creating on GitHub
|
|
105
|
+
logger.newline();
|
|
106
|
+
logger.section('📦 GitHub Setup Plan');
|
|
107
|
+
logger.info(`Milestones to create: ${backlog.milestones.length}`);
|
|
108
|
+
logger.info(`Issues to create: ${backlog.stories.length}`);
|
|
109
|
+
logger.info(`Labels: Priority, Status, Story Points, Epics`);
|
|
110
|
+
logger.newline();
|
|
111
|
+
|
|
112
|
+
if (options.dryRun) {
|
|
113
|
+
logger.warn('DRY RUN - No changes will be made');
|
|
114
|
+
logger.json({ backlog });
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (!options.auto) {
|
|
119
|
+
const { proceed } = await inquirer.prompt([{
|
|
120
|
+
type: 'confirm',
|
|
121
|
+
name: 'proceed',
|
|
122
|
+
message: 'Proceed with GitHub setup?',
|
|
123
|
+
default: true
|
|
124
|
+
}]);
|
|
125
|
+
|
|
126
|
+
if (!proceed) {
|
|
127
|
+
logger.info('Setup cancelled');
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Step 6: Initialize GitHub client
|
|
133
|
+
const github = new GitHubClient();
|
|
134
|
+
|
|
135
|
+
spinner.start('Initializing GitHub client...');
|
|
136
|
+
const initialized = await github.init();
|
|
137
|
+
|
|
138
|
+
if (!initialized) {
|
|
139
|
+
spinner.fail('GitHub initialization failed');
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
spinner.succeed('GitHub client ready');
|
|
144
|
+
|
|
145
|
+
// Get repo info
|
|
146
|
+
const repoInfo = await github.getRepoInfo();
|
|
147
|
+
if (repoInfo) {
|
|
148
|
+
logger.info(`Repository: ${repoInfo.fullName}`);
|
|
149
|
+
logger.newline();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Step 7: Create milestones
|
|
153
|
+
spinner.start('Creating milestones...');
|
|
154
|
+
try {
|
|
155
|
+
await github.createMilestones(backlog.milestones);
|
|
156
|
+
spinner.succeed(`Created ${backlog.milestones.length} milestones`);
|
|
157
|
+
} catch (error) {
|
|
158
|
+
spinner.fail('Milestone creation failed');
|
|
159
|
+
logger.error(error.message);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Step 8: Create labels
|
|
163
|
+
spinner.start('Creating labels...');
|
|
164
|
+
try {
|
|
165
|
+
const epicLabels = (analysis.techStack || []).map((tech, i) => ({
|
|
166
|
+
name: `Epic:E${i + 1}-${tech}`,
|
|
167
|
+
color: '0e8a16'
|
|
168
|
+
}));
|
|
169
|
+
|
|
170
|
+
await github.createLabels(epicLabels);
|
|
171
|
+
spinner.succeed('Labels created');
|
|
172
|
+
} catch (error) {
|
|
173
|
+
spinner.fail('Label creation failed');
|
|
174
|
+
logger.error(error.message);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Step 9: Create issues
|
|
178
|
+
spinner.start('Creating issues...');
|
|
179
|
+
try {
|
|
180
|
+
await github.createIssues(backlog.stories, backlog.milestones);
|
|
181
|
+
spinner.succeed(`Created ${backlog.stories.length} issues`);
|
|
182
|
+
} catch (error) {
|
|
183
|
+
spinner.fail('Issue creation failed');
|
|
184
|
+
logger.error(error.message);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Step 10: Success summary
|
|
188
|
+
logger.newline();
|
|
189
|
+
logger.section('✅ Setup Complete!');
|
|
190
|
+
logger.newline();
|
|
191
|
+
|
|
192
|
+
if (repoInfo) {
|
|
193
|
+
logger.info(`📊 Milestones: ${repoInfo.url}/milestones`);
|
|
194
|
+
logger.info(`📝 Issues: ${repoInfo.url}/issues`);
|
|
195
|
+
logger.newline();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
logger.info('💡 Next steps:');
|
|
199
|
+
logger.dim(' 1. Create a GitHub Project Board manually');
|
|
200
|
+
logger.dim(' 2. Add all issues to the project');
|
|
201
|
+
logger.dim(' 3. Configure project views');
|
|
202
|
+
logger.newline();
|
|
203
|
+
|
|
204
|
+
logger.info('🎯 Or run:');
|
|
205
|
+
logger.dim(' $ gh project create --owner <user> --title "<Name>"');
|
|
206
|
+
logger.dim(' $ den add-to-project <project-number>');
|
|
207
|
+
logger.newline();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async function selectTemplate() {
|
|
211
|
+
const { template } = await inquirer.prompt([{
|
|
212
|
+
type: 'list',
|
|
213
|
+
name: 'template',
|
|
214
|
+
message: 'Select a template:',
|
|
215
|
+
choices: [
|
|
216
|
+
{ name: '📦 Simple (3 milestones, ~10 issues)', value: 'simple' },
|
|
217
|
+
{ name: '🚀 Startup MVP (4 milestones, ~30 issues)', value: 'startup' },
|
|
218
|
+
{ name: '🏃 Agile/Scrum (Sprint-based)', value: 'agile' },
|
|
219
|
+
{ name: '🏢 Enterprise (5+ phases)', value: 'enterprise' }
|
|
220
|
+
]
|
|
221
|
+
}]);
|
|
222
|
+
|
|
223
|
+
return template;
|
|
224
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Logger } from '../utils/logger.js';
|
|
2
|
+
|
|
3
|
+
const TEMPLATES = {
|
|
4
|
+
simple: {
|
|
5
|
+
name: 'Simple',
|
|
6
|
+
description: 'Basic 3-milestone structure for small projects',
|
|
7
|
+
milestones: 3,
|
|
8
|
+
issues: '~10',
|
|
9
|
+
bestFor: 'Personal projects, side projects'
|
|
10
|
+
},
|
|
11
|
+
startup: {
|
|
12
|
+
name: 'Startup MVP',
|
|
13
|
+
description: 'MVP-focused with 4 milestones',
|
|
14
|
+
milestones: 4,
|
|
15
|
+
issues: '~30',
|
|
16
|
+
bestFor: 'Startups, product development'
|
|
17
|
+
},
|
|
18
|
+
agile: {
|
|
19
|
+
name: 'Agile/Scrum',
|
|
20
|
+
description: 'Sprint-based with recurring milestones',
|
|
21
|
+
milestones: 'Flexible (sprints)',
|
|
22
|
+
issues: '~50',
|
|
23
|
+
bestFor: 'Teams using Scrum/Agile'
|
|
24
|
+
},
|
|
25
|
+
enterprise: {
|
|
26
|
+
name: 'Enterprise',
|
|
27
|
+
description: 'Comprehensive 5+ phase structure',
|
|
28
|
+
milestones: '5+',
|
|
29
|
+
issues: '50+',
|
|
30
|
+
bestFor: 'Large organizations, complex projects'
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export async function templatesCommand(options) {
|
|
35
|
+
const logger = new Logger();
|
|
36
|
+
|
|
37
|
+
if (options.list || !options.show) {
|
|
38
|
+
logger.section('📋 Available Templates');
|
|
39
|
+
logger.newline();
|
|
40
|
+
|
|
41
|
+
for (const [key, template] of Object.entries(TEMPLATES)) {
|
|
42
|
+
logger.bold(`${template.name} (${key})`);
|
|
43
|
+
logger.dim(` ${template.description}`);
|
|
44
|
+
logger.info(` Milestones: ${template.milestones} | Issues: ${template.issues}`);
|
|
45
|
+
logger.dim(` Best for: ${template.bestFor}`);
|
|
46
|
+
logger.newline();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
logger.info('💡 Usage:');
|
|
50
|
+
logger.dim(' $ den init --template simple');
|
|
51
|
+
logger.dim(' $ den init --template startup');
|
|
52
|
+
logger.newline();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (options.show) {
|
|
56
|
+
const template = TEMPLATES[options.show];
|
|
57
|
+
|
|
58
|
+
if (!template) {
|
|
59
|
+
logger.error(`Template "${options.show}" not found`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
logger.section(`📋 Template: ${template.name}`);
|
|
64
|
+
logger.newline();
|
|
65
|
+
logger.info(`Description: ${template.description}`);
|
|
66
|
+
logger.info(`Milestones: ${template.milestones}`);
|
|
67
|
+
logger.info(`Expected Issues: ${template.issues}`);
|
|
68
|
+
logger.info(`Best For: ${template.bestFor}`);
|
|
69
|
+
logger.newline();
|
|
70
|
+
}
|
|
71
|
+
}
|