learn-anything-cli 0.1.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/LICENSE +21 -0
- package/README.md +96 -0
- package/README.zh-CN.md +96 -0
- package/bin/learn-anything.js +3 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +88 -0
- package/dist/core/command-generation/adapters/claude.d.ts +3 -0
- package/dist/core/command-generation/adapters/claude.js +31 -0
- package/dist/core/command-generation/adapters/codex.d.ts +3 -0
- package/dist/core/command-generation/adapters/codex.js +26 -0
- package/dist/core/command-generation/adapters/cursor.d.ts +3 -0
- package/dist/core/command-generation/adapters/cursor.js +27 -0
- package/dist/core/command-generation/adapters/gemini.d.ts +3 -0
- package/dist/core/command-generation/adapters/gemini.js +23 -0
- package/dist/core/command-generation/adapters/index.d.ts +5 -0
- package/dist/core/command-generation/adapters/index.js +5 -0
- package/dist/core/command-generation/generator.d.ts +4 -0
- package/dist/core/command-generation/generator.js +10 -0
- package/dist/core/command-generation/index.d.ts +4 -0
- package/dist/core/command-generation/index.js +3 -0
- package/dist/core/command-generation/registry.d.ts +8 -0
- package/dist/core/command-generation/registry.js +20 -0
- package/dist/core/command-generation/types.d.ts +18 -0
- package/dist/core/command-generation/types.js +2 -0
- package/dist/core/config.d.ts +11 -0
- package/dist/core/config.js +33 -0
- package/dist/core/init.d.ts +22 -0
- package/dist/core/init.js +133 -0
- package/dist/core/shared/index.d.ts +3 -0
- package/dist/core/shared/index.js +2 -0
- package/dist/core/shared/skill-generation.d.ts +16 -0
- package/dist/core/shared/skill-generation.js +49 -0
- package/dist/core/templates/skill-templates.d.ts +7 -0
- package/dist/core/templates/skill-templates.js +6 -0
- package/dist/core/templates/types.d.ts +16 -0
- package/dist/core/templates/types.js +2 -0
- package/dist/core/templates/workflows/learn-explain.d.ts +4 -0
- package/dist/core/templates/workflows/learn-explain.js +203 -0
- package/dist/core/templates/workflows/learn-practice.d.ts +4 -0
- package/dist/core/templates/workflows/learn-practice.js +247 -0
- package/dist/core/templates/workflows/learn-review.d.ts +4 -0
- package/dist/core/templates/workflows/learn-review.js +167 -0
- package/dist/core/templates/workflows/learn-status.d.ts +4 -0
- package/dist/core/templates/workflows/learn-status.js +114 -0
- package/dist/core/templates/workflows/learn-topic.d.ts +4 -0
- package/dist/core/templates/workflows/learn-topic.js +191 -0
- package/dist/i18n/index.d.ts +6 -0
- package/dist/i18n/index.js +30 -0
- package/dist/i18n/locales/en.d.ts +3 -0
- package/dist/i18n/locales/en.js +28 -0
- package/dist/i18n/locales/zh-CN.d.ts +3 -0
- package/dist/i18n/locales/zh-CN.js +28 -0
- package/dist/i18n/types.d.ts +31 -0
- package/dist/i18n/types.js +2 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +4 -0
- package/dist/utils/file-system.d.ts +8 -0
- package/dist/utils/file-system.js +38 -0
- package/dist/utils/interactive.d.ts +2 -0
- package/dist/utils/interactive.js +4 -0
- package/package.json +69 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import { createRequire } from 'module';
|
|
5
|
+
import { FileSystemUtils } from '../utils/file-system.js';
|
|
6
|
+
import { AI_TOOLS, LEARN_DIR } from './config.js';
|
|
7
|
+
import { isInteractive } from '../utils/interactive.js';
|
|
8
|
+
import { generateCommands, CommandAdapterRegistry, } from './command-generation/index.js';
|
|
9
|
+
import { getSkillTemplates, getCommandContents, generateSkillContent, } from './shared/index.js';
|
|
10
|
+
import { getMessages } from '../i18n/index.js';
|
|
11
|
+
const require = createRequire(import.meta.url);
|
|
12
|
+
const { version: VERSION } = require('../../package.json');
|
|
13
|
+
export class InitCommand {
|
|
14
|
+
toolsArg;
|
|
15
|
+
force;
|
|
16
|
+
locale;
|
|
17
|
+
isUpdate;
|
|
18
|
+
constructor(options = {}) {
|
|
19
|
+
this.toolsArg = options.tools;
|
|
20
|
+
this.force = options.force ?? false;
|
|
21
|
+
this.locale = options.locale ?? 'en';
|
|
22
|
+
this.isUpdate = options.update ?? false;
|
|
23
|
+
}
|
|
24
|
+
async execute(targetPath = '.') {
|
|
25
|
+
const resolvedPath = path.resolve(targetPath);
|
|
26
|
+
const m = getMessages(this.locale);
|
|
27
|
+
// Ensure target directory exists
|
|
28
|
+
await FileSystemUtils.ensureDir(resolvedPath);
|
|
29
|
+
// Create .learn/ directory in the target project
|
|
30
|
+
const learnDir = path.join(resolvedPath, LEARN_DIR);
|
|
31
|
+
await FileSystemUtils.ensureDir(path.join(learnDir, 'topics'));
|
|
32
|
+
console.log(chalk.bold(m.init.header));
|
|
33
|
+
// Detect available tools
|
|
34
|
+
const availableTools = await this.detectTools(resolvedPath);
|
|
35
|
+
// Select tools
|
|
36
|
+
let selectedTools;
|
|
37
|
+
if (this.toolsArg === 'all') {
|
|
38
|
+
selectedTools = availableTools.filter((t) => t.available);
|
|
39
|
+
}
|
|
40
|
+
else if (this.toolsArg === 'none') {
|
|
41
|
+
selectedTools = [];
|
|
42
|
+
}
|
|
43
|
+
else if (this.toolsArg) {
|
|
44
|
+
const toolIds = this.toolsArg.split(',').map((t) => t.trim());
|
|
45
|
+
selectedTools = availableTools.filter((t) => toolIds.includes(t.value));
|
|
46
|
+
}
|
|
47
|
+
else if (this.isUpdate || !isInteractive()) {
|
|
48
|
+
// Update mode or non-interactive: auto-detect existing tool dirs
|
|
49
|
+
selectedTools = availableTools.filter((t) => t.available && this.hasToolDir(resolvedPath, t));
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
selectedTools = await this.interactiveSelect(availableTools);
|
|
53
|
+
}
|
|
54
|
+
if (selectedTools.length === 0) {
|
|
55
|
+
console.log(chalk.yellow(m.init.noToolsSelected));
|
|
56
|
+
console.log(chalk.dim(m.init.availableTools(availableTools.filter((t) => t.available).map((t) => t.value).join(', '))));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// Generate skill files for each tool
|
|
60
|
+
for (const tool of selectedTools) {
|
|
61
|
+
if (!tool.skillsDir)
|
|
62
|
+
continue;
|
|
63
|
+
await this.generateSkillsForTool(resolvedPath, tool);
|
|
64
|
+
await this.generateCommandsForTool(resolvedPath, tool);
|
|
65
|
+
console.log(chalk.green(m.init.skillGenerated(tool.name)));
|
|
66
|
+
}
|
|
67
|
+
console.log('');
|
|
68
|
+
console.log(chalk.bold(m.init.initComplete));
|
|
69
|
+
console.log(chalk.dim(m.init.globalDataPath(LEARN_DIR)));
|
|
70
|
+
console.log(chalk.dim(m.init.startLearning('/learn javascript')));
|
|
71
|
+
console.log(chalk.bold(m.init.availableCommands));
|
|
72
|
+
const cmd = m.init.cmdLine;
|
|
73
|
+
console.log(cmd(chalk.cyan('/learn:topic <topic-name>'), chalk.dim(' — Initialize or load a learning topic')));
|
|
74
|
+
console.log(cmd(chalk.cyan('/learn:explain <concept-name>'), chalk.dim(' — Recursively deep-dive into a concept')));
|
|
75
|
+
console.log(cmd(chalk.cyan('/learn:practice <concept-name>'), chalk.dim(' — TDD-style coding exercises')));
|
|
76
|
+
console.log(cmd(chalk.cyan('/learn:review [topic-name]'), chalk.dim(' — Review progress, spaced repetition recommendations')));
|
|
77
|
+
console.log(cmd(chalk.cyan('/learn:status [topic-name]'), chalk.dim(' — Visualize learning state as knowledge map heatmap')));
|
|
78
|
+
console.log('');
|
|
79
|
+
}
|
|
80
|
+
async detectTools(resolvedPath) {
|
|
81
|
+
return AI_TOOLS;
|
|
82
|
+
}
|
|
83
|
+
hasToolDir(resolvedPath, tool) {
|
|
84
|
+
if (!tool.skillsDir)
|
|
85
|
+
return false;
|
|
86
|
+
const dirPath = path.join(resolvedPath, tool.skillsDir);
|
|
87
|
+
try {
|
|
88
|
+
return fs.statSync(dirPath).isDirectory();
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async interactiveSelect(tools) {
|
|
95
|
+
const availableTools = tools.filter((t) => t.available && t.skillsDir);
|
|
96
|
+
const { search, checkbox } = await import('@inquirer/prompts');
|
|
97
|
+
// Auto-detect existing tool dirs and pre-select them
|
|
98
|
+
const detected = availableTools.filter((t) => this.hasToolDir(process.cwd(), t));
|
|
99
|
+
const detectedValues = new Set(detected.map((t) => t.value));
|
|
100
|
+
const choices = availableTools.map((t) => ({
|
|
101
|
+
name: t.name,
|
|
102
|
+
value: t.value,
|
|
103
|
+
checked: detectedValues.has(t.value),
|
|
104
|
+
}));
|
|
105
|
+
const selected = await checkbox({
|
|
106
|
+
message: getMessages(this.locale).init.interactiveSelectPrompt,
|
|
107
|
+
choices,
|
|
108
|
+
pageSize: 15,
|
|
109
|
+
});
|
|
110
|
+
return availableTools.filter((t) => selected.includes(t.value));
|
|
111
|
+
}
|
|
112
|
+
async generateSkillsForTool(resolvedPath, tool) {
|
|
113
|
+
const skillTemplates = getSkillTemplates();
|
|
114
|
+
for (const entry of skillTemplates) {
|
|
115
|
+
const skillDir = path.join(resolvedPath, tool.skillsDir, 'skills', entry.dirName);
|
|
116
|
+
const skillFile = path.join(skillDir, 'SKILL.md');
|
|
117
|
+
const content = generateSkillContent(entry.template, VERSION);
|
|
118
|
+
await FileSystemUtils.writeFile(skillFile, content);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async generateCommandsForTool(resolvedPath, tool) {
|
|
122
|
+
const adapter = CommandAdapterRegistry.get(tool.value);
|
|
123
|
+
if (!adapter)
|
|
124
|
+
return;
|
|
125
|
+
const commandContents = getCommandContents();
|
|
126
|
+
const generatedCommands = generateCommands(commandContents, adapter);
|
|
127
|
+
for (const cmd of generatedCommands) {
|
|
128
|
+
const filePath = path.resolve(resolvedPath, cmd.path);
|
|
129
|
+
await FileSystemUtils.writeFile(filePath, cmd.fileContent);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getLearnTopicCommandTemplate, type SkillTemplate } from '../templates/skill-templates.js';
|
|
2
|
+
import type { CommandContent } from '../command-generation/index.js';
|
|
3
|
+
export interface SkillTemplateEntry {
|
|
4
|
+
template: SkillTemplate;
|
|
5
|
+
dirName: string;
|
|
6
|
+
workflowId: string;
|
|
7
|
+
}
|
|
8
|
+
export interface CommandTemplateEntry {
|
|
9
|
+
template: ReturnType<typeof getLearnTopicCommandTemplate>;
|
|
10
|
+
id: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function getSkillTemplates(): SkillTemplateEntry[];
|
|
13
|
+
export declare function getCommandTemplates(): CommandTemplateEntry[];
|
|
14
|
+
export declare function getCommandContents(): CommandContent[];
|
|
15
|
+
export declare function generateSkillContent(template: SkillTemplate, generatedByVersion: string, transformInstructions?: (instructions: string) => string): string;
|
|
16
|
+
//# sourceMappingURL=skill-generation.d.ts.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { getLearnTopicSkillTemplate, getLearnExplainSkillTemplate, getLearnPracticeSkillTemplate, getLearnReviewSkillTemplate, getLearnStatusSkillTemplate, getLearnTopicCommandTemplate, getLearnExplainCommandTemplate, getLearnPracticeCommandTemplate, getLearnReviewCommandTemplate, getLearnStatusCommandTemplate, } from '../templates/skill-templates.js';
|
|
2
|
+
export function getSkillTemplates() {
|
|
3
|
+
return [
|
|
4
|
+
{ template: getLearnTopicSkillTemplate(), dirName: 'learn-anything-topic', workflowId: 'topic' },
|
|
5
|
+
{ template: getLearnExplainSkillTemplate(), dirName: 'learn-anything-explain', workflowId: 'explain' },
|
|
6
|
+
{ template: getLearnPracticeSkillTemplate(), dirName: 'learn-anything-practice', workflowId: 'practice' },
|
|
7
|
+
{ template: getLearnReviewSkillTemplate(), dirName: 'learn-anything-review', workflowId: 'review' },
|
|
8
|
+
{ template: getLearnStatusSkillTemplate(), dirName: 'learn-anything-status', workflowId: 'status' },
|
|
9
|
+
];
|
|
10
|
+
}
|
|
11
|
+
export function getCommandTemplates() {
|
|
12
|
+
return [
|
|
13
|
+
{ template: getLearnTopicCommandTemplate(), id: 'topic' },
|
|
14
|
+
{ template: getLearnExplainCommandTemplate(), id: 'explain' },
|
|
15
|
+
{ template: getLearnPracticeCommandTemplate(), id: 'practice' },
|
|
16
|
+
{ template: getLearnReviewCommandTemplate(), id: 'review' },
|
|
17
|
+
{ template: getLearnStatusCommandTemplate(), id: 'status' },
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
export function getCommandContents() {
|
|
21
|
+
const commandTemplates = getCommandTemplates();
|
|
22
|
+
return commandTemplates.map(({ template, id }) => ({
|
|
23
|
+
id,
|
|
24
|
+
name: template.name,
|
|
25
|
+
description: template.description,
|
|
26
|
+
category: template.category,
|
|
27
|
+
tags: template.tags,
|
|
28
|
+
body: template.content,
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
export function generateSkillContent(template, generatedByVersion, transformInstructions) {
|
|
32
|
+
const instructions = transformInstructions
|
|
33
|
+
? transformInstructions(template.instructions)
|
|
34
|
+
: template.instructions;
|
|
35
|
+
return `---
|
|
36
|
+
name: ${template.name}
|
|
37
|
+
description: ${template.description}
|
|
38
|
+
license: ${template.license || 'MIT'}
|
|
39
|
+
compatibility: ${template.compatibility || 'Requires learn-anything CLI.'}
|
|
40
|
+
metadata:
|
|
41
|
+
author: ${template.metadata?.author || 'learn-anything'}
|
|
42
|
+
version: "${template.metadata?.version || '1.0'}"
|
|
43
|
+
generatedBy: "${generatedByVersion}"
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
${instructions}
|
|
47
|
+
`;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=skill-generation.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type { SkillTemplate, CommandTemplate } from './types.js';
|
|
2
|
+
export { getLearnTopicSkillTemplate, getLearnTopicCommandTemplate } from './workflows/learn-topic.js';
|
|
3
|
+
export { getLearnExplainSkillTemplate, getLearnExplainCommandTemplate } from './workflows/learn-explain.js';
|
|
4
|
+
export { getLearnPracticeSkillTemplate, getLearnPracticeCommandTemplate } from './workflows/learn-practice.js';
|
|
5
|
+
export { getLearnReviewSkillTemplate, getLearnReviewCommandTemplate } from './workflows/learn-review.js';
|
|
6
|
+
export { getLearnStatusSkillTemplate, getLearnStatusCommandTemplate } from './workflows/learn-status.js';
|
|
7
|
+
//# sourceMappingURL=skill-templates.d.ts.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { getLearnTopicSkillTemplate, getLearnTopicCommandTemplate } from './workflows/learn-topic.js';
|
|
2
|
+
export { getLearnExplainSkillTemplate, getLearnExplainCommandTemplate } from './workflows/learn-explain.js';
|
|
3
|
+
export { getLearnPracticeSkillTemplate, getLearnPracticeCommandTemplate } from './workflows/learn-practice.js';
|
|
4
|
+
export { getLearnReviewSkillTemplate, getLearnReviewCommandTemplate } from './workflows/learn-review.js';
|
|
5
|
+
export { getLearnStatusSkillTemplate, getLearnStatusCommandTemplate } from './workflows/learn-status.js';
|
|
6
|
+
//# sourceMappingURL=skill-templates.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface SkillTemplate {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
instructions: string;
|
|
5
|
+
license?: string;
|
|
6
|
+
compatibility?: string;
|
|
7
|
+
metadata?: Record<string, string>;
|
|
8
|
+
}
|
|
9
|
+
export interface CommandTemplate {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
category: string;
|
|
13
|
+
tags: string[];
|
|
14
|
+
content: string;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
const SKILL_NAME = 'learn-anything-explain';
|
|
2
|
+
const SKILL_DESCRIPTION = 'Recursively deep-dive into a concept. AI explains, identifies deeper sub-topics, and lets you choose your own depth direction.';
|
|
3
|
+
const INSTRUCTIONS = `Always respond in the same language the user uses.
|
|
4
|
+
If the user speaks Chinese, explain all concepts, examples, and guidance in Chinese.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are Learn Anything's Explanation Mentor. You excel at explaining complex concepts in simple, clear language.
|
|
9
|
+
Your explanations follow the "Recursive Learning Method": first establish a foundation of understanding, then identify deeper sub-topics, letting the user choose whether to go deeper.
|
|
10
|
+
|
|
11
|
+
## Your Teaching Philosophy
|
|
12
|
+
|
|
13
|
+
1. **Understanding over Information** — Explaining one concept thoroughly matters more than covering ten superficially
|
|
14
|
+
2. **Analogies Build Intuition** — Every abstract concept should have a real-world analogy
|
|
15
|
+
3. **Socratic Guidance, Not Interrogation** — Questions help users discover answers themselves, not test them
|
|
16
|
+
4. **Know When to Stop** — When the user signals understanding, offer depth options without pushing
|
|
17
|
+
5. **Connect to the Knowledge Map** — Always show where the current concept fits in the broader knowledge system
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Command: /learn-explain <concept-name>
|
|
22
|
+
|
|
23
|
+
### Step 1: Load Context
|
|
24
|
+
|
|
25
|
+
1. **Match topic**: Infer the parent topic from the concept name.
|
|
26
|
+
- Look at all directories under \`./.learn/topics/\`
|
|
27
|
+
- If there's only one topic, use it directly
|
|
28
|
+
- If there are multiple topics, search knowledge maps for the concept name
|
|
29
|
+
- If no matching topic is found, ask the user "Which topic would you like to learn this concept under? Available topics: [list]"
|
|
30
|
+
|
|
31
|
+
2. **Read knowledge map**: Use the Read tool to read \`./.learn/topics/<topic-name>/knowledge-map.md\`, locating the concept's position in the knowledge tree.
|
|
32
|
+
|
|
33
|
+
3. **Read learning state**: Use the Read tool to read \`./.learn/topics/<topic-name>/state.yaml\`, finding the concept's current status.
|
|
34
|
+
|
|
35
|
+
### Step 2: Assess User Level
|
|
36
|
+
|
|
37
|
+
Synthesize these signals to judge whether the user is beginner, intermediate, or advanced:
|
|
38
|
+
|
|
39
|
+
**Beginner signals:**
|
|
40
|
+
- Short, vague questions (e.g., "What is a closure?")
|
|
41
|
+
- Uses general descriptors ("I don't really get it", "completely lost")
|
|
42
|
+
- Concept status is \`unexplored\`
|
|
43
|
+
- Related concept confidence in state.yaml < 0.3
|
|
44
|
+
|
|
45
|
+
**Intermediate signals:**
|
|
46
|
+
- Uses some technical terms, though not always precise
|
|
47
|
+
- Questions are targeted ("How do closures cause memory leaks?")
|
|
48
|
+
- Concept status is \`in_progress\`
|
|
49
|
+
- Related concept confidence in state.yaml 0.3-0.7
|
|
50
|
+
|
|
51
|
+
**Advanced signals:**
|
|
52
|
+
- Uses precise technical terminology
|
|
53
|
+
- Questions go deep ("How does V8 optimize scope chain lookups for closures?")
|
|
54
|
+
- Concept status is \`mastered\` but seeking deeper discussion
|
|
55
|
+
- Related concept confidence in state.yaml > 0.7
|
|
56
|
+
|
|
57
|
+
**Level-adaptive strategy:**
|
|
58
|
+
- Beginners: Explanation-heavy (70% explanation + 30% guided questions), heavy use of analogies
|
|
59
|
+
- Intermediate: Balanced (50% explanation + 50% guidance), encourage self-derivation
|
|
60
|
+
- Advanced: Guidance and challenge-heavy (30% supplement + 70% deep discussion), quickly skip basics
|
|
61
|
+
|
|
62
|
+
### Step 3: Explain the Concept
|
|
63
|
+
|
|
64
|
+
**Explanation structure (for beginner/intermediate):**
|
|
65
|
+
|
|
66
|
+
1. **Positioning** — Where is this concept in the knowledge map? (One sentence)
|
|
67
|
+
> "Closures sit in the **Functions → Scope & Closures** branch of the JavaScript knowledge tree. To understand closures, you first need to know what scope is."
|
|
68
|
+
|
|
69
|
+
2. **Analogy** — Build intuition with a real-world metaphor
|
|
70
|
+
> "Think of a function as a backpack. Every time you create a function, it packs up all the variables visible around it at that moment..."
|
|
71
|
+
|
|
72
|
+
3. **Core Mechanism** — Explain "what" and "why" in clear language
|
|
73
|
+
> "A closure is the combination of a function and its lexical environment. When a function 'remembers' the scope it was created in..."
|
|
74
|
+
|
|
75
|
+
4. **Code Example** — A minimal but complete example
|
|
76
|
+
> \`\`\`javascript
|
|
77
|
+
> function createCounter() {
|
|
78
|
+
> let count = 0;
|
|
79
|
+
> return function() { count++; return count; };
|
|
80
|
+
> }
|
|
81
|
+
> const counter = createCounter();
|
|
82
|
+
> counter(); // 1
|
|
83
|
+
> counter(); // 2 — it "remembers" count
|
|
84
|
+
> \`\`\`
|
|
85
|
+
|
|
86
|
+
5. **Common Misconceptions** — Point out the most common beginner mistakes
|
|
87
|
+
> "Many people think a closure is just a function defined inside another function. The key is actually 'capturing external variables'..."
|
|
88
|
+
|
|
89
|
+
6. **Socratic Check** — Use 1-2 natural questions to confirm understanding (NOT a quiz!)
|
|
90
|
+
> "If I create 5 closures inside a loop using var versus let, what would be different? Take a guess?"
|
|
91
|
+
|
|
92
|
+
Note: This is a thinking-guiding question, tone should be curious and exploratory, not exam-like. If the user is unsure, give the answer immediately — don't wait.
|
|
93
|
+
|
|
94
|
+
### Step 4: Identify Sub-topics (Recursive Entry Points)
|
|
95
|
+
|
|
96
|
+
After the explanation, identify deeper sub-topics under this concept. These aren't a bullet list of facts — they flow naturally into the closing:
|
|
97
|
+
|
|
98
|
+
> Now you understand the basics of closures. If you'd like to go deeper, we can explore:
|
|
99
|
+
>
|
|
100
|
+
> 🔍 **Classic Closure Patterns**
|
|
101
|
+
> - Module Pattern — Using closures for private variables
|
|
102
|
+
> - Currying — One of the most elegant uses of closures
|
|
103
|
+
> - Debounce & Throttle — Closures in real-world frontend
|
|
104
|
+
>
|
|
105
|
+
> 🔍 **Closure Performance**
|
|
106
|
+
> - Memory leaks — When do closures cause problems?
|
|
107
|
+
> - V8 hidden classes and closure optimization
|
|
108
|
+
>
|
|
109
|
+
> Which direction interests you? Or would you rather do some practice exercises to solidify?
|
|
110
|
+
|
|
111
|
+
**Sub-topic identification rules:**
|
|
112
|
+
- Sub-topics should be organic extensions, not random tangents
|
|
113
|
+
- List 2-4 sub-directions, each with 1-2 sentences explaining why it's worth learning
|
|
114
|
+
- Always offer the "practice" option alongside
|
|
115
|
+
- For advanced users, sub-topics should be deeper
|
|
116
|
+
- For beginners, sub-topics should lean practical and applied
|
|
117
|
+
- **Never rush**, let the user decide their next step
|
|
118
|
+
|
|
119
|
+
### Step 5: Record Learning Session
|
|
120
|
+
|
|
121
|
+
After each explanation, append a session record to \`./.learn/topics/<topic-name>/sessions/YYYY-MM-DD.md\`:
|
|
122
|
+
|
|
123
|
+
\`\`\`markdown
|
|
124
|
+
# Learning Session - <date>
|
|
125
|
+
|
|
126
|
+
## Content
|
|
127
|
+
- Concept: [concept name]
|
|
128
|
+
- Path: [path in knowledge map, e.g., "Functions/Closures"]
|
|
129
|
+
- Depth: beginner/intermediate/advanced explanation
|
|
130
|
+
|
|
131
|
+
## Key Points Covered
|
|
132
|
+
- [point 1]
|
|
133
|
+
- [point 2]
|
|
134
|
+
|
|
135
|
+
## Sub-topics Explored by User
|
|
136
|
+
(If the user chose to go deeper, record which direction)
|
|
137
|
+
|
|
138
|
+
## Follow-ups
|
|
139
|
+
(If the user expressed confusion that wasn't fully resolved, record it here)
|
|
140
|
+
\`\`\`
|
|
141
|
+
|
|
142
|
+
**Also update state.yaml:**
|
|
143
|
+
- If concept status is \`unexplored\`, update to \`in_progress\`
|
|
144
|
+
- Update \`last_session\` to current date
|
|
145
|
+
- If the user showed good understanding (asked questions, answered correctly), slightly increase \`confidence\` (+0.05 to +0.1)
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Edge Cases
|
|
150
|
+
|
|
151
|
+
- **Concept name mismatch**: Fuzzy search the concept name in the knowledge map.
|
|
152
|
+
E.g., user enters "closure principles", matches to "Functions/Closures". "Did you mean **Closures** (under the Functions branch)?"
|
|
153
|
+
|
|
154
|
+
- **Multiple matches**: List all matching concepts for the user to choose.
|
|
155
|
+
"I found several possible matches in the knowledge map:
|
|
156
|
+
1. Functions/Closures — A function combined with its lexical environment
|
|
157
|
+
2. Rust/Ownership & Borrowing — Ownership rules similar to closures
|
|
158
|
+
Which would you like to learn?"
|
|
159
|
+
|
|
160
|
+
- **Concept not in knowledge map**:
|
|
161
|
+
"'Micro-frontends' isn't in the current JavaScript knowledge map. This might be a more advanced or cross-domain concept.
|
|
162
|
+
I can:
|
|
163
|
+
- Add this concept to the JavaScript knowledge map
|
|
164
|
+
- Or create a separate 'Micro-frontends' learning topic
|
|
165
|
+
Which do you prefer?"
|
|
166
|
+
|
|
167
|
+
- **Topic doesn't exist**: Prompt user to create a topic first with \`/learn <topic-name>\`.
|
|
168
|
+
"You haven't created a related topic yet. Run \`/learn <topic-name>\` first to start learning!"
|
|
169
|
+
|
|
170
|
+
- **User is clearly a beginner**: Adjust explanation style:
|
|
171
|
+
- More analogies, fewer technical terms
|
|
172
|
+
- More comprehension checks ("Does that make sense?")
|
|
173
|
+
- Prioritize "why we need this concept" over "how it works internally"
|
|
174
|
+
- Provide simpler code examples`;
|
|
175
|
+
const COMMAND_NAME = 'Learn: Explain';
|
|
176
|
+
const COMMAND_DESCRIPTION = 'Recursively deep-dive into a concept — AI explains, guides thinking, you choose the depth';
|
|
177
|
+
const COMMAND_CONTENT = `Use the learn-anything-explain skill to handle the user's /learn-explain <concept-name> request.
|
|
178
|
+
Follow the workflow defined in the skill:
|
|
179
|
+
1. Load context: match topic → read knowledge map → read learning state
|
|
180
|
+
2. Assess user level (beginner/intermediate/advanced) and adjust teaching strategy
|
|
181
|
+
3. Follow the explanation structure: positioning → analogy → core mechanism → code example → common misconceptions → Socratic check
|
|
182
|
+
4. Identify sub-topics as recursive entry points
|
|
183
|
+
5. Record learning session and update state.yaml`;
|
|
184
|
+
export function getLearnExplainSkillTemplate() {
|
|
185
|
+
return {
|
|
186
|
+
name: SKILL_NAME,
|
|
187
|
+
description: SKILL_DESCRIPTION,
|
|
188
|
+
instructions: INSTRUCTIONS,
|
|
189
|
+
license: 'MIT',
|
|
190
|
+
compatibility: 'Requires learn-anything CLI.',
|
|
191
|
+
metadata: { author: 'learn-anything', version: '1.0' },
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
export function getLearnExplainCommandTemplate() {
|
|
195
|
+
return {
|
|
196
|
+
name: COMMAND_NAME,
|
|
197
|
+
description: COMMAND_DESCRIPTION,
|
|
198
|
+
category: 'Learning',
|
|
199
|
+
tags: ['learning', 'explain', 'socratic', 'recursive'],
|
|
200
|
+
content: COMMAND_CONTENT,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=learn-explain.js.map
|