@aikdna/studio-core 0.3.0 → 0.4.1
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 +1 -1
- package/src/compile/index.js +123 -111
- package/src/packaging/index.js +26 -24
- package/src/quality/index.js +47 -111
- package/src/testlab/delta.js +55 -22
- package/src/versioning/index.js +86 -124
- package/tests/e2e.test.js +276 -0
- package/tests/milestone2.test.js +13 -11
- package/tests/milestone3.test.js +3 -3
package/package.json
CHANGED
package/src/compile/index.js
CHANGED
|
@@ -1,114 +1,145 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Compile locked cards into KDNA domain JSON files.
|
|
2
|
+
* Compile locked cards into KDNA domain JSON files — SPEC-compatible output.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* KDNA SPEC v1.0-rc requirements:
|
|
5
|
+
* - Every file MUST have meta: { version, domain, created, purpose, load_condition }
|
|
6
|
+
* - Minimum output: KDNA_Core.json + KDNA_Patterns.json
|
|
7
|
+
* - Maximum 6 KDNA JSON files per domain
|
|
8
|
+
* - KDNA_Scenarios.json: { meta, scenes[] }
|
|
9
|
+
* - KDNA_Reasoning.json: { meta, reasoning_chains[] }
|
|
10
|
+
* - KDNA_Evolution.json: { meta, stages[], capability_layers[], measurements[] }
|
|
11
|
+
*
|
|
12
|
+
* Only locked cards enter compilation. Draft/Revised excluded silently.
|
|
7
13
|
*/
|
|
8
|
-
const provenance = require('../provenance');
|
|
9
14
|
|
|
10
|
-
function
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
15
|
+
function makeMeta(project) {
|
|
16
|
+
return {
|
|
17
|
+
version: (project.release && project.release.version) || '0.1.0',
|
|
18
|
+
domain: project.name,
|
|
19
|
+
created: project.created || new Date().toISOString().slice(0, 10),
|
|
20
|
+
purpose: project.release?.description || `Domain judgment for ${project.name}`,
|
|
21
|
+
load_condition: 'Load when the task matches applies_when on domain axioms.',
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function compileCore(cards, project) {
|
|
26
|
+
const lockedAxioms = cards.filter(c => c.type === 'axiom' && c.locked).map(c => ({ id: c.id, ...c.fields }));
|
|
27
|
+
const lockedOntology = cards.filter(c => c.type === 'ontology' && c.locked).map(c => ({ id: c.id, ...c.fields }));
|
|
28
|
+
const lockedBoundaries = cards.filter(c => c.type === 'boundary' && c.locked);
|
|
29
|
+
const lockedRisks = cards.filter(c => c.type === 'risk' && c.locked).map(c => ({ id: c.id, ...c.fields }));
|
|
22
30
|
|
|
23
|
-
return {
|
|
31
|
+
return {
|
|
32
|
+
meta: makeMeta(project),
|
|
33
|
+
axioms: lockedAxioms,
|
|
34
|
+
ontology: lockedOntology,
|
|
35
|
+
frameworks: [],
|
|
36
|
+
stances: [],
|
|
37
|
+
core_structure: [],
|
|
38
|
+
boundaries: lockedBoundaries.map(c => ({
|
|
39
|
+
id: c.id,
|
|
40
|
+
scope: c.fields?.scope || '',
|
|
41
|
+
out_of_scope: c.fields?.out_of_scope || '',
|
|
42
|
+
acceptable_exceptions: c.fields?.acceptable_exceptions || [],
|
|
43
|
+
})),
|
|
44
|
+
risks: lockedRisks,
|
|
45
|
+
};
|
|
24
46
|
}
|
|
25
47
|
|
|
26
|
-
function compilePatterns(cards) {
|
|
27
|
-
const
|
|
48
|
+
function compilePatterns(cards, project) {
|
|
49
|
+
const lockedMisunderstandings = cards.filter(c => c.type === 'misunderstanding' && c.locked).map(c => ({
|
|
28
50
|
id: c.id,
|
|
29
51
|
wrong: c.fields?.wrong || '',
|
|
30
52
|
correct: c.fields?.correct || '',
|
|
31
53
|
key_distinction: c.fields?.key_distinction || '',
|
|
32
|
-
|
|
54
|
+
why: c.fields?.why || `What bad judgment results from believing "${(c.fields?.wrong || '').slice(0, 40)}"`,
|
|
55
|
+
failure_risk: c.fields?.failure_risk || 'No specific failure risk declared',
|
|
33
56
|
applies_when: c.fields?.applies_when || [],
|
|
34
57
|
does_not_apply_when: c.fields?.does_not_apply_when || [],
|
|
35
58
|
}));
|
|
36
|
-
const
|
|
37
|
-
const
|
|
59
|
+
const lockedSelfChecks = cards.filter(c => c.type === 'self_check' && c.locked).map(c => c.fields?.question || '');
|
|
60
|
+
const lockedAesthetics = cards.filter(c => c.type === 'aesthetic' && c.locked).map(c => ({ id: c.id, ...c.fields }));
|
|
38
61
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
62
|
+
return {
|
|
63
|
+
meta: makeMeta(project),
|
|
64
|
+
terminology: {
|
|
65
|
+
standard_terms: [],
|
|
66
|
+
banned_terms: [],
|
|
67
|
+
},
|
|
68
|
+
misunderstandings: lockedMisunderstandings,
|
|
69
|
+
self_check: lockedSelfChecks,
|
|
70
|
+
aesthetics: lockedAesthetics,
|
|
42
71
|
};
|
|
43
|
-
|
|
44
|
-
return { terminology, misunderstandings, self_check: selfCheckQuestions, aesthetics };
|
|
45
72
|
}
|
|
46
73
|
|
|
47
|
-
function compileScenarios(cards) {
|
|
74
|
+
function compileScenarios(cards, project) {
|
|
48
75
|
const locked = cards.filter(c => c.type === 'scenario' && c.locked);
|
|
49
|
-
if (locked.length === 0) return
|
|
50
|
-
return
|
|
76
|
+
if (locked.length === 0) return null;
|
|
77
|
+
return {
|
|
78
|
+
meta: makeMeta(project),
|
|
79
|
+
scenes: locked.map(c => ({ id: c.id, ...c.fields })),
|
|
80
|
+
};
|
|
51
81
|
}
|
|
52
82
|
|
|
53
|
-
function compileCases(cards) {
|
|
83
|
+
function compileCases(cards, project) {
|
|
54
84
|
const locked = cards.filter(c => c.type === 'case' && c.locked);
|
|
55
|
-
if (locked.length === 0) return
|
|
56
|
-
return
|
|
85
|
+
if (locked.length === 0) return null;
|
|
86
|
+
return {
|
|
87
|
+
meta: makeMeta(project),
|
|
88
|
+
cases: locked.map(c => ({ id: c.id, ...c.fields })),
|
|
89
|
+
};
|
|
57
90
|
}
|
|
58
91
|
|
|
59
|
-
function compileReasoning(cards) {
|
|
60
|
-
// Reasoning chains from axiom implications
|
|
92
|
+
function compileReasoning(cards, project) {
|
|
61
93
|
const lockedAxioms = cards.filter(c => c.type === 'axiom' && c.locked);
|
|
62
|
-
if (lockedAxioms.length === 0) return
|
|
63
|
-
return
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
94
|
+
if (lockedAxioms.length === 0) return null;
|
|
95
|
+
return {
|
|
96
|
+
meta: makeMeta(project),
|
|
97
|
+
reasoning_chains: lockedAxioms.map(ax => ({
|
|
98
|
+
id: `chain_${ax.id}`,
|
|
99
|
+
one_sentence: ax.fields?.one_sentence || '',
|
|
100
|
+
logic: [ax.fields?.full_statement || ''],
|
|
101
|
+
so_what: ax.fields?.why || 'Agent judgment changes when this axiom is loaded.',
|
|
102
|
+
})),
|
|
103
|
+
};
|
|
69
104
|
}
|
|
70
105
|
|
|
71
|
-
function compileEvolution(cards) {
|
|
106
|
+
function compileEvolution(cards, project) {
|
|
72
107
|
const lockedCards = cards.filter(c => c.locked);
|
|
73
|
-
if (lockedCards.length === 0) return
|
|
108
|
+
if (lockedCards.length === 0) return null;
|
|
74
109
|
|
|
75
|
-
// Build evolution from audit logs
|
|
76
110
|
const stages = [];
|
|
77
111
|
const seenAxioms = new Set();
|
|
78
112
|
for (const card of lockedCards) {
|
|
79
113
|
if (seenAxioms.has(card.id)) continue;
|
|
80
114
|
seenAxioms.add(card.id);
|
|
81
115
|
for (const entry of (card.audit_log || [])) {
|
|
82
|
-
if (entry.event === 'locked'
|
|
116
|
+
if (entry.event === 'locked') {
|
|
83
117
|
stages.push({
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
118
|
+
id: `stage_${card.id}`,
|
|
119
|
+
name: card.fields?.one_sentence || card.fields?.question || card.id,
|
|
120
|
+
description: `Card ${card.id} was locked by ${entry.by} at ${entry.at}. Type: ${card.type}.`,
|
|
121
|
+
indicators: [`${card.type} card locked`, 'Human judgment confirmed'],
|
|
88
122
|
});
|
|
89
123
|
}
|
|
90
124
|
}
|
|
91
125
|
}
|
|
92
126
|
|
|
93
127
|
return {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
128
|
+
meta: makeMeta(project),
|
|
129
|
+
stages: stages.sort((a, b) => a.id.localeCompare(b.id)),
|
|
130
|
+
evolution_layers: [
|
|
131
|
+
{ id: 'layer_1', name: 'Foundation', capability: 'Core axioms and patterns established.', from_stage: stages[0]?.id || 'none', to_stage: stages[stages.length - 1]?.id || 'none' },
|
|
97
132
|
],
|
|
98
|
-
|
|
99
|
-
{
|
|
100
|
-
{
|
|
101
|
-
{
|
|
133
|
+
measurement: [
|
|
134
|
+
{ id: 'meas_axioms', what: 'locked_axioms', how: 'Count of locked axiom cards', threshold: `${lockedCards.filter(c => c.type === 'axiom').length}` },
|
|
135
|
+
{ id: 'meas_misunderstandings', what: 'locked_misunderstandings', how: 'Count of locked misunderstanding cards', threshold: `${lockedCards.filter(c => c.type === 'misunderstanding').length}` },
|
|
136
|
+
{ id: 'meas_self_checks', what: 'self_checks', how: 'Count of locked self-check cards', threshold: `${lockedCards.filter(c => c.type === 'self_check').length}` },
|
|
102
137
|
],
|
|
103
138
|
};
|
|
104
139
|
}
|
|
105
140
|
|
|
106
|
-
function compileManifest(project) {
|
|
107
|
-
const
|
|
108
|
-
const cards = project.cards || [];
|
|
109
|
-
const hasScenarios = cards.some(c => c.type === 'scenario' && c.locked);
|
|
110
|
-
const hasCases = cards.some(c => c.type === 'case' && c.locked);
|
|
111
|
-
const fileCount = 2 + (hasScenarios ? 1 : 0) + (hasCases ? 1 : 0) + 2; // Core+Patterns+Reasoning+Evolution (+ Scenarios + Cases)
|
|
141
|
+
function compileManifest(project, files) {
|
|
142
|
+
const kdnaFileCount = Object.keys(files).filter(f => f.startsWith('KDNA_')).length;
|
|
112
143
|
return {
|
|
113
144
|
kdna_spec: '1.0-rc',
|
|
114
145
|
name: project.name,
|
|
@@ -116,31 +147,30 @@ function compileManifest(project) {
|
|
|
116
147
|
status: 'experimental',
|
|
117
148
|
access: (project.release && project.release.access) || 'open',
|
|
118
149
|
author: project.author || { name: '', id: '' },
|
|
119
|
-
description: project.name,
|
|
120
|
-
file_count:
|
|
121
|
-
created: project.created,
|
|
122
|
-
updated: project.updated,
|
|
150
|
+
description: project.release?.description || project.name,
|
|
151
|
+
file_count: kdnaFileCount,
|
|
152
|
+
created: project.created || new Date().toISOString().slice(0, 10),
|
|
153
|
+
updated: project.updated || new Date().toISOString().slice(0, 10),
|
|
123
154
|
};
|
|
124
155
|
}
|
|
125
156
|
|
|
126
157
|
function compileDomain(project) {
|
|
127
158
|
const cards = project.cards || [];
|
|
128
|
-
const core = compileCore(cards);
|
|
129
|
-
const patterns = compilePatterns(cards);
|
|
130
|
-
const scenarios = compileScenarios(cards);
|
|
131
|
-
const cases = compileCases(cards);
|
|
132
|
-
const reasoning = compileReasoning(cards);
|
|
133
|
-
const evolution = compileEvolution(cards);
|
|
134
|
-
const manifest = compileManifest(project);
|
|
159
|
+
const core = compileCore(cards, project);
|
|
160
|
+
const patterns = compilePatterns(cards, project);
|
|
161
|
+
const scenarios = compileScenarios(cards, project);
|
|
162
|
+
const cases = compileCases(cards, project);
|
|
163
|
+
const reasoning = compileReasoning(cards, project);
|
|
164
|
+
const evolution = compileEvolution(cards, project);
|
|
135
165
|
|
|
136
166
|
const files = {};
|
|
137
167
|
files['KDNA_Core.json'] = JSON.stringify(core, null, 2);
|
|
138
168
|
files['KDNA_Patterns.json'] = JSON.stringify(patterns, null, 2);
|
|
139
|
-
if (scenarios
|
|
140
|
-
if (cases
|
|
141
|
-
if (reasoning
|
|
142
|
-
if (evolution
|
|
143
|
-
files['kdna.json'] = JSON.stringify(
|
|
169
|
+
if (scenarios) files['KDNA_Scenarios.json'] = JSON.stringify(scenarios, null, 2);
|
|
170
|
+
if (cases) files['KDNA_Cases.json'] = JSON.stringify(cases, null, 2);
|
|
171
|
+
if (reasoning) files['KDNA_Reasoning.json'] = JSON.stringify(reasoning, null, 2);
|
|
172
|
+
if (evolution) files['KDNA_Evolution.json'] = JSON.stringify(evolution, null, 2);
|
|
173
|
+
files['kdna.json'] = JSON.stringify(compileManifest(project, files), null, 2);
|
|
144
174
|
|
|
145
175
|
const excludedCount = cards.filter(c => !c.locked && !['deprecated'].includes(c.status)).length;
|
|
146
176
|
|
|
@@ -151,7 +181,8 @@ function compileDomain(project) {
|
|
|
151
181
|
locked_cards: cards.filter(c => c.locked).length,
|
|
152
182
|
excluded_cards: excludedCount,
|
|
153
183
|
deprecated_cards: cards.filter(c => c.status === 'deprecated').length,
|
|
154
|
-
|
|
184
|
+
kdna_files: Object.keys(files).filter(f => f.startsWith('KDNA_')).length,
|
|
185
|
+
total_files: Object.keys(files).length,
|
|
155
186
|
},
|
|
156
187
|
};
|
|
157
188
|
}
|
|
@@ -168,12 +199,8 @@ function generateReadme(project, options = {}) {
|
|
|
168
199
|
const lines = [];
|
|
169
200
|
lines.push(`# ${project.name}`);
|
|
170
201
|
lines.push('');
|
|
171
|
-
if (options.description) {
|
|
172
|
-
lines.push(options.description);
|
|
173
|
-
lines.push('');
|
|
174
|
-
}
|
|
202
|
+
if (options.description) { lines.push(options.description); lines.push(''); }
|
|
175
203
|
|
|
176
|
-
// Four Questions
|
|
177
204
|
lines.push('## Where it comes from');
|
|
178
205
|
lines.push('');
|
|
179
206
|
lines.push(options.origin || `Domain expertise encoded into ${locked.length} judgment cards through structured interview and human lock.`);
|
|
@@ -182,11 +209,7 @@ function generateReadme(project, options = {}) {
|
|
|
182
209
|
lines.push('## Where it applies');
|
|
183
210
|
lines.push('');
|
|
184
211
|
const appliesWhen = [...new Set(lockedAxioms.flatMap(ax => ax.fields?.applies_when || []))];
|
|
185
|
-
|
|
186
|
-
appliesWhen.forEach(w => lines.push(`- ${w}`));
|
|
187
|
-
} else {
|
|
188
|
-
lines.push('- As declared in each axiom\'s applies_when field.');
|
|
189
|
-
}
|
|
212
|
+
appliesWhen.length ? appliesWhen.forEach(w => lines.push(`- ${w}`)) : lines.push('- As declared in each axiom\'s applies_when field.');
|
|
190
213
|
lines.push('');
|
|
191
214
|
|
|
192
215
|
lines.push('## How it is verified');
|
|
@@ -200,19 +223,14 @@ function generateReadme(project, options = {}) {
|
|
|
200
223
|
lines.push('## When it does NOT apply');
|
|
201
224
|
lines.push('');
|
|
202
225
|
const notApply = [...new Set(lockedAxioms.flatMap(ax => ax.fields?.does_not_apply_when || []))];
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
const outOfScope = lockedBoundaries.flatMap(b => [b.fields?.out_of_scope || '']).filter(Boolean);
|
|
207
|
-
for (const oos of outOfScope) {
|
|
226
|
+
notApply.forEach(w => lines.push(`- ${w}`));
|
|
227
|
+
for (const oos of lockedBoundaries.flatMap(b => [b.fields?.out_of_scope || '']).filter(Boolean)) {
|
|
208
228
|
if (!notApply.includes(oos)) lines.push(`- ${oos}`);
|
|
209
229
|
}
|
|
210
230
|
lines.push('');
|
|
211
231
|
|
|
212
|
-
// Top Axioms
|
|
213
232
|
if (lockedAxioms.length > 0) {
|
|
214
|
-
lines.push('## Top Axioms');
|
|
215
|
-
lines.push('');
|
|
233
|
+
lines.push('## Top Axioms'); lines.push('');
|
|
216
234
|
lockedAxioms.forEach(ax => {
|
|
217
235
|
lines.push(`- **${ax.fields?.one_sentence || ax.id}**`);
|
|
218
236
|
if (ax.fields?.failure_risk) lines.push(` - Failure risk: ${ax.fields.failure_risk}`);
|
|
@@ -220,10 +238,8 @@ function generateReadme(project, options = {}) {
|
|
|
220
238
|
lines.push('');
|
|
221
239
|
}
|
|
222
240
|
|
|
223
|
-
// Top Misunderstandings
|
|
224
241
|
if (lockedMisunderstandings.length > 0) {
|
|
225
|
-
lines.push('## Top Misunderstandings');
|
|
226
|
-
lines.push('');
|
|
242
|
+
lines.push('## Top Misunderstandings'); lines.push('');
|
|
227
243
|
lockedMisunderstandings.forEach(ms => {
|
|
228
244
|
lines.push(`- WRONG: ${ms.fields?.wrong}`);
|
|
229
245
|
lines.push(` CORRECT: ${ms.fields?.correct}`);
|
|
@@ -231,24 +247,20 @@ function generateReadme(project, options = {}) {
|
|
|
231
247
|
lines.push('');
|
|
232
248
|
}
|
|
233
249
|
|
|
234
|
-
// Self-checks
|
|
235
250
|
if (lockedSelfChecks.length > 0) {
|
|
236
|
-
lines.push('## Eval Score');
|
|
237
|
-
lines.push('');
|
|
251
|
+
lines.push('## Eval Score'); lines.push('');
|
|
238
252
|
lines.push(`- quality_badge: ${tests.filter(t => t.result === 'with_kdna_better').length >= 5 ? 'tested' : 'untested'}`);
|
|
239
253
|
lines.push(`- eval cases: ${tests.length}`);
|
|
240
254
|
lines.push('');
|
|
241
255
|
}
|
|
242
256
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
lines.push('');
|
|
246
|
-
const fileCount = 2
|
|
257
|
+
lines.push('## Files'); lines.push('');
|
|
258
|
+
const kdnaFileCount = 2
|
|
247
259
|
+ (cards.filter(c => c.type === 'scenario' && c.locked).length > 0 ? 1 : 0)
|
|
248
260
|
+ (cards.filter(c => c.type === 'case' && c.locked).length > 0 ? 1 : 0)
|
|
249
261
|
+ (lockedAxioms.length > 0 ? 1 : 0)
|
|
250
|
-
+ (
|
|
251
|
-
lines.push(`${
|
|
262
|
+
+ (locked.length > 0 ? 1 : 0);
|
|
263
|
+
lines.push(`${kdnaFileCount} KDNA JSON files + evals/ + demo/`);
|
|
252
264
|
lines.push('');
|
|
253
265
|
|
|
254
266
|
return lines.join('\n');
|
package/src/packaging/index.js
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Packaging adapter —
|
|
2
|
+
* Packaging adapter — secure delegation to kdna-cli.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* All subprocess calls use execFileSync (not execSync with string interpolation)
|
|
5
|
+
* to prevent command injection. Studio Core calls kdna-cli as the canonical
|
|
6
|
+
* implementation of pack/verify/sign/publish operations.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
|
-
const {
|
|
9
|
+
const { execFileSync } = require('child_process');
|
|
9
10
|
const path = require('path');
|
|
10
11
|
|
|
11
12
|
function packDomain(domainDir, outputDir = null) {
|
|
12
13
|
const args = ['pack', domainDir];
|
|
13
14
|
if (outputDir) args.push('--output', outputDir);
|
|
14
|
-
const result =
|
|
15
|
+
const result = execFileSync('kdna', args, { encoding: 'utf8', timeout: 60000 });
|
|
15
16
|
return { success: true, output: result.trim() };
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
function packEncryptedDomain(domainDir, licensePath, outputDir = null) {
|
|
19
20
|
const args = ['pack', domainDir, '--encrypt', '--license', licensePath];
|
|
20
21
|
if (outputDir) args.push('--output', outputDir);
|
|
21
|
-
const result =
|
|
22
|
+
const result = execFileSync('kdna', args, { encoding: 'utf8', timeout: 60000 });
|
|
22
23
|
return { success: true, output: result.trim() };
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
function verifyDomain(domainPath) {
|
|
26
27
|
try {
|
|
27
|
-
const result =
|
|
28
|
+
const result = execFileSync('kdna', ['verify', domainPath, '--json'], { encoding: 'utf8', timeout: 30000 });
|
|
28
29
|
return JSON.parse(result);
|
|
29
30
|
} catch (e) {
|
|
30
31
|
const stdout = (e.stdout || '').toString();
|
|
@@ -32,23 +33,28 @@ function verifyDomain(domainPath) {
|
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
function validateDomain(domainPath) {
|
|
37
|
+
try {
|
|
38
|
+
const result = execFileSync('kdna', ['validate', domainPath], { encoding: 'utf8', timeout: 30000 });
|
|
39
|
+
return { success: true, output: result.trim() };
|
|
40
|
+
} catch (e) {
|
|
41
|
+
return { success: false, error: e.message, stderr: (e.stderr || '').toString() };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
35
45
|
function inspectContainer(filePath) {
|
|
36
46
|
try {
|
|
37
|
-
const result =
|
|
47
|
+
const result = execFileSync('kdna', ['inspect', filePath, '--json'], { encoding: 'utf8', timeout: 15000 });
|
|
38
48
|
return JSON.parse(result);
|
|
39
|
-
} catch {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
49
|
+
} catch { return null; }
|
|
42
50
|
}
|
|
43
51
|
|
|
44
|
-
function signDomain(domainDir
|
|
45
|
-
// Uses kdna publish --check for signing
|
|
46
|
-
const args = ['publish', '--check', domainDir];
|
|
52
|
+
function signDomain(domainDir) {
|
|
47
53
|
try {
|
|
48
|
-
const result =
|
|
54
|
+
const result = execFileSync('kdna', ['publish', '--check', domainDir], { encoding: 'utf8', timeout: 30000 });
|
|
49
55
|
return { success: true, output: result.trim() };
|
|
50
56
|
} catch (e) {
|
|
51
|
-
return { success: false, error: e.stderr
|
|
57
|
+
return { success: false, error: (e.stderr || '').toString() || e.message };
|
|
52
58
|
}
|
|
53
59
|
}
|
|
54
60
|
|
|
@@ -56,18 +62,14 @@ function generateLicense(domain, issuedTo, savePath = null) {
|
|
|
56
62
|
const args = ['license', 'generate', domain, '--to', issuedTo];
|
|
57
63
|
if (savePath) args.push('--save', savePath);
|
|
58
64
|
try {
|
|
59
|
-
const result =
|
|
65
|
+
const result = execFileSync('kdna', args, { encoding: 'utf8', timeout: 15000 });
|
|
60
66
|
return { success: true, output: result.trim() };
|
|
61
67
|
} catch (e) {
|
|
62
|
-
return { success: false, error: e.stderr
|
|
68
|
+
return { success: false, error: (e.stderr || '').toString() || e.message };
|
|
63
69
|
}
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
module.exports = {
|
|
67
|
-
packDomain,
|
|
68
|
-
|
|
69
|
-
verifyDomain,
|
|
70
|
-
inspectContainer,
|
|
71
|
-
signDomain,
|
|
72
|
-
generateLicense,
|
|
73
|
+
packDomain, packEncryptedDomain, verifyDomain, validateDomain,
|
|
74
|
+
inspectContainer, signDomain, generateLicense,
|
|
73
75
|
};
|