@aikdna/kdna-studio-cli 0.8.16 → 0.9.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 CHANGED
@@ -8,7 +8,7 @@ Distillation-first authoring is domain-first: declare the target domain, owner s
8
8
 
9
9
  This package provides the `kdna-studio` command. It creates Studio projects,
10
10
  imports evidence, manages judgment cards, records optional review/provenance
11
- signals, compiles reviewed project content, and exports canonical `.kdna`
11
+ signals, compiles project content, and exports canonical `.kdna`
12
12
  assets with build reports.
13
13
 
14
14
  It is intentionally separate from `@aikdna/kdna-cli`:
@@ -37,7 +37,7 @@ kdna-studio target declare my_domain \
37
37
  --task "longform article review" \
38
38
  --include "argument structure,tone,revision" \
39
39
  --exclude "life habits,food preference"
40
- kdna-studio source classify my_domain
40
+ kdna-studio source my_domain
41
41
  kdna-studio distill my_domain --candidates candidates.json
42
42
  kdna-studio candidate list my_domain
43
43
  kdna-studio candidate accept my_domain <candidate-id>
@@ -48,17 +48,19 @@ kdna-studio card add my_domain axiom \
48
48
  --field why="Broad claims hide the actual reason for a judgment, so reviewers cannot tell whether the conclusion is evidence based, reusable, or merely plausible sounding." \
49
49
  --field applies_when='["reviewing content"]' \
50
50
  --field does_not_apply_when='["pure formatting"]' \
51
- --field failure_risk="generic advice"
51
+ --field failure_risk="generic advice" \
52
+ --field confidence='high' \
53
+ --field evidence_type='practice'
54
+ # Optional: record review provenance
52
55
  kdna-studio card approve my_domain --all --by expert --statement "I confirm this judgment."
53
56
  kdna-studio export my_domain --out dist/my_domain.kdna
54
57
  ```
55
58
 
56
59
  Candidate promotion is scope-gated: only candidates with `status == accepted` and `scope_fit == true` are promoted to cards by default. Use `kdna-studio candidate override <project> <candidate-id>` only when a human intentionally overrides the scope gate.
57
60
 
58
- The current Studio CLI export workflow uses approved cards as release evidence.
59
- This is Studio project policy, not a KDNA format-validity rule. Human
60
- Lock and other provenance records are optional review evidence, not validity
61
- requirements.
61
+ The Studio CLI exports complete, non-deprecated cards. Human Lock and other
62
+ provenance records are optional review evidence, not creation permission or
63
+ format-validity requirements.
62
64
 
63
65
  After export, use the runtime CLI:
64
66
 
@@ -77,14 +79,11 @@ loading existing `.kdna` assets.
77
79
  If you just installed and want to ship a KDNA asset without an LLM:
78
80
 
79
81
  ```bash
80
- # 1. Init identity (required for the export signature)
81
- kdna-studio identity init --name "Your Name"
82
-
83
- # 2. Create a project
82
+ # 1. Create a project
84
83
  kdna-studio create my_domain --name @yourscope/my_domain
85
84
 
86
- # 3. Add at least one judgment card
87
- kdna-studio card add . axiom \
85
+ # 2. Add at least one judgment card
86
+ kdna-studio card add my_domain axiom \
88
87
  --field one_sentence='specific evidence outranks broad claims' \
89
88
  --field full_statement='Always cite the specific source that supports a judgment; broad claims without evidence are the most common cause of bad agent advice.' \
90
89
  --field why='because vague advice fails in production' \
@@ -92,15 +91,15 @@ kdna-studio card add . axiom \
92
91
  --field does_not_apply_when='["formatting"]' \
93
92
  --field failure_risk='praise without diagnosis' \
94
93
  --field confidence='high' \
95
- --field evidence_type='observation'
94
+ --field evidence_type='practice'
96
95
 
97
- # 4. Approve and lock
98
- kdna-studio card approve . --all --by me --statement "i confirm"
96
+ # 3. Optional: approve and record Human Lock provenance
97
+ kdna-studio card approve my_domain --all --by me --statement "i confirm"
99
98
 
100
- # 5. Export the asset
101
- kdna-studio export . --out my_domain.kdna
99
+ # 4. Export the asset
100
+ kdna-studio export my_domain --out my_domain.kdna
102
101
 
