learn-anything-cli 0.3.0 → 0.4.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.
Files changed (34) hide show
  1. package/README.md +6 -0
  2. package/README.zh-CN.md +6 -0
  3. package/dist/cli/index.js +3 -0
  4. package/dist/core/init.d.ts +6 -0
  5. package/dist/core/init.js +67 -2
  6. package/dist/core/learn-protocol/index.d.ts +8 -0
  7. package/dist/core/learn-protocol/index.js +5 -0
  8. package/dist/core/learn-protocol/migrate.d.ts +52 -0
  9. package/dist/core/learn-protocol/migrate.js +259 -0
  10. package/dist/core/learn-protocol/parser.d.ts +33 -0
  11. package/dist/core/learn-protocol/parser.js +150 -0
  12. package/dist/core/learn-protocol/schema.d.ts +38 -0
  13. package/dist/core/learn-protocol/schema.js +43 -0
  14. package/dist/core/learn-protocol/slug.d.ts +13 -0
  15. package/dist/core/learn-protocol/slug.js +28 -0
  16. package/dist/core/learn-protocol/types.d.ts +63 -0
  17. package/dist/core/learn-protocol/types.js +2 -0
  18. package/dist/core/templates/context7-guidance.d.ts +13 -0
  19. package/dist/core/templates/context7-guidance.js +24 -0
  20. package/dist/core/templates/workflows/learn-explain.js +56 -139
  21. package/dist/core/templates/workflows/learn-practice.js +88 -284
  22. package/dist/core/templates/workflows/learn-review.js +35 -93
  23. package/dist/core/templates/workflows/learn-status.js +26 -69
  24. package/dist/core/templates/workflows/learn-topic.js +73 -82
  25. package/dist/i18n/locales/en.js +4 -0
  26. package/dist/i18n/locales/zh-CN.js +4 -0
  27. package/dist/i18n/types.d.ts +4 -0
  28. package/dist/scripts/render.d.mts +13 -0
  29. package/dist/scripts/render.mjs +112 -0
  30. package/dist/scripts/status.d.mts +31 -0
  31. package/dist/scripts/status.mjs +418 -0
  32. package/dist/scripts/utils.d.mts +43 -0
  33. package/dist/scripts/utils.mjs +124 -0
  34. package/package.json +4 -1
