concept-atlas-dense-explain 0.2.0 → 0.2.2
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/package.json +12 -3
- package/skill/SKILL.md +84 -59
- package/skill/assets/template/content/compile-runtime.mdx +158 -158
- package/skill/assets/template/index.html +16 -16
- package/skill/assets/template/package.json +20 -20
- package/skill/assets/template/scripts/build.mjs +37 -37
- package/skill/assets/template/scripts/clean-temp.mjs +27 -27
- package/skill/assets/template/src/app/App.jsx +239 -239
- package/skill/assets/template/src/components/MDXComponents.jsx +503 -477
- package/skill/assets/template/src/components/index.js +1 -1
- package/skill/assets/template/src/main.jsx +16 -16
- package/skill/assets/template/src/model/concept-schema.js +169 -169
- package/skill/assets/template/src/model/normalize-content.js +241 -236
- package/skill/assets/template/src/model/relation-types.js +90 -90
- package/skill/assets/template/src/styles/concept-explain.css +290 -9
- package/skill/assets/template/src/views/NodeExplorer.jsx +59 -20
- package/skill/assets/template/src/views/RelationGraph.jsx +16 -1
- package/skill/assets/template/vite.config.js +21 -21
- package/skill/references/components.md +74 -64
- package/skill/references/prompting.md +77 -77
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from './MDXComponents.jsx';
|
|
1
|
+
export * from './MDXComponents.jsx';
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import ReactDOM from 'react-dom/client';
|
|
3
|
-
import { App } from './app/App.jsx';
|
|
4
|
-
import * as Components from './components/index.js';
|
|
5
|
-
import CompileRuntimeDoc from '../content/compile-runtime.mdx';
|
|
6
|
-
|
|
7
|
-
// Mount MDX application to DOM
|
|
8
|
-
const rootElement = document.getElementById('root') || document.getElementById('app');
|
|
9
|
-
if (rootElement) {
|
|
10
|
-
const root = ReactDOM.createRoot(rootElement);
|
|
11
|
-
root.render(
|
|
12
|
-
<React.StrictMode>
|
|
13
|
-
<App mdxContent={<CompileRuntimeDoc components={Components} />} />
|
|
14
|
-
</React.StrictMode>
|
|
15
|
-
);
|
|
16
|
-
}
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom/client';
|
|
3
|
+
import { App } from './app/App.jsx';
|
|
4
|
+
import * as Components from './components/index.js';
|
|
5
|
+
import CompileRuntimeDoc from '../content/compile-runtime.mdx';
|
|
6
|
+
|
|
7
|
+
// Mount MDX application to DOM
|
|
8
|
+
const rootElement = document.getElementById('root') || document.getElementById('app');
|
|
9
|
+
if (rootElement) {
|
|
10
|
+
const root = ReactDOM.createRoot(rootElement);
|
|
11
|
+
root.render(
|
|
12
|
+
<React.StrictMode>
|
|
13
|
+
<App mdxContent={<CompileRuntimeDoc components={Components} />} />
|
|
14
|
+
</React.StrictMode>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -1,169 +1,169 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { RELATION_TYPES, LEVEL_DEFS } from './relation-types.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Creates an empty Concept Knowledge Graph structure
|
|
6
|
-
*/
|
|
7
|
-
export function createConceptGraphState() {
|
|
8
|
-
return {
|
|
9
|
-
meta: {
|
|
10
|
-
id: '',
|
|
11
|
-
title: '',
|
|
12
|
-
summary: '',
|
|
13
|
-
rootId: ''
|
|
14
|
-
},
|
|
15
|
-
nodes: new Map(), // id -> NodeObject
|
|
16
|
-
relations: [], // Array<{ from, to, type, label, description }>
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Normalizes raw node data extracted from MDX AST or React component tree
|
|
22
|
-
*/
|
|
23
|
-
export function normalizeNode(raw) {
|
|
24
|
-
const id = raw.id || String(Math.random());
|
|
25
|
-
return {
|
|
26
|
-
id,
|
|
27
|
-
title: raw.title || id,
|
|
28
|
-
level: raw.level || 'L2',
|
|
29
|
-
parent: raw.parent || null,
|
|
30
|
-
children: Array.isArray(raw.children) ? raw.children : [],
|
|
31
|
-
|
|
32
|
-
// Semantic Content Sections
|
|
33
|
-
summary: raw.summary || '',
|
|
34
|
-
overview: raw.overview || null,
|
|
35
|
-
definition: raw.definition || null,
|
|
36
|
-
mechanism: raw.mechanism || null,
|
|
37
|
-
input: raw.input || null,
|
|
38
|
-
output: raw.output || null,
|
|
39
|
-
prerequisites: raw.prerequisites || [],
|
|
40
|
-
implementation: raw.implementation || null, // { language, code } or React node
|
|
41
|
-
examples: raw.examples || [],
|
|
42
|
-
counterexamples: raw.counterexamples || [],
|
|
43
|
-
boundaries: raw.boundaries || [],
|
|
44
|
-
glossary: raw.glossary || [],
|
|
45
|
-
customSections: raw.customSections || [],
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Validates and indexes nodes and relations to build a graph model
|
|
51
|
-
*/
|
|
52
|
-
export function buildGraphModel(rawGraph) {
|
|
53
|
-
const nodes = new Map();
|
|
54
|
-
const diagnostics = [];
|
|
55
|
-
const rawNodes = rawGraph.nodes || [];
|
|
56
|
-
const rawRelations = rawGraph.relations || [];
|
|
57
|
-
|
|
58
|
-
// Register all nodes
|
|
59
|
-
rawNodes.forEach(n => {
|
|
60
|
-
const node = normalizeNode(n);
|
|
61
|
-
if (nodes.has(node.id)) diagnostics.push({ level: 'error', code: 'DUPLICATE_NODE_ID', nodeId: node.id });
|
|
62
|
-
nodes.set(node.id, node);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
// Build tree hierarchy: ensure parent <-> children consistency
|
|
66
|
-
nodes.forEach(node => {
|
|
67
|
-
if (node.parent && nodes.has(node.parent)) {
|
|
68
|
-
const parentNode = nodes.get(node.parent);
|
|
69
|
-
if (!parentNode.children.includes(node.id)) {
|
|
70
|
-
parentNode.children.push(node.id);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
// Explicit children references (from <ConceptRef />)
|
|
76
|
-
nodes.forEach(node => {
|
|
77
|
-
node.children.forEach(childId => {
|
|
78
|
-
if (nodes.has(childId)) {
|
|
79
|
-
const childNode = nodes.get(childId);
|
|
80
|
-
if (!childNode.parent) {
|
|
81
|
-
childNode.parent = node.id;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
else diagnostics.push({ level: 'warning', code: 'MISSING_CHILD', nodeId: node.id, targetId: childId });
|
|
85
|
-
});
|
|
86
|
-
if (node.parent && !nodes.has(node.parent)) diagnostics.push({ level: 'warning', code: 'ORPHAN_NODE', nodeId: node.id, targetId: node.parent });
|
|
87
|
-
if (!LEVEL_DEFS[node.level]) diagnostics.push({ level: 'warning', code: 'UNKNOWN_LEVEL', nodeId: node.id, level: node.level });
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
// Filter valid relations
|
|
91
|
-
const validRelations = [];
|
|
92
|
-
rawRelations.forEach(rel => {
|
|
93
|
-
if (nodes.has(rel.from) && nodes.has(rel.to)) {
|
|
94
|
-
const typeDef = RELATION_TYPES[rel.type] || {
|
|
95
|
-
label: rel.type,
|
|
96
|
-
color: '#94a3b8',
|
|
97
|
-
hasArrow: true
|
|
98
|
-
};
|
|
99
|
-
validRelations.push({
|
|
100
|
-
...rel,
|
|
101
|
-
typeLabel: rel.label || typeDef.label,
|
|
102
|
-
typeInfo: typeDef
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// Determine root
|
|
108
|
-
let rootId = rawGraph.meta?.rootId;
|
|
109
|
-
if (!rootId || !nodes.has(rootId)) {
|
|
110
|
-
// Find node with no parent or level L0
|
|
111
|
-
for (const [id, node] of nodes.entries()) {
|
|
112
|
-
if (!node.parent || node.level === 'L0') {
|
|
113
|
-
rootId = id;
|
|
114
|
-
break;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return {
|
|
120
|
-
meta: {
|
|
121
|
-
...rawGraph.meta,
|
|
122
|
-
rootId: rootId || (nodes.size > 0 ? Array.from(nodes.keys())[0] : null)
|
|
123
|
-
},
|
|
124
|
-
nodes,
|
|
125
|
-
relations: validRelations,
|
|
126
|
-
diagnostics
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Helper to compute ancestor path from root to current node
|
|
132
|
-
*/
|
|
133
|
-
export function getAncestorPath(nodes, nodeId) {
|
|
134
|
-
const path = [];
|
|
135
|
-
let current = nodes.get(nodeId);
|
|
136
|
-
const visited = new Set();
|
|
137
|
-
while (current && !visited.has(current.id)) {
|
|
138
|
-
visited.add(current.id);
|
|
139
|
-
path.unshift(current);
|
|
140
|
-
if (!current.parent) break;
|
|
141
|
-
current = nodes.get(current.parent);
|
|
142
|
-
}
|
|
143
|
-
return path;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Helper to get siblings of a node
|
|
148
|
-
*/
|
|
149
|
-
export function getSiblingNodes(nodes, nodeId) {
|
|
150
|
-
const current = nodes.get(nodeId);
|
|
151
|
-
if (!current || !current.parent) {
|
|
152
|
-
// If root or has no parent, find other root nodes
|
|
153
|
-
return Array.from(nodes.values()).filter(n => !n.parent && n.id !== nodeId);
|
|
154
|
-
}
|
|
155
|
-
const parent = nodes.get(current.parent);
|
|
156
|
-
if (!parent) return [];
|
|
157
|
-
return parent.children
|
|
158
|
-
.filter(id => id !== nodeId && nodes.has(id))
|
|
159
|
-
.map(id => nodes.get(id));
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Helper to get all incoming and outgoing relations for a node
|
|
164
|
-
*/
|
|
165
|
-
export function getNodeRelations(relations, nodeId) {
|
|
166
|
-
const incoming = relations.filter(r => r.to === nodeId);
|
|
167
|
-
const outgoing = relations.filter(r => r.from === nodeId);
|
|
168
|
-
return { incoming, outgoing };
|
|
169
|
-
}
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { RELATION_TYPES, LEVEL_DEFS } from './relation-types.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates an empty Concept Knowledge Graph structure
|
|
6
|
+
*/
|
|
7
|
+
export function createConceptGraphState() {
|
|
8
|
+
return {
|
|
9
|
+
meta: {
|
|
10
|
+
id: '',
|
|
11
|
+
title: '',
|
|
12
|
+
summary: '',
|
|
13
|
+
rootId: ''
|
|
14
|
+
},
|
|
15
|
+
nodes: new Map(), // id -> NodeObject
|
|
16
|
+
relations: [], // Array<{ from, to, type, label, description }>
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Normalizes raw node data extracted from MDX AST or React component tree
|
|
22
|
+
*/
|
|
23
|
+
export function normalizeNode(raw) {
|
|
24
|
+
const id = raw.id || String(Math.random());
|
|
25
|
+
return {
|
|
26
|
+
id,
|
|
27
|
+
title: raw.title || id,
|
|
28
|
+
level: raw.level || 'L2',
|
|
29
|
+
parent: raw.parent || null,
|
|
30
|
+
children: Array.isArray(raw.children) ? raw.children : [],
|
|
31
|
+
|
|
32
|
+
// Semantic Content Sections
|
|
33
|
+
summary: raw.summary || '',
|
|
34
|
+
overview: raw.overview || null,
|
|
35
|
+
definition: raw.definition || null,
|
|
36
|
+
mechanism: raw.mechanism || null,
|
|
37
|
+
input: raw.input || null,
|
|
38
|
+
output: raw.output || null,
|
|
39
|
+
prerequisites: raw.prerequisites || [],
|
|
40
|
+
implementation: raw.implementation || null, // { language, code } or React node
|
|
41
|
+
examples: raw.examples || [],
|
|
42
|
+
counterexamples: raw.counterexamples || [],
|
|
43
|
+
boundaries: raw.boundaries || [],
|
|
44
|
+
glossary: raw.glossary || [],
|
|
45
|
+
customSections: raw.customSections || [],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Validates and indexes nodes and relations to build a graph model
|
|
51
|
+
*/
|
|
52
|
+
export function buildGraphModel(rawGraph) {
|
|
53
|
+
const nodes = new Map();
|
|
54
|
+
const diagnostics = [];
|
|
55
|
+
const rawNodes = rawGraph.nodes || [];
|
|
56
|
+
const rawRelations = rawGraph.relations || [];
|
|
57
|
+
|
|
58
|
+
// Register all nodes
|
|
59
|
+
rawNodes.forEach(n => {
|
|
60
|
+
const node = normalizeNode(n);
|
|
61
|
+
if (nodes.has(node.id)) diagnostics.push({ level: 'error', code: 'DUPLICATE_NODE_ID', nodeId: node.id });
|
|
62
|
+
nodes.set(node.id, node);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Build tree hierarchy: ensure parent <-> children consistency
|
|
66
|
+
nodes.forEach(node => {
|
|
67
|
+
if (node.parent && nodes.has(node.parent)) {
|
|
68
|
+
const parentNode = nodes.get(node.parent);
|
|
69
|
+
if (!parentNode.children.includes(node.id)) {
|
|
70
|
+
parentNode.children.push(node.id);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Explicit children references (from <ConceptRef />)
|
|
76
|
+
nodes.forEach(node => {
|
|
77
|
+
node.children.forEach(childId => {
|
|
78
|
+
if (nodes.has(childId)) {
|
|
79
|
+
const childNode = nodes.get(childId);
|
|
80
|
+
if (!childNode.parent) {
|
|
81
|
+
childNode.parent = node.id;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else diagnostics.push({ level: 'warning', code: 'MISSING_CHILD', nodeId: node.id, targetId: childId });
|
|
85
|
+
});
|
|
86
|
+
if (node.parent && !nodes.has(node.parent)) diagnostics.push({ level: 'warning', code: 'ORPHAN_NODE', nodeId: node.id, targetId: node.parent });
|
|
87
|
+
if (!LEVEL_DEFS[node.level]) diagnostics.push({ level: 'warning', code: 'UNKNOWN_LEVEL', nodeId: node.id, level: node.level });
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Filter valid relations
|
|
91
|
+
const validRelations = [];
|
|
92
|
+
rawRelations.forEach(rel => {
|
|
93
|
+
if (nodes.has(rel.from) && nodes.has(rel.to)) {
|
|
94
|
+
const typeDef = RELATION_TYPES[rel.type] || {
|
|
95
|
+
label: rel.type,
|
|
96
|
+
color: '#94a3b8',
|
|
97
|
+
hasArrow: true
|
|
98
|
+
};
|
|
99
|
+
validRelations.push({
|
|
100
|
+
...rel,
|
|
101
|
+
typeLabel: rel.label || typeDef.label,
|
|
102
|
+
typeInfo: typeDef
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Determine root
|
|
108
|
+
let rootId = rawGraph.meta?.rootId;
|
|
109
|
+
if (!rootId || !nodes.has(rootId)) {
|
|
110
|
+
// Find node with no parent or level L0
|
|
111
|
+
for (const [id, node] of nodes.entries()) {
|
|
112
|
+
if (!node.parent || node.level === 'L0') {
|
|
113
|
+
rootId = id;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
meta: {
|
|
121
|
+
...rawGraph.meta,
|
|
122
|
+
rootId: rootId || (nodes.size > 0 ? Array.from(nodes.keys())[0] : null)
|
|
123
|
+
},
|
|
124
|
+
nodes,
|
|
125
|
+
relations: validRelations,
|
|
126
|
+
diagnostics
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Helper to compute ancestor path from root to current node
|
|
132
|
+
*/
|
|
133
|
+
export function getAncestorPath(nodes, nodeId) {
|
|
134
|
+
const path = [];
|
|
135
|
+
let current = nodes.get(nodeId);
|
|
136
|
+
const visited = new Set();
|
|
137
|
+
while (current && !visited.has(current.id)) {
|
|
138
|
+
visited.add(current.id);
|
|
139
|
+
path.unshift(current);
|
|
140
|
+
if (!current.parent) break;
|
|
141
|
+
current = nodes.get(current.parent);
|
|
142
|
+
}
|
|
143
|
+
return path;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Helper to get siblings of a node
|
|
148
|
+
*/
|
|
149
|
+
export function getSiblingNodes(nodes, nodeId) {
|
|
150
|
+
const current = nodes.get(nodeId);
|
|
151
|
+
if (!current || !current.parent) {
|
|
152
|
+
// If root or has no parent, find other root nodes
|
|
153
|
+
return Array.from(nodes.values()).filter(n => !n.parent && n.id !== nodeId);
|
|
154
|
+
}
|
|
155
|
+
const parent = nodes.get(current.parent);
|
|
156
|
+
if (!parent) return [];
|
|
157
|
+
return parent.children
|
|
158
|
+
.filter(id => id !== nodeId && nodes.has(id))
|
|
159
|
+
.map(id => nodes.get(id));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Helper to get all incoming and outgoing relations for a node
|
|
164
|
+
*/
|
|
165
|
+
export function getNodeRelations(relations, nodeId) {
|
|
166
|
+
const incoming = relations.filter(r => r.to === nodeId);
|
|
167
|
+
const outgoing = relations.filter(r => r.from === nodeId);
|
|
168
|
+
return { incoming, outgoing };
|
|
169
|
+
}
|