@ngxtm/devkit 3.4.1 → 3.6.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/cli/index.js +37 -17
- package/cli/init.js +247 -123
- package/cli/utils.js +110 -1
- package/package.json +4 -1
- package/skills/learn/SKILL.md +476 -0
package/cli/index.js
CHANGED
|
@@ -41,6 +41,9 @@ function parseArgs(args) {
|
|
|
41
41
|
help: false,
|
|
42
42
|
installed: false,
|
|
43
43
|
ruleArgs: [],
|
|
44
|
+
// New v3.6 options
|
|
45
|
+
all: false,
|
|
46
|
+
tools: [],
|
|
44
47
|
// Legacy options (deprecated)
|
|
45
48
|
tool: null,
|
|
46
49
|
minimal: false,
|
|
@@ -62,10 +65,14 @@ function parseArgs(args) {
|
|
|
62
65
|
options.clean = true;
|
|
63
66
|
} else if (arg === '--installed' || arg === '-i') {
|
|
64
67
|
options.installed = true;
|
|
68
|
+
} else if (arg === '--all' || arg === '-a') {
|
|
69
|
+
options.all = true;
|
|
65
70
|
} else if (arg === '--status' || arg === '-s') {
|
|
66
71
|
options.command = 'status';
|
|
67
72
|
} else if (arg.startsWith('--path=')) {
|
|
68
73
|
options.path = arg.split('=')[1];
|
|
74
|
+
} else if (arg.startsWith('--tools=')) {
|
|
75
|
+
options.tools = arg.split('=')[1].split(',').map(t => t.trim());
|
|
69
76
|
} else if (arg.startsWith('--')) {
|
|
70
77
|
// Handle legacy options for backwards compatibility
|
|
71
78
|
if (arg === '--minimal' || arg === '-m') options.minimal = true;
|
|
@@ -93,9 +100,9 @@ USAGE:
|
|
|
93
100
|
devkit <command> [options]
|
|
94
101
|
|
|
95
102
|
COMMANDS:
|
|
96
|
-
init Initialize devkit in current project
|
|
97
|
-
|
|
98
|
-
|
|
103
|
+
init Initialize devkit in current project
|
|
104
|
+
Shows interactive tool selection menu.
|
|
105
|
+
Auto-detects tech stack and installs relevant rules.
|
|
99
106
|
|
|
100
107
|
update Update existing installation
|
|
101
108
|
Re-detects project type and updates rules accordingly.
|
|
@@ -124,23 +131,34 @@ COMMANDS:
|
|
|
124
131
|
|
|
125
132
|
OPTIONS:
|
|
126
133
|
--force, -f Force overwrite existing installation
|
|
134
|
+
--all, -a Install for all supported tools (skip menu)
|
|
135
|
+
--tools=LIST Install for specific tools (comma-separated)
|
|
136
|
+
Example: --tools=claude,cursor
|
|
127
137
|
--clean, -c Remove rules for technologies no longer detected (with update)
|
|
128
138
|
--installed, -i Show only installed rules (with rules command)
|
|
129
139
|
--path=DIR Specify project directory (default: current directory)
|
|
130
140
|
--help, -h Show this help
|
|
131
141
|
|
|
142
|
+
SUPPORTED TOOLS:
|
|
143
|
+
claude Claude Code
|
|
144
|
+
cursor Cursor
|
|
145
|
+
copilot GitHub Copilot
|
|
146
|
+
gemini Gemini CLI
|
|
147
|
+
|
|
132
148
|
EXAMPLES:
|
|
133
|
-
devkit init
|
|
134
|
-
devkit init --
|
|
135
|
-
devkit
|
|
136
|
-
devkit
|
|
137
|
-
devkit
|
|
138
|
-
devkit
|
|
139
|
-
devkit
|
|
140
|
-
devkit
|
|
141
|
-
devkit
|
|
142
|
-
devkit
|
|
143
|
-
devkit
|
|
149
|
+
devkit init # Interactive tool selection
|
|
150
|
+
devkit init --all # Install for all tools
|
|
151
|
+
devkit init --tools=claude,cursor # Install for specific tools
|
|
152
|
+
devkit init --force # Overwrite existing installation
|
|
153
|
+
devkit update # Update and re-detect technologies
|
|
154
|
+
devkit update --clean # Update and remove old rules
|
|
155
|
+
devkit detect # Show what would be detected
|
|
156
|
+
devkit rules # List all available rules
|
|
157
|
+
devkit rules --installed # Show installed rules
|
|
158
|
+
devkit add golang docker # Add golang and docker rules
|
|
159
|
+
devkit remove flutter # Remove flutter rule
|
|
160
|
+
devkit status # Show current installation
|
|
161
|
+
devkit uninstall # Remove from current project
|
|
144
162
|
|
|
145
163
|
HOW IT WORKS:
|
|
146
164
|
1. devkit init analyzes your project files:
|
|
@@ -181,13 +199,15 @@ This auto-detects your tech stack and installs only relevant rules.
|
|
|
181
199
|
|
|
182
200
|
// Command handlers
|
|
183
201
|
const commands = {
|
|
184
|
-
// Primary command - per-project init
|
|
185
|
-
init: (options) => {
|
|
202
|
+
// Primary command - per-project init (now async with tool selection)
|
|
203
|
+
init: async (options) => {
|
|
186
204
|
const projectPath = validatePath(options.path) || process.cwd();
|
|
187
205
|
return initProject({
|
|
188
206
|
path: projectPath,
|
|
189
207
|
force: options.force,
|
|
190
|
-
update: options.update
|
|
208
|
+
update: options.update,
|
|
209
|
+
all: options.all,
|
|
210
|
+
tools: options.tools
|
|
191
211
|
});
|
|
192
212
|
},
|
|
193
213
|
|
package/cli/init.js
CHANGED
|
@@ -3,167 +3,280 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Devkit Init - Per-Project Installation
|
|
5
5
|
*
|
|
6
|
-
* Installs devkit to the current project
|
|
7
|
-
* -
|
|
6
|
+
* Installs devkit to the current project with support for multiple AI tools:
|
|
7
|
+
* - Claude Code, Cursor, GitHub Copilot, Gemini CLI
|
|
8
|
+
* - Interactive tool selection with auto-detection
|
|
8
9
|
* - Tech-specific rules (based on project detection)
|
|
9
|
-
* -
|
|
10
|
-
* - Essential hooks
|
|
10
|
+
* - Merged commands and essential hooks
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
const fs = require('fs');
|
|
14
14
|
const path = require('path');
|
|
15
15
|
|
|
16
|
-
const { detectProjectType, getRulesForTypes
|
|
17
|
-
const { copyDir, getDirSize,
|
|
16
|
+
const { detectProjectType, getRulesForTypes } = require('./detect');
|
|
17
|
+
const { copyDir, getDirSize, detectInstalledTools, TOOLS } = require('./utils');
|
|
18
18
|
|
|
19
19
|
const VERSION = require('../package.json').version;
|
|
20
20
|
const PACKAGE_ROOT = path.join(__dirname, '..');
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
23
|
+
* Show interactive tool selection menu
|
|
24
|
+
* @param {Object} detectedTools - Results from detectInstalledTools()
|
|
25
|
+
* @returns {Promise<string[]>} - Array of selected tool ids
|
|
24
26
|
*/
|
|
25
|
-
function
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
async function showToolSelectionMenu(detectedTools) {
|
|
28
|
+
// Dynamic import for inquirer (ES module)
|
|
29
|
+
const inquirer = (await import('inquirer')).default;
|
|
30
|
+
|
|
31
|
+
console.log('\n Detecting installed AI tools...\n');
|
|
32
|
+
|
|
33
|
+
const choices = Object.entries(TOOLS).map(([id, tool]) => {
|
|
34
|
+
const detected = detectedTools[id]?.detected;
|
|
35
|
+
const status = detected ? '(detected)' : '(not detected)';
|
|
36
|
+
return {
|
|
37
|
+
name: `${tool.name} ${status}`,
|
|
38
|
+
value: id,
|
|
39
|
+
checked: detected // Pre-select detected tools
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const { selectedTools } = await inquirer.prompt([
|
|
44
|
+
{
|
|
45
|
+
type: 'checkbox',
|
|
46
|
+
name: 'selectedTools',
|
|
47
|
+
message: 'Select AI tools to install devkit for:',
|
|
48
|
+
choices,
|
|
49
|
+
validate: (answer) => {
|
|
50
|
+
if (answer.length === 0) {
|
|
51
|
+
return 'Please select at least one tool.';
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
]);
|
|
33
57
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
console.log(`\n .claude/ folder already exists.`);
|
|
37
|
-
console.log(' Use --force to overwrite or --update to update.\n');
|
|
38
|
-
return { success: false, reason: 'exists' };
|
|
39
|
-
}
|
|
58
|
+
return selectedTools;
|
|
59
|
+
}
|
|
40
60
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Install devkit for a single tool
|
|
63
|
+
* @param {string} toolId - Tool identifier
|
|
64
|
+
* @param {Object} tool - Tool configuration
|
|
65
|
+
* @param {string} projectDir - Project directory
|
|
66
|
+
* @param {Object} options - Install options
|
|
67
|
+
* @returns {Object} - Installation result
|
|
68
|
+
*/
|
|
69
|
+
function installForTool(toolId, tool, projectDir, options = {}) {
|
|
70
|
+
const targetDir = path.join(projectDir, tool.projectPath);
|
|
71
|
+
const isUpdate = options.update || false;
|
|
45
72
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
73
|
+
// Check if already exists
|
|
74
|
+
if (fs.existsSync(targetDir) && !isUpdate && !options.force) {
|
|
75
|
+
return {
|
|
76
|
+
success: false,
|
|
77
|
+
reason: 'exists',
|
|
78
|
+
message: `${tool.projectPath}/ already exists`
|
|
79
|
+
};
|
|
52
80
|
}
|
|
53
81
|
|
|
54
|
-
// Create
|
|
55
|
-
fs.mkdirSync(
|
|
82
|
+
// Create target directory
|
|
83
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
56
84
|
|
|
57
85
|
let totalFiles = 0;
|
|
58
86
|
const stats = {};
|
|
59
87
|
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
stats.commands = count;
|
|
68
|
-
totalFiles += count;
|
|
69
|
-
console.log(` Commands: ${count} files`);
|
|
70
|
-
} else {
|
|
71
|
-
// Fallback to commands-claudekit if merged not available
|
|
72
|
-
const fallbackDir = path.join(PACKAGE_ROOT, 'commands-claudekit');
|
|
73
|
-
if (fs.existsSync(fallbackDir)) {
|
|
74
|
-
const count = copyDir(fallbackDir, commandsDir);
|
|
88
|
+
// 1. Install commands (if tool supports it)
|
|
89
|
+
if (tool.commandsPath) {
|
|
90
|
+
const mergedCommandsDir = path.join(PACKAGE_ROOT, 'merged-commands');
|
|
91
|
+
const commandsDir = path.join(targetDir, tool.commandsPath);
|
|
92
|
+
|
|
93
|
+
if (fs.existsSync(mergedCommandsDir)) {
|
|
94
|
+
const count = copyDir(mergedCommandsDir, commandsDir);
|
|
75
95
|
stats.commands = count;
|
|
76
96
|
totalFiles += count;
|
|
77
|
-
console.log(` Commands (claudekit): ${count} files`);
|
|
78
97
|
}
|
|
79
98
|
}
|
|
80
99
|
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
100
|
+
// 2. Install rules
|
|
101
|
+
if (tool.rulesPath && options.rules && options.rules.length > 0) {
|
|
102
|
+
const rulesDir = path.join(targetDir, tool.rulesPath);
|
|
103
|
+
let rulesCount = 0;
|
|
104
|
+
|
|
105
|
+
for (const ruleType of options.rules) {
|
|
106
|
+
const srcRulesDir = path.join(PACKAGE_ROOT, 'templates', ruleType, 'rules');
|
|
107
|
+
if (fs.existsSync(srcRulesDir)) {
|
|
108
|
+
const destRulesDir = path.join(rulesDir, ruleType);
|
|
109
|
+
const count = copyDir(srcRulesDir, destRulesDir);
|
|
110
|
+
rulesCount += count;
|
|
111
|
+
}
|
|
91
112
|
}
|
|
92
|
-
}
|
|
93
113
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
114
|
+
if (rulesCount > 0) {
|
|
115
|
+
stats.rules = rulesCount;
|
|
116
|
+
totalFiles += rulesCount;
|
|
117
|
+
}
|
|
98
118
|
}
|
|
99
119
|
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
|
|
120
|
+
// 3. Install hooks (if tool supports it)
|
|
121
|
+
if (tool.supportsHooks && tool.hooksPath) {
|
|
122
|
+
const srcHooksDir = path.join(PACKAGE_ROOT, 'templates', 'base', 'hooks');
|
|
123
|
+
const hooksDir = path.join(targetDir, tool.hooksPath);
|
|
103
124
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
stats.hooks = count;
|
|
107
|
-
totalFiles += count;
|
|
108
|
-
console.log(` Hooks: ${count} files`);
|
|
109
|
-
} else {
|
|
110
|
-
// Fallback to main hooks directory (essential only)
|
|
111
|
-
const fallbackHooks = path.join(PACKAGE_ROOT, 'hooks');
|
|
112
|
-
if (fs.existsSync(fallbackHooks)) {
|
|
113
|
-
const count = copyDir(fallbackHooks, hooksDir);
|
|
125
|
+
if (fs.existsSync(srcHooksDir)) {
|
|
126
|
+
const count = copyDir(srcHooksDir, hooksDir);
|
|
114
127
|
stats.hooks = count;
|
|
115
128
|
totalFiles += count;
|
|
116
|
-
|
|
129
|
+
} else {
|
|
130
|
+
const fallbackHooks = path.join(PACKAGE_ROOT, 'hooks');
|
|
131
|
+
if (fs.existsSync(fallbackHooks)) {
|
|
132
|
+
const count = copyDir(fallbackHooks, hooksDir);
|
|
133
|
+
stats.hooks = count;
|
|
134
|
+
totalFiles += count;
|
|
135
|
+
}
|
|
117
136
|
}
|
|
118
137
|
}
|
|
119
138
|
|
|
120
|
-
//
|
|
139
|
+
// 4. Install skills index
|
|
121
140
|
const skillsIndexSrc = path.join(PACKAGE_ROOT, 'skills-index.json');
|
|
122
|
-
const skillsIndexDest = path.join(claudeDir, 'skills-index.json');
|
|
123
|
-
|
|
124
141
|
if (fs.existsSync(skillsIndexSrc)) {
|
|
125
|
-
fs.copyFileSync(skillsIndexSrc,
|
|
142
|
+
fs.copyFileSync(skillsIndexSrc, path.join(targetDir, 'skills-index.json'));
|
|
126
143
|
totalFiles++;
|
|
127
|
-
console.log(` Skills Index: 1 file`);
|
|
128
144
|
}
|
|
129
145
|
|
|
130
|
-
//
|
|
146
|
+
// 5. Create devkit.json tracking file
|
|
131
147
|
const devkitConfig = {
|
|
132
148
|
version: VERSION,
|
|
133
|
-
|
|
134
|
-
|
|
149
|
+
tool: toolId,
|
|
150
|
+
toolName: tool.name,
|
|
151
|
+
detectedTypes: options.detectedTypes || [],
|
|
152
|
+
installedRules: options.rules || [],
|
|
135
153
|
installedAt: new Date().toISOString(),
|
|
136
154
|
updatedAt: isUpdate ? new Date().toISOString() : null,
|
|
137
155
|
stats: {
|
|
138
156
|
totalFiles: totalFiles,
|
|
139
|
-
sizeKB: Math.round(getDirSize(
|
|
157
|
+
sizeKB: Math.round(getDirSize(targetDir) / 1024)
|
|
140
158
|
}
|
|
141
159
|
};
|
|
142
160
|
|
|
143
161
|
fs.writeFileSync(
|
|
144
|
-
path.join(
|
|
162
|
+
path.join(targetDir, 'devkit.json'),
|
|
145
163
|
JSON.stringify(devkitConfig, null, 2)
|
|
146
164
|
);
|
|
147
165
|
totalFiles++;
|
|
148
166
|
|
|
149
|
-
//
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
includeCoAuthoredBy: false
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
167
|
+
// 6. Create settings.json if not exists (for tools that use it)
|
|
168
|
+
if (toolId === 'claude') {
|
|
169
|
+
const settingsPath = path.join(targetDir, 'settings.json');
|
|
170
|
+
if (!fs.existsSync(settingsPath)) {
|
|
171
|
+
const settings = { includeCoAuthoredBy: false };
|
|
172
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
173
|
+
totalFiles++;
|
|
174
|
+
}
|
|
157
175
|
}
|
|
158
176
|
|
|
159
|
-
|
|
160
|
-
|
|
177
|
+
return {
|
|
178
|
+
success: true,
|
|
179
|
+
tool: toolId,
|
|
180
|
+
toolName: tool.name,
|
|
181
|
+
path: targetDir,
|
|
182
|
+
stats: {
|
|
183
|
+
files: totalFiles,
|
|
184
|
+
sizeKB: Math.round(getDirSize(targetDir) / 1024),
|
|
185
|
+
...stats
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Initialize devkit in a project directory
|
|
192
|
+
* @param {Object} options - Installation options
|
|
193
|
+
*/
|
|
194
|
+
async function initProject(options = {}) {
|
|
195
|
+
const projectDir = options.path || process.cwd();
|
|
196
|
+
const isUpdate = options.update || false;
|
|
197
|
+
|
|
198
|
+
console.log('\n' + '='.repeat(60));
|
|
199
|
+
console.log(' DEVKIT v' + VERSION + (isUpdate ? ' - UPDATE' : ' - INIT'));
|
|
200
|
+
console.log('='.repeat(60));
|
|
201
|
+
|
|
202
|
+
// Determine which tools to install
|
|
203
|
+
let selectedTools = [];
|
|
204
|
+
|
|
205
|
+
if (options.all) {
|
|
206
|
+
// --all flag: install for all tools
|
|
207
|
+
selectedTools = Object.keys(TOOLS);
|
|
208
|
+
console.log('\n Installing for all tools...');
|
|
209
|
+
} else if (options.tools && options.tools.length > 0) {
|
|
210
|
+
// Specific tools via --tools flag
|
|
211
|
+
selectedTools = options.tools;
|
|
212
|
+
} else {
|
|
213
|
+
// Interactive mode: show selection menu
|
|
214
|
+
const detectedTools = detectInstalledTools();
|
|
215
|
+
selectedTools = await showToolSelectionMenu(detectedTools);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (selectedTools.length === 0) {
|
|
219
|
+
console.log('\n No tools selected. Exiting.\n');
|
|
220
|
+
return { success: false, reason: 'no_selection' };
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Detect project type
|
|
224
|
+
console.log('\n Detecting project type...');
|
|
225
|
+
const detectedTypes = detectProjectType(projectDir);
|
|
226
|
+
const rulesToInstall = getRulesForTypes(detectedTypes);
|
|
227
|
+
|
|
228
|
+
if (detectedTypes.length > 0) {
|
|
229
|
+
console.log(` Detected: ${detectedTypes.join(', ')}`);
|
|
230
|
+
console.log(` Rules: ${rulesToInstall.join(', ')}`);
|
|
231
|
+
} else {
|
|
232
|
+
console.log(' No specific technology detected.');
|
|
233
|
+
console.log(' Installing base commands only.');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Install for each selected tool
|
|
237
|
+
console.log('\n Installing components...');
|
|
238
|
+
const results = [];
|
|
239
|
+
|
|
240
|
+
for (const toolId of selectedTools) {
|
|
241
|
+
const tool = TOOLS[toolId];
|
|
242
|
+
if (!tool) {
|
|
243
|
+
console.log(` [!] Unknown tool: ${toolId}`);
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const result = installForTool(toolId, tool, projectDir, {
|
|
248
|
+
...options,
|
|
249
|
+
detectedTypes,
|
|
250
|
+
rules: rulesToInstall
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
if (result.success) {
|
|
254
|
+
console.log(` [+] ${tool.name}: ${result.stats.files} files (${result.stats.sizeKB} KB)`);
|
|
255
|
+
} else {
|
|
256
|
+
console.log(` [-] ${tool.name}: ${result.message || result.reason}`);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
results.push(result);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Summary
|
|
263
|
+
const successCount = results.filter(r => r.success).length;
|
|
264
|
+
const totalFiles = results.reduce((sum, r) => sum + (r.stats?.files || 0), 0);
|
|
265
|
+
const totalSize = results.reduce((sum, r) => sum + (r.stats?.sizeKB || 0), 0);
|
|
161
266
|
|
|
162
267
|
console.log('\n' + '='.repeat(60));
|
|
163
268
|
console.log(' INSTALLATION COMPLETE');
|
|
164
269
|
console.log('='.repeat(60));
|
|
165
|
-
console.log(`\n
|
|
166
|
-
console.log(`
|
|
270
|
+
console.log(`\n Tools: ${successCount}/${selectedTools.length} installed`);
|
|
271
|
+
console.log(` Total: ${totalFiles} files (${totalSize} KB)`);
|
|
272
|
+
|
|
273
|
+
// Show installed locations
|
|
274
|
+
console.log('\n Installed to:');
|
|
275
|
+
for (const result of results) {
|
|
276
|
+
if (result.success) {
|
|
277
|
+
console.log(` - ${result.path}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
167
280
|
|
|
168
281
|
console.log('\n Available commands:');
|
|
169
282
|
console.log(' /plan - Plan implementation');
|
|
@@ -176,15 +289,16 @@ function initProject(options = {}) {
|
|
|
176
289
|
console.log(`\n Tech-specific rules loaded for: ${detectedTypes.join(', ')}`);
|
|
177
290
|
}
|
|
178
291
|
|
|
179
|
-
console.log('\n Restart
|
|
292
|
+
console.log('\n Restart your AI tool to use the new skills.\n');
|
|
180
293
|
|
|
181
294
|
return {
|
|
182
|
-
success:
|
|
295
|
+
success: successCount > 0,
|
|
296
|
+
tools: results,
|
|
183
297
|
detected: detectedTypes,
|
|
184
298
|
rules: rulesToInstall,
|
|
185
299
|
stats: {
|
|
186
300
|
files: totalFiles,
|
|
187
|
-
sizeKB:
|
|
301
|
+
sizeKB: totalSize
|
|
188
302
|
}
|
|
189
303
|
};
|
|
190
304
|
}
|
|
@@ -194,52 +308,62 @@ function initProject(options = {}) {
|
|
|
194
308
|
*/
|
|
195
309
|
function uninstallProject(options = {}) {
|
|
196
310
|
const projectDir = options.path || process.cwd();
|
|
197
|
-
const claudeDir = path.join(projectDir, '.claude');
|
|
198
311
|
|
|
199
312
|
console.log('\n' + '='.repeat(60));
|
|
200
313
|
console.log(' DEVKIT - UNINSTALL');
|
|
201
314
|
console.log('='.repeat(60));
|
|
202
315
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
316
|
+
let removedCount = 0;
|
|
317
|
+
|
|
318
|
+
for (const [toolId, tool] of Object.entries(TOOLS)) {
|
|
319
|
+
const targetDir = path.join(projectDir, tool.projectPath);
|
|
320
|
+
const devkitConfig = path.join(targetDir, 'devkit.json');
|
|
207
321
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
return { success: false, reason: 'not_devkit' };
|
|
322
|
+
if (fs.existsSync(devkitConfig)) {
|
|
323
|
+
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
324
|
+
console.log(` Removed: ${targetDir}`);
|
|
325
|
+
removedCount++;
|
|
326
|
+
}
|
|
214
327
|
}
|
|
215
328
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
329
|
+
if (removedCount === 0) {
|
|
330
|
+
console.log('\n No devkit installations found.\n');
|
|
331
|
+
return { success: false, reason: 'not_found' };
|
|
332
|
+
}
|
|
220
333
|
|
|
221
|
-
|
|
334
|
+
console.log(`\n Uninstalled ${removedCount} tool(s) successfully.\n`);
|
|
335
|
+
return { success: true, removed: removedCount };
|
|
222
336
|
}
|
|
223
337
|
|
|
224
338
|
module.exports = {
|
|
225
339
|
initProject,
|
|
226
340
|
uninstallProject,
|
|
227
|
-
|
|
228
|
-
|
|
341
|
+
installForTool,
|
|
342
|
+
showToolSelectionMenu
|
|
229
343
|
};
|
|
230
344
|
|
|
231
345
|
// Run if called directly
|
|
232
346
|
if (require.main === module) {
|
|
233
347
|
const args = process.argv.slice(2);
|
|
348
|
+
|
|
349
|
+
// Parse --tools=claude,cursor format
|
|
350
|
+
const toolsArg = args.find(a => a.startsWith('--tools='));
|
|
351
|
+
const tools = toolsArg ? toolsArg.split('=')[1].split(',') : [];
|
|
352
|
+
|
|
234
353
|
const options = {
|
|
235
354
|
force: args.includes('--force') || args.includes('-f'),
|
|
236
355
|
update: args.includes('--update') || args.includes('-u'),
|
|
237
|
-
|
|
356
|
+
all: args.includes('--all') || args.includes('-a'),
|
|
357
|
+
tools: tools,
|
|
358
|
+
path: args.find(a => !a.startsWith('-') && !a.includes('=')) || process.cwd()
|
|
238
359
|
};
|
|
239
360
|
|
|
240
361
|
if (args.includes('--uninstall')) {
|
|
241
362
|
uninstallProject(options);
|
|
242
363
|
} else {
|
|
243
|
-
initProject(options)
|
|
364
|
+
initProject(options).catch(err => {
|
|
365
|
+
console.error('Error:', err.message);
|
|
366
|
+
process.exit(1);
|
|
367
|
+
});
|
|
244
368
|
}
|
|
245
369
|
}
|
package/cli/utils.js
CHANGED
|
@@ -6,6 +6,112 @@
|
|
|
6
6
|
|
|
7
7
|
const fs = require('fs');
|
|
8
8
|
const path = require('path');
|
|
9
|
+
const os = require('os');
|
|
10
|
+
const { execSync } = require('child_process');
|
|
11
|
+
|
|
12
|
+
const HOME = os.homedir();
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Supported AI tools configuration
|
|
16
|
+
*/
|
|
17
|
+
const TOOLS = {
|
|
18
|
+
'claude': {
|
|
19
|
+
id: 'claude',
|
|
20
|
+
name: 'Claude Code',
|
|
21
|
+
basePath: path.join(HOME, '.claude'),
|
|
22
|
+
projectPath: '.claude',
|
|
23
|
+
skillsPath: 'skills',
|
|
24
|
+
rulesPath: 'rules',
|
|
25
|
+
hooksPath: 'hooks',
|
|
26
|
+
commandsPath: 'commands',
|
|
27
|
+
supportsHooks: true,
|
|
28
|
+
configFile: 'CLAUDE.md',
|
|
29
|
+
detectCmd: 'claude --version',
|
|
30
|
+
detectFolder: path.join(HOME, '.claude')
|
|
31
|
+
},
|
|
32
|
+
'cursor': {
|
|
33
|
+
id: 'cursor',
|
|
34
|
+
name: 'Cursor',
|
|
35
|
+
basePath: path.join(HOME, '.cursor'),
|
|
36
|
+
projectPath: '.cursor',
|
|
37
|
+
skillsPath: 'skills',
|
|
38
|
+
rulesPath: 'rules',
|
|
39
|
+
hooksPath: 'hooks',
|
|
40
|
+
commandsPath: 'commands',
|
|
41
|
+
supportsHooks: false,
|
|
42
|
+
configFile: 'CURSOR.md',
|
|
43
|
+
detectCmd: null,
|
|
44
|
+
detectFolder: path.join(HOME, '.cursor')
|
|
45
|
+
},
|
|
46
|
+
'copilot': {
|
|
47
|
+
id: 'copilot',
|
|
48
|
+
name: 'GitHub Copilot',
|
|
49
|
+
basePath: path.join(HOME, '.copilot'),
|
|
50
|
+
projectPath: '.github',
|
|
51
|
+
skillsPath: 'skills',
|
|
52
|
+
rulesPath: 'rules',
|
|
53
|
+
hooksPath: null,
|
|
54
|
+
commandsPath: null,
|
|
55
|
+
supportsHooks: false,
|
|
56
|
+
configFile: null,
|
|
57
|
+
detectCmd: 'gh copilot --version',
|
|
58
|
+
detectFolder: path.join(HOME, '.copilot')
|
|
59
|
+
},
|
|
60
|
+
'gemini': {
|
|
61
|
+
id: 'gemini',
|
|
62
|
+
name: 'Gemini CLI',
|
|
63
|
+
basePath: path.join(HOME, '.gemini'),
|
|
64
|
+
projectPath: '.gemini',
|
|
65
|
+
skillsPath: 'skills',
|
|
66
|
+
rulesPath: 'rules',
|
|
67
|
+
hooksPath: null,
|
|
68
|
+
commandsPath: null,
|
|
69
|
+
supportsHooks: false,
|
|
70
|
+
configFile: 'GEMINI.md',
|
|
71
|
+
detectCmd: 'gemini --version',
|
|
72
|
+
detectFolder: path.join(HOME, '.gemini')
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Detect which AI tools are installed on the system
|
|
78
|
+
* @returns {Object} - Object with tool ids as keys and detection status
|
|
79
|
+
*/
|
|
80
|
+
function detectInstalledTools() {
|
|
81
|
+
const results = {};
|
|
82
|
+
|
|
83
|
+
for (const [toolId, tool] of Object.entries(TOOLS)) {
|
|
84
|
+
let detected = false;
|
|
85
|
+
let method = null;
|
|
86
|
+
|
|
87
|
+
// Try command detection first
|
|
88
|
+
if (tool.detectCmd) {
|
|
89
|
+
try {
|
|
90
|
+
execSync(tool.detectCmd, { stdio: 'pipe' });
|
|
91
|
+
detected = true;
|
|
92
|
+
method = 'cli';
|
|
93
|
+
} catch (e) {
|
|
94
|
+
// Command not found
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Fallback to folder detection
|
|
99
|
+
if (!detected && tool.detectFolder) {
|
|
100
|
+
if (fs.existsSync(tool.detectFolder)) {
|
|
101
|
+
detected = true;
|
|
102
|
+
method = 'folder';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
results[toolId] = {
|
|
107
|
+
...tool,
|
|
108
|
+
detected,
|
|
109
|
+
method
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return results;
|
|
114
|
+
}
|
|
9
115
|
|
|
10
116
|
/**
|
|
11
117
|
* Copy directory recursively
|
|
@@ -191,5 +297,8 @@ module.exports = {
|
|
|
191
297
|
getDirSize,
|
|
192
298
|
parseJsonFile,
|
|
193
299
|
validatePath,
|
|
194
|
-
getAllEntries
|
|
300
|
+
getAllEntries,
|
|
301
|
+
detectInstalledTools,
|
|
302
|
+
TOOLS,
|
|
303
|
+
HOME
|
|
195
304
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ngxtm/devkit",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "Per-project AI skills with smart tech detection - lightweight and context-optimized",
|
|
5
5
|
"main": "cli/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -47,6 +47,9 @@
|
|
|
47
47
|
"type": "git",
|
|
48
48
|
"url": "git+https://github.com/ngxtm/devkit.git"
|
|
49
49
|
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"inquirer": "^9.2.12"
|
|
52
|
+
},
|
|
50
53
|
"devDependencies": {
|
|
51
54
|
"@semantic-release/changelog": "^6.0.3",
|
|
52
55
|
"@semantic-release/commit-analyzer": "^11.1.0",
|
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: learn
|
|
3
|
+
description: Interactive step-by-step learning mode. Teaches concepts from basics to advanced while solving real problems. Auto-detects language, verifies code at each step, creates markdown tutorials. Triggers on "/learn [topic]". Features: concept explanation, incremental coding with auto-verify, user checkpoints, optional quiz, saves tutorial to .claude/learn/.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Learn Mode - Interactive Step-by-Step Learning
|
|
7
|
+
|
|
8
|
+
> **Version 1.0.0** | Learn by Doing | Verified at Every Step
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
Learn Mode helps you understand concepts deeply while solving real problems. Instead of just giving you code, it:
|
|
15
|
+
|
|
16
|
+
1. Explains concepts from basics to advanced
|
|
17
|
+
2. Guides you through implementation step-by-step
|
|
18
|
+
3. Verifies code actually works at each step
|
|
19
|
+
4. Saves everything to a markdown tutorial for future reference
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Activation
|
|
24
|
+
|
|
25
|
+
User invokes with: `/learn "topic or problem to solve"`
|
|
26
|
+
|
|
27
|
+
Examples:
|
|
28
|
+
- `/learn "implement debounce function in TypeScript"`
|
|
29
|
+
- `/learn "add JWT authentication to Express API"`
|
|
30
|
+
- `/learn "create custom React hook for form validation"`
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Execution Flow
|
|
35
|
+
|
|
36
|
+
### Phase 0: INIT - Setup & Context Gathering
|
|
37
|
+
|
|
38
|
+
**Actions:**
|
|
39
|
+
1. Create output directory if not exists: `.claude/learn/`
|
|
40
|
+
2. Generate filename: `YYYY-MM-DD-{topic-slug}.md`
|
|
41
|
+
3. Scan project for language detection:
|
|
42
|
+
- Check for config files: `tsconfig.json`, `package.json`, `go.mod`, `Cargo.toml`, `requirements.txt`, `pyproject.toml`, `pom.xml`, `composer.json`, `Gemfile`, etc.
|
|
43
|
+
- Identify primary language(s)
|
|
44
|
+
4. Set verify strategy based on detected language
|
|
45
|
+
5. Read relevant existing code for context
|
|
46
|
+
|
|
47
|
+
**Language Detection & Verify Strategy:**
|
|
48
|
+
|
|
49
|
+
| Language | Config Files | Verify Command |
|
|
50
|
+
|----------|--------------|----------------|
|
|
51
|
+
| TypeScript | `tsconfig.json`, `*.ts`, `*.tsx` | `npx tsc --noEmit` |
|
|
52
|
+
| JavaScript | `package.json`, `*.js`, `*.mjs` | `node --check <file>` |
|
|
53
|
+
| Python | `requirements.txt`, `pyproject.toml`, `*.py` | `python -m py_compile <file>` |
|
|
54
|
+
| Go | `go.mod`, `*.go` | `go build ./...` |
|
|
55
|
+
| Rust | `Cargo.toml`, `*.rs` | `cargo check` |
|
|
56
|
+
| Java | `pom.xml`, `build.gradle`, `*.java` | `javac <file>` or `./gradlew compileJava` |
|
|
57
|
+
| C# | `*.csproj`, `*.cs` | `dotnet build --no-restore` |
|
|
58
|
+
| PHP | `composer.json`, `*.php` | `php -l <file>` |
|
|
59
|
+
| Ruby | `Gemfile`, `*.rb` | `ruby -c <file>` |
|
|
60
|
+
| Shell | `*.sh`, `*.bash` | `bash -n <file>` |
|
|
61
|
+
| C/C++ | `Makefile`, `CMakeLists.txt`, `*.c`, `*.cpp` | `make` or `cmake --build .` |
|
|
62
|
+
|
|
63
|
+
**If multiple languages detected:** Ask user which one to use for this session.
|
|
64
|
+
**If no language detected:** Ask user to specify.
|
|
65
|
+
|
|
66
|
+
**Markdown Header (write to file):**
|
|
67
|
+
```markdown
|
|
68
|
+
# Learn: {Topic}
|
|
69
|
+
|
|
70
|
+
> Generated: {YYYY-MM-DD HH:MM}
|
|
71
|
+
> Language: {detected_language}
|
|
72
|
+
> Project: {project_name}
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
### Phase 1: CONCEPT - Knowledge Foundation
|
|
80
|
+
|
|
81
|
+
**Goal:** Explain the underlying concepts before writing any code.
|
|
82
|
+
|
|
83
|
+
**Actions:**
|
|
84
|
+
1. Break down the topic into fundamental concepts
|
|
85
|
+
2. Explain each concept clearly:
|
|
86
|
+
- What is it?
|
|
87
|
+
- Why does it exist? What problem does it solve?
|
|
88
|
+
- How does it work (high-level)?
|
|
89
|
+
- Real-world analogies if helpful
|
|
90
|
+
3. Compare with related concepts (if applicable)
|
|
91
|
+
- e.g., debounce vs throttle
|
|
92
|
+
- e.g., JWT vs session-based auth
|
|
93
|
+
4. Show simple diagrams using ASCII if helpful
|
|
94
|
+
|
|
95
|
+
**Write to markdown:**
|
|
96
|
+
```markdown
|
|
97
|
+
## 1. Concepts
|
|
98
|
+
|
|
99
|
+
### What is {topic}?
|
|
100
|
+
{explanation}
|
|
101
|
+
|
|
102
|
+
### Why use {topic}?
|
|
103
|
+
{use cases and benefits}
|
|
104
|
+
|
|
105
|
+
### How it works
|
|
106
|
+
{mechanism explanation}
|
|
107
|
+
|
|
108
|
+
### Related Concepts
|
|
109
|
+
| Concept A | Concept B |
|
|
110
|
+
|-----------|-----------|
|
|
111
|
+
| ... | ... |
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**User Checkpoint:**
|
|
117
|
+
```
|
|
118
|
+
Phase 1/5: CONCEPT complete.
|
|
119
|
+
|
|
120
|
+
Do you understand these concepts?
|
|
121
|
+
[ ] Yes, continue to planning
|
|
122
|
+
[ ] Need more explanation (specify what)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**STOP and wait for user response before proceeding.**
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
### Phase 2: PLAN - Implementation Strategy
|
|
130
|
+
|
|
131
|
+
**Goal:** Create a clear, step-by-step implementation plan.
|
|
132
|
+
|
|
133
|
+
**Actions:**
|
|
134
|
+
1. Break implementation into small, verifiable steps (3-7 steps typically)
|
|
135
|
+
2. Each step should:
|
|
136
|
+
- Have a clear goal
|
|
137
|
+
- Be independently verifiable
|
|
138
|
+
- Build on previous steps
|
|
139
|
+
3. Identify files to create/modify
|
|
140
|
+
4. Note any dependencies needed
|
|
141
|
+
|
|
142
|
+
**Write to markdown:**
|
|
143
|
+
```markdown
|
|
144
|
+
## 2. Implementation Plan
|
|
145
|
+
|
|
146
|
+
### Files
|
|
147
|
+
- `{path/to/file1}` - {purpose}
|
|
148
|
+
- `{path/to/file2}` - {purpose}
|
|
149
|
+
|
|
150
|
+
### Steps
|
|
151
|
+
1. **{Step 1 title}** - {brief description}
|
|
152
|
+
2. **{Step 2 title}** - {brief description}
|
|
153
|
+
3. **{Step 3 title}** - {brief description}
|
|
154
|
+
...
|
|
155
|
+
|
|
156
|
+
### Dependencies
|
|
157
|
+
- {dependency 1} - {why needed}
|
|
158
|
+
- {dependency 2} - {why needed}
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**User Checkpoint:**
|
|
164
|
+
```
|
|
165
|
+
Phase 2/5: PLAN complete.
|
|
166
|
+
|
|
167
|
+
Ready to start coding?
|
|
168
|
+
[ ] Yes, let's code
|
|
169
|
+
[ ] Modify plan (specify changes)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**STOP and wait for user response before proceeding.**
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### Phase 3: CODE + VERIFY - Incremental Implementation
|
|
177
|
+
|
|
178
|
+
**Goal:** Implement each step, verify it works, ensure user understands.
|
|
179
|
+
|
|
180
|
+
**For each step in the plan:**
|
|
181
|
+
|
|
182
|
+
#### 3.1 Explain Before Coding
|
|
183
|
+
- What we're about to do
|
|
184
|
+
- Why we're doing it this way
|
|
185
|
+
- Key things to understand
|
|
186
|
+
|
|
187
|
+
#### 3.2 Write the Code
|
|
188
|
+
- Write complete, working code (no placeholders)
|
|
189
|
+
- Include all necessary imports
|
|
190
|
+
- Add inline comments explaining non-obvious parts
|
|
191
|
+
- Use Edit tool to modify existing files, Write for new files
|
|
192
|
+
|
|
193
|
+
#### 3.3 Auto-Verify
|
|
194
|
+
Run the appropriate verify command:
|
|
195
|
+
```bash
|
|
196
|
+
# Execute verify command based on language
|
|
197
|
+
{verify_command}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**If verify FAILS:**
|
|
201
|
+
1. Analyze the error
|
|
202
|
+
2. Explain what went wrong (teaching moment)
|
|
203
|
+
3. Fix the code
|
|
204
|
+
4. Re-verify
|
|
205
|
+
5. Repeat until pass
|
|
206
|
+
|
|
207
|
+
**If verify PASSES:** Continue to user checkpoint.
|
|
208
|
+
|
|
209
|
+
#### 3.4 Write to Markdown
|
|
210
|
+
```markdown
|
|
211
|
+
### Step {N}: {Title}
|
|
212
|
+
|
|
213
|
+
**Goal:** {what this step accomplishes}
|
|
214
|
+
|
|
215
|
+
**Why:** {explanation of approach}
|
|
216
|
+
|
|
217
|
+
**Code:**
|
|
218
|
+
```{language}
|
|
219
|
+
{code with comments}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Key Points:**
|
|
223
|
+
- {important thing 1}
|
|
224
|
+
- {important thing 2}
|
|
225
|
+
|
|
226
|
+
**Verify:** {verify_command} - PASSED
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
#### 3.5 User Checkpoint
|
|
232
|
+
```
|
|
233
|
+
Step {N}/{total} complete and verified.
|
|
234
|
+
|
|
235
|
+
[ ] Understood, next step
|
|
236
|
+
[ ] Need more explanation
|
|
237
|
+
[ ] Code doesn't work on my machine (paste error)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**If user reports error:**
|
|
241
|
+
1. Ask for the error message
|
|
242
|
+
2. Debug and fix
|
|
243
|
+
3. Re-verify locally
|
|
244
|
+
4. Update the markdown with the fix
|
|
245
|
+
|
|
246
|
+
**STOP and wait for user response before next step.**
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
### Phase 4: SUMMARY - Knowledge Consolidation
|
|
251
|
+
|
|
252
|
+
**Goal:** Reinforce learning with summary and best practices.
|
|
253
|
+
|
|
254
|
+
**Actions:**
|
|
255
|
+
1. Summarize what was built
|
|
256
|
+
2. List key takeaways
|
|
257
|
+
3. Document common mistakes to avoid
|
|
258
|
+
4. Suggest next steps for deeper learning
|
|
259
|
+
|
|
260
|
+
**Write to markdown:**
|
|
261
|
+
```markdown
|
|
262
|
+
## 4. Summary
|
|
263
|
+
|
|
264
|
+
### What We Built
|
|
265
|
+
{summary of implementation}
|
|
266
|
+
|
|
267
|
+
### Key Takeaways
|
|
268
|
+
1. {takeaway 1}
|
|
269
|
+
2. {takeaway 2}
|
|
270
|
+
3. {takeaway 3}
|
|
271
|
+
|
|
272
|
+
### Common Mistakes to Avoid
|
|
273
|
+
- {mistake 1} - {why it's bad}
|
|
274
|
+
- {mistake 2} - {why it's bad}
|
|
275
|
+
|
|
276
|
+
### Next Steps
|
|
277
|
+
- {suggestion for further learning 1}
|
|
278
|
+
- {suggestion for further learning 2}
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**User Checkpoint:**
|
|
284
|
+
```
|
|
285
|
+
Phase 4/5: SUMMARY complete.
|
|
286
|
+
|
|
287
|
+
Would you like to take a quiz to reinforce learning?
|
|
288
|
+
[ ] Yes, quiz me
|
|
289
|
+
[ ] No, finish up
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
### Phase 5: QUIZ (Optional)
|
|
295
|
+
|
|
296
|
+
**Goal:** Test understanding with practical questions.
|
|
297
|
+
|
|
298
|
+
**Only if user opted in.**
|
|
299
|
+
|
|
300
|
+
**Question Types:**
|
|
301
|
+
1. **Conceptual:** Test understanding of the "why"
|
|
302
|
+
2. **Code Reading:** Given code, predict behavior
|
|
303
|
+
3. **Code Writing:** Small exercise to implement variation
|
|
304
|
+
4. **Debugging:** Find the bug in given code
|
|
305
|
+
|
|
306
|
+
**Format:**
|
|
307
|
+
```
|
|
308
|
+
QUIZ MODE
|
|
309
|
+
|
|
310
|
+
Q1 (Conceptual): {question}
|
|
311
|
+
|
|
312
|
+
Your answer: [wait for user]
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
Correct answer: {answer}
|
|
317
|
+
Explanation: {why}
|
|
318
|
+
|
|
319
|
+
Score: {X}/4
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**Write to markdown:**
|
|
323
|
+
```markdown
|
|
324
|
+
## 5. Quiz
|
|
325
|
+
|
|
326
|
+
<details>
|
|
327
|
+
<summary>Q1: {question}</summary>
|
|
328
|
+
|
|
329
|
+
**Answer:** {answer}
|
|
330
|
+
|
|
331
|
+
**Explanation:** {explanation}
|
|
332
|
+
</details>
|
|
333
|
+
|
|
334
|
+
<details>
|
|
335
|
+
<summary>Q2: {question}</summary>
|
|
336
|
+
...
|
|
337
|
+
</details>
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
### Phase 6: COMPLETE
|
|
345
|
+
|
|
346
|
+
**Actions:**
|
|
347
|
+
1. Finalize markdown file
|
|
348
|
+
2. Display completion message
|
|
349
|
+
|
|
350
|
+
**Add to markdown:**
|
|
351
|
+
```markdown
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
> Tutorial completed: {timestamp}
|
|
355
|
+
> Total steps: {N}
|
|
356
|
+
> All code verified and working
|
|
357
|
+
|
|
358
|
+
Happy coding!
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
**Display to user:**
|
|
362
|
+
```
|
|
363
|
+
LEARN MODE COMPLETE
|
|
364
|
+
|
|
365
|
+
Tutorial saved: .claude/learn/{filename}.md
|
|
366
|
+
You can review this file anytime to refresh your knowledge.
|
|
367
|
+
|
|
368
|
+
What you learned:
|
|
369
|
+
- {concept 1}
|
|
370
|
+
- {concept 2}
|
|
371
|
+
- {concept 3}
|
|
372
|
+
|
|
373
|
+
Great job!
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## Error Handling
|
|
379
|
+
|
|
380
|
+
### Verify Command Not Available
|
|
381
|
+
If the verify command fails because tool is not installed:
|
|
382
|
+
1. Inform user: "Verify tool not available: {command}"
|
|
383
|
+
2. Ask: "Install it now, or proceed with manual verification?"
|
|
384
|
+
3. If install: run appropriate install command
|
|
385
|
+
4. If manual: ask user to confirm code works after each step
|
|
386
|
+
|
|
387
|
+
### User Reports Code Doesn't Work
|
|
388
|
+
1. Ask for exact error message
|
|
389
|
+
2. Ask for their environment (OS, versions)
|
|
390
|
+
3. Debug systematically
|
|
391
|
+
4. Update tutorial with fix
|
|
392
|
+
5. Add to "Common Issues" section in markdown
|
|
393
|
+
|
|
394
|
+
### Language Not Detected
|
|
395
|
+
1. List common languages
|
|
396
|
+
2. Ask user to specify
|
|
397
|
+
3. Set verify strategy accordingly
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
## Principles
|
|
402
|
+
|
|
403
|
+
1. **No code without understanding** - Always explain before implementing
|
|
404
|
+
2. **Verify everything** - Never assume code works, always test
|
|
405
|
+
3. **Fix before proceed** - Don't move on until current step works
|
|
406
|
+
4. **User controls pace** - Always checkpoint before next phase
|
|
407
|
+
5. **Document for future** - Create reusable tutorial
|
|
408
|
+
6. **Basics to advanced** - Start simple, build up complexity
|
|
409
|
+
7. **Real working code** - No pseudocode, no placeholders
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
## Example Session
|
|
414
|
+
|
|
415
|
+
```
|
|
416
|
+
User: /learn "implement debounce in TypeScript"
|
|
417
|
+
|
|
418
|
+
[INIT]
|
|
419
|
+
Detected: TypeScript (tsconfig.json found)
|
|
420
|
+
Verify command: npx tsc --noEmit
|
|
421
|
+
Creating: .claude/learn/2024-02-06-debounce-typescript.md
|
|
422
|
+
|
|
423
|
+
[CONCEPT]
|
|
424
|
+
Debounce is a technique that delays executing a function until
|
|
425
|
+
after a specified time has passed since the last call...
|
|
426
|
+
[detailed explanation]
|
|
427
|
+
|
|
428
|
+
Ready to continue? [Yes/Explain more]
|
|
429
|
+
|
|
430
|
+
User: Yes
|
|
431
|
+
|
|
432
|
+
[PLAN]
|
|
433
|
+
Step 1: Create utils/debounce.ts with basic structure
|
|
434
|
+
Step 2: Implement core debounce logic
|
|
435
|
+
Step 3: Add TypeScript generics for type safety
|
|
436
|
+
Step 4: Write unit tests
|
|
437
|
+
|
|
438
|
+
Ready to code? [Yes/Modify plan]
|
|
439
|
+
|
|
440
|
+
User: Yes
|
|
441
|
+
|
|
442
|
+
[CODE Step 1/4]
|
|
443
|
+
Creating utils/debounce.ts...
|
|
444
|
+
[code with explanation]
|
|
445
|
+
|
|
446
|
+
Verifying: npx tsc --noEmit
|
|
447
|
+
PASSED
|
|
448
|
+
|
|
449
|
+
Understood? [Yes/Explain more/Error on my machine]
|
|
450
|
+
|
|
451
|
+
User: Yes
|
|
452
|
+
|
|
453
|
+
[CODE Step 2/4]
|
|
454
|
+
...
|
|
455
|
+
|
|
456
|
+
[After all steps]
|
|
457
|
+
|
|
458
|
+
[SUMMARY]
|
|
459
|
+
Key takeaways:
|
|
460
|
+
1. Debounce delays execution until activity stops
|
|
461
|
+
2. clearTimeout prevents stale callbacks
|
|
462
|
+
3. Generics preserve function type signatures
|
|
463
|
+
|
|
464
|
+
Quiz? [Yes/No]
|
|
465
|
+
|
|
466
|
+
User: No
|
|
467
|
+
|
|
468
|
+
COMPLETE
|
|
469
|
+
Tutorial saved: .claude/learn/2024-02-06-debounce-typescript.md
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
## Version History
|
|
475
|
+
|
|
476
|
+
- **1.0.0** - Initial release with full interactive learning flow
|