@@ -0,0 +1,124 @@
1
+ /**
2
+ * utils.mts — shared types, validation, and helpers for scripts.
3
+ *
4
+ * This file is compiled from src/scripts/utils.mts via tsc and
5
+ * copied into each skill's scripts/ directory by init/update.
6
+ * It MUST NOT import any project modules — only Node.js built-ins.
7
+ */
8
+ /* ------------------------------------------------------------------ */
9
+ /* Status display helpers */
10
+ /* ------------------------------------------------------------------ */
11
+ export const STATUS_ICON = {
12
+ mastered: '🟢',
13
+ in_progress: '🔵',
14
+ needs_practice: '🟠',
15
+ unexplored: '⚪',
16
+ };
17
+ export const STATUS_LABEL = {
18
+ mastered: 'mastered',
19
+ in_progress: 'in progress',
20
+ needs_practice: 'needs practice',
21
+ unexplored: 'unexplored',
22
+ };
23
+ /* ------------------------------------------------------------------ */
24
+ /* Text helpers */
25
+ /* ------------------------------------------------------------------ */
26
+ /** Escape underscores in text destined for Markdown output. */
27
+ export const esc = (s) => s.replace(/_/g, '\\_');
28
+ // ── Checker factories ────────────────────────────────────────────────
29
+ const literal = (expected) => (v) => v !== expected ? `Must be ${JSON.stringify(expected)}` : null;
30
+ const str = (min = 1) => (v) => typeof v !== 'string' || v.length < min
31
+ ? `Must be a non-empty string`
32
+ : null;
33
+ const num = (opts) => (v) => {
34
+ if (typeof v !== 'number')
35
+ return 'Must be a number';
36
+ if (opts?.min !== undefined && v < opts.min)
37
+ return `Must be >= ${opts.min}`;
38
+ if (opts?.max !== undefined && v > opts.max)
39
+ return `Must be <= ${opts.max}`;
40
+ if (opts?.int && !Number.isInteger(v))
41
+ return 'Must be an integer';
42
+ return null;
43
+ };
44
+ const DATE_RE = /^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}:\d{2})?$/;
45
+ const dateStr = (v) => typeof v !== 'string' || !DATE_RE.test(v)
46
+ ? 'Must match YYYY-MM-DD or YYYY-MM-DD HH:mm:ss'
47
+ : null;
48
+ const nullable = (inner) => (v) => v === null ? null : inner(v);
49
+ const arr = (itemChecker) => (v) => {
50
+ if (!Array.isArray(v))
51
+ return 'Must be an array';
52
+ if (itemChecker)
53
+ for (const item of v) {
54
+ const err = itemChecker(item);
55
+ if (err)
56
+ return err;
57
+ }
58
+ return null;
59
+ };
60
+ const oneOf = (...values) => (v) => !values.includes(v) ? `Must be one of: ${values.join(', ')}` : null;
61
+ // ── Validation schemas ───────────────────────────────────────────────
62
+ const STATE_RULES = {
63
+ version: literal(1),
64
+ topic: str(),
65
+ slug: str(),
66
+ created: dateStr,
67
+ domains: arr(),
68
+ };
69
+ const DOMAIN_RULES = {
70
+ name: str(),
71
+ slug: str(),
72
+ concepts: arr(),
73
+ };
74
+ const CONCEPT_RULES = {
75
+ name: str(),
76
+ slug: str(),
77
+ status: oneOf('unexplored', 'in_progress', 'needs_practice', 'mastered'),
78
+ confidence: num({ min: 0, max: 1 }),
79
+ practice_count: num({ min: 0, int: true }),
80
+ explain_count: num({ min: 0, int: true }),
81
+ last_explained: nullable(dateStr),
82
+ last_practiced: nullable(dateStr),
83
+ details: arr(str()),
84
+ };
85
+ // ── Core engine ──────────────────────────────────────────────────────
86
+ function checkFields(obj, rules, prefix, errors) {
87
+ if (obj === null || typeof obj !== 'object')
88
+ return;
89
+ const record = obj;
90
+ for (const [key, checker] of Object.entries(rules)) {
91
+ const msg = checker(record[key]);
92
+ if (msg)
93
+ errors.push({ path: prefix ? `${prefix}.${key}` : key, message: msg });
94
+ }
95
+ }
96
+ export function validateStateV1(data) {
97
+ if (data === null || typeof data !== 'object' || Array.isArray(data))
98
+ return [{ path: '', message: 'Expected a non-null object' }];
99
+ const errors = [];
100
+ checkFields(data, STATE_RULES, '', errors);
101
+ if (Array.isArray(data.domains)) {
102
+ const domains = data.domains;
103
+ for (const [di, domain] of domains.entries()) {
104
+ const dp = `domains[${di}]`;
105
+ checkFields(domain, DOMAIN_RULES, dp, errors);
106
+ if (Array.isArray(domain.concepts)) {
107
+ const concepts = domain.concepts;
108
+ for (const [ci, concept] of concepts.entries())
109
+ checkFields(concept, CONCEPT_RULES, `${dp}.concepts[${ci}]`, errors);
110
+ }
111
+ }
112
+ }
113
+ return errors;
114
+ }
115
+ /* ------------------------------------------------------------------ */
116
+ /* Helpers */
117
+ /* ------------------------------------------------------------------ */
118
+ export function totalCount(state) {
119
+ return state.domains.reduce((sum, d) => sum + d.concepts.length, 0);
120
+ }
121
+ export function masteredCount(state) {
122
+ return state.domains.reduce((sum, d) => sum + d.concepts.filter((c) => c.status === 'mastered').length, 0);
123
+ }
124
+ //# sourceMappingURL=utils.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "learn-anything-cli",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "AI-powered recursive learning system with Socratic method and TDD practice",
5
5
  "keywords": [
6
6
  "learn-anything-cli",
@@ -58,6 +58,7 @@
58
58
  "@commitlint/cli": "^21.0.2",
59
59
  "@commitlint/config-conventional": "^21.0.2",
60
60
  "@eslint/js": "^10.0.1",
61
+ "@types/mdast": "^4.0.4",
61
62
  "@types/node": "^24.2.0",
62
63
  "eslint": "^9.39.2",
63
64
  "eslint-config-prettier": "^10.1.8",
@@ -73,6 +74,8 @@
73
74
  "chalk": "^5.5.0",
74
75
  "commander": "^14.0.0",
75
76
  "fast-glob": "^3.3.3",
77
+ "remark-parse": "^11.0.0",
78
+ "unified": "^11.0.5",
76
79
  "yaml": "^2.8.2",
77
80
  "zod": "^4.0.17"
78
81
  },