learngraph 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.
Files changed (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +25 -0
  3. package/dist/cjs/education/index.js +18 -0
  4. package/dist/cjs/education/index.js.map +1 -0
  5. package/dist/cjs/graph/index.js +14 -0
  6. package/dist/cjs/graph/index.js.map +1 -0
  7. package/dist/cjs/index.js +61 -0
  8. package/dist/cjs/index.js.map +1 -0
  9. package/dist/cjs/llm/index.js +12 -0
  10. package/dist/cjs/llm/index.js.map +1 -0
  11. package/dist/cjs/parsers/index.js +11 -0
  12. package/dist/cjs/parsers/index.js.map +1 -0
  13. package/dist/cjs/query/index.js +12 -0
  14. package/dist/cjs/query/index.js.map +1 -0
  15. package/dist/cjs/storage/index.js +12 -0
  16. package/dist/cjs/storage/index.js.map +1 -0
  17. package/dist/cjs/types/bloom.js +174 -0
  18. package/dist/cjs/types/bloom.js.map +1 -0
  19. package/dist/cjs/types/edge.js +42 -0
  20. package/dist/cjs/types/edge.js.map +1 -0
  21. package/dist/cjs/types/graph.js +8 -0
  22. package/dist/cjs/types/graph.js.map +1 -0
  23. package/dist/cjs/types/index.js +32 -0
  24. package/dist/cjs/types/index.js.map +1 -0
  25. package/dist/cjs/types/mastery.js +31 -0
  26. package/dist/cjs/types/mastery.js.map +1 -0
  27. package/dist/cjs/types/query.js +3 -0
  28. package/dist/cjs/types/query.js.map +1 -0
  29. package/dist/cjs/types/skill.js +38 -0
  30. package/dist/cjs/types/skill.js.map +1 -0
  31. package/dist/cjs/types/storage.js +3 -0
  32. package/dist/cjs/types/storage.js.map +1 -0
  33. package/dist/esm/education/index.js +12 -0
  34. package/dist/esm/education/index.js.map +1 -0
  35. package/dist/esm/graph/index.js +10 -0
  36. package/dist/esm/graph/index.js.map +1 -0
  37. package/dist/esm/index.js +44 -0
  38. package/dist/esm/index.js.map +1 -0
  39. package/dist/esm/llm/index.js +12 -0
  40. package/dist/esm/llm/index.js.map +1 -0
  41. package/dist/esm/parsers/index.js +11 -0
  42. package/dist/esm/parsers/index.js.map +1 -0
  43. package/dist/esm/query/index.js +11 -0
  44. package/dist/esm/query/index.js.map +1 -0
  45. package/dist/esm/storage/index.js +11 -0
  46. package/dist/esm/storage/index.js.map +1 -0
  47. package/dist/esm/types/bloom.js +168 -0
  48. package/dist/esm/types/bloom.js.map +1 -0
  49. package/dist/esm/types/edge.js +36 -0
  50. package/dist/esm/types/edge.js.map +1 -0
  51. package/dist/esm/types/graph.js +5 -0
  52. package/dist/esm/types/graph.js.map +1 -0
  53. package/dist/esm/types/index.js +11 -0
  54. package/dist/esm/types/index.js.map +1 -0
  55. package/dist/esm/types/mastery.js +26 -0
  56. package/dist/esm/types/mastery.js.map +1 -0
  57. package/dist/esm/types/query.js +2 -0
  58. package/dist/esm/types/query.js.map +1 -0
  59. package/dist/esm/types/skill.js +32 -0
  60. package/dist/esm/types/skill.js.map +1 -0
  61. package/dist/esm/types/storage.js +2 -0
  62. package/dist/esm/types/storage.js.map +1 -0
  63. package/dist/types/education/index.d.ts +8 -0
  64. package/dist/types/education/index.d.ts.map +1 -0
  65. package/dist/types/graph/index.d.ts +8 -0
  66. package/dist/types/graph/index.d.ts.map +1 -0
  67. package/dist/types/index.d.ts +38 -0
  68. package/dist/types/index.d.ts.map +1 -0
  69. package/dist/types/llm/index.d.ts +6 -0
  70. package/dist/types/llm/index.d.ts.map +1 -0
  71. package/dist/types/parsers/index.d.ts +6 -0
  72. package/dist/types/parsers/index.d.ts.map +1 -0
  73. package/dist/types/query/index.d.ts +7 -0
  74. package/dist/types/query/index.d.ts.map +1 -0
  75. package/dist/types/storage/index.d.ts +7 -0
  76. package/dist/types/storage/index.d.ts.map +1 -0
  77. package/dist/types/types/bloom.d.ts +33 -0
  78. package/dist/types/types/bloom.d.ts.map +1 -0
  79. package/dist/types/types/edge.d.ts +80 -0
  80. package/dist/types/types/edge.d.ts.map +1 -0
  81. package/dist/types/types/graph.d.ts +99 -0
  82. package/dist/types/types/graph.d.ts.map +1 -0
  83. package/dist/types/types/index.d.ts +18 -0
  84. package/dist/types/types/index.d.ts.map +1 -0
  85. package/dist/types/types/mastery.d.ts +89 -0
  86. package/dist/types/types/mastery.d.ts.map +1 -0
  87. package/dist/types/types/query.d.ts +155 -0
  88. package/dist/types/types/query.d.ts.map +1 -0
  89. package/dist/types/types/skill.d.ts +107 -0
  90. package/dist/types/types/skill.d.ts.map +1 -0
  91. package/dist/types/types/storage.d.ts +214 -0
  92. package/dist/types/types/storage.d.ts.map +1 -0
  93. package/package.json +149 -0
@@ -0,0 +1,80 @@
1
+ import type { SkillId } from './skill.js';
2
+ /**
3
+ * Unique identifier for edges
4
+ */
5
+ export type EdgeId = string & {
6
+ readonly __brand: unique symbol;
7
+ };
8
+ /**
9
+ * Create a typed EdgeId from a string
10
+ */
11
+ export declare function createEdgeId(id: string): EdgeId;
12
+ /**
13
+ * Types of prerequisite relationships
14
+ */
15
+ export type EdgeType =
16
+ /** Absolutely required - cannot learn target without mastering this first */
17
+ 'hard'
18
+ /** Important but not blocking - will struggle without it */
19
+ | 'soft'
20
+ /** Enhances learning but is optional */
21
+ | 'recommended';
22
+ /**
23
+ * Prerequisite edge representing a dependency between skills.
24
+ *
25
+ * Direction: source (prerequisite) -> target (dependent skill)
26
+ * Meaning: "You should master {source} before learning {target}"
27
+ */
28
+ export interface PrerequisiteEdge {
29
+ /** Unique identifier for the edge */
30
+ id: EdgeId;
31
+ /** The prerequisite skill ID (what should be learned first) */
32
+ sourceId: SkillId;
33
+ /** The dependent skill ID (what requires the prerequisite) */
34
+ targetId: SkillId;
35
+ /**
36
+ * Strength of the dependency (0-1 scale)
37
+ * - 1.0: Absolutely essential
38
+ * - 0.7-0.9: Very important
39
+ * - 0.4-0.6: Helpful but not critical
40
+ * - 0.1-0.3: Nice to have
41
+ */
42
+ strength: number;
43
+ /** Type of prerequisite relationship */
44
+ type: EdgeType;
45
+ /**
46
+ * Optional reasoning for why this relationship exists
47
+ * Useful for debugging and educator review
48
+ */
49
+ reasoning?: string;
50
+ /** Arbitrary metadata for extensibility */
51
+ metadata: Record<string, unknown>;
52
+ /** ISO 8601 timestamp of creation */
53
+ createdAt: string;
54
+ }
55
+ /**
56
+ * Input for creating a new edge (without generated fields)
57
+ */
58
+ export type PrerequisiteEdgeInput = Omit<PrerequisiteEdge, 'id' | 'createdAt'> & {
59
+ id?: EdgeId;
60
+ };
61
+ /**
62
+ * Default edge strength thresholds
63
+ */
64
+ export declare const EDGE_STRENGTH_THRESHOLDS: {
65
+ /** Minimum strength to be considered a meaningful dependency */
66
+ readonly minimum: 0.3;
67
+ /** Strength threshold for "hard" prerequisites */
68
+ readonly hard: 0.8;
69
+ /** Strength threshold for "soft" prerequisites */
70
+ readonly soft: 0.5;
71
+ };
72
+ /**
73
+ * Validate an edge strength is in valid range
74
+ */
75
+ export declare function isValidEdgeStrength(strength: number): boolean;
76
+ /**
77
+ * Suggest edge type based on strength
78
+ */
79
+ export declare function suggestEdgeType(strength: number): EdgeType;
80
+ //# sourceMappingURL=edge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge.d.ts","sourceRoot":"","sources":["../../../src/types/edge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,MAAM,CAAA;CAAE,CAAC;AAElE;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;GAEG;AACH,MAAM,MAAM,QAAQ;AAClB,6EAA6E;AAC3E,MAAM;AACR,4DAA4D;GAC1D,MAAM;AACR,wCAAwC;GACtC,aAAa,CAAC;AAElB;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qCAAqC;IACrC,EAAE,EAAE,MAAM,CAAC;IAEX,+DAA+D;IAC/D,QAAQ,EAAE,OAAO,CAAC;IAElB,8DAA8D;IAC9D,QAAQ,EAAE,OAAO,CAAC;IAElB;;;;;;OAMG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB,wCAAwC;IACxC,IAAI,EAAE,QAAQ,CAAC;IAEf;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAElC,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,gBAAgB,EAAE,IAAI,GAAG,WAAW,CAAC,GAAG;IAC/E,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wBAAwB;IACnC,gEAAgE;;IAEhE,kDAAkD;;IAElD,kDAAkD;;CAE1C,CAAC;AAEX;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAQ1D"}
@@ -0,0 +1,99 @@
1
+ import type { SkillNode, SkillId } from './skill.js';
2
+ import type { PrerequisiteEdge, EdgeId } from './edge.js';
3
+ /**
4
+ * A subgraph extracted from the full knowledge graph
5
+ */
6
+ export interface Subgraph {
7
+ /** Root node ID that the subgraph was extracted from */
8
+ rootId: SkillId;
9
+ /** Depth of traversal from root */
10
+ depth: number;
11
+ /** All nodes in the subgraph */
12
+ nodes: SkillNode[];
13
+ /** All edges in the subgraph */
14
+ edges: PrerequisiteEdge[];
15
+ }
16
+ /**
17
+ * Complete graph export format
18
+ */
19
+ export interface GraphExport {
20
+ /** Schema version for compatibility */
21
+ version: string;
22
+ /** Export timestamp */
23
+ exportedAt: string;
24
+ /** All skill nodes */
25
+ nodes: SkillNode[];
26
+ /** All prerequisite edges */
27
+ edges: PrerequisiteEdge[];
28
+ /** Optional metadata about the graph */
29
+ metadata?: {
30
+ name?: string;
31
+ description?: string;
32
+ domain?: string;
33
+ source?: string;
34
+ };
35
+ }
36
+ /**
37
+ * Graph statistics for analysis
38
+ */
39
+ export interface GraphStats {
40
+ /** Total number of skill nodes */
41
+ nodeCount: number;
42
+ /** Total number of prerequisite edges */
43
+ edgeCount: number;
44
+ /** Number of threshold concepts */
45
+ thresholdConceptCount: number;
46
+ /** Number of root nodes (no prerequisites) */
47
+ rootNodeCount: number;
48
+ /** Number of leaf nodes (no dependents) */
49
+ leafNodeCount: number;
50
+ /** Maximum depth of the graph */
51
+ maxDepth: number;
52
+ /** Average number of prerequisites per skill */
53
+ avgPrerequisites: number;
54
+ /** Average number of dependents per skill */
55
+ avgDependents: number;
56
+ /** Distribution of Bloom's levels */
57
+ bloomDistribution: Record<string, number>;
58
+ /** Distribution of difficulty levels */
59
+ difficultyDistribution: {
60
+ foundational: number;
61
+ basic: number;
62
+ intermediate: number;
63
+ advanced: number;
64
+ expert: number;
65
+ };
66
+ }
67
+ /**
68
+ * Result of graph validation
69
+ */
70
+ export interface GraphValidation {
71
+ /** Whether the graph is valid */
72
+ isValid: boolean;
73
+ /** List of validation errors */
74
+ errors: GraphValidationError[];
75
+ /** List of validation warnings */
76
+ warnings: GraphValidationWarning[];
77
+ }
78
+ /**
79
+ * Graph validation error (prevents use)
80
+ */
81
+ export interface GraphValidationError {
82
+ type: 'cycle_detected' | 'orphan_edge' | 'duplicate_node' | 'duplicate_edge' | 'self_reference' | 'invalid_bloom_level' | 'invalid_difficulty';
83
+ message: string;
84
+ nodeIds?: SkillId[];
85
+ edgeIds?: EdgeId[];
86
+ }
87
+ /**
88
+ * Graph validation warning (degraded experience)
89
+ */
90
+ export interface GraphValidationWarning {
91
+ type: 'disconnected_component' | 'very_deep_path' | 'high_in_degree' | 'missing_threshold_scaffolds' | 'inconsistent_difficulty';
92
+ message: string;
93
+ nodeIds?: SkillId[];
94
+ }
95
+ /**
96
+ * Current graph version for exports
97
+ */
98
+ export declare const GRAPH_VERSION = "1.0.0";
99
+ //# sourceMappingURL=graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../../src/types/graph.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,wDAAwD;IACxD,MAAM,EAAE,OAAO,CAAC;IAEhB,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IAEd,gCAAgC;IAChC,KAAK,EAAE,SAAS,EAAE,CAAC;IAEnB,gCAAgC;IAChC,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAEhB,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAC;IAEnB,sBAAsB;IACtB,KAAK,EAAE,SAAS,EAAE,CAAC;IAEnB,6BAA6B;IAC7B,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAE1B,wCAAwC;IACxC,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;IAElB,yCAAyC;IACzC,SAAS,EAAE,MAAM,CAAC;IAElB,mCAAmC;IACnC,qBAAqB,EAAE,MAAM,CAAC;IAE9B,8CAA8C;IAC9C,aAAa,EAAE,MAAM,CAAC;IAEtB,2CAA2C;IAC3C,aAAa,EAAE,MAAM,CAAC;IAEtB,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;IAEjB,gDAAgD;IAChD,gBAAgB,EAAE,MAAM,CAAC;IAEzB,6CAA6C;IAC7C,aAAa,EAAE,MAAM,CAAC;IAEtB,qCAAqC;IACrC,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE1C,wCAAwC;IACxC,sBAAsB,EAAE;QACtB,YAAY,EAAE,MAAM,CAAC;QACrB,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,iCAAiC;IACjC,OAAO,EAAE,OAAO,CAAC;IAEjB,gCAAgC;IAChC,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAE/B,kCAAkC;IAClC,QAAQ,EAAE,sBAAsB,EAAE,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EACA,gBAAgB,GAChB,aAAa,GACb,gBAAgB,GAChB,gBAAgB,GAChB,gBAAgB,GAChB,qBAAqB,GACrB,oBAAoB,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,EACA,wBAAwB,GACxB,gBAAgB,GAChB,gBAAgB,GAChB,6BAA6B,GAC7B,yBAAyB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,UAAU,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Core type definitions for LearnGraph (jali)
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ export type { BloomLevel } from './bloom.js';
7
+ export { BLOOM_LEVEL_ORDER, BLOOM_VERBS, detectBloomLevel, compareBloomLevels, meetsBloomThreshold, } from './bloom.js';
8
+ export type { SkillId, SkillNode, SkillNodeInput, SkillNodeUpdate } from './skill.js';
9
+ export { createSkillId, SKILL_DEFAULTS, THRESHOLD_CONCEPT_MASTERY, isValidDifficulty, isValidMasteryThreshold, } from './skill.js';
10
+ export type { EdgeId, EdgeType, PrerequisiteEdge, PrerequisiteEdgeInput } from './edge.js';
11
+ export { createEdgeId, EDGE_STRENGTH_THRESHOLDS, isValidEdgeStrength, suggestEdgeType, } from './edge.js';
12
+ export type { MasteryState, ResponseRecord, MasteryTrajectory } from './mastery.js';
13
+ export { MASTERY_THRESHOLDS, hasMastery, masteryGap } from './mastery.js';
14
+ export type { Subgraph, GraphExport, GraphStats, GraphValidation, GraphValidationError, GraphValidationWarning, } from './graph.js';
15
+ export { GRAPH_VERSION } from './graph.js';
16
+ export type { QueryOperator, QueryFilter, QuerySort, QueryPagination, SkillQuery, ZPDResult, LearningPath, LearningSession, ReviewSchedule, ReviewItem, ZPDOptions, PathOptions, ReviewOptions, } from './query.js';
17
+ export type { StorageBackend, StorageConfigBase, Neo4jConfig, LevelGraphConfig, MemoryConfig, StorageConfig, ConnectionStatus, ImportResult, GraphStorage, StorageFactory, } from './storage.js';
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EACL,iBAAiB,EACjB,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAKpB,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACtF,OAAO,EACL,aAAa,EACb,cAAc,EACd,yBAAyB,EACzB,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,YAAY,CAAC;AAKpB,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAC3F,OAAO,EACL,YAAY,EACZ,wBAAwB,EACxB,mBAAmB,EACnB,eAAe,GAChB,MAAM,WAAW,CAAC;AAKnB,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAK1E,YAAY,EACV,QAAQ,EACR,WAAW,EACX,UAAU,EACV,eAAe,EACf,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAK3C,YAAY,EACV,aAAa,EACb,WAAW,EACX,SAAS,EACT,eAAe,EACf,UAAU,EACV,SAAS,EACT,YAAY,EACZ,eAAe,EACf,cAAc,EACd,UAAU,EACV,UAAU,EACV,WAAW,EACX,aAAa,GACd,MAAM,YAAY,CAAC;AAKpB,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,cAAc,GACf,MAAM,cAAc,CAAC"}
@@ -0,0 +1,89 @@
1
+ import type { SkillId } from './skill.js';
2
+ /**
3
+ * Mastery state for a learner on a specific skill.
4
+ *
5
+ * This is the primary interface for tracking learner progress.
6
+ * Note: LearnGraph stores the graph structure, not learner data.
7
+ * This interface is provided for consuming applications.
8
+ */
9
+ export interface MasteryState {
10
+ /** The skill this mastery state refers to */
11
+ skillId: SkillId;
12
+ /**
13
+ * Current mastery estimate (0-1 scale)
14
+ * Updated via BKT or similar algorithm
15
+ */
16
+ mastery: number;
17
+ /** Timestamp of last practice attempt */
18
+ lastAttempt: Date | null;
19
+ /** Total number of practice attempts */
20
+ attempts: number;
21
+ /** Consecutive correct responses (for streak tracking) */
22
+ streak: number;
23
+ /**
24
+ * Spaced repetition interval (in milliseconds)
25
+ * Time until next recommended review
26
+ */
27
+ nextReviewInterval?: number;
28
+ /**
29
+ * SM-2 easiness factor (1.3 - 2.5)
30
+ * Used for spaced repetition calculations
31
+ */
32
+ easinessFactor?: number;
33
+ }
34
+ /**
35
+ * Response record for a single practice attempt
36
+ */
37
+ export interface ResponseRecord {
38
+ /** Skill being practiced */
39
+ skillId: SkillId;
40
+ /** Whether the response was correct */
41
+ correct: boolean;
42
+ /** Timestamp of the response */
43
+ timestamp: Date;
44
+ /** Time taken to respond (in milliseconds) */
45
+ responseTimeMs?: number;
46
+ /** Selected answer (for wrong answer analysis) */
47
+ selectedAnswer?: string;
48
+ /** Correct answer (for comparison) */
49
+ correctAnswer?: string;
50
+ /** Item/question identifier */
51
+ itemId?: string;
52
+ /** Session identifier for grouping responses */
53
+ sessionId?: string;
54
+ }
55
+ /**
56
+ * Mastery trajectory showing progression over time
57
+ */
58
+ export interface MasteryTrajectory {
59
+ /** Mastery values after each response */
60
+ trajectory: number[];
61
+ /** Final mastery value */
62
+ finalMastery: number;
63
+ /** Whether mastery threshold was achieved */
64
+ masteryAchieved: boolean;
65
+ /** Estimated responses until mastery (null if uncertain) */
66
+ responsesUntilMastery: number | null;
67
+ }
68
+ /**
69
+ * Mastery threshold values
70
+ */
71
+ export declare const MASTERY_THRESHOLDS: {
72
+ /** Default mastery threshold for standard skills */
73
+ readonly default: 0.8;
74
+ /** Mastery threshold for threshold concepts */
75
+ readonly thresholdConcept: 0.9;
76
+ /** Minimum mastery to be considered "learned" */
77
+ readonly minimum: 0.5;
78
+ /** High mastery for expert-level */
79
+ readonly expert: 0.95;
80
+ };
81
+ /**
82
+ * Check if mastery level meets threshold
83
+ */
84
+ export declare function hasMastery(mastery: number, threshold?: number): boolean;
85
+ /**
86
+ * Calculate mastery gap (how much more is needed)
87
+ */
88
+ export declare function masteryGap(current: number, threshold?: number): number;
89
+ //# sourceMappingURL=mastery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mastery.d.ts","sourceRoot":"","sources":["../../../src/types/mastery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,6CAA6C;IAC7C,OAAO,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB,yCAAyC;IACzC,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;IAEzB,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;IAEjB,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,4BAA4B;IAC5B,OAAO,EAAE,OAAO,CAAC;IAEjB,uCAAuC;IACvC,OAAO,EAAE,OAAO,CAAC;IAEjB,gCAAgC;IAChC,SAAS,EAAE,IAAI,CAAC;IAEhB,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,sCAAsC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,+BAA+B;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,UAAU,EAAE,MAAM,EAAE,CAAC;IAErB,0BAA0B;IAC1B,YAAY,EAAE,MAAM,CAAC;IAErB,6CAA6C;IAC7C,eAAe,EAAE,OAAO,CAAC;IAEzB,4DAA4D;IAC5D,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB;IAC7B,oDAAoD;;IAEpD,+CAA+C;;IAE/C,iDAAiD;;IAEjD,oCAAoC;;CAE5B,CAAC;AAEX;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,GAAE,MAAmC,GAAG,OAAO,CAEnG;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,GAAE,MAAmC,GAAG,MAAM,CAElG"}
@@ -0,0 +1,155 @@
1
+ import type { SkillNode, SkillId } from './skill.js';
2
+ /**
3
+ * Query operators for filtering
4
+ */
5
+ export type QueryOperator = 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'nin' | 'contains' | 'startsWith' | 'endsWith';
6
+ /**
7
+ * Single filter condition
8
+ */
9
+ export interface QueryFilter {
10
+ field: keyof SkillNode | string;
11
+ operator: QueryOperator;
12
+ value: unknown;
13
+ }
14
+ /**
15
+ * Sort specification
16
+ */
17
+ export interface QuerySort {
18
+ field: keyof SkillNode | string;
19
+ direction: 'asc' | 'desc';
20
+ }
21
+ /**
22
+ * Pagination parameters
23
+ */
24
+ export interface QueryPagination {
25
+ offset: number;
26
+ limit: number;
27
+ }
28
+ /**
29
+ * Complete skill query specification
30
+ */
31
+ export interface SkillQuery {
32
+ filters: QueryFilter[];
33
+ sorting: QuerySort[];
34
+ pagination: QueryPagination;
35
+ }
36
+ /**
37
+ * ZPD (Zone of Proximal Development) calculation result
38
+ */
39
+ export interface ZPDResult {
40
+ /**
41
+ * Skills in the ZPD - ready to learn
42
+ * Prerequisites met, not yet mastered
43
+ */
44
+ zpd: SkillNode[];
45
+ /**
46
+ * Skills that are "ready" (in ZPD and within difficulty tolerance)
47
+ */
48
+ ready: SkillNode[];
49
+ /**
50
+ * Skills blocked by unmet prerequisites
51
+ * Map of skill ID -> list of unmet prerequisite names
52
+ */
53
+ blocked: Map<SkillId, string[]>;
54
+ /** Summary statistics */
55
+ stats: {
56
+ totalSkills: number;
57
+ mastered: number;
58
+ inZPD: number;
59
+ blocked: number;
60
+ };
61
+ }
62
+ /**
63
+ * Learning path from current state to target skill
64
+ */
65
+ export interface LearningPath {
66
+ /** Target skill */
67
+ target: SkillNode;
68
+ /** Ordered list of skills to learn */
69
+ skills: SkillNode[];
70
+ /** Total estimated time in minutes */
71
+ totalMinutes: number;
72
+ /** Skills grouped into suggested sessions */
73
+ sessions: LearningSession[];
74
+ /** Key checkpoint skills along the path */
75
+ checkpoints: SkillNode[];
76
+ }
77
+ /**
78
+ * A single learning session (grouping of skills)
79
+ */
80
+ export interface LearningSession {
81
+ /** Session number (1-indexed) */
82
+ sessionNumber: number;
83
+ /** Skills in this session */
84
+ skills: SkillNode[];
85
+ /** Estimated duration in minutes */
86
+ durationMinutes: number;
87
+ /** Focus area or theme for the session */
88
+ focus?: string;
89
+ }
90
+ /**
91
+ * Review schedule for spaced repetition
92
+ */
93
+ export interface ReviewSchedule {
94
+ /** Skills due for review now */
95
+ dueNow: ReviewItem[];
96
+ /** Upcoming reviews (scheduled but not yet due) */
97
+ upcoming: ReviewItem[];
98
+ /** Total estimated review time in minutes */
99
+ totalReviewMinutes: number;
100
+ }
101
+ /**
102
+ * Single review item
103
+ */
104
+ export interface ReviewItem {
105
+ /** Skill to review */
106
+ skill: SkillNode;
107
+ /** Current mastery state */
108
+ state: {
109
+ mastery: number;
110
+ lastAttempt: Date | null;
111
+ streak: number;
112
+ };
113
+ /** When the review is due */
114
+ nextReview: Date;
115
+ /** Priority score for ordering (higher = more urgent) */
116
+ priority: number;
117
+ }
118
+ /**
119
+ * Options for ZPD calculation
120
+ */
121
+ export interface ZPDOptions {
122
+ /** Difficulty tolerance above learner level (default: 0.2) */
123
+ difficultyTolerance?: number;
124
+ /** Whether to prioritize threshold concepts (default: true) */
125
+ prioritizeThresholdConcepts?: boolean;
126
+ /** Maximum number of skills to return in ZPD (default: unlimited) */
127
+ maxResults?: number;
128
+ /** Filter to specific tags */
129
+ filterTags?: string[];
130
+ /** Filter to specific domain */
131
+ filterDomain?: string;
132
+ }
133
+ /**
134
+ * Options for learning path generation
135
+ */
136
+ export interface PathOptions {
137
+ /** Target session length in minutes (default: 30) */
138
+ sessionMinutes?: number;
139
+ /** Maximum total path length in skills (default: unlimited) */
140
+ maxPathLength?: number;
141
+ /** Whether to include already-mastered skills for review (default: false) */
142
+ includeReview?: boolean;
143
+ }
144
+ /**
145
+ * Options for review schedule generation
146
+ */
147
+ export interface ReviewOptions {
148
+ /** Include upcoming reviews (not just due now) */
149
+ includeUpcoming?: boolean;
150
+ /** How far ahead to look for upcoming reviews (in days) */
151
+ upcomingDays?: number;
152
+ /** Maximum number of reviews to return */
153
+ maxReviews?: number;
154
+ }
155
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../src/types/query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ import type { BloomLevel } from './bloom.js';
2
+ /**
3
+ * Unique identifier for skills
4
+ */
5
+ export type SkillId = string & {
6
+ readonly __brand: unique symbol;
7
+ };
8
+ /**
9
+ * Create a typed SkillId from a string
10
+ */
11
+ export declare function createSkillId(id: string): SkillId;
12
+ /**
13
+ * Core skill node representing a discrete, teachable competency.
14
+ *
15
+ * This is the primary vertex type in the knowledge graph.
16
+ * Each skill represents something a learner can master.
17
+ */
18
+ export interface SkillNode {
19
+ /** Unique identifier for the skill */
20
+ id: SkillId;
21
+ /** Concise name (3-8 words recommended) */
22
+ name: string;
23
+ /** Detailed description of what mastery looks like */
24
+ description: string;
25
+ /** Bloom's Taxonomy cognitive level */
26
+ bloomLevel: BloomLevel;
27
+ /**
28
+ * Normalized difficulty score (0-1 scale)
29
+ * - 0.0-0.2: Foundational/introductory
30
+ * - 0.2-0.4: Basic
31
+ * - 0.4-0.6: Intermediate
32
+ * - 0.6-0.8: Advanced
33
+ * - 0.8-1.0: Expert/mastery-level
34
+ */
35
+ difficulty: number;
36
+ /**
37
+ * Whether this is a threshold concept.
38
+ *
39
+ * Threshold concepts are transformative ideas that:
40
+ * - Fundamentally change understanding
41
+ * - Expose previously hidden interrelations
42
+ * - Are unlikely to be forgotten once learned
43
+ * - May be initially counter-intuitive
44
+ *
45
+ * @see Meyer & Land (2003)
46
+ */
47
+ isThresholdConcept: boolean;
48
+ /**
49
+ * Mastery threshold required before progression (0-1 scale)
50
+ * - Default: 0.80 (80%)
51
+ * - Threshold concepts: 0.90 (90%)
52
+ */
53
+ masteryThreshold: number;
54
+ /**
55
+ * Estimated time to achieve mastery (in minutes)
56
+ * Based on typical learner, includes practice time
57
+ */
58
+ estimatedMinutes: number;
59
+ /** Categorization tags for filtering and organization */
60
+ tags: string[];
61
+ /**
62
+ * Optional standard alignment (Common Core, NGSS, etc.)
63
+ * Format: "STANDARD_CODE" (e.g., "CCSS.MATH.6.EE.A.2")
64
+ */
65
+ standardAlignment?: string[];
66
+ /**
67
+ * Subject domain (e.g., "mathematics", "physics", "programming")
68
+ */
69
+ domain?: string;
70
+ /**
71
+ * Grade level or audience (e.g., "6", "undergraduate", "professional")
72
+ */
73
+ gradeLevel?: string;
74
+ /** Arbitrary metadata for extensibility */
75
+ metadata: Record<string, unknown>;
76
+ /** ISO 8601 timestamp of creation */
77
+ createdAt: string;
78
+ /** ISO 8601 timestamp of last update */
79
+ updatedAt: string;
80
+ }
81
+ /**
82
+ * Input for creating a new skill (without generated fields)
83
+ */
84
+ export type SkillNodeInput = Omit<SkillNode, 'id' | 'createdAt' | 'updatedAt'> & {
85
+ id?: SkillId;
86
+ };
87
+ /**
88
+ * Partial update for an existing skill
89
+ */
90
+ export type SkillNodeUpdate = Partial<Omit<SkillNode, 'id' | 'createdAt' | 'updatedAt'>>;
91
+ /**
92
+ * Default values for optional skill fields
93
+ */
94
+ export declare const SKILL_DEFAULTS: Pick<SkillNode, 'masteryThreshold' | 'isThresholdConcept' | 'tags' | 'metadata'>;
95
+ /**
96
+ * Mastery threshold for threshold concepts
97
+ */
98
+ export declare const THRESHOLD_CONCEPT_MASTERY = 0.9;
99
+ /**
100
+ * Validate a difficulty value is in valid range
101
+ */
102
+ export declare function isValidDifficulty(difficulty: number): boolean;
103
+ /**
104
+ * Validate a mastery threshold is in valid range
105
+ */
106
+ export declare function isValidMasteryThreshold(threshold: number): boolean;
107
+ //# sourceMappingURL=skill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../../../src/types/skill.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,MAAM,CAAA;CAAE,CAAC;AAEnE;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,sCAAsC;IACtC,EAAE,EAAE,OAAO,CAAC;IAEZ,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IAEb,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;IAEpB,uCAAuC;IACvC,UAAU,EAAE,UAAU,CAAC;IAEvB;;;;;;;OAOG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;;;;;;;;;OAUG;IACH,kBAAkB,EAAE,OAAO,CAAC;IAE5B;;;;OAIG;IACH,gBAAgB,EAAE,MAAM,CAAC;IAEzB;;;OAGG;IACH,gBAAgB,EAAE,MAAM,CAAC;IAEzB,yDAAyD;IACzD,IAAI,EAAE,MAAM,EAAE,CAAC;IAEf;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE7B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAElC,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAElB,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,CAAC,GAAG;IAC/E,EAAE,CAAC,EAAE,OAAO,CAAC;CACd,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC;AAEzF;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,IAAI,CAC/B,SAAS,EACT,kBAAkB,GAAG,oBAAoB,GAAG,MAAM,GAAG,UAAU,CAMvD,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAElE"}