@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.
- package/README.md +1101 -0
- package/dist/assembly/index.cjs +213 -0
- package/dist/assembly/index.cjs.map +1 -0
- package/dist/assembly/index.d.cts +66 -0
- package/dist/assembly/index.d.ts +66 -0
- package/dist/assembly/index.mjs +4 -0
- package/dist/assembly/index.mjs.map +1 -0
- package/dist/chunk-3H2HX7PR.mjs +324 -0
- package/dist/chunk-3H2HX7PR.mjs.map +1 -0
- package/dist/chunk-3VVPSRAM.mjs +1297 -0
- package/dist/chunk-3VVPSRAM.mjs.map +1 -0
- package/dist/chunk-DRVOV5ZD.mjs +314 -0
- package/dist/chunk-DRVOV5ZD.mjs.map +1 -0
- package/dist/chunk-F4RZNBOE.mjs +3 -0
- package/dist/chunk-F4RZNBOE.mjs.map +1 -0
- package/dist/chunk-GEUDHZE7.mjs +446 -0
- package/dist/chunk-GEUDHZE7.mjs.map +1 -0
- package/dist/chunk-HH4UX65C.mjs +100 -0
- package/dist/chunk-HH4UX65C.mjs.map +1 -0
- package/dist/chunk-KMYENICQ.mjs +3 -0
- package/dist/chunk-KMYENICQ.mjs.map +1 -0
- package/dist/chunk-KNDBODUQ.mjs +153 -0
- package/dist/chunk-KNDBODUQ.mjs.map +1 -0
- package/dist/chunk-MM2RWYNW.mjs +3 -0
- package/dist/chunk-MM2RWYNW.mjs.map +1 -0
- package/dist/chunk-MOKNFLUD.mjs +851 -0
- package/dist/chunk-MOKNFLUD.mjs.map +1 -0
- package/dist/chunk-ONQHJ4OH.mjs +211 -0
- package/dist/chunk-ONQHJ4OH.mjs.map +1 -0
- package/dist/chunk-PM42MMDJ.mjs +516 -0
- package/dist/chunk-PM42MMDJ.mjs.map +1 -0
- package/dist/chunk-RKRNOVKO.mjs +166 -0
- package/dist/chunk-RKRNOVKO.mjs.map +1 -0
- package/dist/chunk-VFART56O.mjs +884 -0
- package/dist/chunk-VFART56O.mjs.map +1 -0
- package/dist/chunk-XMHKWHVK.mjs +218 -0
- package/dist/chunk-XMHKWHVK.mjs.map +1 -0
- package/dist/conceptEscalator-YfMKIKCZ.d.ts +40 -0
- package/dist/conceptEscalator-ltRLtPhf.d.cts +40 -0
- package/dist/concepts/index.cjs +155 -0
- package/dist/concepts/index.cjs.map +1 -0
- package/dist/concepts/index.d.cts +79 -0
- package/dist/concepts/index.d.ts +79 -0
- package/dist/concepts/index.mjs +4 -0
- package/dist/concepts/index.mjs.map +1 -0
- package/dist/curriculumFeedSchema-TEeQg2bY.d.cts +549 -0
- package/dist/curriculumFeedSchema-TEeQg2bY.d.ts +549 -0
- package/dist/detector/index.cjs +889 -0
- package/dist/detector/index.cjs.map +1 -0
- package/dist/detector/index.d.cts +112 -0
- package/dist/detector/index.d.ts +112 -0
- package/dist/detector/index.mjs +3 -0
- package/dist/detector/index.mjs.map +1 -0
- package/dist/domainProfileSchema-CwT3Ffsw.d.cts +105 -0
- package/dist/domainProfileSchema-CwT3Ffsw.d.ts +105 -0
- package/dist/extractors/index.cjs +387 -0
- package/dist/extractors/index.cjs.map +1 -0
- package/dist/extractors/index.d.cts +46 -0
- package/dist/extractors/index.d.ts +46 -0
- package/dist/extractors/index.mjs +4 -0
- package/dist/extractors/index.mjs.map +1 -0
- package/dist/feed/index.cjs +421 -0
- package/dist/feed/index.cjs.map +1 -0
- package/dist/feed/index.d.cts +23 -0
- package/dist/feed/index.d.ts +23 -0
- package/dist/feed/index.mjs +4 -0
- package/dist/feed/index.mjs.map +1 -0
- package/dist/graph/index.cjs +2167 -0
- package/dist/graph/index.cjs.map +1 -0
- package/dist/graph/index.d.cts +226 -0
- package/dist/graph/index.d.ts +226 -0
- package/dist/graph/index.mjs +4 -0
- package/dist/graph/index.mjs.map +1 -0
- package/dist/graphVerifier-DsTP9uAN.d.ts +37 -0
- package/dist/graphVerifier-QjgDAJce.d.cts +37 -0
- package/dist/hybridGraphSchema-BCgXicgA.d.cts +2840 -0
- package/dist/hybridGraphSchema-BCgXicgA.d.ts +2840 -0
- package/dist/index.cjs +5539 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.mjs +17 -0
- package/dist/index.mjs.map +1 -0
- package/dist/keywordExtractor-CKaXqSku.d.ts +34 -0
- package/dist/keywordExtractor-zPAz2isq.d.cts +34 -0
- package/dist/llmClient-ysPhLjcH.d.cts +16 -0
- package/dist/llmClient-ysPhLjcH.d.ts +16 -0
- package/dist/parsers/index.cjs +323 -0
- package/dist/parsers/index.cjs.map +1 -0
- package/dist/parsers/index.d.cts +98 -0
- package/dist/parsers/index.d.ts +98 -0
- package/dist/parsers/index.mjs +4 -0
- package/dist/parsers/index.mjs.map +1 -0
- package/dist/pipeline/index.cjs +2166 -0
- package/dist/pipeline/index.cjs.map +1 -0
- package/dist/pipeline/index.d.cts +45 -0
- package/dist/pipeline/index.d.ts +45 -0
- package/dist/pipeline/index.mjs +8 -0
- package/dist/pipeline/index.mjs.map +1 -0
- package/dist/projectGraphSchema-DnD7orZV.d.cts +2581 -0
- package/dist/projectGraphSchema-DnD7orZV.d.ts +2581 -0
- package/dist/schemas/index.cjs +675 -0
- package/dist/schemas/index.cjs.map +1 -0
- package/dist/schemas/index.d.cts +253 -0
- package/dist/schemas/index.d.ts +253 -0
- package/dist/schemas/index.mjs +4 -0
- package/dist/schemas/index.mjs.map +1 -0
- 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
|
+
[](https://typescriptlang.org)
|
|
6
|
+
[](https://zod.dev)
|
|
7
|
+
[](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
|