learn-anything-cli 0.2.1 → 0.4.0-beta.1
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/README.md +2 -0
- package/dist/cli/index.js +1 -1
- package/dist/core/command-generation/registry.js +1 -1
- package/dist/core/config.js +148 -20
- package/dist/core/init.d.ts +2 -0
- package/dist/core/init.js +36 -6
- package/dist/core/learn-protocol/index.d.ts +8 -0
- package/dist/core/learn-protocol/index.js +5 -0
- package/dist/core/learn-protocol/migrate.d.ts +52 -0
- package/dist/core/learn-protocol/migrate.js +259 -0
- package/dist/core/learn-protocol/parser.d.ts +33 -0
- package/dist/core/learn-protocol/parser.js +150 -0
- package/dist/core/learn-protocol/schema.d.ts +38 -0
- package/dist/core/learn-protocol/schema.js +43 -0
- package/dist/core/learn-protocol/slug.d.ts +13 -0
- package/dist/core/learn-protocol/slug.js +28 -0
- package/dist/core/learn-protocol/types.d.ts +63 -0
- package/dist/core/learn-protocol/types.js +2 -0
- package/dist/core/shared/skill-generation.js +25 -5
- package/dist/core/templates/skill-templates.d.ts +5 -5
- package/dist/core/templates/skill-templates.js +5 -5
- package/dist/core/templates/workflows/learn-explain.js +65 -142
- package/dist/core/templates/workflows/learn-practice.js +88 -282
- package/dist/core/templates/workflows/learn-review.js +35 -93
- package/dist/core/templates/workflows/learn-status.js +26 -69
- package/dist/core/templates/workflows/learn-topic.js +73 -82
- package/dist/i18n/index.js +1 -4
- package/dist/i18n/locales/en.js +1 -0
- package/dist/i18n/locales/zh-CN.js +1 -0
- package/dist/i18n/types.d.ts +1 -0
- package/dist/scripts/render.d.mts +13 -0
- package/dist/scripts/render.mjs +112 -0
- package/dist/scripts/status.d.mts +31 -0
- package/dist/scripts/status.mjs +418 -0
- package/dist/scripts/utils.d.mts +43 -0
- package/dist/scripts/utils.mjs +124 -0
- package/package.json +24 -2
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown parser for v0 knowledge-map.md.
|
|
3
|
+
*
|
|
4
|
+
* Uses unified + remark-parse to extract the hierarchical structure
|
|
5
|
+
* (domains -> concepts -> details) from the v0 knowledge-map format.
|
|
6
|
+
*
|
|
7
|
+
* This is used ONLY during migration (init/update), not at AI runtime.
|
|
8
|
+
*
|
|
9
|
+
* v0 knowledge-map.md format:
|
|
10
|
+
*
|
|
11
|
+
* ```md
|
|
12
|
+
* # Topic Name
|
|
13
|
+
* ## Domain 1
|
|
14
|
+
* - Concept A
|
|
15
|
+
* - Detail A1
|
|
16
|
+
* - Detail A2
|
|
17
|
+
* - Concept B
|
|
18
|
+
* ## Domain 2
|
|
19
|
+
* - Concept C
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
import { unified } from 'unified';
|
|
23
|
+
import remarkParse from 'remark-parse';
|
|
24
|
+
// ---- Helpers -----------------------------------------------------------
|
|
25
|
+
/** Recursively extract plain text from an AST node.
|
|
26
|
+
*
|
|
27
|
+
* Does NOT descend into nested `list` nodes — those are structural
|
|
28
|
+
* children (details under a concept) and should not contribute to
|
|
29
|
+
* the parent concept's name.
|
|
30
|
+
*/
|
|
31
|
+
function extractText(node) {
|
|
32
|
+
if (!node || typeof node !== 'object')
|
|
33
|
+
return '';
|
|
34
|
+
const n = node;
|
|
35
|
+
if (n.type === 'text' && typeof n.value === 'string') {
|
|
36
|
+
return n.value;
|
|
37
|
+
}
|
|
38
|
+
// Don't descend into lists: their content belongs to child concepts/details.
|
|
39
|
+
if (n.type === 'list')
|
|
40
|
+
return '';
|
|
41
|
+
if (Array.isArray(n.children)) {
|
|
42
|
+
return n.children.map(extractText).join('');
|
|
43
|
+
}
|
|
44
|
+
return '';
|
|
45
|
+
}
|
|
46
|
+
/** Narrow a child node to a specific type. */
|
|
47
|
+
function isHeading(node, depth) {
|
|
48
|
+
if (!node || typeof node !== 'object')
|
|
49
|
+
return false;
|
|
50
|
+
const n = node;
|
|
51
|
+
return n.type === 'heading' && n.depth === depth;
|
|
52
|
+
}
|
|
53
|
+
function isList(node) {
|
|
54
|
+
if (!node || typeof node !== 'object')
|
|
55
|
+
return false;
|
|
56
|
+
return node.type === 'list';
|
|
57
|
+
}
|
|
58
|
+
// ---- Public API ---------------------------------------------------------
|
|
59
|
+
/**
|
|
60
|
+
* Parse a v0 knowledge-map.md file content into a structured representation.
|
|
61
|
+
*
|
|
62
|
+
* The parser walks the mdast tree:
|
|
63
|
+
* - `# Title` (h1) -> topic name
|
|
64
|
+
* - `## DomainName` (h2) -> start a new domain
|
|
65
|
+
* - `- Concept` (top-level list item) -> add concept to current domain
|
|
66
|
+
* - ` - Detail` (nested list item) -> add detail to preceding concept
|
|
67
|
+
*/
|
|
68
|
+
export function parseKnowledgeMap(markdown) {
|
|
69
|
+
const tree = unified().use(remarkParse).parse(markdown);
|
|
70
|
+
let topic = '';
|
|
71
|
+
const domains = [];
|
|
72
|
+
let currentDomain = null;
|
|
73
|
+
for (const node of tree.children) {
|
|
74
|
+
// # Title
|
|
75
|
+
if (isHeading(node, 1)) {
|
|
76
|
+
topic = extractText(node).trim();
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
// ## DomainName
|
|
80
|
+
if (isHeading(node, 2)) {
|
|
81
|
+
if (currentDomain)
|
|
82
|
+
domains.push(currentDomain);
|
|
83
|
+
currentDomain = {
|
|
84
|
+
name: extractText(node).trim(),
|
|
85
|
+
concepts: [],
|
|
86
|
+
};
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
// - Concept list (only process if we're inside a domain)
|
|
90
|
+
if (isList(node) && currentDomain) {
|
|
91
|
+
const list = node;
|
|
92
|
+
for (const item of list.children) {
|
|
93
|
+
processListItem(item, currentDomain, markdown);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Push the last domain
|
|
98
|
+
if (currentDomain)
|
|
99
|
+
domains.push(currentDomain);
|
|
100
|
+
return { topic, domains };
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Get list-item text via source position slicing.
|
|
104
|
+
*
|
|
105
|
+
* remark-parse consumes `__init__` as `<strong>init</strong>`, losing the
|
|
106
|
+
* underscores. By slicing the original markdown source at the paragraph's
|
|
107
|
+
* position offsets, we preserve the exact original text including any
|
|
108
|
+
* markdown formatting characters.
|
|
109
|
+
*/
|
|
110
|
+
function extractListItemText(item, source) {
|
|
111
|
+
for (const child of item.children) {
|
|
112
|
+
if (child.type === 'paragraph') {
|
|
113
|
+
const para = child;
|
|
114
|
+
const pos = para.position;
|
|
115
|
+
if (pos?.start && pos?.end) {
|
|
116
|
+
const start = pos.start;
|
|
117
|
+
const end = pos.end;
|
|
118
|
+
if (start.offset !== undefined && end.offset !== undefined) {
|
|
119
|
+
return source.slice(start.offset, end.offset);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Fallback to recursive text extraction
|
|
125
|
+
return extractText(item);
|
|
126
|
+
}
|
|
127
|
+
/** Strip common Markdown escape backslashes (e.g. `\_` → `_`, `\*` → `*`). */
|
|
128
|
+
function unescapeMarkdown(text) {
|
|
129
|
+
return text.replace(/\\([\\`*{}[\]()#+\-.!_>~|])/g, '$1');
|
|
130
|
+
}
|
|
131
|
+
/** Extract a concept (and its optional details) from a list item. */
|
|
132
|
+
function processListItem(item, domain, source) {
|
|
133
|
+
const name = unescapeMarkdown(extractListItemText(item, source).trim());
|
|
134
|
+
if (!name)
|
|
135
|
+
return;
|
|
136
|
+
const concept = { name, children: [] };
|
|
137
|
+
// Look for a nested list inside this list item (these are third-level details)
|
|
138
|
+
for (const child of item.children) {
|
|
139
|
+
if (isList(child)) {
|
|
140
|
+
for (const nestedItem of child.children) {
|
|
141
|
+
const detailName = unescapeMarkdown(extractListItemText(nestedItem, source).trim());
|
|
142
|
+
if (detailName) {
|
|
143
|
+
concept.children.push(detailName);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
domain.concepts.push(concept);
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const stateV1Schema: z.ZodObject<{
|
|
3
|
+
version: z.ZodLiteral<1>;
|
|
4
|
+
topic: z.ZodString;
|
|
5
|
+
slug: z.ZodString;
|
|
6
|
+
created: z.ZodString;
|
|
7
|
+
domains: z.ZodArray<z.ZodObject<{
|
|
8
|
+
name: z.ZodString;
|
|
9
|
+
slug: z.ZodString;
|
|
10
|
+
concepts: z.ZodArray<z.ZodObject<{
|
|
11
|
+
name: z.ZodString;
|
|
12
|
+
slug: z.ZodString;
|
|
13
|
+
status: z.ZodEnum<{
|
|
14
|
+
unexplored: "unexplored";
|
|
15
|
+
in_progress: "in_progress";
|
|
16
|
+
needs_practice: "needs_practice";
|
|
17
|
+
mastered: "mastered";
|
|
18
|
+
}>;
|
|
19
|
+
confidence: z.ZodNumber;
|
|
20
|
+
practice_count: z.ZodNumber;
|
|
21
|
+
explain_count: z.ZodNumber;
|
|
22
|
+
last_explained: z.ZodNullable<z.ZodString>;
|
|
23
|
+
last_practiced: z.ZodNullable<z.ZodString>;
|
|
24
|
+
details: z.ZodArray<z.ZodString>;
|
|
25
|
+
}, z.core.$strip>>;
|
|
26
|
+
}, z.core.$strip>>;
|
|
27
|
+
}, z.core.$strip>;
|
|
28
|
+
export type StateV1Schema = z.infer<typeof stateV1Schema>;
|
|
29
|
+
export type ValidationResult = {
|
|
30
|
+
success: true;
|
|
31
|
+
data: StateV1Schema;
|
|
32
|
+
} | {
|
|
33
|
+
success: false;
|
|
34
|
+
errors: z.ZodIssue[];
|
|
35
|
+
};
|
|
36
|
+
/** Validate an unknown value against the StateV1 schema. */
|
|
37
|
+
export declare function validateStateV1(value: unknown): ValidationResult;
|
|
38
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
// ---- Helpers -----------------------------------------------------------
|
|
3
|
+
/** Datetime: YYYY-MM-DD or YYYY-MM-DD HH:mm:ss. */
|
|
4
|
+
const dateTimeStr = () => z
|
|
5
|
+
.string()
|
|
6
|
+
.regex(/^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}:\d{2})?$/, 'Expected YYYY-MM-DD or YYYY-MM-DD HH:mm:ss');
|
|
7
|
+
const nullableDateTimeStr = () => dateTimeStr().nullable();
|
|
8
|
+
// ---- Concept schema ----------------------------------------------------
|
|
9
|
+
const conceptSchema = z.object({
|
|
10
|
+
name: z.string().min(1),
|
|
11
|
+
slug: z.string().min(1),
|
|
12
|
+
status: z.enum(['unexplored', 'in_progress', 'needs_practice', 'mastered']),
|
|
13
|
+
confidence: z.number().min(0).max(1),
|
|
14
|
+
practice_count: z.number().int().min(0),
|
|
15
|
+
explain_count: z.number().int().min(0),
|
|
16
|
+
last_explained: nullableDateTimeStr(),
|
|
17
|
+
last_practiced: nullableDateTimeStr(),
|
|
18
|
+
details: z.array(z.string()),
|
|
19
|
+
});
|
|
20
|
+
// ---- Domain schema -----------------------------------------------------
|
|
21
|
+
const domainSchema = z.object({
|
|
22
|
+
name: z.string().min(1),
|
|
23
|
+
slug: z.string().min(1),
|
|
24
|
+
concepts: z.array(conceptSchema),
|
|
25
|
+
});
|
|
26
|
+
// ---- Top-level StateV1 schema ------------------------------------------
|
|
27
|
+
export const stateV1Schema = z.object({
|
|
28
|
+
version: z.literal(1),
|
|
29
|
+
topic: z.string().min(1),
|
|
30
|
+
slug: z.string().min(1),
|
|
31
|
+
created: dateTimeStr(),
|
|
32
|
+
domains: z.array(domainSchema),
|
|
33
|
+
});
|
|
34
|
+
// ---- Public API ---------------------------------------------------------
|
|
35
|
+
/** Validate an unknown value against the StateV1 schema. */
|
|
36
|
+
export function validateStateV1(value) {
|
|
37
|
+
const result = stateV1Schema.safeParse(value);
|
|
38
|
+
if (result.success) {
|
|
39
|
+
return { success: true, data: result.data };
|
|
40
|
+
}
|
|
41
|
+
return { success: false, errors: result.error.issues };
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a stable kebab-case slug from a human-readable name.
|
|
3
|
+
*
|
|
4
|
+
* Rules (applied in order):
|
|
5
|
+
* 1. Replace `/` with `-`
|
|
6
|
+
* 2. Replace spaces with `-`
|
|
7
|
+
* 3. Remove characters that are NOT letters, digits, `-`, or `_`
|
|
8
|
+
* 4. Convert ASCII letters to lowercase; preserve non-ASCII characters
|
|
9
|
+
* 5. Collapse consecutive `-` into a single `-`
|
|
10
|
+
* 6. Trim leading / trailing `-`
|
|
11
|
+
*/
|
|
12
|
+
export declare function generateSlug(name: string): string;
|
|
13
|
+
//# sourceMappingURL=slug.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a stable kebab-case slug from a human-readable name.
|
|
3
|
+
*
|
|
4
|
+
* Rules (applied in order):
|
|
5
|
+
* 1. Replace `/` with `-`
|
|
6
|
+
* 2. Replace spaces with `-`
|
|
7
|
+
* 3. Remove characters that are NOT letters, digits, `-`, or `_`
|
|
8
|
+
* 4. Convert ASCII letters to lowercase; preserve non-ASCII characters
|
|
9
|
+
* 5. Collapse consecutive `-` into a single `-`
|
|
10
|
+
* 6. Trim leading / trailing `-`
|
|
11
|
+
*/
|
|
12
|
+
export function generateSlug(name) {
|
|
13
|
+
const slug = name
|
|
14
|
+
// 1. / → -
|
|
15
|
+
.replace(/\//g, '-')
|
|
16
|
+
// 2. space → -
|
|
17
|
+
.replace(/\s/g, '-')
|
|
18
|
+
// 3. Remove chars that are NOT [letter, digit, -, _]
|
|
19
|
+
.replace(/[^\p{L}\p{N}\-_]/gu, '')
|
|
20
|
+
// 4. ASCII letters to lowercase (preserves non-ASCII)
|
|
21
|
+
.replace(/[A-Z]/g, (ch) => ch.toLowerCase())
|
|
22
|
+
// 5. Collapse consecutive -
|
|
23
|
+
.replace(/-{2,}/g, '-')
|
|
24
|
+
// 6. Trim leading/trailing -
|
|
25
|
+
.replace(/^-+|-+$/g, '');
|
|
26
|
+
return slug;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=slug.js.map
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/** Valid status values for a concept's learning state. */
|
|
2
|
+
export type ConceptStatus = 'unexplored' | 'in_progress' | 'needs_practice' | 'mastered';
|
|
3
|
+
/** A third-level detail under a concept — plain name, no independent state. */
|
|
4
|
+
export type Detail = string;
|
|
5
|
+
/** A single concept within a domain — the minimum trackable unit. */
|
|
6
|
+
export interface Concept {
|
|
7
|
+
name: string;
|
|
8
|
+
slug: string;
|
|
9
|
+
status: ConceptStatus;
|
|
10
|
+
confidence: number;
|
|
11
|
+
practice_count: number;
|
|
12
|
+
explain_count: number;
|
|
13
|
+
last_explained: string | null;
|
|
14
|
+
last_practiced: string | null;
|
|
15
|
+
details: Detail[];
|
|
16
|
+
}
|
|
17
|
+
/** A top-level knowledge domain containing concepts. */
|
|
18
|
+
export interface Domain {
|
|
19
|
+
name: string;
|
|
20
|
+
slug: string;
|
|
21
|
+
concepts: Concept[];
|
|
22
|
+
}
|
|
23
|
+
/** state.json v1 top-level structure — the single source of truth. */
|
|
24
|
+
export interface StateV1 {
|
|
25
|
+
version: 1;
|
|
26
|
+
topic: string;
|
|
27
|
+
slug: string;
|
|
28
|
+
created: string;
|
|
29
|
+
domains: Domain[];
|
|
30
|
+
}
|
|
31
|
+
/** A single concept entry in v0 state.yaml. */
|
|
32
|
+
export interface V0Concept {
|
|
33
|
+
path: string;
|
|
34
|
+
status: string;
|
|
35
|
+
last_practiced: string | null;
|
|
36
|
+
practice_count: number;
|
|
37
|
+
confidence: number;
|
|
38
|
+
/** v0 used `last_session` — migrate maps it to `last_explained`. */
|
|
39
|
+
last_session?: string | null;
|
|
40
|
+
explain_count?: number;
|
|
41
|
+
}
|
|
42
|
+
/** Top-level shape of v0 state.yaml. */
|
|
43
|
+
export interface V0State {
|
|
44
|
+
topic: string;
|
|
45
|
+
created: string;
|
|
46
|
+
concepts: V0Concept[];
|
|
47
|
+
}
|
|
48
|
+
/** Parsed structure extracted from v0 knowledge-map.md. */
|
|
49
|
+
export interface ParsedConcept {
|
|
50
|
+
name: string;
|
|
51
|
+
children: string[];
|
|
52
|
+
}
|
|
53
|
+
/** A domain extracted from v0 knowledge-map.md. */
|
|
54
|
+
export interface ParsedDomain {
|
|
55
|
+
name: string;
|
|
56
|
+
concepts: ParsedConcept[];
|
|
57
|
+
}
|
|
58
|
+
/** Result of parsing a v0 knowledge-map.md. */
|
|
59
|
+
export interface ParsedKnowledgeMap {
|
|
60
|
+
topic: string;
|
|
61
|
+
domains: ParsedDomain[];
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1,11 +1,31 @@
|
|
|
1
1
|
import { getLearnTopicSkillTemplate, getLearnExplainSkillTemplate, getLearnPracticeSkillTemplate, getLearnReviewSkillTemplate, getLearnStatusSkillTemplate, getLearnTopicCommandTemplate, getLearnExplainCommandTemplate, getLearnPracticeCommandTemplate, getLearnReviewCommandTemplate, getLearnStatusCommandTemplate, } from '../templates/skill-templates.js';
|
|
2
2
|
export function getSkillTemplates() {
|
|
3
3
|
return [
|
|
4
|
-
{
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
{
|
|
5
|
+
template: getLearnTopicSkillTemplate(),
|
|
6
|
+
dirName: 'learn-anything-topic',
|
|
7
|
+
workflowId: 'topic',
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
template: getLearnExplainSkillTemplate(),
|
|
11
|
+
dirName: 'learn-anything-explain',
|
|
12
|
+
workflowId: 'explain',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
template: getLearnPracticeSkillTemplate(),
|
|
16
|
+
dirName: 'learn-anything-practice',
|
|
17
|
+
workflowId: 'practice',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
template: getLearnReviewSkillTemplate(),
|
|
21
|
+
dirName: 'learn-anything-review',
|
|
22
|
+
workflowId: 'review',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
template: getLearnStatusSkillTemplate(),
|
|
26
|
+
dirName: 'learn-anything-status',
|
|
27
|
+
workflowId: 'status',
|
|
28
|
+
},
|
|
9
29
|
];
|
|
10
30
|
}
|
|
11
31
|
export function getCommandTemplates() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
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';
|
|
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
7
|
//# sourceMappingURL=skill-templates.d.ts.map
|
|
@@ -1,6 +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';
|
|
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
6
|
//# sourceMappingURL=skill-templates.js.map
|