@jwdobeutechsolutions/dobeutech-claude-code-custom 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/CLAUDE.md +174 -0
- package/CONTRIBUTING.md +191 -0
- package/README.md +345 -0
- package/agents/accessibility-auditor.md +315 -0
- package/agents/api-designer.md +265 -0
- package/agents/architect.md +211 -0
- package/agents/build-error-resolver.md +532 -0
- package/agents/ci-cd-generator.md +318 -0
- package/agents/code-reviewer.md +104 -0
- package/agents/database-migrator.md +258 -0
- package/agents/deployment-manager.md +296 -0
- package/agents/doc-updater.md +452 -0
- package/agents/docker-specialist.md +293 -0
- package/agents/e2e-runner.md +708 -0
- package/agents/fullstack-architect.md +293 -0
- package/agents/infrastructure-engineer.md +297 -0
- package/agents/integration-tester.md +320 -0
- package/agents/performance-tester.md +243 -0
- package/agents/planner.md +119 -0
- package/agents/refactor-cleaner.md +306 -0
- package/agents/security-reviewer.md +545 -0
- package/agents/tdd-guide.md +280 -0
- package/agents/unit-test-generator.md +290 -0
- package/bin/claude-config.js +290 -0
- package/commands/api-design.md +55 -0
- package/commands/audit-accessibility.md +37 -0
- package/commands/audit-performance.md +38 -0
- package/commands/audit-security.md +43 -0
- package/commands/build-fix.md +29 -0
- package/commands/changelog.md +31 -0
- package/commands/code-review.md +40 -0
- package/commands/deploy.md +51 -0
- package/commands/docs-api.md +41 -0
- package/commands/e2e.md +363 -0
- package/commands/plan.md +113 -0
- package/commands/refactor-clean.md +28 -0
- package/commands/tdd.md +326 -0
- package/commands/test-coverage.md +27 -0
- package/commands/update-codemaps.md +17 -0
- package/commands/update-docs.md +31 -0
- package/hooks/hooks.json +121 -0
- package/mcp-configs/mcp-servers.json +163 -0
- package/package.json +53 -0
- package/rules/agents.md +49 -0
- package/rules/coding-style.md +70 -0
- package/rules/git-workflow.md +45 -0
- package/rules/hooks.md +46 -0
- package/rules/patterns.md +55 -0
- package/rules/performance.md +47 -0
- package/rules/security.md +36 -0
- package/rules/testing.md +30 -0
- package/scripts/install.js +254 -0
- package/skills/backend-patterns.md +582 -0
- package/skills/clickhouse-io.md +429 -0
- package/skills/coding-standards.md +520 -0
- package/skills/frontend-patterns.md +631 -0
- package/skills/project-guidelines-example.md +345 -0
- package/skills/security-review/SKILL.md +494 -0
- package/skills/tdd-workflow/SKILL.md +409 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
|
|
7
|
+
// Colors for console output
|
|
8
|
+
const colors = {
|
|
9
|
+
reset: '\x1b[0m',
|
|
10
|
+
bright: '\x1b[1m',
|
|
11
|
+
green: '\x1b[32m',
|
|
12
|
+
yellow: '\x1b[33m',
|
|
13
|
+
blue: '\x1b[34m',
|
|
14
|
+
red: '\x1b[31m',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function log(message, color = 'reset') {
|
|
18
|
+
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Detect installation scope
|
|
22
|
+
function isGlobalInstall() {
|
|
23
|
+
// Check npm_config_global environment variable
|
|
24
|
+
if (process.env.npm_config_global === 'true') {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Check if we're in a global node_modules location
|
|
29
|
+
const installPath = __dirname;
|
|
30
|
+
const globalPaths = [
|
|
31
|
+
path.join(os.homedir(), '.npm'),
|
|
32
|
+
path.join(os.homedir(), 'AppData', 'Roaming', 'npm'),
|
|
33
|
+
'/usr/local/lib/node_modules',
|
|
34
|
+
'/usr/lib/node_modules',
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
return globalPaths.some(globalPath => installPath.includes(globalPath));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Get target directory
|
|
41
|
+
function getTargetDir() {
|
|
42
|
+
if (isGlobalInstall()) {
|
|
43
|
+
// Global installation: ~/.claude/
|
|
44
|
+
return path.join(os.homedir(), '.claude');
|
|
45
|
+
} else {
|
|
46
|
+
// Local installation: ./.claude/ in project root
|
|
47
|
+
// Find project root by looking for package.json or .git
|
|
48
|
+
let currentDir = process.cwd();
|
|
49
|
+
let projectRoot = currentDir;
|
|
50
|
+
|
|
51
|
+
while (currentDir !== path.dirname(currentDir)) {
|
|
52
|
+
if (fs.existsSync(path.join(currentDir, 'package.json')) ||
|
|
53
|
+
fs.existsSync(path.join(currentDir, '.git'))) {
|
|
54
|
+
projectRoot = currentDir;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
currentDir = path.dirname(currentDir);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return path.join(projectRoot, '.claude');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Get source directory (where package files are)
|
|
65
|
+
function getSourceDir() {
|
|
66
|
+
// When installed via npm, files are in node_modules/@jwdobeutechsolutions/dobeutech-claude-code-custom
|
|
67
|
+
// When running from source, files are in the repo root
|
|
68
|
+
const possiblePaths = [
|
|
69
|
+
path.join(__dirname, '..'), // From scripts/install.js -> repo root
|
|
70
|
+
path.join(process.cwd(), 'node_modules', '@jwdobeutechsolutions', 'dobeutech-claude-code-custom'),
|
|
71
|
+
path.join(process.cwd(), 'node_modules', 'dobeutech-claude-code-custom'),
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
for (const possiblePath of possiblePaths) {
|
|
75
|
+
if (fs.existsSync(path.join(possiblePath, 'agents'))) {
|
|
76
|
+
return possiblePath;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Fallback to __dirname/..
|
|
81
|
+
return path.join(__dirname, '..');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Ensure directory exists
|
|
85
|
+
function ensureDir(dirPath) {
|
|
86
|
+
if (!fs.existsSync(dirPath)) {
|
|
87
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Copy directory recursively
|
|
92
|
+
function copyDir(src, dest) {
|
|
93
|
+
ensureDir(dest);
|
|
94
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
95
|
+
|
|
96
|
+
for (const entry of entries) {
|
|
97
|
+
const srcPath = path.join(src, entry.name);
|
|
98
|
+
const destPath = path.join(dest, entry.name);
|
|
99
|
+
|
|
100
|
+
if (entry.isDirectory()) {
|
|
101
|
+
copyDir(srcPath, destPath);
|
|
102
|
+
} else {
|
|
103
|
+
fs.copyFileSync(srcPath, destPath);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Copy file
|
|
109
|
+
function copyFile(src, dest) {
|
|
110
|
+
ensureDir(path.dirname(dest));
|
|
111
|
+
fs.copyFileSync(src, dest);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Merge JSON files
|
|
115
|
+
function mergeJson(targetPath, sourceData, mergeKey) {
|
|
116
|
+
let targetData = {};
|
|
117
|
+
|
|
118
|
+
if (fs.existsSync(targetPath)) {
|
|
119
|
+
try {
|
|
120
|
+
const content = fs.readFileSync(targetPath, 'utf8');
|
|
121
|
+
targetData = JSON.parse(content);
|
|
122
|
+
} catch (err) {
|
|
123
|
+
log(`Warning: Could not parse existing ${path.basename(targetPath)}: ${err.message}`, 'yellow');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Merge based on structure
|
|
128
|
+
if (mergeKey === 'hooks') {
|
|
129
|
+
// For hooks.json, merge into settings.json
|
|
130
|
+
if (!targetData.hooks) {
|
|
131
|
+
targetData.hooks = {};
|
|
132
|
+
}
|
|
133
|
+
if (sourceData.hooks) {
|
|
134
|
+
// Merge each hook category
|
|
135
|
+
for (const [category, hooks] of Object.entries(sourceData.hooks)) {
|
|
136
|
+
if (!targetData.hooks[category]) {
|
|
137
|
+
targetData.hooks[category] = [];
|
|
138
|
+
}
|
|
139
|
+
// Add new hooks that don't already exist (by matcher)
|
|
140
|
+
const existingMatchers = new Set(
|
|
141
|
+
targetData.hooks[category].map(h => h.matcher).filter(Boolean)
|
|
142
|
+
);
|
|
143
|
+
for (const hook of hooks) {
|
|
144
|
+
if (!hook.matcher || !existingMatchers.has(hook.matcher)) {
|
|
145
|
+
targetData.hooks[category].push(hook);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
} else if (mergeKey === 'mcpServers') {
|
|
151
|
+
// For mcp-servers.json, merge into .claude.json
|
|
152
|
+
if (!targetData.mcpServers) {
|
|
153
|
+
targetData.mcpServers = {};
|
|
154
|
+
}
|
|
155
|
+
if (sourceData.mcpServers) {
|
|
156
|
+
// Merge MCP servers, preserving existing API keys
|
|
157
|
+
for (const [serverName, serverConfig] of Object.entries(sourceData.mcpServers)) {
|
|
158
|
+
if (!targetData.mcpServers[serverName]) {
|
|
159
|
+
targetData.mcpServers[serverName] = serverConfig;
|
|
160
|
+
} else {
|
|
161
|
+
// Preserve existing env vars (API keys)
|
|
162
|
+
if (targetData.mcpServers[serverName].env) {
|
|
163
|
+
serverConfig.env = {
|
|
164
|
+
...serverConfig.env,
|
|
165
|
+
...targetData.mcpServers[serverName].env,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
targetData.mcpServers[serverName] = {
|
|
169
|
+
...serverConfig,
|
|
170
|
+
...targetData.mcpServers[serverName],
|
|
171
|
+
env: serverConfig.env || targetData.mcpServers[serverName].env,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return targetData;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Main installation function
|
|
182
|
+
function install() {
|
|
183
|
+
try {
|
|
184
|
+
const sourceDir = getSourceDir();
|
|
185
|
+
const targetDir = getTargetDir();
|
|
186
|
+
const isGlobal = isGlobalInstall();
|
|
187
|
+
|
|
188
|
+
log(`\n${colors.bright}Installing Claude Code Configurations${colors.reset}`, 'bright');
|
|
189
|
+
log(`Source: ${sourceDir}`, 'blue');
|
|
190
|
+
log(`Target: ${targetDir}`, 'blue');
|
|
191
|
+
log(`Scope: ${isGlobal ? 'Global' : 'Local'}\n`, 'blue');
|
|
192
|
+
|
|
193
|
+
// Verify source directory has required files
|
|
194
|
+
if (!fs.existsSync(path.join(sourceDir, 'agents'))) {
|
|
195
|
+
log(`Error: Source directory does not contain 'agents' folder`, 'red');
|
|
196
|
+
log(`Expected: ${path.join(sourceDir, 'agents')}`, 'red');
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Create target directory structure
|
|
201
|
+
ensureDir(targetDir);
|
|
202
|
+
|
|
203
|
+
// Copy directories
|
|
204
|
+
const dirsToCopy = ['agents', 'skills', 'commands', 'rules', 'templates', 'docs'];
|
|
205
|
+
for (const dir of dirsToCopy) {
|
|
206
|
+
const srcPath = path.join(sourceDir, dir);
|
|
207
|
+
const destPath = path.join(targetDir, dir);
|
|
208
|
+
|
|
209
|
+
if (fs.existsSync(srcPath)) {
|
|
210
|
+
log(`Copying ${dir}/...`, 'green');
|
|
211
|
+
copyDir(srcPath, destPath);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Handle hooks.json -> settings.json merge
|
|
216
|
+
const hooksSrc = path.join(sourceDir, 'hooks', 'hooks.json');
|
|
217
|
+
if (fs.existsSync(hooksSrc)) {
|
|
218
|
+
log(`Merging hooks into settings.json...`, 'green');
|
|
219
|
+
const hooksData = JSON.parse(fs.readFileSync(hooksSrc, 'utf8'));
|
|
220
|
+
const settingsPath = path.join(targetDir, 'settings.json');
|
|
221
|
+
const mergedSettings = mergeJson(settingsPath, hooksData, 'hooks');
|
|
222
|
+
fs.writeFileSync(settingsPath, JSON.stringify(mergedSettings, null, 2));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Handle mcp-servers.json -> .claude.json merge
|
|
226
|
+
const mcpSrc = path.join(sourceDir, 'mcp-configs', 'mcp-servers.json');
|
|
227
|
+
if (fs.existsSync(mcpSrc)) {
|
|
228
|
+
log(`Merging MCP servers into .claude.json...`, 'green');
|
|
229
|
+
const mcpData = JSON.parse(fs.readFileSync(mcpSrc, 'utf8'));
|
|
230
|
+
const claudeJsonPath = path.join(targetDir, '.claude.json');
|
|
231
|
+
const mergedMcp = mergeJson(claudeJsonPath, mcpData, 'mcpServers');
|
|
232
|
+
fs.writeFileSync(claudeJsonPath, JSON.stringify(mergedMcp, null, 2));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
log(`\n${colors.bright}✓ Installation complete!${colors.reset}`, 'green');
|
|
236
|
+
log(`\nConfiguration files installed to: ${targetDir}`, 'blue');
|
|
237
|
+
log(`\nNext steps:`, 'bright');
|
|
238
|
+
log(`1. Review and configure API keys in ${path.join(targetDir, '.claude.json')}`, 'yellow');
|
|
239
|
+
log(`2. Customize settings in ${path.join(targetDir, 'settings.json')} if needed`, 'yellow');
|
|
240
|
+
log(`3. Run 'claude-config update' to sync latest changes`, 'yellow');
|
|
241
|
+
log(``, 'reset');
|
|
242
|
+
|
|
243
|
+
} catch (error) {
|
|
244
|
+
log(`\n${colors.red}Error during installation:${colors.reset}`, 'red');
|
|
245
|
+
log(error.message, 'red');
|
|
246
|
+
if (error.stack) {
|
|
247
|
+
log(error.stack, 'red');
|
|
248
|
+
}
|
|
249
|
+
process.exit(1);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Run installation
|
|
254
|
+
install();
|