@thanh01.pmt/domain-kit 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 (108) hide show
  1. package/README.md +1101 -0
  2. package/dist/assembly/index.cjs +213 -0
  3. package/dist/assembly/index.cjs.map +1 -0
  4. package/dist/assembly/index.d.cts +66 -0
  5. package/dist/assembly/index.d.ts +66 -0
  6. package/dist/assembly/index.mjs +4 -0
  7. package/dist/assembly/index.mjs.map +1 -0
  8. package/dist/chunk-3H2HX7PR.mjs +324 -0
  9. package/dist/chunk-3H2HX7PR.mjs.map +1 -0
  10. package/dist/chunk-3VVPSRAM.mjs +1297 -0
  11. package/dist/chunk-3VVPSRAM.mjs.map +1 -0
  12. package/dist/chunk-DRVOV5ZD.mjs +314 -0
  13. package/dist/chunk-DRVOV5ZD.mjs.map +1 -0
  14. package/dist/chunk-F4RZNBOE.mjs +3 -0
  15. package/dist/chunk-F4RZNBOE.mjs.map +1 -0
  16. package/dist/chunk-GEUDHZE7.mjs +446 -0
  17. package/dist/chunk-GEUDHZE7.mjs.map +1 -0
  18. package/dist/chunk-HH4UX65C.mjs +100 -0
  19. package/dist/chunk-HH4UX65C.mjs.map +1 -0
  20. package/dist/chunk-KMYENICQ.mjs +3 -0
  21. package/dist/chunk-KMYENICQ.mjs.map +1 -0
  22. package/dist/chunk-KNDBODUQ.mjs +153 -0
  23. package/dist/chunk-KNDBODUQ.mjs.map +1 -0
  24. package/dist/chunk-MM2RWYNW.mjs +3 -0
  25. package/dist/chunk-MM2RWYNW.mjs.map +1 -0
  26. package/dist/chunk-MOKNFLUD.mjs +851 -0
  27. package/dist/chunk-MOKNFLUD.mjs.map +1 -0
  28. package/dist/chunk-ONQHJ4OH.mjs +211 -0
  29. package/dist/chunk-ONQHJ4OH.mjs.map +1 -0
  30. package/dist/chunk-PM42MMDJ.mjs +516 -0
  31. package/dist/chunk-PM42MMDJ.mjs.map +1 -0
  32. package/dist/chunk-RKRNOVKO.mjs +166 -0
  33. package/dist/chunk-RKRNOVKO.mjs.map +1 -0
  34. package/dist/chunk-VFART56O.mjs +884 -0
  35. package/dist/chunk-VFART56O.mjs.map +1 -0
  36. package/dist/chunk-XMHKWHVK.mjs +218 -0
  37. package/dist/chunk-XMHKWHVK.mjs.map +1 -0
  38. package/dist/conceptEscalator-YfMKIKCZ.d.ts +40 -0
  39. package/dist/conceptEscalator-ltRLtPhf.d.cts +40 -0
  40. package/dist/concepts/index.cjs +155 -0
  41. package/dist/concepts/index.cjs.map +1 -0
  42. package/dist/concepts/index.d.cts +79 -0
  43. package/dist/concepts/index.d.ts +79 -0
  44. package/dist/concepts/index.mjs +4 -0
  45. package/dist/concepts/index.mjs.map +1 -0
  46. package/dist/curriculumFeedSchema-TEeQg2bY.d.cts +549 -0
  47. package/dist/curriculumFeedSchema-TEeQg2bY.d.ts +549 -0
  48. package/dist/detector/index.cjs +889 -0
  49. package/dist/detector/index.cjs.map +1 -0
  50. package/dist/detector/index.d.cts +112 -0
  51. package/dist/detector/index.d.ts +112 -0
  52. package/dist/detector/index.mjs +3 -0
  53. package/dist/detector/index.mjs.map +1 -0
  54. package/dist/domainProfileSchema-CwT3Ffsw.d.cts +105 -0
  55. package/dist/domainProfileSchema-CwT3Ffsw.d.ts +105 -0
  56. package/dist/extractors/index.cjs +387 -0
  57. package/dist/extractors/index.cjs.map +1 -0
  58. package/dist/extractors/index.d.cts +46 -0
  59. package/dist/extractors/index.d.ts +46 -0
  60. package/dist/extractors/index.mjs +4 -0
  61. package/dist/extractors/index.mjs.map +1 -0
  62. package/dist/feed/index.cjs +421 -0
  63. package/dist/feed/index.cjs.map +1 -0
  64. package/dist/feed/index.d.cts +23 -0
  65. package/dist/feed/index.d.ts +23 -0
  66. package/dist/feed/index.mjs +4 -0
  67. package/dist/feed/index.mjs.map +1 -0
  68. package/dist/graph/index.cjs +2167 -0
  69. package/dist/graph/index.cjs.map +1 -0
  70. package/dist/graph/index.d.cts +226 -0
  71. package/dist/graph/index.d.ts +226 -0
  72. package/dist/graph/index.mjs +4 -0
  73. package/dist/graph/index.mjs.map +1 -0
  74. package/dist/graphVerifier-DsTP9uAN.d.ts +37 -0
  75. package/dist/graphVerifier-QjgDAJce.d.cts +37 -0
  76. package/dist/hybridGraphSchema-BCgXicgA.d.cts +2840 -0
  77. package/dist/hybridGraphSchema-BCgXicgA.d.ts +2840 -0
  78. package/dist/index.cjs +5539 -0
  79. package/dist/index.cjs.map +1 -0
  80. package/dist/index.d.cts +18 -0
  81. package/dist/index.d.ts +18 -0
  82. package/dist/index.mjs +17 -0
  83. package/dist/index.mjs.map +1 -0
  84. package/dist/keywordExtractor-CKaXqSku.d.ts +34 -0
  85. package/dist/keywordExtractor-zPAz2isq.d.cts +34 -0
  86. package/dist/llmClient-ysPhLjcH.d.cts +16 -0
  87. package/dist/llmClient-ysPhLjcH.d.ts +16 -0
  88. package/dist/parsers/index.cjs +323 -0
  89. package/dist/parsers/index.cjs.map +1 -0
  90. package/dist/parsers/index.d.cts +98 -0
  91. package/dist/parsers/index.d.ts +98 -0
  92. package/dist/parsers/index.mjs +4 -0
  93. package/dist/parsers/index.mjs.map +1 -0
  94. package/dist/pipeline/index.cjs +2166 -0
  95. package/dist/pipeline/index.cjs.map +1 -0
  96. package/dist/pipeline/index.d.cts +45 -0
  97. package/dist/pipeline/index.d.ts +45 -0
  98. package/dist/pipeline/index.mjs +8 -0
  99. package/dist/pipeline/index.mjs.map +1 -0
  100. package/dist/projectGraphSchema-DnD7orZV.d.cts +2581 -0
  101. package/dist/projectGraphSchema-DnD7orZV.d.ts +2581 -0
  102. package/dist/schemas/index.cjs +675 -0
  103. package/dist/schemas/index.cjs.map +1 -0
  104. package/dist/schemas/index.d.cts +253 -0
  105. package/dist/schemas/index.d.ts +253 -0
  106. package/dist/schemas/index.mjs +4 -0
  107. package/dist/schemas/index.mjs.map +1 -0
  108. package/package.json +71 -0
