@aikdna/kdna-cli 0.19.2 → 0.20.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/LICENSE +1 -1
- package/README.md +42 -28
- package/package.json +4 -4
- package/skills/kdna-loader/SKILL.md +3 -1
- package/src/capsule-verify.js +70 -0
- package/src/cli.js +72 -47
- package/src/cmds/_common.js +66 -8
- package/src/cmds/domain.js +20 -1
- package/src/cmds/governance.js +1 -1
- package/src/cmds/protect.js +313 -0
- package/src/cmds/protect.js.bak +245 -0
- package/src/cmds/protocol.js +181 -0
- package/src/cmds/studio.js +7 -10
- package/src/cmds/workpack.js +875 -0
- package/src/dev-pack-v2.js +117 -0
- package/src/init.js +14 -6
- package/src/install.js +116 -2
- package/src/kdf-spec.js +42 -0
- package/src/package-store.js +29 -7
- package/src/paths.js +3 -2
- package/src/publish.js +92 -184
- package/src/registry.js +73 -3
- package/src/signature.js +39 -0
- package/src/verify.js +78 -0
- package/templates/cluster/README.md +1 -1
- package/templates/standard-domain/USAGE.md +2 -1
- package/templates/standard-domain/kdna.json +1 -1
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
const { readFileSync } = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { error, EXIT } = require('./_common');
|
|
4
|
+
|
|
5
|
+
const SCHEMA_DIR = path.join(
|
|
6
|
+
path.dirname(require.resolve('@aikdna/kdna-core/package.json')),
|
|
7
|
+
'..',
|
|
8
|
+
'..',
|
|
9
|
+
'specs',
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
const SCHEMAS = {
|
|
13
|
+
'artifact-envelope': 'artifact-envelope.schema.json',
|
|
14
|
+
'stage-definition': 'stage-definition.schema.json',
|
|
15
|
+
'fidelity-result': 'fidelity-result.schema.json',
|
|
16
|
+
'product-runtime': 'product-runtime.schema.json',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function validate(args) {
|
|
20
|
+
const file = args.filter((a) => !a.startsWith('--'))[1];
|
|
21
|
+
const schemaName = args.includes('--schema') ? args[args.indexOf('--schema') + 1] : null;
|
|
22
|
+
|
|
23
|
+
if (!file) {
|
|
24
|
+
error('Usage: kdna protocol validate <file.json> [--schema <name>]', EXIT.INPUT_ERROR);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let data;
|
|
28
|
+
try {
|
|
29
|
+
data = JSON.parse(readFileSync(file, 'utf8'));
|
|
30
|
+
} catch (e) {
|
|
31
|
+
error(`Failed to read or parse ${file}: ${e.message}`, EXIT.INPUT_ERROR);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const schemasToCheck = schemaName ? [schemaName] : Object.keys(SCHEMAS);
|
|
35
|
+
let passed = 0;
|
|
36
|
+
let failed = 0;
|
|
37
|
+
|
|
38
|
+
for (const name of schemasToCheck) {
|
|
39
|
+
const schemaFile = SCHEMAS[name];
|
|
40
|
+
if (!schemaFile) {
|
|
41
|
+
error(
|
|
42
|
+
`Unknown schema: ${name}. Available: ${Object.keys(SCHEMAS).join(', ')}`,
|
|
43
|
+
EXIT.INPUT_ERROR,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const schemaPath = path.join(SCHEMA_DIR, schemaFile);
|
|
49
|
+
const schema = JSON.parse(readFileSync(schemaPath, 'utf8'));
|
|
50
|
+
const { validate: ajvValidate } = loadAjv();
|
|
51
|
+
const valid = ajvValidate(schema, data);
|
|
52
|
+
if (valid) {
|
|
53
|
+
console.log(` ✓ ${name} (${schemaFile})`);
|
|
54
|
+
passed++;
|
|
55
|
+
} else {
|
|
56
|
+
console.log(` ✗ ${name} (${schemaFile})`);
|
|
57
|
+
failed++;
|
|
58
|
+
}
|
|
59
|
+
} catch (e) {
|
|
60
|
+
console.log(` ✗ ${name}: ${e.message}`);
|
|
61
|
+
failed++;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (failed > 0) {
|
|
66
|
+
error(`Validation failed: ${failed}/${passed + failed} schema(s)`, EXIT.VALIDATION_FAILED);
|
|
67
|
+
}
|
|
68
|
+
console.log(`Validation passed: ${passed}/${passed + failed} schema(s)`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function inspect(args) {
|
|
72
|
+
const file = args.filter((a) => !a.startsWith('--'))[1];
|
|
73
|
+
if (!file) {
|
|
74
|
+
error('Usage: kdna protocol inspect <file.json>', EXIT.INPUT_ERROR);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let data;
|
|
78
|
+
try {
|
|
79
|
+
data = JSON.parse(readFileSync(file, 'utf8'));
|
|
80
|
+
} catch (e) {
|
|
81
|
+
error(`Failed to read ${file}: ${e.message}`, EXIT.INPUT_ERROR);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (args.includes('--json')) {
|
|
85
|
+
console.log(JSON.stringify(summarize(data), null, 2));
|
|
86
|
+
} else {
|
|
87
|
+
const summary = summarize(data);
|
|
88
|
+
console.log(`Type: ${summary.type}`);
|
|
89
|
+
if (summary.artifact_type) console.log(`Artifact: ${summary.artifact_type}`);
|
|
90
|
+
if (summary.generator)
|
|
91
|
+
console.log(`Generator: ${summary.generator.engine} v${summary.generator.version}`);
|
|
92
|
+
if (summary.source_kdna_count) console.log(`KDNA domains: ${summary.source_kdna_count}`);
|
|
93
|
+
if (summary.stages_count) console.log(`Stages: ${summary.stages_count}`);
|
|
94
|
+
if (summary.quality) console.log(`Quality: ${summary.quality}`);
|
|
95
|
+
if (summary.fidelity) console.log(`Fidelity: ${summary.fidelity}`);
|
|
96
|
+
if (summary.review) console.log(`Review: ${summary.review}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function summarize(data) {
|
|
101
|
+
const summary = { type: 'unknown' };
|
|
102
|
+
|
|
103
|
+
if (data.format === 'kdna-pipeline') {
|
|
104
|
+
summary.type = 'pipeline';
|
|
105
|
+
summary.stages_count = data.stages?.length || 0;
|
|
106
|
+
if (data.pipeline_kdna) summary.kdna_mode = data.pipeline_kdna.mode;
|
|
107
|
+
if (data.artifacts?.enabled) summary.artifacts_enabled = true;
|
|
108
|
+
if (data.trace?.enabled) summary.trace_enabled = true;
|
|
109
|
+
} else if (data.artifact_id && data.artifact_type) {
|
|
110
|
+
summary.type = 'artifact';
|
|
111
|
+
summary.artifact_type = data.artifact_type;
|
|
112
|
+
if (data.generator) summary.generator = data.generator;
|
|
113
|
+
summary.source_kdna_count = data.source_kdna?.length || 0;
|
|
114
|
+
if (data.quality?.overall_result) summary.quality = data.quality.overall_result;
|
|
115
|
+
if (data.review?.status) summary.review = data.review.status;
|
|
116
|
+
if (data.quality?.fidelity?.score !== undefined)
|
|
117
|
+
summary.fidelity = `${data.quality.fidelity.score} (v${data.quality.fidelity.protocol_version})`;
|
|
118
|
+
} else if (
|
|
119
|
+
data.fidelity_id &&
|
|
120
|
+
(data.protocol_version !== undefined || data.protocolVersion !== undefined)
|
|
121
|
+
) {
|
|
122
|
+
summary.type = 'fidelity_result';
|
|
123
|
+
summary.overall_score = data.overall_score ?? data.overallScore;
|
|
124
|
+
summary.passed = data.passed;
|
|
125
|
+
const cmp = data.comparison;
|
|
126
|
+
if (cmp) {
|
|
127
|
+
if (cmp.blind_delta !== undefined) summary.blind_delta = cmp.blind_delta;
|
|
128
|
+
else if (cmp.blindDelta !== undefined) summary.blind_delta = cmp.blindDelta;
|
|
129
|
+
}
|
|
130
|
+
} else if (data.format === 'kdna-product-runtime') {
|
|
131
|
+
summary.type = 'product_runtime';
|
|
132
|
+
if (data.schedule) summary.schedule_type = data.schedule.type;
|
|
133
|
+
if (data.selection) summary.selection_type = data.selection.type;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return summary;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
let _ajv = null;
|
|
140
|
+
function loadAjv() {
|
|
141
|
+
if (_ajv) return _ajv;
|
|
142
|
+
try {
|
|
143
|
+
const Ajv = require('ajv');
|
|
144
|
+
const addFormats = require('ajv-formats');
|
|
145
|
+
const ajv = new Ajv({ allErrors: true, strict: false, validateSchema: false });
|
|
146
|
+
addFormats(ajv);
|
|
147
|
+
_ajv = { ajv, validate: (schema, data) => ajv.validate(schema, data) };
|
|
148
|
+
} catch {
|
|
149
|
+
_ajv = {
|
|
150
|
+
validate: () => {
|
|
151
|
+
throw new Error('ajv not installed. Run: npm install ajv ajv-formats');
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
return _ajv;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function cmdProtocol(args) {
|
|
159
|
+
const sub = args[1];
|
|
160
|
+
const rest = args.slice(1);
|
|
161
|
+
|
|
162
|
+
switch (sub) {
|
|
163
|
+
case 'validate':
|
|
164
|
+
validate(rest);
|
|
165
|
+
break;
|
|
166
|
+
case 'inspect':
|
|
167
|
+
inspect(rest);
|
|
168
|
+
break;
|
|
169
|
+
default:
|
|
170
|
+
error(
|
|
171
|
+
'Usage: kdna protocol <validate|inspect> [file]\n' +
|
|
172
|
+
' kdna protocol validate <file.json> [--schema <name>]\n' +
|
|
173
|
+
' kdna protocol inspect <file.json> [--json]\n' +
|
|
174
|
+
'\nSchemas: ' +
|
|
175
|
+
Object.keys(SCHEMAS).join(', '),
|
|
176
|
+
EXIT.INPUT_ERROR,
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
module.exports = { cmdProtocol };
|
package/src/cmds/studio.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Dev-only Studio project diagnostics retained for old project files.
|
|
3
3
|
*
|
|
4
|
-
* kdna
|
|
4
|
+
* kdna-studio create <name> Create Studio project skeleton
|
|
5
5
|
* kdna cards validate <project.json> Validate Judgment Cards
|
|
6
6
|
* kdna lock verify <project.json> Verify Human Lock status
|
|
7
|
-
* kdna
|
|
8
|
-
* kdna
|
|
7
|
+
* kdna-studio compile <project.json> Compile locked cards into Studio build output
|
|
8
|
+
* kdna-studio report <project.json> Generate Domain Readiness Card
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
const fs = require('fs');
|
|
@@ -80,10 +80,7 @@ const CARD_TEMPLATES = {
|
|
|
80
80
|
|
|
81
81
|
function cmdStudioScaffold(name, args = []) {
|
|
82
82
|
if (!name)
|
|
83
|
-
error(
|
|
84
|
-
'Usage: kdna studio scaffold <name> [--type=domain|cluster] [--minimal]',
|
|
85
|
-
EXIT.INPUT_ERROR,
|
|
86
|
-
);
|
|
83
|
+
error('Usage: kdna-studio create <name> [--type=domain|cluster] [--minimal]', EXIT.INPUT_ERROR);
|
|
87
84
|
if (!/^[a-z][a-z0-9_-]*$/.test(name)) {
|
|
88
85
|
error(
|
|
89
86
|
`Invalid name "${name}". Use lowercase letters, numbers, hyphens, underscores. Start with letter.`,
|
|
@@ -139,7 +136,7 @@ function cmdStudioScaffold(name, args = []) {
|
|
|
139
136
|
// Write exports/README.md
|
|
140
137
|
fs.writeFileSync(
|
|
141
138
|
path.join(targetDir, 'exports', 'README.md'),
|
|
142
|
-
`# ${name}\n\nCompiled KDNA domain files will appear here after \`kdna
|
|
139
|
+
`# ${name}\n\nCompiled KDNA domain files will appear here after \`kdna-studio compile\`.\n`,
|
|
143
140
|
);
|
|
144
141
|
|
|
145
142
|
console.log(`✓ Studio project created: ${targetDir}/`);
|
|
@@ -150,7 +147,7 @@ function cmdStudioScaffold(name, args = []) {
|
|
|
150
147
|
console.log(' 1. Edit cards/ — replace all [TODO] placeholders');
|
|
151
148
|
console.log(' 2. Run: kdna cards validate studio.project.json');
|
|
152
149
|
console.log(' 3. Run: kdna lock verify studio.project.json');
|
|
153
|
-
console.log(' 4. Run: kdna
|
|
150
|
+
console.log(' 4. Run: kdna-studio compile studio.project.json');
|
|
154
151
|
}
|
|
155
152
|
|
|
156
153
|
// ─── Cards Validate ───────────────────────────────────────────────────
|