@aikdna/kdna-core 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/src/loader.js ADDED
@@ -0,0 +1,263 @@
1
+ /**
2
+ * KDNA Core Loader — Pure logic for loading KDNA domain cognition.
3
+ *
4
+ * No fs, no path, no Node.js dependencies.
5
+ * Data-first API: accepts already-parsed JSON objects.
6
+ */
7
+
8
+ const FILE_MAP = {
9
+ core: 'KDNA_Core.json',
10
+ patterns: 'KDNA_Patterns.json',
11
+ scenarios: 'KDNA_Scenarios.json',
12
+ cases: 'KDNA_Cases.json',
13
+ reasoning: 'KDNA_Reasoning.json',
14
+ evolution: 'KDNA_Evolution.json',
15
+ };
16
+
17
+ /**
18
+ * Load the minimum required KDNA data from already-parsed objects.
19
+ * @param {object} coreData — parsed KDNA_Core.json
20
+ * @param {object} patternsData — parsed KDNA_Patterns.json
21
+ * @returns {object|null}
22
+ */
23
+ function loadCorePatternsFromData(coreData, patternsData) {
24
+ if (!coreData || !patternsData) return null;
25
+ return { core: coreData, patterns: patternsData };
26
+ }
27
+
28
+ /**
29
+ * Load a complete KDNA domain from a map of already-parsed data.
30
+ *
31
+ * @param {Object} dataMap — keyed by file type: { core, patterns, scenarios?, cases?, reasoning?, evolution? }
32
+ * @param {object} [options]
33
+ * @param {string} [options.input] — user input text for conditional loading
34
+ * @param {'all'|'minimum'|'auto'} [options.mode='auto']
35
+ * @returns {object|null}
36
+ */
37
+ function loadDomainFromData(dataMap, options = {}) {
38
+ const { input = '', mode = 'auto' } = options;
39
+
40
+ const base = loadCorePatternsFromData(dataMap.core, dataMap.patterns);
41
+ if (!base) return null;
42
+
43
+ const result = { ...base };
44
+
45
+ if (mode === 'minimum') return result;
46
+
47
+ const toLoad =
48
+ mode === 'all'
49
+ ? ['scenarios', 'cases', 'reasoning', 'evolution']
50
+ : classifyInput(input);
51
+
52
+ for (const key of toLoad) {
53
+ if (dataMap[key]) result[key] = dataMap[key];
54
+ }
55
+
56
+ return result;
57
+ }
58
+
59
+ /**
60
+ * Load a KDNA domain from a map keyed by filename.
61
+ * Converts filename keys to type keys, then delegates to loadDomainFromData.
62
+ *
63
+ * @param {Object} fileDataMap — e.g. { 'KDNA_Core.json': parsedObj, 'KDNA_Patterns.json': parsedObj, ... }
64
+ * @param {object} [options] — same as loadDomainFromData
65
+ * @returns {object|null}
66
+ */
67
+ function loadDomainFromFiles(fileDataMap, options = {}) {
68
+ const dataMap = {};
69
+ for (const [key, filename] of Object.entries(FILE_MAP)) {
70
+ if (fileDataMap[filename]) dataMap[key] = fileDataMap[filename];
71
+ }
72
+ return loadDomainFromData(dataMap, options);
73
+ }
74
+
75
+ /**
76
+ * Determine which optional files to load based on user input text.
77
+ * Pure function — no side effects.
78
+ *
79
+ * @param {string} text
80
+ * @returns {string[]}
81
+ */
82
+ function classifyInput(text) {
83
+ const lower = (text || '').toLowerCase();
84
+ const optional = [];
85
+
86
+ if (
87
+ /\b(situation|scenario|conflict|happened|tell\s+me\s+about|describe|instance|specific)\b/.test(
88
+ lower,
89
+ ) ||
90
+ /(情况|场景|冲突|发生了什么|具体|描述一下|谈谈|说说看)/.test(text || '')
91
+ ) {
92
+ optional.push('scenarios');
93
+ }
94
+
95
+ if (
96
+ /\b(example|demonstrat|full\s+case|show\s+me|sample|illustrate|walk\s+through|case)\b/.test(
97
+ lower,
98
+ ) ||
99
+ /(案例|示例|演示|展示一下|完整案例|示范|讲解|举例|举个)/.test(text || '')
100
+ ) {
101
+ optional.push('cases');
102
+ }
103
+
104
+ if (
105
+ /\b(why|rationale|principle|explain|reason|logic|how\s+come|cause)\b/.test(lower) ||
106
+ /(为什么|原理|逻辑|解释|理由|原因|推理|依据)/.test(text || '')
107
+ ) {
108
+ optional.push('reasoning');
109
+ }
110
+
111
+ if (
112
+ /\b(practice|improv|learn|grow|level|progress|measur|assess|evaluat|benchmark)\b/.test(lower) ||
113
+ /(练习|提高|学习|成长|水平|进度|评估|测量|改进|提升|训练)/.test(text || '')
114
+ ) {
115
+ optional.push('evolution');
116
+ }
117
+
118
+ return [...new Set(optional)];
119
+ }
120
+
121
+ /**
122
+ * Format a loaded KDNA domain into a context string suitable for
123
+ * inclusion in an agent's system prompt.
124
+ *
125
+ * @param {object} domain — result from loadDomainFromData() or loadDomainFromFiles()
126
+ * @returns {string}
127
+ */
128
+ function formatContext(domain) {
129
+ if (!domain || !domain.core || !domain.patterns) return '';
130
+
131
+ const parts = [];
132
+ const core = domain.core;
133
+ const pat = domain.patterns;
134
+
135
+ parts.push('## Domain Cognition (KDNA)');
136
+ parts.push(`Domain: ${core.meta.domain}`);
137
+ parts.push('');
138
+
139
+ if (core.stances && core.stances.length) {
140
+ parts.push('### Stances');
141
+ for (const s of core.stances) {
142
+ parts.push(`- ${s}`);
143
+ }
144
+ parts.push('');
145
+ }
146
+
147
+ if (core.axioms && core.axioms.length) {
148
+ parts.push('### Axioms');
149
+ for (const a of core.axioms) {
150
+ parts.push(`- **${a.one_sentence}** ${a.full_statement}`);
151
+ parts.push(` *Why:* ${a.why}`);
152
+ }
153
+ parts.push('');
154
+ }
155
+
156
+ if (core.ontology && core.ontology.length) {
157
+ parts.push('### Key Concepts');
158
+ for (const c of core.ontology) {
159
+ parts.push(`- **${c.id.replace(/_/g, ' ')}** — ${c.one_sentence}`);
160
+ parts.push(` Boundary: ${c.boundary}`);
161
+ }
162
+ parts.push('');
163
+ }
164
+
165
+ if (core.frameworks && core.frameworks.length) {
166
+ parts.push('### Frameworks');
167
+ for (const fw of core.frameworks) {
168
+ parts.push(`- **${fw.name}**: ${fw.when_to_use}`);
169
+ }
170
+ parts.push('');
171
+ }
172
+
173
+ if (pat.terminology && pat.terminology.banned_terms && pat.terminology.banned_terms.length) {
174
+ parts.push('### Avoid These Terms');
175
+ for (const b of pat.terminology.banned_terms) {
176
+ parts.push(`- Avoid "${b.term}". ${b.why} Use "${b.replace_with}" instead.`);
177
+ }
178
+ parts.push('');
179
+ }
180
+
181
+ if (pat.misunderstandings && pat.misunderstandings.length) {
182
+ parts.push('### Watch For These Misunderstandings');
183
+ for (const m of pat.misunderstandings) {
184
+ parts.push(`- **Wrong:** ${m.wrong}`);
185
+ parts.push(` **Correct:** ${m.correct}`);
186
+ }
187
+ parts.push('');
188
+ }
189
+
190
+ if (pat.self_check && pat.self_check.length) {
191
+ parts.push('### Before Responding, Check');
192
+ for (const s of pat.self_check) {
193
+ parts.push(`- [ ] ${s}`);
194
+ }
195
+ parts.push('');
196
+ }
197
+
198
+ if (domain.scenarios && domain.scenarios.scenes) {
199
+ parts.push('### Relevant Scenarios');
200
+ for (const scene of domain.scenarios.scenes) {
201
+ parts.push(`- **${scene.name}**: ${scene.trigger_signal}`);
202
+ }
203
+ parts.push('');
204
+ }
205
+
206
+ if (domain.reasoning && domain.reasoning.reasoning_chains) {
207
+ parts.push('### Reasoning Chains');
208
+ for (const r of domain.reasoning.reasoning_chains) {
209
+ parts.push(`- **${r.one_sentence}** → ${r.so_what}`);
210
+ }
211
+ parts.push('');
212
+ }
213
+
214
+ if (domain.cases && domain.cases.cases && domain.cases.cases.length) {
215
+ parts.push('### Cases');
216
+ for (const c of domain.cases.cases) {
217
+ parts.push(`- **${c.title}**`);
218
+ parts.push(` Context: ${c.context}`);
219
+ parts.push(` What happened: ${c.what_happened}`);
220
+ parts.push(` Learned: ${c.what_was_learned}`);
221
+ parts.push(` Pattern: ${c.structural_pattern}`);
222
+ }
223
+ parts.push('');
224
+ }
225
+
226
+ if (domain.evolution) {
227
+ const evo = domain.evolution;
228
+ if (evo.stages && evo.stages.length) {
229
+ parts.push('### Growth Stages');
230
+ for (const stage of evo.stages) {
231
+ parts.push(`- **${stage.name}**: ${stage.description}`);
232
+ }
233
+ parts.push('');
234
+ }
235
+ if (evo.evolution_layers && evo.evolution_layers.length) {
236
+ parts.push('### Capability Layers');
237
+ for (const layer of evo.evolution_layers) {
238
+ parts.push(
239
+ `- **${layer.name}**: ${layer.capability} (${layer.from_stage} → ${layer.to_stage})`,
240
+ );
241
+ }
242
+ parts.push('');
243
+ }
244
+ if (evo.measurement && evo.measurement.length) {
245
+ parts.push('### Measurement');
246
+ for (const m of evo.measurement) {
247
+ parts.push(`- **${m.what}**: ${m.how} (threshold: ${m.threshold})`);
248
+ }
249
+ parts.push('');
250
+ }
251
+ }
252
+
253
+ return parts.join('\n').trim();
254
+ }
255
+
256
+ module.exports = {
257
+ FILE_MAP,
258
+ loadCorePatternsFromData,
259
+ loadDomainFromData,
260
+ loadDomainFromFiles,
261
+ classifyInput,
262
+ formatContext,
263
+ };
package/src/render.js ADDED
@@ -0,0 +1,111 @@
1
+ /**
2
+ * KDNA Render — Pure HTML rendering for KDNA domain preview.
3
+ *
4
+ * No fs, no path, no Node.js dependencies.
5
+ * Takes a loaded domain object and optional manifest, returns HTML string.
6
+ */
7
+
8
+ /**
9
+ * Escape HTML special characters.
10
+ * @param {string} s
11
+ * @returns {string}
12
+ */
13
+ function escHtml(s) {
14
+ return (s || '')
15
+ .replace(/&/g, '&')
16
+ .replace(/</g, '&lt;')
17
+ .replace(/>/g, '&gt;')
18
+ .replace(/"/g, '&quot;');
19
+ }
20
+
21
+ /**
22
+ * Render a card section.
23
+ * @param {string} title
24
+ * @param {number|undefined} count
25
+ * @param {string} items — HTML string of card items
26
+ * @returns {string}
27
+ */
28
+ function renderCard(title, count, items) {
29
+ if (!count || !items) return '';
30
+ return `<div class="card"><h3>${title} <span>${count}</span></h3>${items}</div>`;
31
+ }
32
+
33
+ /**
34
+ * Render a full KDNA domain as a preview HTML page.
35
+ *
36
+ * @param {object} domain — loaded domain from loadDomainFromData() / loadDomainFromFiles()
37
+ * @param {object} [manifest] — parsed kdna.json manifest
38
+ * @returns {string} complete HTML document
39
+ */
40
+ function renderPreviewHTML(domain, manifest) {
41
+ if (!domain || !domain.core) return '<!DOCTYPE html><html><body><p>No domain data</p></body></html>';
42
+
43
+ const core = domain.core;
44
+ const patterns = domain.patterns;
45
+ const scenarios = domain.scenarios;
46
+ const cases = domain.cases;
47
+ const reasoning = domain.reasoning;
48
+ const evolution = domain.evolution;
49
+
50
+ const name = manifest?.name || core.meta?.domain || 'Unnamed Domain';
51
+ const version = manifest?.version || core.meta?.version || '?';
52
+ const status = manifest?.status || 'experimental';
53
+ const desc = manifest?.description || core.meta?.purpose || '';
54
+
55
+ // Count present files
56
+ const fileCount = ['core', 'patterns', 'scenarios', 'cases', 'reasoning', 'evolution']
57
+ .filter((k) => domain[k])
58
+ .length;
59
+
60
+ return `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>${escHtml(name)} — KDNA Preview</title>
61
+ <style>
62
+ :root{--bg:#08100d;--bg2:#0d1713;--border:#24352b;--text:#f0ead7;--dim:#c3baa0;--muted:#8b836c;--accent:#d1ad63;--green:#76b987;--red:#df806d;--blue:#8fa7d7;--sans:Inter,system-ui,sans-serif;--mono:SF Mono,monospace}
63
+ *{box-sizing:border-box;margin:0;padding:0}body{background:var(--bg);color:var(--text);font-family:var(--sans);line-height:1.6;max-width:960px;margin:0 auto;padding:40px 24px}
64
+ .meta{display:flex;flex-wrap:wrap;gap:16px;align-items:center;padding:20px 24px;border:1px solid var(--border);border-radius:10px;background:var(--bg2);margin-bottom:24px}
65
+ .meta .name{font-size:24px;font-weight:700}
66
+ .meta .ver{color:var(--muted);font-size:14px}
67
+ .meta .badge{padding:3px 12px;border-radius:999px;font-size:11px;font-weight:700}
68
+ .badge-ok{background:rgba(118,185,135,.15);color:var(--green)}
69
+ .badge-warn{background:rgba(209,173,99,.15);color:var(--accent)}
70
+ .desc{color:var(--dim);margin:16px 0 24px;font-size:15px;line-height:1.7}
71
+ .cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(380px,1fr));gap:14px}
72
+ .card{border:1px solid var(--border);border-radius:10px;background:var(--bg2);padding:20px}
73
+ .card h3{font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:14px;display:flex;justify-content:space-between}
74
+ .card h3 span{color:var(--dim);font-weight:400}
75
+ .card .item{padding:10px 0;border-bottom:1px solid rgba(36,53,43,.5)}
76
+ .card .item:last-child{border-bottom:0}
77
+ .card .item strong{display:block;font-size:14px;margin-bottom:2px}
78
+ .card .item .detail{font-size:13px;color:var(--dim);line-height:1.5}
79
+ .card .item .meta{font-size:11px;color:var(--muted);margin-top:2px;padding:0;border:0;background:transparent;margin-bottom:0}
80
+ .card .item .why{color:var(--red);font-size:12px}
81
+ .card .item .replace{color:var(--green);font-size:12px}
82
+ .footer{text-align:center;color:var(--muted);margin-top:40px;font-size:13px}
83
+ .footer a{color:var(--accent)}
84
+ @media(max-width:680px){.cards{grid-template-columns:1fr}}
85
+ </style></head><body>
86
+ <h1 style="font-size:14px;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:16px">KDNA Domain Preview</h1>
87
+ <div class="meta">
88
+ <span class="name">${escHtml(name)}</span>
89
+ <span class="ver">v${escHtml(version)}</span>
90
+ <span class="badge badge-${status === 'validated' || status === 'stable' ? 'ok' : 'warn'}">${escHtml(status)}</span>
91
+ <span style="color:var(--dim);font-size:13px">${fileCount} files</span>
92
+ </div>
93
+ ${desc ? `<p class="desc">${escHtml(desc)}</p>` : ''}
94
+ <div class="cards">
95
+ ${renderCard('Axioms', core.axioms?.length, (core.axioms || []).map((a) => `<div class="item"><strong>${escHtml(a.one_sentence || '')}</strong><div class="detail">${escHtml(a.full_statement || a.why || '')}</div></div>`).join(''))}
96
+ ${renderCard('Concepts', core.ontology?.length, (core.ontology || []).map((o) => `<div class="item"><strong>${escHtml(o.one_sentence || o.id || '')}</strong><div class="detail">${escHtml(o.essence || '')}</div><div class="meta">Boundary: ${escHtml(o.boundary || '')}</div></div>`).join(''))}
97
+ ${renderCard('Frameworks', core.frameworks?.length, (core.frameworks || []).map((f) => `<div class="item"><strong>${escHtml(f.name || '')}</strong><div class="detail">When: ${escHtml(f.when_to_use || '')}</div><div class="detail">Steps: ${(f.steps || []).map((s) => escHtml(s)).join(' → ')}</div></div>`).join(''))}
98
+ ${renderCard('Stances', core.stances?.length, (core.stances || []).map((s) => `<div class="item"><strong>${escHtml(typeof s === 'string' ? s : s.one_sentence || '')}</strong></div>`).join(''))}
99
+ ${renderCard('Banned Terms', patterns?.terminology?.banned_terms?.length, (patterns?.terminology?.banned_terms || []).map((bt) => `<div class="item"><strong>${escHtml(bt.term)} <span class="replace">→ ${escHtml(bt.replace_with || '')}</span></strong><div class="why">${escHtml(bt.why || '')}</div></div>`).join(''))}
100
+ ${renderCard('Misunderstandings', patterns?.misunderstandings?.length, (patterns?.misunderstandings || []).map((mu) => `<div class="item"><strong>Wrong: ${escHtml(mu.wrong || '')}</strong><div class="detail">Correct: ${escHtml(mu.correct || '')}</div><div class="meta">${escHtml(mu.key_distinction || '')}</div></div>`).join(''))}
101
+ ${renderCard('Self-Checks', patterns?.self_check?.length, (patterns?.self_check || []).map((sc) => `<div class="item"><strong>✓ ${escHtml(typeof sc === 'string' ? sc : sc.one_sentence || '')}</strong></div>`).join(''))}
102
+ ${scenarios ? renderCard('Scenarios', scenarios.scenes?.length || 0, (scenarios.scenes || []).map((s) => `<div class="item"><strong>${escHtml(s.name || s.id || '')}</strong><div class="detail">${escHtml(s.trigger_signal || '')}</div></div>`).join('')) : ''}
103
+ ${cases ? renderCard('Cases', cases.cases?.length || 0, (cases.cases || []).map((c) => `<div class="item"><strong>${escHtml(c.title || c.id || '')}</strong><div class="detail">${escHtml((c.what_was_learned || '').substring(0, 150))}</div></div>`).join('')) : ''}
104
+ ${reasoning ? renderCard('Reasoning', reasoning.reasoning_chains?.length || 0, (reasoning.reasoning_chains || []).map((r) => `<div class="item"><strong>${escHtml(r.one_sentence || r.id || '')}</strong><div class="detail">${escHtml(r.so_what || '')}</div></div>`).join('')) : ''}
105
+ ${evolution ? renderCard('Evolution', evolution.stages?.length || 0, (evolution.stages || []).map((s) => `<div class="item"><strong>${escHtml(s.name || s.id || '')}</strong><div class="detail">${escHtml(s.description || '')}</div></div>`).join('')) : ''}
106
+ </div>
107
+ <div class="footer">Generated: ${new Date().toISOString().slice(0, 10)} · <a href="https://aikdna.com">aikdna.com</a></div>
108
+ </body></html>`;
109
+ }
110
+
111
+ module.exports = { renderPreviewHTML, escHtml, renderCard };
package/src/types.d.ts ADDED
@@ -0,0 +1,254 @@
1
+ export interface KDNAMeta {
2
+ version: string;
3
+ domain: string;
4
+ created: string;
5
+ purpose: string;
6
+ load_condition: string;
7
+ }
8
+
9
+ export interface KDNAAxiom {
10
+ id: string;
11
+ one_sentence: string;
12
+ full_statement: string;
13
+ why: string;
14
+ }
15
+
16
+ export interface KDNAOntologyConcept {
17
+ id: string;
18
+ one_sentence: string;
19
+ essence: string;
20
+ boundary: string;
21
+ trigger_signal: string;
22
+ }
23
+
24
+ export interface KDNAFramework {
25
+ id: string;
26
+ name: string;
27
+ when_to_use: string;
28
+ steps: string[];
29
+ }
30
+
31
+ export interface KDNACoreStructure {
32
+ from: string;
33
+ to: string;
34
+ via: string;
35
+ }
36
+
37
+ export interface KDNACore {
38
+ meta: KDNAMeta;
39
+ axioms: KDNAAxiom[];
40
+ ontology: KDNAOntologyConcept[];
41
+ frameworks: KDNAFramework[];
42
+ core_structure: KDNACoreStructure[];
43
+ stances: string[];
44
+ }
45
+
46
+ export interface KDNAStandardTerm {
47
+ term: string;
48
+ definition: string;
49
+ }
50
+
51
+ export interface KDNABannedTerm {
52
+ term: string;
53
+ why: string;
54
+ replace_with: string;
55
+ }
56
+
57
+ export interface KDNATerminology {
58
+ standard_terms: KDNAStandardTerm[];
59
+ banned_terms: KDNABannedTerm[];
60
+ }
61
+
62
+ export interface KDNAMisunderstanding {
63
+ id: string;
64
+ wrong: string;
65
+ correct: string;
66
+ key_distinction: string;
67
+ why: string;
68
+ }
69
+
70
+ export interface KDNAPatterns {
71
+ meta: KDNAMeta;
72
+ terminology: KDNATerminology;
73
+ misunderstandings: KDNAMisunderstanding[];
74
+ self_check: string[];
75
+ }
76
+
77
+ export interface KDNASubScenario {
78
+ id: string;
79
+ trap_belief: string;
80
+ three_questions: {
81
+ belief: string;
82
+ state: string;
83
+ need: string;
84
+ };
85
+ action_template: string[];
86
+ replace: {
87
+ avoid: string;
88
+ use: string;
89
+ }[];
90
+ expected_result: string;
91
+ }
92
+
93
+ export interface KDNAScene {
94
+ id: string;
95
+ name: string;
96
+ trigger_signal: string;
97
+ sub_scenarios: KDNASubScenario[];
98
+ }
99
+
100
+ export interface KDNAScenarios {
101
+ meta: KDNAMeta;
102
+ scenes: KDNAScene[];
103
+ }
104
+
105
+ export interface KDNACase {
106
+ id: string;
107
+ scene_id?: string;
108
+ title: string;
109
+ context: string;
110
+ what_happened: string;
111
+ what_was_learned: string;
112
+ structural_pattern: string;
113
+ }
114
+
115
+ export interface KDNACases {
116
+ meta: KDNAMeta;
117
+ cases: KDNACase[];
118
+ }
119
+
120
+ export interface KDNAReasoningChain {
121
+ id: string;
122
+ one_sentence: string;
123
+ logic: string[];
124
+ so_what: string;
125
+ }
126
+
127
+ export interface KDNAReasoning {
128
+ meta: KDNAMeta;
129
+ reasoning_chains: KDNAReasoningChain[];
130
+ }
131
+
132
+ export interface KDNAStage {
133
+ id: string;
134
+ name: string;
135
+ description: string;
136
+ indicators: string[];
137
+ }
138
+
139
+ export interface KDNAEvolutionLayer {
140
+ id: string;
141
+ name: string;
142
+ capability: string;
143
+ from_stage: string;
144
+ to_stage: string;
145
+ }
146
+
147
+ export interface KDNAMeasurement {
148
+ id: string;
149
+ what: string;
150
+ how: string;
151
+ threshold: string;
152
+ }
153
+
154
+ export interface KDNAEvolution {
155
+ meta: KDNAMeta;
156
+ stages: KDNAStage[];
157
+ evolution_layers: KDNAEvolutionLayer[];
158
+ measurement: KDNAMeasurement[];
159
+ }
160
+
161
+ export type KDNADomainFile =
162
+ | KDNACore
163
+ | KDNAPatterns
164
+ | KDNAScenarios
165
+ | KDNACases
166
+ | KDNAReasoning
167
+ | KDNAEvolution;
168
+
169
+ export interface LoadedDomain {
170
+ core: KDNACore;
171
+ patterns: KDNAPatterns;
172
+ scenarios?: KDNAScenarios;
173
+ cases?: KDNACases;
174
+ reasoning?: KDNAReasoning;
175
+ evolution?: KDNAEvolution;
176
+ }
177
+
178
+ export interface LoadOptions {
179
+ input?: string;
180
+ mode?: 'all' | 'minimum' | 'auto';
181
+ }
182
+
183
+ /** Data map keyed by type (core, patterns, scenarios, etc.) */
184
+ export interface KDNADataMap {
185
+ core: KDNACore;
186
+ patterns: KDNAPatterns;
187
+ scenarios?: KDNAScenarios;
188
+ cases?: KDNACases;
189
+ reasoning?: KDNAReasoning;
190
+ evolution?: KDNAEvolution;
191
+ }
192
+
193
+ /** Data map keyed by filename */
194
+ export interface KDNAFileDataMap {
195
+ 'KDNA_Core.json': KDNACore;
196
+ 'KDNA_Patterns.json': KDNAPatterns;
197
+ 'KDNA_Scenarios.json'?: KDNAScenarios;
198
+ 'KDNA_Cases.json'?: KDNACases;
199
+ 'KDNA_Reasoning.json'?: KDNAReasoning;
200
+ 'KDNA_Evolution.json'?: KDNAEvolution;
201
+ 'kdna.json'?: KDNAManifest;
202
+ [key: string]: any;
203
+ }
204
+
205
+ export interface KDNAManifest {
206
+ kdna_spec: string;
207
+ name: string;
208
+ version: string;
209
+ status: 'experimental' | 'basic' | 'stable' | 'pro';
210
+ access: 'open' | 'licensed' | 'runtime';
211
+ language: string;
212
+ author: { name: string; id?: string };
213
+ license: { type: string; url?: string };
214
+ description: string;
215
+ }
216
+
217
+ export interface LintResult {
218
+ errors: string[];
219
+ warnings: string[];
220
+ }
221
+
222
+ export interface ValidationResult {
223
+ valid: boolean;
224
+ errors: string[];
225
+ warnings: string[];
226
+ }
227
+
228
+ // Loader — data-first API
229
+ export function loadCorePatternsFromData(
230
+ coreData: KDNACore,
231
+ patternsData: KDNAPatterns,
232
+ ): { core: KDNACore; patterns: KDNAPatterns } | null;
233
+
234
+ export function loadDomainFromData(dataMap: KDNADataMap, options?: LoadOptions): LoadedDomain | null;
235
+
236
+ export function loadDomainFromFiles(fileDataMap: KDNAFileDataMap, options?: LoadOptions): LoadedDomain | null;
237
+
238
+ export function classifyInput(text: string): string[];
239
+
240
+ export function formatContext(domain: LoadedDomain): string;
241
+
242
+ export const FILE_MAP: Record<string, string>;
243
+
244
+ // Lint
245
+ export function lintDomain(dataMap: KDNAFileDataMap): LintResult;
246
+
247
+ // Validate
248
+ export function validateDomainSchema(dataMap: KDNAFileDataMap, schemaMap?: Record<string, any>): ValidationResult;
249
+ export function validateCrossFile(dataMap: KDNAFileDataMap): ValidationResult;
250
+
251
+ // Render
252
+ export function renderPreviewHTML(domain: LoadedDomain, manifest?: KDNAManifest): string;
253
+ export function escHtml(s: string): string;
254
+ export function renderCard(title: string, count: number | undefined, items: string): string;