oden-forge 2.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/.claude/CLAUDE.md +75 -0
- package/.claude/commands/oden/architect.md +204 -0
- package/.claude/commands/oden/checklist.md +199 -0
- package/.claude/commands/oden/daily.md +223 -0
- package/.claude/commands/oden/debug.md +203 -0
- package/.claude/commands/oden/epic.md +224 -0
- package/.claude/commands/oden/git.md +259 -0
- package/.claude/commands/oden/help.md +304 -0
- package/.claude/commands/oden/init-agents.md +268 -0
- package/.claude/commands/oden/init-mcp.md +460 -0
- package/.claude/commands/oden/init.md +495 -0
- package/.claude/commands/oden/mcp.md +585 -0
- package/.claude/commands/oden/prd.md +134 -0
- package/.claude/commands/oden/research.md +207 -0
- package/.claude/commands/oden/review.md +146 -0
- package/.claude/commands/oden/spec.md +539 -0
- package/.claude/commands/oden/sync.md +286 -0
- package/.claude/commands/oden/tasks.md +156 -0
- package/.claude/commands/oden/test.md +200 -0
- package/.claude/commands/oden/work.md +791 -0
- package/.claude/epics/.gitkeep +0 -0
- package/.claude/hooks/README.md +130 -0
- package/.claude/hooks/bash-worktree-fix.sh +189 -0
- package/.claude/prds/.gitkeep +0 -0
- package/.claude/rules/agent-coordination.md +224 -0
- package/.claude/rules/branch-operations.md +147 -0
- package/.claude/rules/datetime.md +118 -0
- package/.claude/rules/frontmatter-operations.md +58 -0
- package/.claude/rules/github-operations.md +89 -0
- package/.claude/rules/oden-methodology.md +111 -0
- package/.claude/rules/path-standards.md +155 -0
- package/.claude/rules/standard-patterns.md +174 -0
- package/.claude/rules/strip-frontmatter.md +82 -0
- package/.claude/rules/worktree-operations.md +136 -0
- package/.claude/scripts/oden/blocked.sh +72 -0
- package/.claude/scripts/oden/epic-list.sh +101 -0
- package/.claude/scripts/oden/epic-show.sh +91 -0
- package/.claude/scripts/oden/epic-status.sh +90 -0
- package/.claude/scripts/oden/help.sh +71 -0
- package/.claude/scripts/oden/in-progress.sh +74 -0
- package/.claude/scripts/oden/init.sh +192 -0
- package/.claude/scripts/oden/next.sh +65 -0
- package/.claude/scripts/oden/prd-list.sh +89 -0
- package/.claude/scripts/oden/prd-status.sh +63 -0
- package/.claude/scripts/oden/search.sh +71 -0
- package/.claude/scripts/oden/standup.sh +89 -0
- package/.claude/scripts/oden/status.sh +42 -0
- package/.claude/scripts/oden/validate.sh +101 -0
- package/.claude/settings.json +27 -0
- package/MIGRATION.md +217 -0
- package/README.md +368 -0
- package/bin/install.js +155 -0
- package/bin/migrate.js +191 -0
- package/bin/oden-forge.js +114 -0
- package/bin/post-install.js +47 -0
- package/bin/pre-uninstall.js +108 -0
- package/install.sh +231 -0
- package/package.json +76 -0
package/bin/migrate.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const fs = require('fs-extra');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const inquirer = require('inquirer');
|
|
7
|
+
|
|
8
|
+
async function migrate() {
|
|
9
|
+
console.log('\n' + chalk.blue('π Oden Forge Migration Tool'));
|
|
10
|
+
console.log(chalk.blue('β'.repeat(50)));
|
|
11
|
+
|
|
12
|
+
const claudeDir = path.join(process.env.HOME, '.claude');
|
|
13
|
+
|
|
14
|
+
// Detect what needs migration
|
|
15
|
+
const migrationPlan = await analyzeMigrationNeeds(claudeDir);
|
|
16
|
+
|
|
17
|
+
if (migrationPlan.items.length === 0) {
|
|
18
|
+
console.log(chalk.green('β
No migration needed - you\'re already on v2!'));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
console.log(chalk.yellow(`Found ${migrationPlan.items.length} items to migrate:\n`));
|
|
23
|
+
|
|
24
|
+
migrationPlan.items.forEach(item => {
|
|
25
|
+
console.log(chalk.white(`π ${item.type}:`));
|
|
26
|
+
console.log(chalk.gray(` From: ${item.from}`));
|
|
27
|
+
console.log(chalk.gray(` Action: ${item.action}`));
|
|
28
|
+
console.log('');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const { proceed } = await inquirer.prompt([{
|
|
32
|
+
type: 'confirm',
|
|
33
|
+
name: 'proceed',
|
|
34
|
+
message: 'Proceed with migration?',
|
|
35
|
+
default: true
|
|
36
|
+
}]);
|
|
37
|
+
|
|
38
|
+
if (!proceed) {
|
|
39
|
+
console.log(chalk.blue('β Migration cancelled'));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Execute migration
|
|
44
|
+
await executeMigration(migrationPlan);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function analyzeMigrationNeeds(claudeDir) {
|
|
48
|
+
const migrationItems = [];
|
|
49
|
+
|
|
50
|
+
// Check for old command structures
|
|
51
|
+
const oldCommands = [
|
|
52
|
+
path.join(claudeDir, 'commands', 'pm'),
|
|
53
|
+
path.join(claudeDir, 'commands', 'ccpm')
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
oldCommands.forEach(dir => {
|
|
57
|
+
if (fs.existsSync(dir)) {
|
|
58
|
+
migrationItems.push({
|
|
59
|
+
type: 'Legacy Commands',
|
|
60
|
+
from: dir,
|
|
61
|
+
action: 'Remove (replaced by /oden:* commands)',
|
|
62
|
+
priority: 'high'
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Check for old scripts
|
|
68
|
+
const oldScripts = [
|
|
69
|
+
path.join(claudeDir, 'scripts', 'pm'),
|
|
70
|
+
path.join(claudeDir, 'scripts', 'ccpm')
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
oldScripts.forEach(dir => {
|
|
74
|
+
if (fs.existsSync(dir)) {
|
|
75
|
+
migrationItems.push({
|
|
76
|
+
type: 'Legacy Scripts',
|
|
77
|
+
from: dir,
|
|
78
|
+
action: 'Remove (replaced by new scripts)',
|
|
79
|
+
priority: 'high'
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Check for CCPM installations
|
|
85
|
+
const ccpmPath = path.join(process.env.HOME, '.ccpm');
|
|
86
|
+
if (fs.existsSync(ccpmPath)) {
|
|
87
|
+
migrationItems.push({
|
|
88
|
+
type: 'CCMP Installation',
|
|
89
|
+
from: ccpmPath,
|
|
90
|
+
action: 'Archive and remove (now native)',
|
|
91
|
+
priority: 'medium'
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Check for old PRD/Epic structures
|
|
96
|
+
const oldStructures = [
|
|
97
|
+
path.join(claudeDir, 'pm'),
|
|
98
|
+
path.join(claudeDir, 'ccpm')
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
oldStructures.forEach(dir => {
|
|
102
|
+
if (fs.existsSync(dir)) {
|
|
103
|
+
migrationItems.push({
|
|
104
|
+
type: 'Old Data Structure',
|
|
105
|
+
from: dir,
|
|
106
|
+
action: 'Migrate to new structure',
|
|
107
|
+
priority: 'low'
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
items: migrationItems,
|
|
114
|
+
hasHighPriority: migrationItems.some(i => i.priority === 'high'),
|
|
115
|
+
hasData: migrationItems.some(i => i.priority === 'low')
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function executeMigration(migrationPlan) {
|
|
120
|
+
console.log(chalk.yellow('\nπ Executing migration...\n'));
|
|
121
|
+
|
|
122
|
+
let completed = 0;
|
|
123
|
+
let failed = 0;
|
|
124
|
+
|
|
125
|
+
for (const item of migrationPlan.items) {
|
|
126
|
+
try {
|
|
127
|
+
console.log(chalk.white(`Processing: ${item.type}`));
|
|
128
|
+
|
|
129
|
+
switch (item.priority) {
|
|
130
|
+
case 'high':
|
|
131
|
+
await removeOldInstallation(item);
|
|
132
|
+
break;
|
|
133
|
+
case 'medium':
|
|
134
|
+
await archiveAndRemove(item);
|
|
135
|
+
break;
|
|
136
|
+
case 'low':
|
|
137
|
+
await migrateDataStructure(item);
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
console.log(chalk.green(` β
${item.action}`));
|
|
142
|
+
completed++;
|
|
143
|
+
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.log(chalk.red(` β Failed: ${error.message}`));
|
|
146
|
+
failed++;
|
|
147
|
+
}
|
|
148
|
+
console.log('');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Summary
|
|
152
|
+
console.log(chalk.green('π Migration Complete!'));
|
|
153
|
+
console.log(chalk.green('β'.repeat(30)));
|
|
154
|
+
console.log(chalk.white(`β
Completed: ${completed}`));
|
|
155
|
+
if (failed > 0) {
|
|
156
|
+
console.log(chalk.red(`β Failed: ${failed}`));
|
|
157
|
+
}
|
|
158
|
+
console.log('');
|
|
159
|
+
console.log(chalk.blue('Next Steps:'));
|
|
160
|
+
console.log(chalk.white(' 1. Open Claude Code'));
|
|
161
|
+
console.log(chalk.white(' 2. Run: /oden:init'));
|
|
162
|
+
console.log(chalk.white(' 3. Enjoy Oden Forge 2.0!'));
|
|
163
|
+
console.log('');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function removeOldInstallation(item) {
|
|
167
|
+
if (fs.existsSync(item.from)) {
|
|
168
|
+
fs.removeSync(item.from);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async function archiveAndRemove(item) {
|
|
173
|
+
if (fs.existsSync(item.from)) {
|
|
174
|
+
const archivePath = item.from + '.bak.' + Date.now();
|
|
175
|
+
fs.moveSync(item.from, archivePath);
|
|
176
|
+
console.log(chalk.gray(` Archived to: ${path.basename(archivePath)}`));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async function migrateDataStructure(item) {
|
|
181
|
+
// For now, just archive old data structures
|
|
182
|
+
// In the future, we could implement smart migration of PRDs/Epics
|
|
183
|
+
if (fs.existsSync(item.from)) {
|
|
184
|
+
const backupPath = item.from + '.backup.' + Date.now();
|
|
185
|
+
fs.copySync(item.from, backupPath);
|
|
186
|
+
console.log(chalk.gray(` Backed up to: ${path.basename(backupPath)}`));
|
|
187
|
+
fs.removeSync(item.from);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
module.exports = { migrate };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const { program } = require('commander');
|
|
5
|
+
const fs = require('fs-extra');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const { execSync } = require('child_process');
|
|
8
|
+
|
|
9
|
+
program
|
|
10
|
+
.name('oden-forge')
|
|
11
|
+
.description('Documentation-First Development Toolkit for Claude Code')
|
|
12
|
+
.version('2.0.0');
|
|
13
|
+
|
|
14
|
+
program
|
|
15
|
+
.command('install')
|
|
16
|
+
.description('Install Oden Forge skills to Claude Code')
|
|
17
|
+
.option('-f, --force', 'Force reinstall, overwriting existing')
|
|
18
|
+
.action(async (options) => {
|
|
19
|
+
const { install } = require('./install.js');
|
|
20
|
+
await install(options);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
program
|
|
24
|
+
.command('uninstall')
|
|
25
|
+
.description('Remove Oden Forge skills from Claude Code')
|
|
26
|
+
.action(async () => {
|
|
27
|
+
const { uninstall } = require('./pre-uninstall.js');
|
|
28
|
+
await uninstall();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
program
|
|
32
|
+
.command('status')
|
|
33
|
+
.description('Check installation status')
|
|
34
|
+
.action(() => {
|
|
35
|
+
const claudeDir = path.join(process.env.HOME, '.claude');
|
|
36
|
+
const odenCommands = path.join(claudeDir, 'commands', 'oden');
|
|
37
|
+
|
|
38
|
+
console.log('\n' + chalk.blue('π Oden Forge Status'));
|
|
39
|
+
console.log(chalk.blue('β'.repeat(50)));
|
|
40
|
+
|
|
41
|
+
if (fs.existsSync(odenCommands)) {
|
|
42
|
+
const commands = fs.readdirSync(odenCommands).filter(f => f.endsWith('.md'));
|
|
43
|
+
console.log(chalk.green(`β
Installed: ${commands.length} commands`));
|
|
44
|
+
console.log(chalk.gray(` Location: ${odenCommands}`));
|
|
45
|
+
} else {
|
|
46
|
+
console.log(chalk.red('β Not installed'));
|
|
47
|
+
console.log(chalk.yellow(' Run: oden-forge install'));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Check for legacy v1
|
|
51
|
+
const legacyPaths = [
|
|
52
|
+
path.join(claudeDir, 'commands', 'pm'),
|
|
53
|
+
path.join(claudeDir, 'commands', 'ccpm'),
|
|
54
|
+
path.join(process.env.HOME, '.ccpm')
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const legacyFound = legacyPaths.filter(p => fs.existsSync(p));
|
|
58
|
+
if (legacyFound.length > 0) {
|
|
59
|
+
console.log(chalk.yellow('\nβ οΈ Legacy installations found:'));
|
|
60
|
+
legacyFound.forEach(p => console.log(chalk.gray(` ${p}`)));
|
|
61
|
+
console.log(chalk.yellow(' Run: oden-forge migrate'));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log('\n' + chalk.blue('π‘ Quick Start:'));
|
|
65
|
+
console.log(chalk.white(' 1. cd your-project'));
|
|
66
|
+
console.log(chalk.white(' 2. claude-code (or your Claude Code command)'));
|
|
67
|
+
console.log(chalk.white(' 3. /oden:init'));
|
|
68
|
+
console.log('');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
program
|
|
72
|
+
.command('migrate')
|
|
73
|
+
.description('Migrate from Oden Forge v1 or CCPM')
|
|
74
|
+
.action(async () => {
|
|
75
|
+
const { migrate } = require('./migrate.js');
|
|
76
|
+
await migrate();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
program
|
|
80
|
+
.command('update')
|
|
81
|
+
.description('Update to latest version')
|
|
82
|
+
.action(() => {
|
|
83
|
+
console.log(chalk.yellow('π Updating Oden Forge...'));
|
|
84
|
+
try {
|
|
85
|
+
execSync('npm update -g oden-forge', { stdio: 'inherit' });
|
|
86
|
+
console.log(chalk.green('β
Updated successfully!'));
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.log(chalk.red('β Update failed:'), error.message);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Default action
|
|
93
|
+
program
|
|
94
|
+
.action(() => {
|
|
95
|
+
console.log('\n' + chalk.blue('π¨ Oden Forge - Documentation-First Development'));
|
|
96
|
+
console.log(chalk.blue('β'.repeat(50)));
|
|
97
|
+
console.log(chalk.white('Usage: oden-forge <command>'));
|
|
98
|
+
console.log('');
|
|
99
|
+
console.log(chalk.yellow('Commands:'));
|
|
100
|
+
console.log(' install Install skills to Claude Code');
|
|
101
|
+
console.log(' status Check installation status');
|
|
102
|
+
console.log(' migrate Migrate from v1 or CCPM');
|
|
103
|
+
console.log(' update Update to latest version');
|
|
104
|
+
console.log(' help Show help');
|
|
105
|
+
console.log('');
|
|
106
|
+
console.log(chalk.gray('After installation, use /oden:init in Claude Code'));
|
|
107
|
+
console.log('');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
if (process.argv.length === 2) {
|
|
111
|
+
program.outputHelp();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
program.parse();
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
async function postInstall() {
|
|
4
|
+
// Only run auto-install for global installs
|
|
5
|
+
if (!process.env.npm_config_global) {
|
|
6
|
+
return; // Skip for local installs
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
// Check if dependencies are available
|
|
11
|
+
const chalk = require('chalk');
|
|
12
|
+
const { install } = require('./install.js');
|
|
13
|
+
|
|
14
|
+
console.log(chalk.blue('\nπ Running post-install setup...'));
|
|
15
|
+
|
|
16
|
+
await install({ force: false });
|
|
17
|
+
|
|
18
|
+
console.log(chalk.blue('\nπ‘ Next Steps:'));
|
|
19
|
+
console.log(chalk.white(' 1. Open Claude Code in your project'));
|
|
20
|
+
console.log(chalk.white(' 2. Run: /oden:init'));
|
|
21
|
+
console.log(chalk.white(' 3. Follow the wizard'));
|
|
22
|
+
console.log('');
|
|
23
|
+
console.log(chalk.gray(' π Documentation: https://javikin.github.io/oden-forge'));
|
|
24
|
+
console.log(chalk.gray(' π Help: oden-forge --help'));
|
|
25
|
+
console.log('');
|
|
26
|
+
|
|
27
|
+
} catch (error) {
|
|
28
|
+
// Fallback if dependencies aren't ready yet
|
|
29
|
+
console.log('\nπ Oden Forge 2.0 installed!');
|
|
30
|
+
console.log('');
|
|
31
|
+
console.log('π‘ Next Steps:');
|
|
32
|
+
console.log(' 1. Run: oden-forge install');
|
|
33
|
+
console.log(' 2. Open Claude Code in your project');
|
|
34
|
+
console.log(' 3. Run: /oden:init');
|
|
35
|
+
console.log('');
|
|
36
|
+
console.log('π Documentation: https://javikin.github.io/oden-forge');
|
|
37
|
+
console.log('π Help: oden-forge --help');
|
|
38
|
+
console.log('');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Only run if called directly
|
|
43
|
+
if (require.main === module) {
|
|
44
|
+
postInstall();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = { postInstall };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const fs = require('fs-extra');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const inquirer = require('inquirer');
|
|
7
|
+
|
|
8
|
+
async function uninstall() {
|
|
9
|
+
console.log('\n' + chalk.yellow('ποΈ Uninstalling Oden Forge'));
|
|
10
|
+
console.log(chalk.yellow('β'.repeat(40)));
|
|
11
|
+
|
|
12
|
+
const claudeDir = path.join(process.env.HOME, '.claude');
|
|
13
|
+
const pathsToRemove = [
|
|
14
|
+
path.join(claudeDir, 'commands', 'oden'),
|
|
15
|
+
path.join(claudeDir, 'scripts', 'oden'),
|
|
16
|
+
path.join(claudeDir, 'prds'),
|
|
17
|
+
path.join(claudeDir, 'epics')
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
// Check what exists
|
|
21
|
+
const existingPaths = pathsToRemove.filter(p => fs.existsSync(p));
|
|
22
|
+
|
|
23
|
+
if (existingPaths.length === 0) {
|
|
24
|
+
console.log(chalk.green('β
Oden Forge is not installed'));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
console.log(chalk.white('The following will be removed:'));
|
|
29
|
+
existingPaths.forEach(p => {
|
|
30
|
+
console.log(chalk.gray(` ${p}`));
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Ask for confirmation in interactive mode
|
|
34
|
+
if (process.stdout.isTTY) {
|
|
35
|
+
const { confirm } = await inquirer.prompt([{
|
|
36
|
+
type: 'confirm',
|
|
37
|
+
name: 'confirm',
|
|
38
|
+
message: 'Are you sure you want to remove Oden Forge?',
|
|
39
|
+
default: false
|
|
40
|
+
}]);
|
|
41
|
+
|
|
42
|
+
if (!confirm) {
|
|
43
|
+
console.log(chalk.blue('β Uninstall cancelled'));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Remove files
|
|
49
|
+
console.log(chalk.yellow('\nποΈ Removing files...'));
|
|
50
|
+
let removed = 0;
|
|
51
|
+
|
|
52
|
+
for (const p of existingPaths) {
|
|
53
|
+
try {
|
|
54
|
+
if (fs.existsSync(p)) {
|
|
55
|
+
fs.removeSync(p);
|
|
56
|
+
console.log(chalk.green(` β
Removed: ${path.basename(p)}`));
|
|
57
|
+
removed++;
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.log(chalk.red(` β Failed to remove ${p}: ${error.message}`));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Don't remove ~/.claude/rules as other tools might use it
|
|
65
|
+
// Just remove our specific rules
|
|
66
|
+
const rulesDir = path.join(claudeDir, 'rules');
|
|
67
|
+
if (fs.existsSync(rulesDir)) {
|
|
68
|
+
try {
|
|
69
|
+
const odenRules = [
|
|
70
|
+
'oden-methodology.md',
|
|
71
|
+
'worktree-operations.md',
|
|
72
|
+
'agent-coordination.md',
|
|
73
|
+
'standard-patterns.md',
|
|
74
|
+
'github-operations.md',
|
|
75
|
+
'frontmatter-operations.md',
|
|
76
|
+
'datetime.md',
|
|
77
|
+
'path-standards.md',
|
|
78
|
+
'strip-frontmatter.md'
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
let rulesRemoved = 0;
|
|
82
|
+
odenRules.forEach(rule => {
|
|
83
|
+
const rulePath = path.join(rulesDir, rule);
|
|
84
|
+
if (fs.existsSync(rulePath)) {
|
|
85
|
+
fs.removeSync(rulePath);
|
|
86
|
+
rulesRemoved++;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
if (rulesRemoved > 0) {
|
|
91
|
+
console.log(chalk.green(` β
Removed: ${rulesRemoved} rules`));
|
|
92
|
+
}
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.log(chalk.yellow(` β οΈ Could not clean rules: ${error.message}`));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
console.log(chalk.green(`\nβ
Uninstall complete (${removed + 1} items removed)`));
|
|
99
|
+
console.log(chalk.gray('Your project files remain untouched.'));
|
|
100
|
+
console.log('');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Only run if called directly (not during npm uninstall)
|
|
104
|
+
if (require.main === module) {
|
|
105
|
+
uninstall();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
module.exports = { uninstall };
|
package/install.sh
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# ============================================================================
|
|
4
|
+
# ODEN FORGE - INSTALLER
|
|
5
|
+
# ============================================================================
|
|
6
|
+
# Instala todo lo necesario para usar Oden Forge:
|
|
7
|
+
# - Comandos /oden:* (52 comandos unificados)
|
|
8
|
+
# - Scripts de soporte
|
|
9
|
+
# - Hooks
|
|
10
|
+
# - Rules de Claude
|
|
11
|
+
# - Carpetas para PRDs y Epics
|
|
12
|
+
# - Agentes de desarrollo (opcional)
|
|
13
|
+
# ============================================================================
|
|
14
|
+
|
|
15
|
+
set -e
|
|
16
|
+
|
|
17
|
+
# Colors
|
|
18
|
+
RED='\033[0;31m'
|
|
19
|
+
GREEN='\033[0;32m'
|
|
20
|
+
YELLOW='\033[1;33m'
|
|
21
|
+
BLUE='\033[0;34m'
|
|
22
|
+
NC='\033[0m' # No Color
|
|
23
|
+
|
|
24
|
+
# Get script directory
|
|
25
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
26
|
+
|
|
27
|
+
echo ""
|
|
28
|
+
echo -e "${BLUE}ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ${NC}"
|
|
29
|
+
echo -e "${BLUE}β ODEN FORGE INSTALLER β${NC}"
|
|
30
|
+
echo -e "${BLUE}β Documentation-First Development Toolkit β${NC}"
|
|
31
|
+
echo -e "${BLUE}ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ${NC}"
|
|
32
|
+
echo ""
|
|
33
|
+
|
|
34
|
+
# ============================================================================
|
|
35
|
+
# CHECK PREREQUISITES
|
|
36
|
+
# ============================================================================
|
|
37
|
+
|
|
38
|
+
echo -e "${YELLOW}Verificando requisitos...${NC}"
|
|
39
|
+
|
|
40
|
+
# Check if Claude directory exists
|
|
41
|
+
if [ ! -d "$HOME/.claude" ]; then
|
|
42
|
+
echo -e "${YELLOW}Creando directorio ~/.claude...${NC}"
|
|
43
|
+
mkdir -p "$HOME/.claude"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Check for git
|
|
47
|
+
if ! command -v git &> /dev/null; then
|
|
48
|
+
echo -e "${RED}β Git no estΓ‘ instalado. Por favor instala git primero.${NC}"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
echo -e "${GREEN}β Git instalado${NC}"
|
|
52
|
+
|
|
53
|
+
# Check for GitHub CLI
|
|
54
|
+
if ! command -v gh &> /dev/null; then
|
|
55
|
+
echo -e "${YELLOW}β GitHub CLI (gh) no estΓ‘ instalado.${NC}"
|
|
56
|
+
echo -e " Para sync con GitHub, instala: https://cli.github.com/"
|
|
57
|
+
GH_INSTALLED=false
|
|
58
|
+
else
|
|
59
|
+
echo -e "${GREEN}β GitHub CLI instalado${NC}"
|
|
60
|
+
GH_INSTALLED=true
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
echo ""
|
|
64
|
+
|
|
65
|
+
# ============================================================================
|
|
66
|
+
# INSTALL COMMANDS
|
|
67
|
+
# ============================================================================
|
|
68
|
+
|
|
69
|
+
echo -e "${YELLOW}Instalando comandos /oden:*...${NC}"
|
|
70
|
+
|
|
71
|
+
mkdir -p "$HOME/.claude/commands/oden"
|
|
72
|
+
|
|
73
|
+
if [ -d "$SCRIPT_DIR/.claude/commands/oden" ]; then
|
|
74
|
+
cp -r "$SCRIPT_DIR/.claude/commands/oden/"* "$HOME/.claude/commands/oden/"
|
|
75
|
+
ODEN_COUNT=$(ls "$HOME/.claude/commands/oden/"*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
76
|
+
echo -e "${GREEN}β $ODEN_COUNT comandos /oden:* instalados${NC}"
|
|
77
|
+
else
|
|
78
|
+
echo -e "${RED}β No se encontraron comandos${NC}"
|
|
79
|
+
exit 1
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
echo ""
|
|
83
|
+
|
|
84
|
+
# ============================================================================
|
|
85
|
+
# INSTALL SCRIPTS
|
|
86
|
+
# ============================================================================
|
|
87
|
+
|
|
88
|
+
echo -e "${YELLOW}Instalando scripts...${NC}"
|
|
89
|
+
|
|
90
|
+
mkdir -p "$HOME/.claude/scripts/oden"
|
|
91
|
+
|
|
92
|
+
if [ -d "$SCRIPT_DIR/.claude/scripts/oden" ]; then
|
|
93
|
+
cp -r "$SCRIPT_DIR/.claude/scripts/oden/"* "$HOME/.claude/scripts/oden/"
|
|
94
|
+
chmod +x "$HOME/.claude/scripts/oden/"*.sh 2>/dev/null || true
|
|
95
|
+
SCRIPT_COUNT=$(ls "$HOME/.claude/scripts/oden/"*.sh 2>/dev/null | wc -l | tr -d ' ')
|
|
96
|
+
echo -e "${GREEN}β $SCRIPT_COUNT scripts instalados${NC}"
|
|
97
|
+
else
|
|
98
|
+
echo -e "${YELLOW}β No se encontraron scripts${NC}"
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
echo ""
|
|
102
|
+
|
|
103
|
+
# ============================================================================
|
|
104
|
+
# INSTALL HOOKS
|
|
105
|
+
# ============================================================================
|
|
106
|
+
|
|
107
|
+
echo -e "${YELLOW}Instalando hooks...${NC}"
|
|
108
|
+
|
|
109
|
+
mkdir -p "$HOME/.claude/hooks"
|
|
110
|
+
|
|
111
|
+
if [ -d "$SCRIPT_DIR/.claude/hooks" ]; then
|
|
112
|
+
cp -r "$SCRIPT_DIR/.claude/hooks/"* "$HOME/.claude/hooks/"
|
|
113
|
+
chmod +x "$HOME/.claude/hooks/"*.sh 2>/dev/null || true
|
|
114
|
+
echo -e "${GREEN}β Hooks instalados${NC}"
|
|
115
|
+
else
|
|
116
|
+
echo -e "${YELLOW}β No se encontraron hooks${NC}"
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
echo ""
|
|
120
|
+
|
|
121
|
+
# ============================================================================
|
|
122
|
+
# INSTALL RULES
|
|
123
|
+
# ============================================================================
|
|
124
|
+
|
|
125
|
+
echo -e "${YELLOW}Instalando rules...${NC}"
|
|
126
|
+
|
|
127
|
+
mkdir -p "$HOME/.claude/rules"
|
|
128
|
+
|
|
129
|
+
if [ -d "$SCRIPT_DIR/.claude/rules" ]; then
|
|
130
|
+
cp -r "$SCRIPT_DIR/.claude/rules/"* "$HOME/.claude/rules/"
|
|
131
|
+
RULES_COUNT=$(ls "$HOME/.claude/rules/"*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
132
|
+
echo -e "${GREEN}β $RULES_COUNT rules instaladas${NC}"
|
|
133
|
+
else
|
|
134
|
+
echo -e "${YELLOW}β No se encontraron rules${NC}"
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
echo ""
|
|
138
|
+
|
|
139
|
+
# ============================================================================
|
|
140
|
+
# CREATE FOLDERS
|
|
141
|
+
# ============================================================================
|
|
142
|
+
|
|
143
|
+
echo -e "${YELLOW}Creando carpetas de trabajo...${NC}"
|
|
144
|
+
|
|
145
|
+
mkdir -p "$HOME/.claude/prds"
|
|
146
|
+
mkdir -p "$HOME/.claude/epics"
|
|
147
|
+
touch "$HOME/.claude/prds/.gitkeep" 2>/dev/null || true
|
|
148
|
+
touch "$HOME/.claude/epics/.gitkeep" 2>/dev/null || true
|
|
149
|
+
echo -e "${GREEN}β Carpetas prds/ y epics/ creadas${NC}"
|
|
150
|
+
|
|
151
|
+
echo ""
|
|
152
|
+
|
|
153
|
+
# ============================================================================
|
|
154
|
+
# INSTALL AGENTS (OPTIONAL)
|
|
155
|
+
# ============================================================================
|
|
156
|
+
|
|
157
|
+
echo -e "${YELLOW}ΒΏDeseas instalar los agentes de desarrollo? (y/n)${NC}"
|
|
158
|
+
read -r INSTALL_AGENTS
|
|
159
|
+
|
|
160
|
+
if [[ "$INSTALL_AGENTS" =~ ^[Yy]$ ]]; then
|
|
161
|
+
echo -e "${YELLOW}Instalando agentes...${NC}"
|
|
162
|
+
|
|
163
|
+
mkdir -p "$HOME/.claude/agents"
|
|
164
|
+
|
|
165
|
+
if [ -d "$SCRIPT_DIR/.claude/agents" ]; then
|
|
166
|
+
cp -r "$SCRIPT_DIR/.claude/agents/"* "$HOME/.claude/agents/"
|
|
167
|
+
AGENTS_COUNT=$(ls "$HOME/.claude/agents/"*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
168
|
+
echo -e "${GREEN}β $AGENTS_COUNT agentes instalados${NC}"
|
|
169
|
+
else
|
|
170
|
+
echo -e "${YELLOW}β No se encontraron agentes en el repo.${NC}"
|
|
171
|
+
echo -e " Usa /oden:init-agents dentro de Claude Code para instalarlos.${NC}"
|
|
172
|
+
fi
|
|
173
|
+
else
|
|
174
|
+
echo -e "${BLUE}Agentes no instalados. Usa /oden:init-agents despuΓ©s.${NC}"
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
echo ""
|
|
178
|
+
|
|
179
|
+
# ============================================================================
|
|
180
|
+
# GITHUB CLI SETUP
|
|
181
|
+
# ============================================================================
|
|
182
|
+
|
|
183
|
+
if [ "$GH_INSTALLED" = true ]; then
|
|
184
|
+
# Check if already authenticated
|
|
185
|
+
if gh auth status &> /dev/null; then
|
|
186
|
+
echo -e "${GREEN}β GitHub CLI ya estΓ‘ autenticado${NC}"
|
|
187
|
+
else
|
|
188
|
+
echo -e "${YELLOW}ΒΏDeseas configurar GitHub CLI ahora? (y/n)${NC}"
|
|
189
|
+
read -r SETUP_GH
|
|
190
|
+
|
|
191
|
+
if [[ "$SETUP_GH" =~ ^[Yy]$ ]]; then
|
|
192
|
+
echo -e "${YELLOW}Iniciando autenticaciΓ³n de GitHub...${NC}"
|
|
193
|
+
gh auth login
|
|
194
|
+
fi
|
|
195
|
+
fi
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
echo ""
|
|
199
|
+
|
|
200
|
+
# ============================================================================
|
|
201
|
+
# SUMMARY
|
|
202
|
+
# ============================================================================
|
|
203
|
+
|
|
204
|
+
echo -e "${GREEN}ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ${NC}"
|
|
205
|
+
echo -e "${GREEN}β INSTALACIΓN COMPLETADA β${NC}"
|
|
206
|
+
echo -e "${GREEN}ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ${NC}"
|
|
207
|
+
echo ""
|
|
208
|
+
echo -e "${BLUE}COMANDOS INSTALADOS (/oden:*):${NC}"
|
|
209
|
+
echo -e " Setup: init, init-agents, init-mcp, help"
|
|
210
|
+
echo -e " Pre-Dev: architect, analyze, spec, plan, checklist"
|
|
211
|
+
echo -e " GitHub: prd-new, epic-sync, issue-start, ..."
|
|
212
|
+
echo -e " Desarrollo: dev, test, debug, research, daily"
|
|
213
|
+
echo -e " Git: git start, git pr, git finish"
|
|
214
|
+
echo ""
|
|
215
|
+
echo -e "${BLUE}ESTRUCTURA CREADA:${NC}"
|
|
216
|
+
echo -e " ~/.claude/commands/oden/ β Comandos"
|
|
217
|
+
echo -e " ~/.claude/scripts/oden/ β Scripts"
|
|
218
|
+
echo -e " ~/.claude/hooks/ β Hooks"
|
|
219
|
+
echo -e " ~/.claude/rules/ β Rules"
|
|
220
|
+
echo -e " ~/.claude/prds/ β PRDs"
|
|
221
|
+
echo -e " ~/.claude/epics/ β Epics"
|
|
222
|
+
echo ""
|
|
223
|
+
echo -e "${BLUE}PRΓXIMOS PASOS:${NC}"
|
|
224
|
+
echo -e " 1. Abre Claude Code en tu proyecto"
|
|
225
|
+
echo -e " 2. Ejecuta: /oden:init"
|
|
226
|
+
echo -e " 3. Sigue el wizard"
|
|
227
|
+
echo ""
|
|
228
|
+
echo -e "${YELLOW}DOCUMENTACIΓN:${NC}"
|
|
229
|
+
echo -e " README: $SCRIPT_DIR/README.md"
|
|
230
|
+
echo -e " Help: /oden:help"
|
|
231
|
+
echo ""
|