@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
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/assembly/roadmapAssembler.ts
|
|
4
|
+
function calculateOverhead(rawMinutes, overheadFactor) {
|
|
5
|
+
return Math.ceil(rawMinutes * overheadFactor);
|
|
6
|
+
}
|
|
7
|
+
function splitFeatureIntoMilestones(feature, featureConcepts, maxMinutes, overheadFactor) {
|
|
8
|
+
const steps = feature.steps || [];
|
|
9
|
+
if (steps.length === 0) return [];
|
|
10
|
+
const featureId = feature.id || "F_UNK";
|
|
11
|
+
const stepMinutes = steps.map((s) => s.effort?.estimated_minutes || 15);
|
|
12
|
+
const totalRawMinutes = stepMinutes.reduce((a, b) => a + b, 0);
|
|
13
|
+
if (calculateOverhead(totalRawMinutes, overheadFactor) <= maxMinutes) {
|
|
14
|
+
return [buildMilestone(feature, featureConcepts, steps, stepMinutes, featureId, 1)];
|
|
15
|
+
}
|
|
16
|
+
const milestones = [];
|
|
17
|
+
let currentSteps = [];
|
|
18
|
+
let currentMinutes = [];
|
|
19
|
+
let milestoneIndex = 1;
|
|
20
|
+
for (let i = 0; i < steps.length; i++) {
|
|
21
|
+
const step = steps[i];
|
|
22
|
+
const mins = stepMinutes[i];
|
|
23
|
+
const currentTotal = currentMinutes.reduce((a, b) => a + b, 0);
|
|
24
|
+
if (calculateOverhead(currentTotal + mins, overheadFactor) > maxMinutes && currentSteps.length > 0) {
|
|
25
|
+
milestones.push(buildMilestone(
|
|
26
|
+
feature,
|
|
27
|
+
featureConcepts,
|
|
28
|
+
currentSteps,
|
|
29
|
+
currentMinutes,
|
|
30
|
+
featureId,
|
|
31
|
+
milestoneIndex
|
|
32
|
+
));
|
|
33
|
+
milestoneIndex++;
|
|
34
|
+
currentSteps = [];
|
|
35
|
+
currentMinutes = [];
|
|
36
|
+
}
|
|
37
|
+
currentSteps.push(step);
|
|
38
|
+
currentMinutes.push(mins);
|
|
39
|
+
}
|
|
40
|
+
if (currentSteps.length > 0) {
|
|
41
|
+
milestones.push(buildMilestone(
|
|
42
|
+
feature,
|
|
43
|
+
featureConcepts,
|
|
44
|
+
currentSteps,
|
|
45
|
+
currentMinutes,
|
|
46
|
+
featureId,
|
|
47
|
+
milestoneIndex
|
|
48
|
+
));
|
|
49
|
+
}
|
|
50
|
+
return milestones;
|
|
51
|
+
}
|
|
52
|
+
function buildMilestone(feature, featureConcepts, steps, stepMinutes, featureId, milestoneIndex) {
|
|
53
|
+
const rawMinutes = stepMinutes.reduce((a, b) => a + b, 0);
|
|
54
|
+
const levels = steps.map((s) => s.completion_level || "mvp");
|
|
55
|
+
const completionLevel = levels.includes("extend") ? "extend" : levels.includes("mvp") ? "mvp" : "base";
|
|
56
|
+
const milestoneConcepts = /* @__PURE__ */ new Set();
|
|
57
|
+
const milestoneKeywords = /* @__PURE__ */ new Set();
|
|
58
|
+
for (const step of steps) {
|
|
59
|
+
const stepConceptCodes = step.concept_codes || [];
|
|
60
|
+
for (const code of stepConceptCodes) {
|
|
61
|
+
milestoneConcepts.add(code);
|
|
62
|
+
}
|
|
63
|
+
const stepKws = [...step.keywords || [], ...step.api_usage || []];
|
|
64
|
+
for (const cm of featureConcepts) {
|
|
65
|
+
if (stepKws.includes(cm.keyword)) {
|
|
66
|
+
milestoneConcepts.add(cm.concept_code);
|
|
67
|
+
milestoneKeywords.add(cm.keyword);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const depthCounts = { ulo: 0, cio: 0, sio: 0 };
|
|
72
|
+
for (const cm of featureConcepts) {
|
|
73
|
+
if (milestoneKeywords.has(cm.keyword)) {
|
|
74
|
+
depthCounts[cm.depth]++;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const dominantDepth = depthCounts.sio >= depthCounts.cio && depthCounts.sio >= depthCounts.ulo ? "sio" : depthCounts.cio >= depthCounts.ulo ? "cio" : "ulo";
|
|
78
|
+
return {
|
|
79
|
+
id: milestoneIndex === 1 ? featureId : `${featureId}-M${milestoneIndex}`,
|
|
80
|
+
name: milestoneIndex === 1 ? feature.name || featureId : `${feature.name || featureId} (Part ${milestoneIndex})`,
|
|
81
|
+
description: feature.description || "",
|
|
82
|
+
feature_id: featureId,
|
|
83
|
+
feature_name: feature.name || "",
|
|
84
|
+
concept_code: [...milestoneConcepts].join(", "),
|
|
85
|
+
depth: dominantDepth,
|
|
86
|
+
all_keywords: [],
|
|
87
|
+
new_keywords: [],
|
|
88
|
+
prerequisite_keywords: [],
|
|
89
|
+
steps,
|
|
90
|
+
estimated_minutes: rawMinutes,
|
|
91
|
+
adjusted_minutes: rawMinutes,
|
|
92
|
+
// placeholder — assembleRoadmap() applies actual overheadFactor
|
|
93
|
+
completion_level: completionLevel
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function buildKeywordMap(featureConcepts) {
|
|
97
|
+
const map = /* @__PURE__ */ new Map();
|
|
98
|
+
for (const mappings of featureConcepts.values()) {
|
|
99
|
+
for (const m of mappings) {
|
|
100
|
+
const existing = map.get(m.concept_code) || [];
|
|
101
|
+
if (!existing.includes(m.keyword)) {
|
|
102
|
+
existing.push(m.keyword);
|
|
103
|
+
map.set(m.concept_code, existing);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return map;
|
|
108
|
+
}
|
|
109
|
+
function attachKeywordsToMilestones(milestones, keywordMap) {
|
|
110
|
+
const cumulativeKeywords = /* @__PURE__ */ new Set();
|
|
111
|
+
for (const milestone of milestones) {
|
|
112
|
+
const allKw = /* @__PURE__ */ new Set();
|
|
113
|
+
const conceptCodes = milestone.concept_code.split(",").map((c) => c.trim()).filter(Boolean);
|
|
114
|
+
for (const code of conceptCodes) {
|
|
115
|
+
const kws = keywordMap.get(code) || [];
|
|
116
|
+
for (const kw of kws) allKw.add(kw);
|
|
117
|
+
}
|
|
118
|
+
milestone.all_keywords = Array.from(allKw).sort();
|
|
119
|
+
const newKw = [];
|
|
120
|
+
const prereqKw = [];
|
|
121
|
+
for (const kw of milestone.all_keywords) {
|
|
122
|
+
if (cumulativeKeywords.has(kw)) {
|
|
123
|
+
prereqKw.push(kw);
|
|
124
|
+
} else {
|
|
125
|
+
newKw.push(kw);
|
|
126
|
+
cumulativeKeywords.add(kw);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
milestone.new_keywords = newKw;
|
|
130
|
+
milestone.prerequisite_keywords = prereqKw;
|
|
131
|
+
}
|
|
132
|
+
return milestones;
|
|
133
|
+
}
|
|
134
|
+
function groupIntoPhases(milestones, sessionMinutes) {
|
|
135
|
+
const phases = [];
|
|
136
|
+
let currentMilestones = [];
|
|
137
|
+
let currentMinutes = 0;
|
|
138
|
+
let phaseNum = 1;
|
|
139
|
+
for (const milestone of milestones) {
|
|
140
|
+
const milestoneMinutes = milestone.adjusted_minutes;
|
|
141
|
+
if (currentMinutes + milestoneMinutes > sessionMinutes && currentMilestones.length > 0) {
|
|
142
|
+
phases.push(buildPhase(currentMilestones, phaseNum));
|
|
143
|
+
phaseNum++;
|
|
144
|
+
currentMilestones = [];
|
|
145
|
+
currentMinutes = 0;
|
|
146
|
+
}
|
|
147
|
+
currentMilestones.push(milestone);
|
|
148
|
+
currentMinutes += milestoneMinutes;
|
|
149
|
+
}
|
|
150
|
+
if (currentMilestones.length > 0) {
|
|
151
|
+
phases.push(buildPhase(currentMilestones, phaseNum));
|
|
152
|
+
}
|
|
153
|
+
return phases;
|
|
154
|
+
}
|
|
155
|
+
function buildPhase(milestones, phaseNum) {
|
|
156
|
+
const totalMinutes = milestones.reduce((sum, m) => sum + m.adjusted_minutes, 0);
|
|
157
|
+
const depths = milestones.map((m) => m.depth);
|
|
158
|
+
const uniqueDepths = [...new Set(depths)];
|
|
159
|
+
const progression = uniqueDepths.map((d) => d.toUpperCase()).join(" \u2192 ");
|
|
160
|
+
return {
|
|
161
|
+
phase_id: phaseNum,
|
|
162
|
+
phase_name: `Phase ${phaseNum}`,
|
|
163
|
+
milestones,
|
|
164
|
+
total_minutes: totalMinutes,
|
|
165
|
+
concept_progression: progression
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function assembleRoadmap(options) {
|
|
169
|
+
const {
|
|
170
|
+
projectGraph,
|
|
171
|
+
featureConcepts = /* @__PURE__ */ new Map(),
|
|
172
|
+
sessionMinutes = 90,
|
|
173
|
+
overheadFactor = 1.15,
|
|
174
|
+
maxMilestoneMinutes = 120
|
|
175
|
+
} = options;
|
|
176
|
+
const features = projectGraph.features || [];
|
|
177
|
+
const keywordMap = buildKeywordMap(featureConcepts);
|
|
178
|
+
const allMilestones = [];
|
|
179
|
+
for (const feature of features) {
|
|
180
|
+
const fid = feature.id || "F_UNK";
|
|
181
|
+
const fConcepts = featureConcepts.get(fid) || [];
|
|
182
|
+
const milestones = splitFeatureIntoMilestones(
|
|
183
|
+
feature,
|
|
184
|
+
fConcepts,
|
|
185
|
+
maxMilestoneMinutes,
|
|
186
|
+
overheadFactor
|
|
187
|
+
);
|
|
188
|
+
allMilestones.push(...milestones);
|
|
189
|
+
}
|
|
190
|
+
for (const milestone of allMilestones) {
|
|
191
|
+
milestone.adjusted_minutes = calculateOverhead(milestone.estimated_minutes, overheadFactor);
|
|
192
|
+
}
|
|
193
|
+
attachKeywordsToMilestones(allMilestones, keywordMap);
|
|
194
|
+
const phases = groupIntoPhases(allMilestones, sessionMinutes);
|
|
195
|
+
const totalEstimatedMinutes = allMilestones.reduce((sum, m) => sum + m.estimated_minutes, 0);
|
|
196
|
+
const totalAdjustedMinutes = allMilestones.reduce((sum, m) => sum + m.adjusted_minutes, 0);
|
|
197
|
+
return {
|
|
198
|
+
project: projectGraph.project,
|
|
199
|
+
product: projectGraph.product,
|
|
200
|
+
phases,
|
|
201
|
+
feature_concepts: featureConcepts,
|
|
202
|
+
time_budget: {
|
|
203
|
+
session_minutes: sessionMinutes,
|
|
204
|
+
overhead_factor: overheadFactor,
|
|
205
|
+
total_estimated_minutes: totalEstimatedMinutes,
|
|
206
|
+
total_adjusted_minutes: totalAdjustedMinutes
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
exports.assembleRoadmap = assembleRoadmap;
|
|
212
|
+
//# sourceMappingURL=index.cjs.map
|
|
213
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/assembly/roadmapAssembler.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Roadmap assembly — assembles final roadmap with keyword tracking and time awareness.\n *\n * Ported from knowledge-tree/assemble_roadmap.py\n * Handles: topo sort, phases, keyword-per-milestone tracking.\n *\n * Improvements:\n * - Time budget per session/lesson\n * - Overhead factor (setup, transitions, review)\n * - Smart feature → milestone splitting (respect time constraints)\n * - Phase grouping based on concept progression\n */\n\nimport type { ProjectGraph, Feature, Step } from '../schemas/projectGraphSchema';\nimport type { ConceptMapping } from '../graph/conceptEscalator';\n\nexport interface AssembledMilestone {\n id: string;\n name: string;\n description: string;\n feature_id: string;\n feature_name: string;\n concept_code: string;\n depth: 'ulo' | 'cio' | 'sio';\n all_keywords: string[];\n new_keywords: string[];\n prerequisite_keywords: string[];\n steps: Step[];\n estimated_minutes: number;\n adjusted_minutes: number; // with overhead\n completion_level: string;\n}\n\nexport interface AssembledPhase {\n phase_id: number;\n phase_name: string;\n milestones: AssembledMilestone[];\n total_minutes: number;\n concept_progression: string; // e.g., \"ULO → CIO → SIO\"\n}\n\nexport interface AssembledRoadmap {\n project: ProjectGraph['project'];\n product: ProjectGraph['product'];\n phases: AssembledPhase[];\n feature_concepts: Map<string, ConceptMapping[]>;\n time_budget: {\n session_minutes: number;\n overhead_factor: number;\n total_estimated_minutes: number;\n total_adjusted_minutes: number;\n };\n}\n\nexport interface AssembleOptions {\n projectGraph: ProjectGraph;\n featureConcepts?: Map<string, ConceptMapping[]>;\n sessionMinutes?: number; // Target minutes per session/lesson (default: 90)\n overheadFactor?: number; // Overhead multiplier (default: 1.15 = 15% overhead)\n maxMilestoneMinutes?: number; // Max minutes before splitting a milestone (default: 120)\n}\n\n// ─── Overhead Calculation ────────────────────────────────────────────────────\n\n/**\n * Calculate overhead-adjusted minutes for a milestone.\n * Overhead includes: setup time, transitions, review, Q&A.\n */\nfunction calculateOverhead(\n rawMinutes: number,\n overheadFactor: number,\n): number {\n return Math.ceil(rawMinutes * overheadFactor);\n}\n\n// ─── Milestone Splitting ─────────────────────────────────────────────────────\n\n/**\n * Split a feature's steps into multiple milestones if they exceed maxMilestoneMinutes.\n * Splits at natural break points (between steps of different complexity).\n */\nfunction splitFeatureIntoMilestones(\n feature: Feature,\n featureConcepts: ConceptMapping[],\n maxMinutes: number,\n overheadFactor: number,\n): AssembledMilestone[] {\n const steps = feature.steps || [];\n if (steps.length === 0) return [];\n\n const featureId = feature.id || 'F_UNK';\n\n // Calculate raw minutes per step\n const stepMinutes = steps.map(s => s.effort?.estimated_minutes || 15);\n const totalRawMinutes = stepMinutes.reduce((a, b) => a + b, 0);\n\n // If within budget, return as single milestone\n if (calculateOverhead(totalRawMinutes, overheadFactor) <= maxMinutes) {\n return [buildMilestone(feature, featureConcepts, steps, stepMinutes, featureId, 1)];\n }\n\n // Split into multiple milestones\n const milestones: AssembledMilestone[] = [];\n let currentSteps: Step[] = [];\n let currentMinutes: number[] = [];\n let milestoneIndex = 1;\n\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i];\n const mins = stepMinutes[i];\n\n // Check if adding this step would exceed budget\n const currentTotal = currentMinutes.reduce((a, b) => a + b, 0);\n if (calculateOverhead(currentTotal + mins, overheadFactor) > maxMinutes && currentSteps.length > 0) {\n // Split here\n milestones.push(buildMilestone(\n feature, featureConcepts, currentSteps, currentMinutes,\n featureId, milestoneIndex,\n ));\n milestoneIndex++;\n currentSteps = [];\n currentMinutes = [];\n }\n\n currentSteps.push(step);\n currentMinutes.push(mins);\n }\n\n // Don't forget the last group\n if (currentSteps.length > 0) {\n milestones.push(buildMilestone(\n feature, featureConcepts, currentSteps, currentMinutes,\n featureId, milestoneIndex,\n ));\n }\n\n return milestones;\n}\n\n/**\n * Build a single AssembledMilestone from steps.\n * Concept codes are mapped per-step, not per-feature.\n */\nfunction buildMilestone(\n feature: Feature,\n featureConcepts: ConceptMapping[],\n steps: Step[],\n stepMinutes: number[],\n featureId: string,\n milestoneIndex: number,\n): AssembledMilestone {\n const rawMinutes = stepMinutes.reduce((a, b) => a + b, 0);\n const levels = steps.map(s => s.completion_level || 'mvp');\n const completionLevel = levels.includes('extend') ? 'extend'\n : levels.includes('mvp') ? 'mvp'\n : 'base';\n\n // Collect concept codes PER STEP (not per feature)\n const milestoneConcepts = new Set<string>();\n const milestoneKeywords = new Set<string>();\n for (const step of steps) {\n // Use step-level concept_codes if propagated, else match by keyword\n const stepConceptCodes = step.concept_codes || [];\n for (const code of stepConceptCodes) {\n milestoneConcepts.add(code);\n }\n // Also match by keyword presence\n const stepKws = [...(step.keywords || []), ...(step.api_usage || [])];\n for (const cm of featureConcepts) {\n if (stepKws.includes(cm.keyword)) {\n milestoneConcepts.add(cm.concept_code);\n milestoneKeywords.add(cm.keyword);\n }\n }\n }\n\n // Determine dominant depth from step-level concept mappings\n const depthCounts = { ulo: 0, cio: 0, sio: 0 };\n for (const cm of featureConcepts) {\n if (milestoneKeywords.has(cm.keyword)) {\n depthCounts[cm.depth]++;\n }\n }\n const dominantDepth: 'ulo' | 'cio' | 'sio' =\n depthCounts.sio >= depthCounts.cio && depthCounts.sio >= depthCounts.ulo ? 'sio'\n : depthCounts.cio >= depthCounts.ulo ? 'cio'\n : 'ulo';\n\n return {\n id: milestoneIndex === 1 ? featureId : `${featureId}-M${milestoneIndex}`,\n name: milestoneIndex === 1 ? (feature.name || featureId) : `${feature.name || featureId} (Part ${milestoneIndex})`,\n description: feature.description || '',\n feature_id: featureId,\n feature_name: feature.name || '',\n concept_code: [...milestoneConcepts].join(', '),\n depth: dominantDepth,\n all_keywords: [],\n new_keywords: [],\n prerequisite_keywords: [],\n steps,\n estimated_minutes: rawMinutes,\n adjusted_minutes: rawMinutes, // placeholder — assembleRoadmap() applies actual overheadFactor\n completion_level: completionLevel,\n };\n}\n\n// ─── Keyword Tracking ────────────────────────────────────────────────────────\n\n/**\n * Build keyword map: concept_code → [keywords]\n */\nfunction buildKeywordMap(\n featureConcepts: Map<string, ConceptMapping[]>,\n): Map<string, string[]> {\n const map = new Map<string, string[]>();\n for (const mappings of featureConcepts.values()) {\n for (const m of mappings) {\n const existing = map.get(m.concept_code) || [];\n if (!existing.includes(m.keyword)) {\n existing.push(m.keyword);\n map.set(m.concept_code, existing);\n }\n }\n }\n return map;\n}\n\n/**\n * Attach keywords to milestones, computing new vs prerequisite.\n */\nfunction attachKeywordsToMilestones(\n milestones: AssembledMilestone[],\n keywordMap: Map<string, string[]>,\n): AssembledMilestone[] {\n const cumulativeKeywords = new Set<string>();\n\n for (const milestone of milestones) {\n // Aggregate keywords from concept codes\n const allKw = new Set<string>();\n const conceptCodes = milestone.concept_code.split(',').map((c: string) => c.trim()).filter(Boolean);\n for (const code of conceptCodes) {\n const kws = keywordMap.get(code) || [];\n for (const kw of kws) allKw.add(kw);\n }\n\n milestone.all_keywords = Array.from(allKw).sort();\n\n // Compute new vs prerequisite\n const newKw: string[] = [];\n const prereqKw: string[] = [];\n for (const kw of milestone.all_keywords) {\n if (cumulativeKeywords.has(kw)) {\n prereqKw.push(kw);\n } else {\n newKw.push(kw);\n cumulativeKeywords.add(kw);\n }\n }\n\n milestone.new_keywords = newKw;\n milestone.prerequisite_keywords = prereqKw;\n }\n\n return milestones;\n}\n\n// ─── Phase Grouping ──────────────────────────────────────────────────────────\n\n/**\n * Group milestones into phases based on time budget and concept progression.\n */\nfunction groupIntoPhases(\n milestones: AssembledMilestone[],\n sessionMinutes: number,\n): AssembledPhase[] {\n const phases: AssembledPhase[] = [];\n let currentMilestones: AssembledMilestone[] = [];\n let currentMinutes = 0;\n let phaseNum = 1;\n\n for (const milestone of milestones) {\n const milestoneMinutes = milestone.adjusted_minutes;\n\n // If adding this milestone would exceed session budget, start new phase\n if (currentMinutes + milestoneMinutes > sessionMinutes && currentMilestones.length > 0) {\n phases.push(buildPhase(currentMilestones, phaseNum));\n phaseNum++;\n currentMilestones = [];\n currentMinutes = 0;\n }\n\n currentMilestones.push(milestone);\n currentMinutes += milestoneMinutes;\n }\n\n // Don't forget the last phase\n if (currentMilestones.length > 0) {\n phases.push(buildPhase(currentMilestones, phaseNum));\n }\n\n return phases;\n}\n\nfunction buildPhase(milestones: AssembledMilestone[], phaseNum: number): AssembledPhase {\n const totalMinutes = milestones.reduce((sum, m) => sum + m.adjusted_minutes, 0);\n\n // Determine concept progression\n const depths = milestones.map(m => m.depth);\n const uniqueDepths = [...new Set(depths)];\n const progression = uniqueDepths.map(d => d.toUpperCase()).join(' → ');\n\n return {\n phase_id: phaseNum,\n phase_name: `Phase ${phaseNum}`,\n milestones,\n total_minutes: totalMinutes,\n concept_progression: progression,\n };\n}\n\n// ─── Main Assembly ───────────────────────────────────────────────────────────\n\n/**\n * Assemble project graph into a roadmap with phases and keyword tracking.\n */\nexport function assembleRoadmap(options: AssembleOptions): AssembledRoadmap {\n const {\n projectGraph,\n featureConcepts = new Map(),\n sessionMinutes = 90,\n overheadFactor = 1.15,\n maxMilestoneMinutes = 120,\n } = options;\n\n const features = projectGraph.features || [];\n const keywordMap = buildKeywordMap(featureConcepts);\n\n // Build milestones from features (with splitting)\n const allMilestones: AssembledMilestone[] = [];\n\n for (const feature of features) {\n const fid = feature.id || 'F_UNK';\n const fConcepts = featureConcepts.get(fid) || [];\n\n const milestones = splitFeatureIntoMilestones(\n feature,\n fConcepts,\n maxMilestoneMinutes,\n overheadFactor,\n );\n\n allMilestones.push(...milestones);\n }\n\n // Apply overhead factor\n for (const milestone of allMilestones) {\n milestone.adjusted_minutes = calculateOverhead(milestone.estimated_minutes, overheadFactor);\n }\n\n // Attach keywords (new vs prerequisite)\n attachKeywordsToMilestones(allMilestones, keywordMap);\n\n // Group into phases based on session time\n const phases = groupIntoPhases(allMilestones, sessionMinutes);\n\n // Calculate totals\n const totalEstimatedMinutes = allMilestones.reduce((sum, m) => sum + m.estimated_minutes, 0);\n const totalAdjustedMinutes = allMilestones.reduce((sum, m) => sum + m.adjusted_minutes, 0);\n\n return {\n project: projectGraph.project,\n product: projectGraph.product,\n phases,\n feature_concepts: featureConcepts,\n time_budget: {\n session_minutes: sessionMinutes,\n overhead_factor: overheadFactor,\n total_estimated_minutes: totalEstimatedMinutes,\n total_adjusted_minutes: totalAdjustedMinutes,\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { u as ProjectGraph, c as Step } from '../projectGraphSchema-DnD7orZV.cjs';
|
|
2
|
+
import { C as ConceptMapping } from '../conceptEscalator-ltRLtPhf.cjs';
|
|
3
|
+
import 'zod';
|
|
4
|
+
import '../llmClient-ysPhLjcH.cjs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Roadmap assembly — assembles final roadmap with keyword tracking and time awareness.
|
|
8
|
+
*
|
|
9
|
+
* Ported from knowledge-tree/assemble_roadmap.py
|
|
10
|
+
* Handles: topo sort, phases, keyword-per-milestone tracking.
|
|
11
|
+
*
|
|
12
|
+
* Improvements:
|
|
13
|
+
* - Time budget per session/lesson
|
|
14
|
+
* - Overhead factor (setup, transitions, review)
|
|
15
|
+
* - Smart feature → milestone splitting (respect time constraints)
|
|
16
|
+
* - Phase grouping based on concept progression
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
interface AssembledMilestone {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
description: string;
|
|
23
|
+
feature_id: string;
|
|
24
|
+
feature_name: string;
|
|
25
|
+
concept_code: string;
|
|
26
|
+
depth: 'ulo' | 'cio' | 'sio';
|
|
27
|
+
all_keywords: string[];
|
|
28
|
+
new_keywords: string[];
|
|
29
|
+
prerequisite_keywords: string[];
|
|
30
|
+
steps: Step[];
|
|
31
|
+
estimated_minutes: number;
|
|
32
|
+
adjusted_minutes: number;
|
|
33
|
+
completion_level: string;
|
|
34
|
+
}
|
|
35
|
+
interface AssembledPhase {
|
|
36
|
+
phase_id: number;
|
|
37
|
+
phase_name: string;
|
|
38
|
+
milestones: AssembledMilestone[];
|
|
39
|
+
total_minutes: number;
|
|
40
|
+
concept_progression: string;
|
|
41
|
+
}
|
|
42
|
+
interface AssembledRoadmap {
|
|
43
|
+
project: ProjectGraph['project'];
|
|
44
|
+
product: ProjectGraph['product'];
|
|
45
|
+
phases: AssembledPhase[];
|
|
46
|
+
feature_concepts: Map<string, ConceptMapping[]>;
|
|
47
|
+
time_budget: {
|
|
48
|
+
session_minutes: number;
|
|
49
|
+
overhead_factor: number;
|
|
50
|
+
total_estimated_minutes: number;
|
|
51
|
+
total_adjusted_minutes: number;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
interface AssembleOptions {
|
|
55
|
+
projectGraph: ProjectGraph;
|
|
56
|
+
featureConcepts?: Map<string, ConceptMapping[]>;
|
|
57
|
+
sessionMinutes?: number;
|
|
58
|
+
overheadFactor?: number;
|
|
59
|
+
maxMilestoneMinutes?: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Assemble project graph into a roadmap with phases and keyword tracking.
|
|
63
|
+
*/
|
|
64
|
+
declare function assembleRoadmap(options: AssembleOptions): AssembledRoadmap;
|
|
65
|
+
|
|
66
|
+
export { type AssembleOptions, type AssembledMilestone, type AssembledPhase, type AssembledRoadmap, assembleRoadmap };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { u as ProjectGraph, c as Step } from '../projectGraphSchema-DnD7orZV.js';
|
|
2
|
+
import { C as ConceptMapping } from '../conceptEscalator-YfMKIKCZ.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
import '../llmClient-ysPhLjcH.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Roadmap assembly — assembles final roadmap with keyword tracking and time awareness.
|
|
8
|
+
*
|
|
9
|
+
* Ported from knowledge-tree/assemble_roadmap.py
|
|
10
|
+
* Handles: topo sort, phases, keyword-per-milestone tracking.
|
|
11
|
+
*
|
|
12
|
+
* Improvements:
|
|
13
|
+
* - Time budget per session/lesson
|
|
14
|
+
* - Overhead factor (setup, transitions, review)
|
|
15
|
+
* - Smart feature → milestone splitting (respect time constraints)
|
|
16
|
+
* - Phase grouping based on concept progression
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
interface AssembledMilestone {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
description: string;
|
|
23
|
+
feature_id: string;
|
|
24
|
+
feature_name: string;
|
|
25
|
+
concept_code: string;
|
|
26
|
+
depth: 'ulo' | 'cio' | 'sio';
|
|
27
|
+
all_keywords: string[];
|
|
28
|
+
new_keywords: string[];
|
|
29
|
+
prerequisite_keywords: string[];
|
|
30
|
+
steps: Step[];
|
|
31
|
+
estimated_minutes: number;
|
|
32
|
+
adjusted_minutes: number;
|
|
33
|
+
completion_level: string;
|
|
34
|
+
}
|
|
35
|
+
interface AssembledPhase {
|
|
36
|
+
phase_id: number;
|
|
37
|
+
phase_name: string;
|
|
38
|
+
milestones: AssembledMilestone[];
|
|
39
|
+
total_minutes: number;
|
|
40
|
+
concept_progression: string;
|
|
41
|
+
}
|
|
42
|
+
interface AssembledRoadmap {
|
|
43
|
+
project: ProjectGraph['project'];
|
|
44
|
+
product: ProjectGraph['product'];
|
|
45
|
+
phases: AssembledPhase[];
|
|
46
|
+
feature_concepts: Map<string, ConceptMapping[]>;
|
|
47
|
+
time_budget: {
|
|
48
|
+
session_minutes: number;
|
|
49
|
+
overhead_factor: number;
|
|
50
|
+
total_estimated_minutes: number;
|
|
51
|
+
total_adjusted_minutes: number;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
interface AssembleOptions {
|
|
55
|
+
projectGraph: ProjectGraph;
|
|
56
|
+
featureConcepts?: Map<string, ConceptMapping[]>;
|
|
57
|
+
sessionMinutes?: number;
|
|
58
|
+
overheadFactor?: number;
|
|
59
|
+
maxMilestoneMinutes?: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Assemble project graph into a roadmap with phases and keyword tracking.
|
|
63
|
+
*/
|
|
64
|
+
declare function assembleRoadmap(options: AssembleOptions): AssembledRoadmap;
|
|
65
|
+
|
|
66
|
+
export { type AssembleOptions, type AssembledMilestone, type AssembledPhase, type AssembledRoadmap, assembleRoadmap };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.mjs"}
|