103
- # 6. Verify with the runtime CLI
102
+ # 5. Verify with the runtime CLI
104
103
  kdna load my_domain.kdna --profile=compact
105
104
  ```
106
105
 
@@ -155,7 +154,7 @@ kdna-studio identity show
155
154
  ## Import from existing KDNA or legacy folders
156
155
 
157
156
  ```bash
158
- # Fork an existing .kdna asset (cards imported as draft — review before Studio export)
157
+ # Fork an existing canonical .kdna asset (cards are imported as draft)
159
158
  kdna-studio create forked --from-kdna ./parent.kdna --name @scope/forked
160
159
 
161
160
  # Migrate a legacy JSON source folder
@@ -410,10 +410,14 @@ function resetImportedIds() { _importedIds.clear(); }
410
410
  function decodePayload(bytes, manifest = {}) {
411
411
  const raw = Buffer.isBuffer(bytes) ? bytes : Buffer.from(bytes);
412
412
  const encoding = manifest.payload?.encoding || manifest.container?.payload_encoding || null;
413
- if (encoding === 'json' || raw[0] === 0x7b || raw[0] === 0x5b) {
414
- return JSON.parse(raw.toString('utf8'));
413
+ if (encoding && encoding !== 'cbor') {
414
+ throw new Error(`unsupported payload encoding "${encoding}"; current .kdna assets require CBOR`);
415
+ }
416
+ try {
417
+ return cbor.decode(raw);
418
+ } catch (error) {
419
+ throw new Error(`payload.kdnab is not valid CBOR: ${error.message}`);
415
420
  }
416
- return cbor.decode(raw);
417
421
  }
418
422
 
419
423
  // Runtime path: trust the producer (export-runtime) to have already shaped
@@ -561,97 +565,11 @@ function cardsFromRuntimePayload(payload) {
561
565
  return cards;
562
566
  }
563
567
 
564
- function cardsFromLegacyPayload(payload) {
565
- resetImportedIds();
566
- const cards = [];
567
- const judgment = payload.judgment || {};
568
- const core = judgment.core || {};
569
- const patterns = judgment.patterns || {};
570
-
571
- for (const ax of (Array.isArray(core.axioms) ? core.axioms : [])) {
572
- pushImportedCard(cards, 'axiom', {
573
- one_sentence: ax.one_sentence || '',
574
- full_statement: ax.full_statement || '',
575
- why: ax.why || '',
576
- applies_when: ax.applies_when || [],
577
- does_not_apply_when: ax.does_not_apply_when || [],
578
- failure_risk: ax.failure_risk || '',
579
- }, ax.id || null);
580
- }
581
- for (const ont of (Array.isArray(core.ontology) ? core.ontology : [])) {
582
- pushImportedCard(cards, 'ontology', {
583
- one_sentence: ont.one_sentence || ont.essence || '',
584
- essence: ont.essence || '',
585
- boundary: ont.boundary || '',
586
- trigger_signal: ont.trigger_signal || '',
587
- }, ont.id || null);
588
- }
589
- for (const boundary of (Array.isArray(core.boundaries) ? core.boundaries : [])) {
590
- pushImportedCard(cards, 'boundary', {
591
- scope: boundary.scope || '',
592
- out_of_scope: boundary.out_of_scope || '',
593
- acceptable_exceptions: boundary.acceptable_exceptions || [],
594
- }, boundary.id || null);
595
- }
596
- for (const risk of (Array.isArray(core.risks) ? core.risks : [])) {
597
- pushImportedCard(cards, 'risk', risk, risk.id || null);
598
- }
599
- // Bug (#63): prior version skipped `core.stances` and
600
- // `core.frameworks`, so a legacy asset that authored either type
601
- // round-tripped out as zero cards. The fix adds both loops.
602
- for (const stance of (Array.isArray(core.stances) ? core.stances : [])) {
603
- pushImportedCard(cards, 'stance', stance, stance.id || null);
604
- }
605
- for (const fw of (Array.isArray(core.frameworks) ? core.frameworks : [])) {
606
- pushImportedCard(cards, 'framework', fw, fw.id || null);
607
- }
608
- for (const term of (Array.isArray(patterns.terminology?.standard_terms) ? patterns.terminology?.standard_terms : [])) {
609
- pushImportedCard(cards, 'term', term, term.id || null);
610
- }
611
- for (const banned of (Array.isArray(patterns.terminology?.banned_terms) ? patterns.terminology?.banned_terms : [])) {
612
- pushImportedCard(cards, 'banned_term', banned, banned.id || null);
613
- }
614
- for (const ms of (Array.isArray(patterns.misunderstandings) ? patterns.misunderstandings : [])) {
615
- pushImportedCard(cards, 'misunderstanding', {
616
- wrong: ms.wrong || '',
617
- correct: ms.correct || '',
618
- key_distinction: ms.key_distinction || '',
619
- why: ms.why || '',
620
- applies_when: ms.applies_when || [],
621
- does_not_apply_when: ms.does_not_apply_when || [],
622
- failure_risk: ms.failure_risk || '',
623
- }, ms.id || null);
624
- }
625
- for (const sc of (Array.isArray(patterns.self_check) ? patterns.self_check : [])) {
626
- const question = typeof sc === 'string' ? sc : sc.question || '';
627
- pushImportedCard(cards, 'self_check', { question }, sc.id || null);
628
- }
629
- for (const aesthetic of (Array.isArray(patterns.aesthetics) ? patterns.aesthetics : [])) {
630
- pushImportedCard(cards, 'aesthetic', aesthetic, aesthetic.id || null);
631
- }
632
- for (const scene of (Array.isArray(judgment.scenarios?.scenes) ? judgment.scenarios?.scenes : [])) {
633
- pushImportedCard(cards, 'scenario', scene, scene.id || null);
634
- }
635
- for (const item of (Array.isArray(judgment.cases?.cases) ? judgment.cases?.cases : [])) {
636
- pushImportedCard(cards, 'case', item, item.id || null);
637
- }
638
- for (const chain of (Array.isArray(judgment.reasoning?.reasoning_chains) ? judgment.reasoning?.reasoning_chains : [])) {
639
- pushImportedCard(cards, 'reasoning', chain, chain.id || null);
640
- }
641
- for (const stage of (Array.isArray(judgment.evolution?.stages) ? judgment.evolution?.stages : [])) {
642
- pushImportedCard(cards, 'evolution_stage', stage, stage.id || null);
643
- }
644
- return cards;
645
- }
646
-
647
568
  function cardsFromPayload(payload) {
648
569
  if (!payload || typeof payload !== 'object') return [];
649
570
  if (payload.profile === 'judgment-profile-v1' || payload.core || payload.source_cards) {
650
571
  return cardsFromRuntimePayload(payload);
651
572
  }
652
- if (payload.kind === 'kdna.payload' || payload.judgment) {
653
- return cardsFromLegacyPayload(payload);
654
- }
655
573
  return [];
656
574
  }
657
575
 
@@ -688,7 +606,7 @@ function buildManifest(project, name) {
688
606
  id: author.id || project.author?.id || undefined,
689
607
  },
690
608
  compatibility: { min_loader_version: '1.0.0', profile: 'judgment-profile-v1' },
691
- payload: { path: 'payload.kdnab', encoding: 'json', encrypted: false },
609
+ payload: { path: 'payload.kdnab', encoding: 'cbor', encrypted: false },
692
610
  summary: source.core_insight || project.release?.description || source.description || '',
693
611
  description: source.description || project.release?.description || '',
694
612
  language: source.default_language || project.default_language || (Array.isArray(source.languages) ? source.languages[0] : undefined),
@@ -821,6 +739,14 @@ function importFromKdna(kdnaPath) {
821
739
  if (stats.size > 50 * 1024 * 1024) {
822
740
  fail(`KDNA file too large (${(stats.size / (1024 * 1024)).toFixed(1)} MiB, max 50 MiB): ${absKdna}`);
823
741
  }
742
+ let runtimeCore;
743
+ try { runtimeCore = require('@aikdna/kdna-core'); } catch {
744
+ fail('@aikdna/kdna-core is required to validate --from-kdna imports.');
745
+ }
746
+ const validation = runtimeCore.validate(absKdna);
747
+ if (!validation.overall_valid) {
748
+ fail(`Not a current .kdna asset: ${(validation.problems || []).join('; ')}`);
749
+ }
824
750
  const zipBuf = fs.readFileSync(absKdna);
825
751
  const entries = readZipEntries(zipBuf);
826
752
  if (!entries.has('kdna.json')) fail('Not a valid .kdna asset: missing kdna.json');
@@ -834,122 +760,21 @@ function importFromKdna(kdnaPath) {
834
760
  parent_asset_digest: manifest.content_digest || manifest.asset_digest || null,
835
761
  };
836
762
 
837
- // Extract cards. Current packages carry `kdna.json` + `payload.kdnab`
838
- // and use the unified judgment profile. Legacy packages split content
839
- // across KDNA_*.json files. Prefer payload.kdnab when present — it
840
- // covers all 8+ card types (axiom / boundary / risk / aesthetic /
841
- // ontology / misunderstanding / self_check / scenario / case /
842
- // reasoning / evolution_stage / stance / framework / term / banned_term)
843
- // via cardsFromRuntimePayload / cardsFromLegacyPayload.
763
+ // Current assets carry strict-CBOR `payload.kdnab`. Legacy source folders
764
+ // are migrated explicitly with --from-folder; they are not runtime assets.
844
765
  const importedCards = [];
845
- if (entries.has('payload.kdnab')) {
846
- try {
847
- const payload = decodePayload(entries.get('payload.kdnab'), manifest);
848
- importedCards.push(...cardsFromPayload(payload));
849
- } catch (e) {
850
- fail(`Could not import cards from payload.kdnab: ${e.message}`);
851
- }
852
- } else if (entries.has('KDNA_Core.json') || entries.has('KDNA_Patterns.json')) {
853
- // Source-tree fallback — used when an imported source has no payload.kdnab
854
- // (i.e. the asset predates the 0.7 split). Bug (#67): prior
855
- // version only handled axiom / ontology / boundary / misunderstanding
856
- // / self_check — 5 of the 14 card types — so every other type
857
- // (risk / stance / framework / term / banned_term / aesthetic /
858
- // scenario / case / reasoning / evolution_stage) round-tripped
859
- // out as zero cards. The fix threads every type this CLI can
860
- // import through, and prefers the same field-shape rules as
861
- // cardsFromLegacyPayload so the round-trip is symmetric.
862
- if (entries.has('KDNA_Core.json')) {
863
- const core = JSON.parse(entries.get('KDNA_Core.json').toString());
864
- for (const ax of (Array.isArray(core.axioms) ? core.axioms : [])) {
865
- const fields = {};
866
- for (const k of ['one_sentence','full_statement','why','applies_when','does_not_apply_when','failure_risk','confidence','evidence_type']) {
867
- if (k in ax) fields[k] = ax[k];
868
- }
869
- importedCards.push(cardApi.createCard('axiom', fields));
870
- }
871
- for (const ont of (Array.isArray(core.ontology) ? core.ontology : [])) {
872
- importedCards.push(cardApi.createCard('ontology', {
873
- one_sentence: ont.one_sentence || ont.essence || '',
874
- essence: ont.essence || '', boundary: ont.boundary || '',
875
- trigger_signal: ont.trigger_signal || '',
876
- }));
877
- }
878
- for (const b of (Array.isArray(core.boundaries) ? core.boundaries : [])) {
879
- importedCards.push(cardApi.createCard('boundary', {
880
- scope: b.scope || '', out_of_scope: b.out_of_scope || '',
881
- acceptable_exceptions: b.acceptable_exceptions || [],
882
- }));
883
- }
884
- // Accept risks as a top-level array (`risks`) or wrapped in `risk_model`
885
- // (either as `{risks: [...]}` or as an array itself). Uses the same
886
- // Array.isArray ladder pattern as the safe path at lines 1033-1040.
887
- let risksSource = core.risks;
888
- if (!Array.isArray(risksSource)) {
889
- if (Array.isArray(core.risk_model)) risksSource = core.risk_model;
890
- else if (Array.isArray(core.risk_model?.risks)) risksSource = core.risk_model.risks;
891
- else risksSource = [];
892
- }
893
- for (const risk of risksSource) {
894
- importedCards.push(cardApi.createCard('risk', risk.fields || risk));
895
- }
896
- for (const stance of (Array.isArray(core.stances) ? core.stances : [])) {
897
- importedCards.push(cardApi.createCard('stance', stance.fields || stance));
898
- }
899
- for (const fw of (Array.isArray(core.frameworks) ? core.frameworks : [])) {
900
- importedCards.push(cardApi.createCard('framework', fw.fields || fw));
901
- }
902
- }
903
- if (entries.has('KDNA_Patterns.json')) {
904
- const pat = JSON.parse(entries.get('KDNA_Patterns.json').toString());
905
- for (const ms of (Array.isArray(pat.misunderstandings) ? pat.misunderstandings : [])) {
906
- importedCards.push(cardApi.createCard('misunderstanding', {
907
- wrong: ms.wrong || '', correct: ms.correct || '',
908
- key_distinction: ms.key_distinction || '', why: ms.why || '',
909
- }));
910
- }
911
- for (const sc of (Array.isArray(pat.self_check) ? pat.self_check : [])) {
912
- const q = typeof sc === 'string' ? sc : sc.question || '';
913
- importedCards.push(cardApi.createCard('self_check', { question: q }));
914
- }
915
- for (const aesthetic of (Array.isArray(pat.aesthetics) ? pat.aesthetics : [])) {
916
- importedCards.push(cardApi.createCard('aesthetic', aesthetic.fields || aesthetic));
917
- }
918
- for (const term of (Array.isArray(pat.terminology?.standard_terms) ? pat.terminology?.standard_terms : [])) {
919
- importedCards.push(cardApi.createCard('term', term));
920
- }
921
- for (const banned of (Array.isArray(pat.terminology?.banned_terms) ? pat.terminology?.banned_terms : [])) {
922
- importedCards.push(cardApi.createCard('banned_term', banned));
923
- }
924
- }
925
- if (entries.has('KDNA_Scenarios.json')) {
926
- const scen = JSON.parse(entries.get('KDNA_Scenarios.json').toString());
927
- for (const s of (Array.isArray(scen.scenes) ? scen.scenes : [])) {
928
- importedCards.push(cardApi.createCard('scenario', s));
929
- }
930
- }
931
- if (entries.has('KDNA_Cases.json')) {
932
- const cases = JSON.parse(entries.get('KDNA_Cases.json').toString());
933
- for (const c of (Array.isArray(cases.cases) ? cases.cases : [])) {
934
- importedCards.push(cardApi.createCard('case', c));
935
- }
936
- }
937
- if (entries.has('KDNA_Reasoning.json')) {
938
- const reasoning = JSON.parse(entries.get('KDNA_Reasoning.json').toString());
939
- for (const chain of (Array.isArray(reasoning.reasoning_chains) ? reasoning.reasoning_chains : [])) {
940
- importedCards.push(cardApi.createCard('reasoning', chain));
941
- }
942
- }
943
- if (entries.has('KDNA_Evolution.json')) {
944
- const evolution = JSON.parse(entries.get('KDNA_Evolution.json').toString());
945
- for (const stage of (Array.isArray(evolution.stages) ? evolution.stages : [])) {
946
- importedCards.push(cardApi.createCard('evolution_stage', stage));
947
- }
948
- }
766
+ if (!entries.has('payload.kdnab')) {
767
+ fail('Not a current .kdna asset: missing payload.kdnab. Use --from-folder for legacy JSON source migration.');
768
+ }
769
+ try {
770
+ const payload = decodePayload(entries.get('payload.kdnab'), manifest);
771
+ importedCards.push(...cardsFromPayload(payload));
772
+ } catch (e) {
773
+ fail(`Could not import cards from payload.kdnab: ${e.message}`);
949
774
  }
950
775
 
951
776
  if (importedCards.length === 0) {
952
- fail(`No cards could be extracted from ${absKdna}. Expected payload.kdnab or an importable KDNA_Core.json + KDNA_Patterns.json source tree.`);
777
+ fail(`No current judgment cards could be extracted from ${absKdna}.`);
953
778
  }
954
779
 
955
780
  // Bug #15 / #28 follow-up: surface the source's KDNA_Patterns /
@@ -958,23 +783,13 @@ function importFromKdna(kdnaPath) {
958
783
  // compileDomain via exportRuntimeAsset, which preserves
959
784
  // changelog / version_notes / reasoning_chains / banned_terms
960
785
  // through the round-trip.
961
- const sourcePatterns = entries.has('KDNA_Patterns.json')
962
- ? JSON.parse(entries.get('KDNA_Patterns.json').toString())
963
- : null;
964
- const sourceReasoning = entries.has('KDNA_Reasoning.json')
965
- ? JSON.parse(entries.get('KDNA_Reasoning.json').toString())
966
- : null;
967
- const sourceEvolution = entries.has('KDNA_Evolution.json')
968
- ? JSON.parse(entries.get('KDNA_Evolution.json').toString())
969
- : null;
970
-
971
786
  return {
972
787
  lineage,
973
788
  cards: importedCards,
974
789
  source_manifest: manifest,
975
- source_patterns: sourcePatterns,
976
- source_reasoning: sourceReasoning,
977
- source_evolution: sourceEvolution,
790
+ source_patterns: null,
791
+ source_reasoning: null,
792
+ source_evolution: null,
978
793
  };
979
794
  }
980
795
 
@@ -1992,17 +1807,7 @@ function exportProject(project, name, outPath, opts = {}) {
1992
1807
  );
1993
1808
  }
1994
1809
  }
1995
- const gate = projectApi.checkHumanLockGate(project);
1996
- if (gate.blocked) {
1997
- if (opts.allowIncomplete) {
1998
- console.warn('Human Lock Gate bypassed (--allow-incomplete):');
1999
- for (const issue of gate.issues) console.warn(` - ${issue.cardId}: ${issue.reason}`);
2000
- } else {
2001
- const reasons = gate.issues.map((i) => `${i.cardId}: ${i.reason}`).join('\n - ');
2002
- fail(`Human Lock Gate blocked export:\n - ${reasons}\nUse --allow-incomplete to bypass.`, EXIT.HUMAN_LOCK_REQUIRED);
2003
- }
2004
- }
2005
- const lockedCards = (project.cards || []).filter(c => c.locked);
1810
+ const exportedCards = (project.cards || []).filter(c => c.status !== 'deprecated');
2006
1811
  const runtimeDir = trackTempDir(fs.mkdtempSync(path.join(os.tmpdir(), 'kdna-runtime-')));
2007
1812
  try {
2008
1813
  const manifestDefaults = buildManifest(project, name);
@@ -2021,7 +1826,7 @@ function exportProject(project, name, outPath, opts = {}) {
2021
1826
  const vr = core.validate(outPath);
2022
1827
  if (!vr.overall_valid) fail('runtime export validation failed: ' + (vr.problems || []).join('; '));
2023
1828
  console.log('Exported: ' + outPath);
2024
- console.log(' Name: ' + name + ' Cards: ' + lockedCards.length + ' Validated: all gates pass');
1829
+ console.log(' Name: ' + name + ' Cards: ' + exportedCards.length + ' Validated: runtime contract passed');
2025
1830
  } finally {
2026
1831
  try { fs.rmSync(runtimeDir, { recursive: true }); } catch { /* cleanup */ }
2027
1832
  }
@@ -2029,11 +1834,6 @@ function exportProject(project, name, outPath, opts = {}) {
2029
1834
 
2030
1835
  function compileProject(projectInput) {
2031
1836
  const { project } = readProject(projectInput);
2032
- const gate = projectApi.checkHumanLockGate(project);
2033
- if (gate.blocked) {
2034
- const reasons = gate.issues.map((i) => `${i.cardId}: ${i.reason}`).join('\n - ');
2035
- fail(`Human Lock Gate blocked compile:\n - ${reasons}`, EXIT.HUMAN_LOCK_REQUIRED);
2036
- }
2037
1837
  return { project, result: compileApi.compileDomain(project) };
2038
1838
  }
2039
1839
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aikdna/kdna-studio-cli",
3
- "version": "0.8.16",
3
+ "version": "0.9.0",
4
4
  "description": "Official KDNA Studio command-line authoring entry for creating, reviewing, compiling, and exporting .kdna judgment assets through the KDNA toolchain.",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -41,8 +41,8 @@
41
41
  "node": ">=18"
42
42
  },
43
43
  "dependencies": {
44
- "@aikdna/kdna-core": "0.15.12",
45
- "@aikdna/kdna-studio-core": "1.7.13",
44
+ "@aikdna/kdna-core": "0.16.0",
45
+ "@aikdna/kdna-studio-core": "1.8.0",
46
46
  "ajv": "^8.20.0",
47
47
  "ajv-formats": "^3.0.1",
48
48
  "cbor-x": "^1.6.4"