package/README.md ADDED
@@ -0,0 +1,1101 @@
1
+ # `@thanh01.pmt/domain-kit`
2
+
3
+ > **Project graph generation engine** — decomposes any domain (software, hardware, math, science, language...) into structured domain graphs for curriculum planning.
4
+
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue.svg)](https://typescriptlang.org)
6
+ [![Zod](https://img.shields.io/badge/Zod-3.23-3248ff.svg)](https://zod.dev)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
8
+
9
+ ---
10
+
11
+ ## Table of Contents
12
+
13
+ - [Overview](#overview)
14
+ - [Installation](#installation)
15
+ - [Quick Start](#quick-start)
16
+ - [5. Emit Curriculum Feed](#5-emit-curriculum-feed-from-any-graph)
17
+ - [Architecture](#architecture)
18
+ - [Input → Processing → Output](#input--processing--output)
19
+ - [Domain Detection](#domain-detection)
20
+ - [Ambiguous Domain Handling](#ambiguous-domain-handling)
21
+ - [Confidence & Fallback](#confidence--fallback)
22
+ - [Graph Types](#graph-types)
23
+ - [Schemas](#schemas)
24
+ - [API Reference](#api-reference)
25
+ - [Pipeline Details](#pipeline-details)
26
+ - [AI Agent Guide](#ai-agent-guide)
27
+ - [Examples](#examples)
28
+ - [Contributing](#contributing)
29
+
30
+ ---
31
+
32
+ ## Overview
33
+
34
+ `domain-kit` is a TypeScript package that analyzes a learning domain and produces a structured **domain_graph** — the single source of truth consumed by `curriculum-kit` to generate lessons, activities, assessments, and all pedagogical artifacts.
35
+
36
+ **Key capabilities:**
37
+
38
+ - **Auto-detect** input type (repo, syllabus, description) and domain category (software, math, science...) with multi-language support (EN, VI, ZH, JA, KO, FR)
39
+ - **Context-dependent domain detection** — `.cpp` files default to `software`; `hardware_iot` only when Arduino/ESP32/sensor context is present
40
+ - **Choose graph type** automatically: `project_graph` (product-driven) or `knowledge_graph` (concept-driven) or `hybrid_graph`
41
+ - **AST-level parsing** of Swift, TypeScript, Python, C++ source code
42
+ - **LLM-powered decomposition** of projects into features → steps → keywords
43
+ - **ULO/CIO/SIO depth classification** — each keyword/concept mapped to WHAT (ulo), HOW (cio), or IMPLEMENTATION (sio)
44
+ - **Concept resolution** with ULO/CIO-aware matching against Master Tree concept codes
45
+ - **Prerequisite cycle detection** — DFS cycle detection + Kahn's topological sort for knowledge graphs
46
+ - **Keyword-per-milestone tracking** with new vs prerequisite distinction
47
+ - **Time-budget-aware assembly** — configurable session duration, overhead factor, and automatic milestone splitting
48
+
49
+ ---
50
+
51
+ ## Installation
52
+
53
+ ```bash
54
+ npm install @thanh01.pmt/domain-kit
55
+ ```
56
+
57
+ Or with workspace link:
58
+
59
+ ```bash
60
+ npm link @thanh01.pmt/domain-kit
61
+ ```
62
+
63
+ ### Peer Dependencies
64
+
65
+ ```json
66
+ {
67
+ "zod": "^3.23.8"
68
+ }
69
+ ```
70
+
71
+ ### Environment Variables (for LLM features)
72
+
73
+ ```bash
74
+ LLM_API_KEY=sk-... # OpenAI-compatible API key
75
+ LLM_BASE_URL=https://api.openai.com/v1 # API base URL
76
+ LLM_MODEL=gpt-4o-mini # Model to use
77
+ LLM_MAX_TOKENS=16384 # Max output tokens
78
+ ```
79
+
80
+ ---
81
+
82
+ ## Quick Start
83
+
84
+ ### 1. Detect Domain Profile
85
+
86
+ ```typescript
87
+ import { detectDomainProfile } from '@thanh01.pmt/domain-kit';
88
+
89
+ const profile = detectDomainProfile({
90
+ repoUrl: 'https://github.com/user/talky',
91
+ goal: 'Build iOS chat app with SwiftUI and Firebase',
92
+ techStack: 'Swift,SwiftUI,Firebase',
93
+ });
94
+
95
+ console.log(profile.graphType); // 'project_graph'
96
+ console.log(profile.domainCategory); // 'software'
97
+ console.log(profile.learningMode); // 'product'
98
+ ```
99
+
100
+ ### 2. Generate Project Graph (Software)
101
+
102
+ ```typescript
103
+ import { runProjectGraphPipeline } from '@thanh01.pmt/domain-kit';
104
+
105
+ const result = await runProjectGraphPipeline({
106
+ repoDir: '/path/to/repo',
107
+ goal: 'Build iOS chat app with SwiftUI',
108
+ techStack: 'Swift,SwiftUI,Firebase',
109
+ });
110
+
111
+ console.log(result.projectGraph); // ProjectGraph schema
112
+ console.log(result.roadmap); // AssembledRoadmap with phases
113
+ console.log(result.keywords); // Extracted keywords
114
+ ```
115
+
116
+ ### 3. Generate Knowledge Graph (Math/Science)
117
+
118
+ ```typescript
119
+ import { generateKnowledgeGraph } from '@thanh01.pmt/domain-kit';
120
+
121
+ const result = await generateKnowledgeGraph({
122
+ subject: 'Hình học K12',
123
+ syllabusText: 'Chương 1: Phân loại góc...\nChương 2: Tam giác...',
124
+ gradeBand: [6, 9],
125
+ domain: 'math',
126
+ });
127
+
128
+ console.log(result.knowledgeGraph); // KnowledgeGraph schema
129
+ ```
130
+
131
+ ### 4. Generate Hybrid Graph
132
+
133
+ ```typescript
134
+ import { generateHybridGraph } from '@thanh01.pmt/domain-kit';
135
+
136
+ const result = await generateHybridGraph({
137
+ projectGraph: existingProjectGraph,
138
+ knowledgeGraph: existingKnowledgeGraph,
139
+ });
140
+
141
+ console.log(result.hybridGraph); // HybridGraph with links[]
142
+ ```
143
+
144
+ ### 5. Emit Curriculum Feed (from any graph)
145
+
146
+ ```typescript
147
+ import { emitCurriculumFeed } from '@thanh01.pmt/domain-kit';
148
+
149
+ const feed = emitCurriculumFeed(result.projectGraph); // or knowledgeGraph or hybridGraph
150
+
151
+ console.log(feed.learning_nodes.length); // unified nodes ready for planner
152
+ console.log(feed.dependency_edges.length); // knowledge + task edges
153
+ console.log(feed.suggested_groupings); // feature/category groupings
154
+ // Each node has: bloom_hint, depth_hint, keywords.new/.prerequisite
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Architecture
160
+
161
+ ```
162
+ ┌─────────────────────────────────────────────────────────────┐
163
+ │ domain-kit │
164
+ ├─────────────────────────────────────────────────────────────┤
165
+ │ │
166
+ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
167
+ │ │ schemas/ │ │ detector/ │ │ parsers/ │ │
168
+ │ │ │ │ │ │ │ │
169
+ │ │ ProjectGraph │ │ inputType │ │ Swift │ │
170
+ │ │ KnowledgeGr. │ │ domain │ │ TypeScript │ │
171
+ │ │ HybridGraph │ │ learningMode │ │ Python │ │
172
+ │ │ DomainProfile│ │ orchestrator │ │ C++/Arduino │ │
173
+ │ │ Extensions │ │ │ │ │ │
174
+ │ └──────────────┘ └──────────────┘ └──────────────┘ │
175
+ │ │
176
+ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
177
+ │ │ extractors/ │ │ graph/ │ │ concepts/ │ │
178
+ │ │ │ │ │ │ │ │
179
+ │ │ keywords │ │ scaffold │ │ concept │ │
180
+ │ │ │ │ overview │ │ resolver │ │
181
+ │ │ │ │ steps │ │ │ │
182
+ │ │ │ │ verify │ │ │ │
183
+ │ │ │ │ escalate │ │ │ │
184
+ │ │ │ │ knowledgeKG │ │ │ │
185
+ │ │ │ │ hybridKG │ │ │ │
186
+ │ └──────────────┘ └──────────────┘ └──────────────┘ │
187
+ │ │
188
+ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
189
+ │ │ assembly/ │ │ pipeline/ │ │ feed/ │ │
190
+ │ │ │ │ │ │ │ │
191
+ │ │ roadmap │ │ projectGraph │ │ emitCurricu..│ │
192
+ │ │ assembler │ │ pipeline │ │ lumFeed │ │
193
+ │ └──────────────┘ └──────────────┘ └──────────────┘ │
194
+ │ │
195
+ │ ┌──────────────┐ │
196
+ │ │ utils/ │ │
197
+ │ │ llmClient │ │
198
+ │ │ fileUtils │ │
199
+ │ └──────────────┘ │
200
+ │ │
201
+ └─────────────────────────────────────────────────────────────┘
202
+ ```
203
+
204
+ ---
205
+
206
+ ## Input → Processing → Output
207
+
208
+ ### Input
209
+
210
+ User provides **one or more** of:
211
+
212
+ | Field | Type | Description |
213
+ |---|---|---|
214
+ | `repoUrl` | `string` | Git repository URL |
215
+ | `repoDir` | `string` | Local repository path |
216
+ | `goal` | `string` | Learning goal or project description |
217
+ | `description` | `string` | Subject/project description |
218
+ | `syllabusText` | `string` | Syllabus or curriculum text |
219
+ | `chapters` | `string[]` | Chapter/section names |
220
+ | `techStack` | `string` | Comma-separated technologies |
221
+ | `fileExtensions` | `string[]` | File extensions in repo |
222
+ | `gradeBand` | `[number, number]` | Target grade range |
223
+
224
+ ### Processing
225
+
226
+ ```
227
+ Input
228
+ │
229
+ ▼
230
+ Step 1: DETECT
231
+ ├── detectInputType() → repository | syllabus | description | files | mixed
232
+ ├── detectDomain() → software | hardware_iot | math | science | ...
233
+ │ └── context-dependent: .cpp→software (default), hardware only with ESP32/Arduino context
234
+ ├── detectLearningMode() → product | concept | hybrid
235
+ └── → DomainProfile (with ambiguity flag if domains overlap)
236
+ │
237
+ Step 2: ROUTE (by graphType)
238
+ │
239
+ ├── project_graph → parsers → extractors → graph/LLM → verify → concepts → assembly
240
+ ├── knowledge_graph → LLM decompose → ULO/CIO/SIO → cycle detect → topo sort → problem_types
241
+ └── hybrid_graph → project_graph + knowledge_graph + LLM link features↔concepts
242
+ │
243
+ Step 3: OUTPUT
244
+ └── domain_graph.json
245
+ ```
246
+
247
+ ### Output
248
+
249
+ Always **one of three schemas**:
250
+
251
+ | Graph Type | Schema | When |
252
+ |---|---|---|
253
+ | `project_graph` | `ProjectGraph` | Product-driven (software, hardware, 3D design) |
254
+ | `knowledge_graph` | `KnowledgeGraph` | Concept-driven (math, science, language) |
255
+ | `hybrid_graph` | `HybridGraph` | Both product + concept linked |
256
+
257
+ ---
258
+
259
+ ## Domain Detection
260
+
261
+ ### How it works
262
+
263
+ `detectDomainProfile()` runs three detectors in sequence:
264
+
265
+ 1. **Input Type Detector** — Checks for repo URLs, syllabus text, file extensions, descriptions
266
+ 2. **Domain Detector** — Multi-signal scoring with 200+ keywords across 10 domains, **multi-language support** (EN, VI, ZH, JA, KO, FR), and **context-dependent extension mapping** (e.g., `.cpp` → software by default, hardware only when Arduino/ESP32/sensor context present)
267
+ 3. **Learning Mode Detector** — Combines input signals + domain heuristics + verb patterns
268
+
269
+ ### Ambiguous Domain Handling
270
+
271
+ Some file extensions map to multiple domains (e.g., `.cpp` → software or hardware). The detector:
272
+
273
+ 1. Default-maps ambiguous extensions to `software` (most common use)
274
+ 2. Checks context keywords (e.g., `arduino`, `ESP32`, `GPIO`, `sensor`) to upgrade to `hardware_iot`
275
+ 3. Sets `ambiguous` field in output when detection is borderline
276
+ 4. Agent should **ask user to confirm** when `ambiguous` is set or confidence < 0.6
277
+
278
+ ### Domain Categories
279
+
280
+ | Category | Examples | Keywords (sample) |
281
+ |---|---|---|
282
+ | `software` | App, web, API | swift, react, typescript, docker |
283
+ | `hardware_iot` | Arduino, robotics | arduino, sensor, ESP32, GPIO |
284
+ | `3d_design` | Tinkercad, Fusion360 | shape, dimension, STL, CAD |
285
+ | `math` | Hình học, đại số | tam giác, phương trình, calculus |
286
+ | `science` | Lý, hóa, sinh | thí nghiệm, năng lượng, cell |
287
+ | `language` | Tiếng Anh, writing | grammar, vocabulary, essay |
288
+ | `arts` | Âm nhạc, thiết kế | piano, color theory, typography |
289
+ | `research` | Nghiên cứu, thống kê | methodology, hypothesis, SPSS |
290
+ | `business` | Kinh doanh, tài chính | revenue, agile, business plan |
291
+ | `other` | Fallback | — |
292
+
293
+ ### Confidence & Fallback
294
+
295
+ ```typescript
296
+ const profile = detectDomainProfile({ ... });
297
+
298
+ // Check for ambiguous detection
299
+ if (profile.ambiguous) {
300
+ // E.g., { domain1: 'software', domain2: 'hardware_iot', reason: 'C++ files + ESP32 context' }
301
+ // → Ask user to confirm which domain
302
+ }
303
+
304
+ if (profile.confidence.domainCategory < 0.6) {
305
+ // Low confidence — ask user to confirm
306
+ }
307
+
308
+ if (profile.domainCategory === 'other') {
309
+ // Unknown domain — ask user to specify
310
+ }
311
+ ```
312
+
313
+ ---
314
+
315
+ ## Graph Types
316
+
317
+ ### Project Graph (Product-Driven)
318
+
319
+ For projects where the learner **builds something**: apps, robots, 3D models.
320
+
321
+ ```json
322
+ {
323
+ "project": { "id": "...", "tech_stack": {...} },
324
+ "product": { "goals": [...], "development_stages": [...] },
325
+ "features": [
326
+ {
327
+ "id": "F1",
328
+ "name": "Authentication",
329
+ "steps": [
330
+ {
331
+ "id": "F1-S1",
332
+ "name": "Implement AuthViewModel",
333
+ "keywords": ["@Published", "@EnvironmentObject"],
334
+ "api_usage": ["FirebaseAuth"],
335
+ "effort": { "estimated_minutes": 30 }
336
+ }
337
+ ]
338
+ }
339
+ ]
340
+ }
341
+ ```
342
+
343
+ ### Knowledge Graph (Concept-Driven)
344
+
345
+ For subjects where the learner **understands concepts**: math, science, language.
346
+
347
+ ```json
348
+ {
349
+ "subject": { "id": "geometry-k12", "domain": "math" },
350
+ "concepts": [
351
+ {
352
+ "id": "G1",
353
+ "name": "Angle Classification",
354
+ "ulo": "WHAT: Angles are... WHY: We classify to compare...",
355
+ "cio": "HOW: Measured in degrees, compared using protractor...",
356
+ "sio": ["protractor usage", "angle notation"],
357
+ "prerequisites": [],
358
+ "problem_types": [{ "bloom_level": "Remember", "difficulty": "easy" }]
359
+ }
360
+ ],
361
+ "learning_path": [
362
+ { "concept_id": "G1", "order": 1 },
363
+ { "concept_id": "G2", "order": 2, "depends_on": ["G1"] }
364
+ ]
365
+ }
366
+ ```
367
+
368
+ ### Hybrid Graph
369
+
370
+ For projects that require **both building and understanding**.
371
+
372
+ ```json
373
+ {
374
+ "project_graph": { ... },
375
+ "knowledge_graph": { ... },
376
+ "links": [
377
+ {
378
+ "feature_id": "F2",
379
+ "concept_id": "G3",
380
+ "relationship": "requires",
381
+ "depth": "cio",
382
+ "estimated_prereq_minutes": 30
383
+ }
384
+ ]
385
+ }
386
+ ```
387
+
388
+ ---
389
+
390
+ ## Schemas
391
+
392
+ All schemas are Zod-validated TypeScript types.
393
+
394
+ | Schema | File | Purpose |
395
+ |---|---|---|
396
+ | `ProjectGraphSchema` | `projectGraphSchema.ts` | Software/hardware/3D project structure |
397
+ | `KnowledgeGraphSchema` | `knowledgeGraphSchema.ts` | Concept-driven subject structure |
398
+ | `HybridGraphSchema` | `hybridGraphSchema.ts` | Combined project + knowledge |
399
+ | `DomainProfileSchema` | `domainProfileSchema.ts` | Domain detection output |
400
+ | `HardwareFeatureExtension` | `domainExtensions.ts` | Hardware overlay (wiring, materials) |
401
+ | `ThreeDesignFeatureExtension` | `domainExtensions.ts` | 3D Design overlay (shapes, dimensions) |
402
+ | `CurriculumFeedSchema` | `curriculumFeedSchema.ts` | Planner-ready normalized feed (nodes, edges, groupings) |
403
+ | `FeedNodeSchema` | `curriculumFeedSchema.ts` | Individual learning node (concept, skill, or product step) |
404
+ | `FeedEdgeSchema` | `curriculumFeedSchema.ts` | Dependency edge (knowledge or task) |
405
+ | `FeedGroupingSchema` | `curriculumFeedSchema.ts` | Suggested grouping of nodes (feature or category) |
406
+
407
+ ### Key Types
408
+
409
+ ```typescript
410
+ // Project Graph
411
+ type ProjectGraph = {
412
+ project: ProjectInfo;
413
+ product: Product;
414
+ features: Feature[];
415
+ implementation: { tasks: Task[] };
416
+ }
417
+
418
+ type Feature = {
419
+ id: string;
420
+ name: string;
421
+ steps: Step[];
422
+ depends_on: string[];
423
+ }
424
+
425
+ type Step = {
426
+ id: string;
427
+ name: string;
428
+ keywords: string[];
429
+ api_usage: string[];
430
+ completion_level: 'base' | 'mvp' | 'extend' | 'polish';
431
+ effort: { estimated_minutes: number; complexity: 'low' | 'medium' | 'high' };
432
+ }
433
+
434
+ // Knowledge Graph
435
+ type KnowledgeGraph = {
436
+ subject: SubjectInfo;
437
+ concepts: Concept[];
438
+ categories: ConceptCategory[];
439
+ learning_path: LearningPathStep[];
440
+ }
441
+
442
+ type Concept = {
443
+ id: string;
444
+ name: string;
445
+ ulo: string; // WHAT + WHY
446
+ cio: string; // HOW
447
+ sio: string[]; // Specific implementations
448
+ prerequisites: string[];
449
+ problem_types: ProblemType[];
450
+ }
451
+
452
+ // Domain Detection
453
+ type DomainProfile = {
454
+ inputType: 'repository' | 'syllabus' | 'description' | 'files' | 'mixed';
455
+ domainCategory: 'software' | 'math' | 'science' | ...;
456
+ learningMode: 'product' | 'concept' | 'hybrid';
457
+ graphType: 'project_graph' | 'knowledge_graph' | 'hybrid_graph';
458
+ confidence: { inputType: number; domainCategory: number; learningMode: number };
459
+ ambiguous?: { domain1: DomainCategory; domain2: DomainCategory; reason: string };
460
+ }
461
+
462
+ // Concept Escalation (ULO/CIO/SIO depth)
463
+ type ConceptMapping = {
464
+ keyword: string;
465
+ concept_code: string;
466
+ concept_name: string;
467
+ depth: 'ulo' | 'cio' | 'sio'; // WHAT (ulo), HOW (cio), IMPLEMENTATION (sio)
468
+ rationale: string;
469
+ evidence_files: string[];
470
+ }
471
+
472
+ // Assembled Roadmap (with time budget)
473
+ type AssembledRoadmap = {
474
+ phases: Phase[];
475
+ all_keywords: string[];
476
+ new_keywords: string[];
477
+ prerequisite_keywords: string[];
478
+ time_budget: {
479
+ total_estimated_minutes: number;
480
+ overhead_minutes: number;
481
+ session_minutes: number;
482
+ };
483
+ }
484
+
485
+ // Curriculum Feed (planner-ready projection)
486
+ type CurriculumFeed = {
487
+ schema_version: 2;
488
+ source: { graph_type: 'project_graph' | 'knowledge_graph' | 'hybrid_graph'; warnings: string[]; hallucination_count: number };
489
+ learning_nodes: FeedNode[];
490
+ dependency_edges: FeedEdge[];
491
+ suggested_groupings: FeedGrouping[];
492
+ }
493
+
494
+ type FeedNode = {
495
+ id: string;
496
+ kind: 'skill' | 'concept' | 'product_step';
497
+ name: string;
498
+ concept_codes: string[];
499
+ keywords: { all: string[]; new: string[]; prerequisite: string[] };
500
+ estimated_minutes: number;
501
+ bloom_hint: 'Remember' | 'Understand' | 'Apply' | 'Analyze' | 'Evaluate' | 'Create' | null;
502
+ depth_hint: 'ulo' | 'cio' | 'sio' | null;
503
+ completion_level: 'mvp' | 'standard' | 'stretch';
504
+ scaffolding: { scaffold_candidates: ScaffoldCandidate[]; core_value_minutes: number };
505
+ references: { file: string; evidence: string }[];
506
+ feature_id: string | null;
507
+ concept_ref: string | null;
508
+ }
509
+
510
+ type FeedEdge = {
511
+ from: string; // node id
512
+ to: string; // node id
513
+ kind: 'knowledge' | 'task';
514
+ reason: string;
515
+ }
516
+
517
+ type FeedGrouping = {
518
+ id: string;
519
+ name: string;
520
+ node_ids: string[];
521
+ rationale: string;
522
+ }
523
+ ```
524
+
525
+ ---
526
+
527
+ ## API Reference
528
+
529
+ ### `detectDomainProfile(options) → DomainProfile`
530
+
531
+ Detects input type, domain category, learning mode, and graph type.
532
+
533
+ ```typescript
534
+ import { detectDomainProfile } from '@thanh01.pmt/domain-kit';
535
+
536
+ const profile = detectDomainProfile({
537
+ repoUrl?: string;
538
+ repoDir?: string;
539
+ goal?: string;
540
+ description?: string;
541
+ syllabusText?: string;
542
+ chapters?: string[];
543
+ fileExtensions?: string[];
544
+ techStack?: string;
545
+ gradeBand?: [number, number];
546
+ });
547
+ ```
548
+
549
+ ### `runProjectGraphPipeline(options) → PipelineResult`
550
+
551
+ Full pipeline for product-driven projects. Requires source code repository.
552
+
553
+ ```typescript
554
+ import { runProjectGraphPipeline } from '@thanh01.pmt/domain-kit';
555
+
556
+ const result = await runProjectGraphPipeline({
557
+ repoDir: string; // Required: local repo path
558
+ goal: string; // Required: project goal
559
+ techStack: string; // Required: comma-separated technologies
560
+ llmConfig?: LlmClientConfig;
561
+ embeddings?: Record<string, { embedding?: number[] }>;
562
+ sessionMinutes?: number; // Lesson/session duration (default: 90)
563
+ overheadFactor?: number; // Setup/transition overhead multiplier (default: 1.15)
564
+ maxMilestoneMinutes?: number; // Max minutes before splitting milestone (default: 120)
565
+ onProgress?: (step: string, message: string) => void;
566
+ });
567
+
568
+ // Returns:
569
+ {
570
+ projectGraph: ProjectGraph;
571
+ resolvedConcepts: ResolveConceptsResult;
572
+ roadmap: AssembledRoadmap;
573
+ hallucinations: Hallucination[];
574
+ keywords: Keyword[];
575
+ featureConcepts: Map<string, ConceptMapping[]>;
576
+ }
577
+ ```
578
+
579
+ ### `generateKnowledgeGraph(options) → KnowledgeGraphPipelineResult`
580
+
581
+ Generates knowledge graph for concept-driven subjects.
582
+
583
+ ```typescript
584
+ import { generateKnowledgeGraph } from '@thanh01.pmt/domain-kit';
585
+
586
+ const result = await generateKnowledgeGraph({
587
+ subject: string; // Required: subject name
588
+ description?: string;
589
+ syllabusText?: string; // Full syllabus text (multi-language supported)
590
+ gradeBand?: [number, number];
591
+ domain?: string;
592
+ llmConfig?: LlmClientConfig;
593
+ });
594
+ // Internally runs: LLM decomposition → cycle detection → topological sort → depth estimation
595
+
596
+ // Returns:
597
+ {
598
+ knowledgeGraph: KnowledgeGraph;
599
+ warnings: string[];
600
+ }
601
+ ```
602
+
603
+ ### `generateHybridGraph(options) → HybridGraphPipelineResult`
604
+
605
+ Links project graph with knowledge graph.
606
+
607
+ ```typescript
608
+ import { generateHybridGraph } from '@thanh01.pmt/domain-kit';
609
+
610
+ const result = await generateHybridGraph({
611
+ projectGraph: ProjectGraph;
612
+ knowledgeGraph: KnowledgeGraph;
613
+ llmConfig?: LlmClientConfig;
614
+ });
615
+
616
+ // Returns:
617
+ {
618
+ hybridGraph: HybridGraph;
619
+ warnings: string[];
620
+ }
621
+ ```
622
+
623
+ ### `emitCurriculumFeed(graph, opts?) → CurriculumFeed`
624
+
625
+ Converts any domain graph (project, knowledge, or hybrid) into a unified, planner-ready `CurriculumFeed`. Pure transformation — no LLM calls. Validates output (fail-closed).
626
+
627
+ ```typescript
628
+ import { emitCurriculumFeed } from '@thanh01.pmt/domain-kit';
629
+
630
+ // From any graph type:
631
+ const feed = emitCurriculumFeed(projectGraph); // project_graph
632
+ const feed = emitCurriculumFeed(knowledgeGraph); // knowledge_graph
633
+ const feed = emitCurriculumFeed(hybridGraph); // hybrid_graph
634
+ const feed = emitCurriculumFeed(existingFeed); // pass-through (already a feed)
635
+
636
+ // With options:
637
+ const feed = emitCurriculumFeed(graph, {
638
+ hallucinationCount: 3, // metadata for source info
639
+ warnings: ['Feature F5 had low confidence'],
640
+ });
641
+
642
+ // Returns CurriculumFeed with:
643
+ // - learning_nodes[] — unified node format (concept | skill | product_step)
644
+ // - dependency_edges[] — knowledge (prerequisite) or task (build order) edges
645
+ // - suggested_groupings[] — feature or category groupings
646
+ // - Each node has: bloom_hint, depth_hint (ulo/cio/sio), keywords.new vs .prerequisite
647
+ ```
648
+
649
+ **Key behaviors:**
650
+ - **Hybrid graphs**: concepts emitted first (prerequisite-first), then project steps; hybrid links carry depth hint onto step nodes; `estimated_prereq_minutes` accumulated per concept node
651
+ - **Knowledge graphs**: concepts + prerequisite edges + category groupings
652
+ - **Project graphs**: features → steps + depends_on edges + feature groupings
653
+ - **Pass-through**: if input already has `learning_nodes[]`, validates and returns as-is
654
+ - **Legacy rejection**: throws descriptive error if graph has `implementation.tasks` but no `features[].steps` (old knowledge-tree format)
655
+ - **New/prerequisite keywords**: computed in emission order — first appearance = new, seen before = prerequisite
656
+
657
+ ### Parsers
658
+
659
+ ```typescript
660
+ import { parseSwiftFile, parseTsFile, parsePythonFile, parseCppFile } from '@thanh01.pmt/domain-kit';
661
+
662
+ const swiftResult = parseSwiftFile('AuthViewModel.swift', fileContent);
663
+ // → { imports: ['SwiftUI', 'FirebaseAuth'], types: [...], functions: [...] }
664
+ ```
665
+
666
+ ### Keyword Extraction
667
+
668
+ ```typescript
669
+ import { extractKeywords } from '@thanh01.pmt/domain-kit';
670
+
671
+ const keywords = extractKeywords(parsedSourceContext);
672
+ // → [{ keyword: 'SwiftUI', source: 'import', weight: 1.0, platform: 'app' }]
673
+ ```
674
+
675
+ ---
676
+
677
+ ## Pipeline Details
678
+
679
+ ### Project Graph Pipeline (Product-Driven)
680
+
681
+ ```
682
+ STEP 1: AST Analysis
683
+ → Parse all source files (Swift, TS, Python, C++)
684
+ → Merge by language, extract imports/types/functions/wrappers
685
+
686
+ STEP 2: Keyword Extraction
687
+ → Filter stdlib, assign weights, tag platform (app/esp32)
688
+
689
+ STEP 3: SDK API Index
690
+ → Build symbol index from AST results
691
+
692
+ STEP 4: LLM Graph Generation
693
+ C0: Scaffold F0 (foundation features: tools, setup, minimal knowledge)
694
+ C1: Overview (features meta, journeys, architecture, development stages)
695
+ C2: Steps per feature (batched or per-feature LLM calls)
696
+
697
+ STEP 5: Verification
698
+ → Remove hallucinated files, APIs, keywords not found in code
699
+ → F0 keywords exempt (pedagogical terms)
700
+
701
+ STEP 6: Concept Escalation
702
+ → Map keywords → neutral concepts via LLM
703
+ → Classify each keyword as ULO (WHAT/WHY), CIO (HOW), or SIO (IMPLEMENTATION)
704
+ → Infer depth from code context (function bodies→sio, types→cio, imports→sio, docs→ulo)
705
+ → Join evidence files
706
+
707
+ STEP 7: Concept Resolution
708
+ → Map concepts → Master Tree codes with ULO/CIO-aware scoring:
709
+ - SIO keywords matched against concept.keywords
710
+ - CIO keywords matched against concept.description + concept.cio
711
+ - ULO keywords matched against concept.ulo + concept.description
712
+ → Depth field propagated to resolved concepts
713
+
714
+ STEP 8: Assembly
715
+ → Group features into phases (session-time-aware)
716
+ → Respect sessionMinutes, overheadFactor, maxMilestoneMinutes constraints
717
+ → Split large features across multiple milestones when exceeding time budget
718
+ → Compute all_keywords / new_keywords / prerequisite_keywords per milestone
719
+ → Output time_budget with total_estimated_minutes + overhead_minutes
720
+
721
+ STEP 9: Feed Emission
722
+ → emitCurriculumFeed(graph) — pure transformation, no LLM
723
+ → Convert project_graph → FeedNode[] (kind: product_step) + FeatureGroupings
724
+ → Convert knowledge_graph → FeedNode[] (kind: concept) + CategoryGroupings
725
+ → Convert hybrid_graph → combined nodes + knowledge/task edges + hybrid link depth hints
726
+ → Compute new/prerequisite keywords in emission order
727
+ → Validate: fail-closed (duplicate IDs, edge resolution, self-loops, non-empty)
728
+ ```
729
+
730
+ ### Knowledge Graph Pipeline (Concept-Driven)
731
+
732
+ ```
733
+ STEP 1: LLM Decomposition
734
+ → Decompose subject into concepts with ULO/CIO/SIO
735
+ → Assign prerequisites
736
+ → Generate problem_types per concept (bloom levels)
737
+ → Group into categories
738
+
739
+ STEP 2: Prerequisite Cycle Detection
740
+ → DFS to detect cycles in prerequisite graph
741
+ → Break cycles by removing weakest back-edges
742
+ → Generate warnings for each broken cycle
743
+
744
+ STEP 3: Topological Sort (Kahn's Algorithm)
745
+ → Sort concepts in valid learning order
746
+ → Assign sequential order numbers
747
+ → Estimate concept depth per milestone (ULO→CIO→SIO progression)
748
+
749
+ STEP 4: Validation
750
+ → Check prerequisite references exist
751
+ → Check learning_path references exist
752
+ → Generate warnings for invalid references
753
+
754
+ STEP 5: Feed Emission
755
+ → emitCurriculumFeed(knowledgeGraph) → CurriculumFeed
756
+ → Concept nodes with bloom_hint (from problem_types) + depth_hint (from sio count)
757
+ → Category groupings for suggested lesson grouping
758
+ ```
759
+
760
+ ---
761
+
762
+ ## AI Agent Guide
763
+
764
+ > **This section is specifically for AI agents that need to use domain-kit programmatically.**
765
+
766
+ ### When to Use domain-kit
767
+
768
+ Use `domain-kit` when you need to:
769
+
770
+ 1. **Analyze a project** and understand what it builds, what technologies it uses, what concepts it teaches
771
+ 2. **Decompose a subject** into structured learning concepts with prerequisites
772
+ 3. **Generate a domain graph** that `curriculum-kit` can consume to create lessons, activities, assessments
773
+
774
+ ### Step-by-Step Usage
775
+
776
+ #### Step 1: Detect the Domain
777
+
778
+ **Always start here.** This tells you what kind of input you have and what graph type to generate.
779
+
780
+ ```typescript
781
+ import { detectDomainProfile } from '@thanh01.pmt/domain-kit';
782
+
783
+ const profile = detectDomainProfile({
784
+ // Provide whatever the user gave you:
785
+ repoUrl: userRepoUrl,
786
+ goal: userGoal,
787
+ techStack: userTechStack,
788
+ description: userDescription,
789
+ syllabusText: userSyllabus,
790
+ });
791
+
792
+ // Check the result:
793
+ console.log(profile.graphType); // ← THIS determines your next step
794
+ console.log(profile.domainCategory); // ← THIS tells you the domain
795
+ console.log(profile.confidence); // ← Check if confidence is high enough
796
+ ```
797
+
798
+ **Decision tree after detection:**
799
+
800
+ ```
801
+ profile.graphType === 'project_graph'
802
+ → You need source code. Proceed with runProjectGraphPipeline().
803
+
804
+ profile.graphType === 'knowledge_graph'
805
+ → You need subject description or syllabus. Proceed with generateKnowledgeGraph().
806
+
807
+ profile.graphType === 'hybrid_graph'
808
+ → You need BOTH source code AND subject description.
809
+ → Run projectGraphPipeline() + generateKnowledgeGraph() + generateHybridGraph().
810
+
811
+ profile.confidence < 0.6
812
+ → Low confidence. Ask the user to confirm domain category.
813
+
814
+ profile.ambiguous !== undefined
815
+ → Domain is ambiguous (e.g., .cpp could be software or hardware).
816
+ → Present both options to user with the reason.
817
+
818
+ profile.domainCategory === 'other'
819
+ → Unknown domain. Ask the user what domain this is.
820
+ ```
821
+
822
+ #### Step 2: Generate the Graph
823
+
824
+ **For project_graph (product-driven):**
825
+
826
+ ```typescript
827
+ import { runProjectGraphPipeline } from '@thanh01.pmt/domain-kit';
828
+
829
+ // REQUIRES: source code directory
830
+ const result = await runProjectGraphPipeline({
831
+ repoDir: '/path/to/cloned/repo', // Must be a real directory with source files
832
+ goal: profile.goal,
833
+ techStack: profile.detectedTechStack.join(',') || 'auto',
834
+ });
835
+
836
+ // result.projectGraph ← feed this to curriculum-kit
837
+ // result.roadmap ← has phases, milestones, keyword tracking
838
+ // result.keywords ← all extracted keywords
839
+ // result.hallucinations ← items that were removed during verification
840
+ ```
841
+
842
+ **For knowledge_graph (concept-driven):**
843
+
844
+ ```typescript
845
+ import { generateKnowledgeGraph } from '@thanh01.pmt/domain-kit';
846
+
847
+ // REQUIRES: subject name + syllabus text
848
+ const result = await generateKnowledgeGraph({
849
+ subject: profile.detectedSubject || 'Unknown Subject',
850
+ syllabusText: profile.syllabusText, // ← MUST have syllabus text
851
+ gradeBand: profile.detectedGradeBand,
852
+ domain: profile.domainCategory,
853
+ });
854
+
855
+ // result.knowledgeGraph ← feed this to curriculum-kit
856
+ // result.warnings ← check for invalid references
857
+ ```
858
+
859
+ **For hybrid_graph:**
860
+
861
+ ```typescript
862
+ import { runProjectGraphPipeline, generateKnowledgeGraph, generateHybridGraph } from '@thanh01.pmt/domain-kit';
863
+
864
+ // Step A: Generate project graph
865
+ const projectResult = await runProjectGraphPipeline({
866
+ repoDir: profile.repoDir,
867
+ goal: profile.goal,
868
+ techStack: profile.detectedTechStack.join(','),
869
+ });
870
+
871
+ // Step B: Generate knowledge graph
872
+ const knowledgeResult = await generateKnowledgeGraph({
873
+ subject: profile.detectedSubject,
874
+ syllabusText: profile.syllabusText,
875
+ });
876
+
877
+ // Step C: Link them
878
+ const hybridResult = await generateHybridGraph({
879
+ projectGraph: projectResult.projectGraph,
880
+ knowledgeGraph: knowledgeResult.knowledgeGraph,
881
+ });
882
+
883
+ // hybridResult.hybridGraph ← feed this to curriculum-kit
884
+ ```
885
+
886
+ #### Step 3: Hand Off to curriculum-kit
887
+
888
+ The output of domain-kit (`project_graph.json`, `knowledge_graph.json`, or `hybrid_graph.json`) is consumed by curriculum-kit:
889
+
890
+ ```typescript
891
+ // In curriculum-kit:
892
+ import { convertRoadmapToFoundationSot } from '@thanh01.pmt/curriculum-kit';
893
+
894
+ // For project_graph:
895
+ const sot = convertRoadmapToFoundationSot(roadmapJson, projectGraphJson);
896
+
897
+ // curriculum-kit then generates:
898
+ // - LESSON.md (5E lesson plan)
899
+ // - ACT.md (activity lab)
900
+ // - SLIDE.md (slide deck)
901
+ // - QUIZ.md (diagnostic quiz)
902
+ // - etc.
903
+ ```
904
+
905
+ ### Error Handling
906
+
907
+ ```typescript
908
+ try {
909
+ const result = await runProjectGraphPipeline({ repoDir, goal, techStack });
910
+ } catch (err) {
911
+ if (err instanceof LlmClientError) {
912
+ // LLM API error — check API key, model, rate limits
913
+ console.error('LLM error:', err.message, err.status);
914
+ } else {
915
+ // Other errors — file not found, parse error, etc.
916
+ console.error('Pipeline error:', err);
917
+ }
918
+ }
919
+ ```
920
+
921
+ ### Common Pitfalls
922
+
923
+ 1. **Missing repo directory**: `runProjectGraphPipeline()` requires `repoDir` to exist and contain source files
924
+ 2. **Missing syllabus**: `generateKnowledgeGraph()` needs `syllabusText` to decompose concepts
925
+ 3. **Low confidence detection**: If `profile.confidence.domainCategory < 0.6`, the detection may be wrong — ask user to confirm
926
+ 4. **Ambiguous domain**: If `profile.ambiguous` is set, present both options to user (e.g., `.cpp` with ESP32 context could be software or hardware)
927
+ 5. **LLM not configured**: Graph generation (graph/, concepts/, pipeline/) requires `LLM_API_KEY` env var
928
+ 6. **Large repos**: The pipeline reads up to 70 files / 500K chars — very large repos may be truncated
929
+ 7. **ULO/CIO/SIO depth**: Concept escalation now classifies keywords by depth level — ULO (intro), CIO (mechanism), SIO (implementation). This affects how `curriculum-kit` structures exposition depth per lesson
930
+ 8. **Time budget**: `assembleRoadmap()` respects `sessionMinutes` and `maxMilestoneMinutes` — large features are automatically split across milestones. Set these to match your curriculum constraints
931
+
932
+ ### Available Exports
933
+
934
+ ```typescript
935
+ // Detection
936
+ import { detectDomainProfile, detectInputType, detectDomain, detectLearningMode } from '@thanh01.pmt/domain-kit';
937
+
938
+ // Graph generation
939
+ import { runProjectGraphPipeline, generateKnowledgeGraph, generateHybridGraph } from '@thanh01.pmt/domain-kit';
940
+
941
+ // Parsers
942
+ import { parseSwiftFile, parseTsFile, parsePythonFile, parseCppFile } from '@thanh01.pmt/domain-kit';
943
+
944
+ // Keyword extraction
945
+ import { extractKeywords } from '@thanh01.pmt/domain-kit';
946
+
947
+ // Schema validation
948
+ import {
949
+ ProjectGraphSchema, KnowledgeGraphSchema, HybridGraphSchema,
950
+ DomainProfileSchema, ConceptMappingSchema, AssembledRoadmapSchema,
951
+ KnowledgeConceptSchema, KnowledgeLearningPathStepSchema,
952
+ CurriculumFeedSchema, FeedNodeSchema, FeedEdgeSchema, FeedGroupingSchema,
953
+ } from '@thanh01.pmt/domain-kit';
954
+
955
+ // Roadmap assembly
956
+ import { assembleRoadmap } from '@thanh01.pmt/domain-kit';
957
+
958
+ // Concept resolution (ULO/CIO-aware)
959
+ import { resolveConcepts } from '@thanh01.pmt/domain-kit';
960
+
961
+ // Graph verification
962
+ import { verifyProjectGraph } from '@thanh01.pmt/domain-kit';
963
+
964
+ // Concept escalation (with ULO/CIO/SIO depth classification)
965
+ import { escalateAndMapConcepts } from '@thanh01.pmt/domain-kit';
966
+
967
+ // Curriculum Feed emission (any graph → planner-ready feed)
968
+ import { emitCurriculumFeed } from '@thanh01.pmt/domain-kit';
969
+
970
+ // Feed schema validation
971
+ import { validateCurriculumFeed } from '@thanh01.pmt/domain-kit';
972
+ ```
973
+
974
+ > **Note:** Internal utilities like `detectCycles`, `topologicalSort`, `inferDepthFromContext` are used within the pipelines but not exported directly. They are invoked automatically during `generateKnowledgeGraph()` and concept escalation.
975
+
976
+ ---
977
+
978
+ ## Examples
979
+
980
+ ### Example 1: iOS App Project
981
+
982
+ ```typescript
983
+ import { detectDomainProfile, runProjectGraphPipeline } from '@thanh01.pmt/domain-kit';
984
+
985
+ const profile = detectDomainProfile({
986
+ repoUrl: 'https://github.com/thanh01/Talky',
987
+ goal: 'Build iOS chat app with SwiftUI and Firebase',
988
+ techStack: 'Swift,SwiftUI,Firebase',
989
+ });
990
+ // → { graphType: 'project_graph', domainCategory: 'software' }
991
+
992
+ const result = await runProjectGraphPipeline({
993
+ repoDir: '/tmp/talky',
994
+ goal: profile.goal,
995
+ techStack: profile.detectedTechStack.join(','),
996
+ });
997
+
998
+ // result.projectGraph.features = [
999
+ // { id: 'F0', name: 'FOUNDATION & SETUP', steps: [...] },
1000
+ // { id: 'F1', name: 'Welcome & Onboarding', steps: [...] },
1001
+ // { id: 'F2', name: 'Authentication', steps: [...] },
1002
+ // ...
1003
+ // ]
1004
+ ```
1005
+
1006
+ ### Example 2: Math Syllabus
1007
+
1008
+ ```typescript
1009
+ import { detectDomainProfile, generateKnowledgeGraph } from '@thanh01.pmt/domain-kit';
1010
+
1011
+ const profile = detectDomainProfile({
1012
+ syllabusText: `
1013
+ Chương 1: Phân loại góc (nhọn, vuông, tù, bẹt)
1014
+ Chương 2: Tổng ba góc trong tam giác = 180°
1015
+ Chương 3: Tam giác cân, tam giác đều
1016
+ Chương 4: Định lý Pytago
1017
+ `,
1018
+ goal: 'Hiểu và vận dụng kiến thức hình học',
1019
+ gradeBand: [6, 9],
1020
+ });
1021
+ // → { graphType: 'knowledge_graph', domainCategory: 'math' }
1022
+
1023
+ const result = await generateKnowledgeGraph({
1024
+ subject: 'Hình học K12',
1025
+ syllabusText: profile.syllabusText,
1026
+ gradeBand: profile.detectedGradeBand,
1027
+ domain: 'math',
1028
+ });
1029
+
1030
+ // result.knowledgeGraph.concepts = [
1031
+ // { id: 'G1', name: 'Phân loại góc', ulo: '...', cio: '...', sio: [...] },
1032
+ // { id: 'G2', name: 'Tổng 3 góc tam giác', prerequisites: ['G1'], ... },
1033
+ // ...
1034
+ // ]
1035
+ ```
1036
+
1037
+ ### Example 3: Arduino Robot (Hybrid)
1038
+
1039
+ ```typescript
1040
+ import { detectDomainProfile, runProjectGraphPipeline, generateKnowledgeGraph, generateHybridGraph } from '@thanh01.pmt/domain-kit';
1041
+
1042
+ const profile = detectDomainProfile({
1043
+ repoUrl: 'https://github.com/user/arduino-robot',
1044
+ goal: 'Build Arduino robot và hiểu lý thuyết điện tử',
1045
+ techStack: 'Arduino,ESP32',
1046
+ syllabusText: 'Lý thuyết: Ohm\'s law, PWM, I2C communication',
1047
+ });
1048
+ // → { graphType: 'hybrid_graph', domainCategory: 'hardware_iot' }
1049
+
1050
+ // Step A
1051
+ const projectResult = await runProjectGraphPipeline({
1052
+ repoDir: '/tmp/arduino-robot',
1053
+ goal: profile.goal,
1054
+ techStack: profile.detectedTechStack.join(','),
1055
+ });
1056
+
1057
+ // Step B
1058
+ const knowledgeResult = await generateKnowledgeGraph({
1059
+ subject: 'Lý thuyết điện tử',
1060
+ syllabusText: profile.syllabusText,
1061
+ domain: 'science',
1062
+ });
1063
+
1064
+ // Step C
1065
+ const hybridResult = await generateHybridGraph({
1066
+ projectGraph: projectResult.projectGraph,
1067
+ knowledgeGraph: knowledgeResult.knowledgeGraph,
1068
+ });
1069
+
1070
+ // hybridResult.hybridGraph.links = [
1071
+ // { feature_id: 'F2', concept_id: 'E1', relationship: 'requires', depth: 'cio' },
1072
+ // { feature_id: 'F3', concept_id: 'E2', relationship: 'applies', depth: 'sio' },
1073
+ // ...
1074
+ // ]
1075
+ ```
1076
+
1077
+ ---
1078
+
1079
+ ## Contributing
1080
+
1081
+ 1. Fork the repository
1082
+ 2. Create feature branch: `git checkout -b feature/my-feature`
1083
+ 3. Commit changes: `git commit -m 'Add my feature'`
1084
+ 4. Push to branch: `git push origin feature/my-feature`
1085
+ 5. Open Pull Request
1086
+
1087
+ ### Development
1088
+
1089
+ ```bash
1090
+ cd packages/domain-kit
1091
+ npm install
1092
+ npm run typecheck # Check types
1093
+ npm test # Run tests
1094
+ npm run build # Build dist/
1095
+ ```
1096
+
1097
+ ---
1098
+
1099
+ ## License
1100
+
1101
+ MIT © LearnWell Platform Team