arcane-os 0.1.2 → 0.2.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/NOTICE +5 -3
  3. package/README.md +73 -24
  4. package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +67 -18
  5. package/browser-runtime/ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json +16 -5
  6. package/browser-runtime/ai/browser-kokoro-worker.mjs +3 -0
  7. package/browser-runtime/ai/browser-speech-artifacts.mjs +1108 -0
  8. package/browser-runtime/ai/browser-speech-providers.mjs +780 -0
  9. package/browser-runtime/ai/browser-speech.mjs +9 -0
  10. package/browser-runtime/ai/browser-wasm-llm-provider.mjs +1537 -167
  11. package/browser-runtime/ai/browser-wasm.mjs +46 -1
  12. package/browser-runtime/ai/browser-whisper-worker.mjs +3 -0
  13. package/browser-runtime/ai/browser-wllama-runtime.mjs +677 -132
  14. package/browser-runtime/ai/model-controller.mjs +138 -12
  15. package/browser-runtime/ai/speech-worker-client.mjs +207 -0
  16. package/browser-runtime/ai/speech-worker-runtime.mjs +516 -0
  17. package/browser-runtime/ai/wllama/index.mjs +389 -0
  18. package/docs/architecture.md +132 -22
  19. package/docs/reference/README.md +1 -1
  20. package/docs/reference/ai/browser-wasm.md +101 -42
  21. package/docs/reference/availability-and-normalization.md +19 -5
  22. package/docs/reference/behavioral-testing.md +18 -5
  23. package/docs/reference/cli.md +2 -2
  24. package/docs/reference/inventory/package-api.json +14 -14
  25. package/docs/reference/protocols.md +4 -4
  26. package/docs/reference/sdk-api.md +68 -38
  27. package/docs/work-amplification.md +8 -4
  28. package/package.json +7 -3
  29. package/runtime/ARCANE_RUNTIME_RELEASE.json +50 -20
  30. package/runtime/arcane/components/chat.html +551 -62
  31. package/runtime/arcane/components/speech.html +1113 -265
  32. package/runtime/arcane/entities/Chat.js +246 -43
  33. package/runtime/arcane/modules/AI.js +1394 -162
  34. package/runtime/arcane/modules/AIProviderRuntime.js +2289 -0
  35. package/runtime/arcane/modules/AIRuntimeState.js +872 -0
  36. package/runtime/arcane/modules/ConfiguredAIChatSession.js +382 -31
  37. package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +1106 -0
  38. package/runtime/arcane/modules/DocumentLexicalSearch.js +292 -0
  39. package/runtime/arcane/modules/PersistentAIChatSession.js +268 -0
  40. package/runtime/arcane/modules/StaticDocumentCatalog.js +25 -206
  41. package/schemas/arcane-lock.schema.json +10 -6
  42. package/src/cli/main.mjs +14 -2
  43. package/src/constants.mjs +1 -1
  44. package/src/dev-server.mjs +273 -26
  45. package/src/doctor.mjs +1 -3
  46. package/src/import-map.mjs +193 -84
  47. package/src/packager/core.mjs +313 -41
  48. package/src/runtime.mjs +14 -4
  49. package/src/scaffold.mjs +45 -17
  50. package/src/sdk-browser-runtime.mjs +28 -75
  51. package/src/templates/workspace-template.mjs +27 -8
  52. package/src/toolchain.mjs +13 -2
  53. package/src/workspace-runtime.mjs +1 -1
  54. package/src/workspace.mjs +178 -25
@@ -1,3 +1,10 @@
1
+ import DocumentLexicalSearch,{
2
+ documentContextExcerpt,
3
+ documentSearchTokens,
4
+ normalizedDocumentSearchText,
5
+ scoreDocumentBody,
6
+ } from './DocumentLexicalSearch.js';
7
+
1
8
  const CATALOG_SCHEMA_VERSION=1;
2
9
  const DEFAULT_LIMITS=Object.freeze({
3
10
  cacheTimeoutMs:2000,
@@ -26,15 +33,6 @@ const LANGUAGE_PATTERN=/^[a-z][a-z0-9.+#_-]{0,31}$/;
26
33
  const MEDIA_TYPES=new Set(['text/markdown','text/plain']);
27
34
  const SHA256_PATTERN=/^[a-f0-9]{64}$/;
28
35
  const TEXTUAL_CONTENT_TYPE=/^(?:text\/|application\/(?:javascript|json|xml|xhtml\+xml)(?:;|$)|image\/svg\+xml(?:;|$))/i;
29
- const SEARCH_FIELD_ORDER=Object.freeze([
30
- 'title','searchTerms','tags','headings','summary','category','navigationGroup',
31
- 'navigationParent','audiences','platforms','sourcePath','path','language','id'
32
- ]);
33
- const SEARCH_STOP_WORDS=new Set([
34
- 'a','an','and','are','as','at','be','by','do','does','for','from','how','i',
35
- 'in','is','it','of','on','or','that','the','this','to','use','using','what',
36
- 'when','where','which','who','why','with','you','your'
37
- ]);
38
36
 
39
37
  function isPlainRecord(value){
40
38
  return Boolean(value)
@@ -486,150 +484,6 @@ function normalizeOptions(input){
486
484
  });
487
485
  }
488
486
 
489
- function normalizedSearchText(value){
490
- return value.normalize('NFKD').toLowerCase();
491
- }
492
-
493
- function searchTokens(value){
494
- return [...new Set(normalizedSearchText(value).match(/[\p{L}\p{N}]+/gu)??[])]
495
- .filter(token=>!SEARCH_STOP_WORDS.has(token))
496
- .slice(0,32);
497
- }
498
-
499
- function searchIndex(record){
500
- return Object.freeze({
501
- audiences:record.audiences.map(normalizedSearchText),
502
- category:normalizedSearchText(record.category),
503
- id:normalizedSearchText(record.id),
504
- navigationGroup:normalizedSearchText(record.navigationGroup),
505
- navigationParent:normalizedSearchText(record.navigationParent),
506
- path:normalizedSearchText(record.path),
507
- sourcePath:normalizedSearchText(record.sourcePath),
508
- language:normalizedSearchText(record.language),
509
- platforms:record.platforms.map(normalizedSearchText),
510
- title:normalizedSearchText(record.title),
511
- summary:normalizedSearchText(record.summary),
512
- tags:record.tags.map(normalizedSearchText),
513
- searchTerms:record.searchTerms.map(normalizedSearchText),
514
- headings:record.headings.map(heading=>normalizedSearchText(heading.text)),
515
- });
516
- }
517
-
518
- function fieldScore(index,phrase,tokens){
519
- const matched=new Set();
520
- let score=0;
521
- if(index.title===phrase){score+=120;matched.add('title');}
522
- else if(index.title.includes(phrase)){score+=60;matched.add('title');}
523
- if(index.id===phrase){score+=100;matched.add('id');}
524
- else if(index.id.includes(phrase)){score+=20;matched.add('id');}
525
- if(index.path.includes(phrase)){score+=24;matched.add('path');}
526
- if(index.sourcePath.includes(phrase)){score+=24;matched.add('sourcePath');}
527
- if(index.language===phrase){score+=30;matched.add('language');}
528
- if(index.summary.includes(phrase)){score+=18;matched.add('summary');}
529
- if(index.category===phrase){score+=40;matched.add('category');}
530
- else if(index.category.includes(phrase)){score+=16;matched.add('category');}
531
- if(index.navigationGroup===phrase){score+=40;matched.add('navigationGroup');}
532
- else if(index.navigationGroup.includes(phrase)){score+=16;matched.add('navigationGroup');}
533
- if(index.navigationParent===phrase){score+=36;matched.add('navigationParent');}
534
- else if(index.navigationParent.includes(phrase)){score+=14;matched.add('navigationParent');}
535
- if(index.audiences.some(function audienceEqualsPhrase(audience){return audience===phrase;})){score+=32;matched.add('audiences');}
536
- else if(index.audiences.some(function audienceIncludesPhrase(audience){return audience.includes(phrase);})){score+=12;matched.add('audiences');}
537
- if(index.platforms.some(function platformEqualsPhrase(platform){return platform===phrase;})){score+=32;matched.add('platforms');}
538
- else if(index.platforms.some(function platformIncludesPhrase(platform){return platform.includes(phrase);})){score+=12;matched.add('platforms');}
539
- if(index.searchTerms.some(term=>term===phrase)){score+=110;matched.add('searchTerms');}
540
- else if(index.searchTerms.some(term=>term.includes(phrase))){score+=52;matched.add('searchTerms');}
541
- for(const tag of index.tags){
542
- if(tag===phrase){score+=40;matched.add('tags');}
543
- else if(tag.includes(phrase)){score+=16;matched.add('tags');}
544
- }
545
- if(index.headings.some(heading=>heading.includes(phrase))){score+=22;matched.add('headings');}
546
-
547
- for(const token of tokens){
548
- if(index.title.split(/[^\p{L}\p{N}]+/u).includes(token)){score+=14;matched.add('title');}
549
- else if(index.title.includes(token)){score+=7;matched.add('title');}
550
- if(index.tags.some(tag=>tag===token)){score+=12;matched.add('tags');}
551
- else if(index.tags.some(tag=>tag.includes(token))){score+=5;matched.add('tags');}
552
- if(index.headings.some(heading=>heading.includes(token))){score+=5;matched.add('headings');}
553
- if(index.summary.includes(token)){score+=3;matched.add('summary');}
554
- if(index.category.includes(token)){score+=6;matched.add('category');}
555
- if(index.navigationGroup.includes(token)){score+=6;matched.add('navigationGroup');}
556
- if(index.navigationParent.includes(token)){score+=6;matched.add('navigationParent');}
557
- if(index.audiences.some(function audienceIncludesToken(audience){return audience.includes(token);})){score+=6;matched.add('audiences');}
558
- if(index.platforms.some(function platformIncludesToken(platform){return platform.includes(token);})){score+=6;matched.add('platforms');}
559
- if(index.searchTerms.some(term=>term===token)){score+=18;matched.add('searchTerms');}
560
- else if(index.searchTerms.some(term=>term.includes(token))){score+=9;matched.add('searchTerms');}
561
- if(index.sourcePath.includes(token)){score+=4;matched.add('sourcePath');}
562
- if(index.language===token){score+=8;matched.add('language');}
563
- if(index.path.includes(token)){score+=4;matched.add('path');}
564
- if(index.id.includes(token)){score+=5;matched.add('id');}
565
- }
566
- return {matched,score};
567
- }
568
-
569
- function bodyScore(value,phrase,tokens){
570
- const body=normalizedSearchText(value);
571
- let score=0;
572
- if(phrase&&body.includes(phrase))score+=30;
573
- for(const token of tokens){
574
- if(body.includes(token))score+=6;
575
- }
576
- return score;
577
- }
578
-
579
- function boundedSearchResults(results,limit){
580
- if(results.length<=limit)return results;
581
- const collectionLimit=Math.max(1,Math.floor(limit/4));
582
- const collectionCounts=new Map();
583
- const selected=new Set();
584
- const deferred=[];
585
-
586
- for(const result of results){
587
- if(selected.size>=limit)break;
588
- if(!result.navigationParent){
589
- selected.add(result);
590
- continue;
591
- }
592
- const parent=canonicalKey(result.navigationParent);
593
- const count=collectionCounts.get(parent)??0;
594
- if(count>=collectionLimit){
595
- deferred.push(result);
596
- continue;
597
- }
598
- collectionCounts.set(parent,count+1);
599
- selected.add(result);
600
- }
601
-
602
- for(const result of deferred){
603
- if(selected.size>=limit)break;
604
- selected.add(result);
605
- }
606
-
607
- return results.filter(function selectBoundedSearchResult(result){
608
- return selected.has(result);
609
- });
610
- }
611
-
612
- function relevantSliceStart(value,query,maximum){
613
- if(value.length<=maximum)return 0;
614
- const phrase=String(query||'').trim().toLowerCase();
615
- const tokens=searchTokens(query);
616
- const body=value.toLowerCase();
617
- const positions=[phrase,...tokens]
618
- .filter(Boolean)
619
- .map(term=>body.indexOf(term))
620
- .filter(index=>index>=0);
621
- const match=positions.length?Math.min(...positions):0;
622
- let start=Math.max(0,match-Math.floor(maximum/3));
623
- const priorNewline=start>0?value.lastIndexOf('\n',start-1):-1;
624
- const alignedStart=priorNewline+1;
625
- if(match-alignedStart<=Math.floor(maximum*2/3))start=alignedStart;
626
- if(start>0){
627
- const code=value.charCodeAt(start);
628
- if(code>=0xdc00&&code<=0xdfff)start++;
629
- }
630
- return start;
631
- }
632
-
633
487
  function lineNumberAt(value,offset){
634
488
  let line=1;
635
489
  let cursor=value.indexOf('\n');
@@ -640,18 +494,6 @@ function lineNumberAt(value,offset){
640
494
  return line;
641
495
  }
642
496
 
643
- function contextExcerpt(value,query,maximum,{relevant=false}={}){
644
- const start=relevant?relevantSliceStart(value,query,maximum):0;
645
- const text=safeSlice(value.slice(start),maximum);
646
- const end=start+text.length;
647
- return Object.freeze({
648
- lineEnd:lineNumberAt(value,Math.max(start,end-1)),
649
- lineStart:lineNumberAt(value,start),
650
- text,
651
- truncated:start>0||end<value.length,
652
- });
653
- }
654
-
655
497
  function queryText(value){
656
498
  if(typeof value!=='string') fail('Search query must be a string.','STATIC_DOCUMENT_INVALID_QUERY');
657
499
  const query=value.trim();
@@ -865,14 +707,6 @@ function boundedError(error){
865
707
  });
866
708
  }
867
709
 
868
- function safeSlice(value,maximum){
869
- if(value.length<=maximum) return value;
870
- let end=maximum;
871
- const code=value.charCodeAt(end-1);
872
- if(code>=0xd800&&code<=0xdbff) end--;
873
- return value.slice(0,end);
874
- }
875
-
876
710
  function contextType(record){
877
711
  return record.mediaType==='text/plain'?'SOURCE CODE':'DOCUMENT';
878
712
  }
@@ -910,7 +744,7 @@ export default class StaticDocumentCatalog{
910
744
  #cache;
911
745
  #digest;
912
746
  #fetchImpl;
913
- #indexes;
747
+ #lexicalSearch;
914
748
  #limits;
915
749
  #manifest;
916
750
  #onCacheError;
@@ -930,7 +764,10 @@ export default class StaticDocumentCatalog{
930
764
  this.#fetchImpl=normalizedOptions.fetchImpl;
931
765
  this.#onCacheError=normalizedOptions.onCacheError;
932
766
  this.#recordsById=new Map(this.#manifest.documents.map(record=>[record.id,record]));
933
- this.#indexes=new Map(this.#manifest.documents.map(record=>[record.id,searchIndex(record)]));
767
+ this.#lexicalSearch=new DocumentLexicalSearch(
768
+ this.#manifest.documents,
769
+ {maxResults:this.#limits.maxResults},
770
+ );
934
771
  this.#verifiedHydrations=new Map();
935
772
  }
936
773
 
@@ -948,30 +785,13 @@ export default class StaticDocumentCatalog{
948
785
  }
949
786
 
950
787
  search(query,options={}){
951
- const text=queryText(query);
952
- const normalized=normalizedSearchText(text);
953
- const tokens=searchTokens(text);
788
+ queryText(query);
954
789
  const settings=searchOptions(options,this.#limits.maxResults);
955
- const results=[];
956
- for(const record of this.#manifest.documents){
957
- if(settings.kinds&&!settings.kinds.has(record.kind)) continue;
958
- if(settings.tags&&![...settings.tags].every(tag=>record.tags.some(item=>canonicalKey(item)===tag))) continue;
959
- const {matched,score}=text
960
- ?fieldScore(this.#indexes.get(record.id),normalized,tokens)
961
- :{matched:new Set(),score:0};
962
- if(text&&!score) continue;
963
- results.push(Object.freeze({
964
- ...record,
965
- score,
966
- matchedFields:Object.freeze(SEARCH_FIELD_ORDER.filter(field=>matched.has(field))),
967
- }));
968
- }
969
- results.sort((left,right)=>
970
- right.score-left.score
971
- ||compareText(normalizedSearchText(left.title),normalizedSearchText(right.title))
972
- ||compareText(left.id,right.id)
973
- );
974
- return Object.freeze(boundedSearchResults(results,settings.limit));
790
+ return this.#lexicalSearch.search(query,{
791
+ kinds:settings.kinds?[...settings.kinds]:undefined,
792
+ limit:settings.limit,
793
+ tags:settings.tags?[...settings.tags]:undefined,
794
+ });
975
795
  }
976
796
 
977
797
  #cacheKey(record){
@@ -1147,15 +967,14 @@ export default class StaticDocumentCatalog{
1147
967
  'Context body-search scan limit',
1148
968
  {minimum:1,maximum:Math.min(this.size,100)},
1149
969
  ):0;
1150
- const indexedMatches=this.search(queryValue,{limit:this.#limits.maxResults});
1151
- const searchTermMatch=indexedMatches.some(match=>match.matchedFields.includes('searchTerms'));
970
+ const indexedMatches=this.#lexicalSearch.rank(queryValue);
1152
971
  const candidates=new Map(indexedMatches.map(match=>[match.id,match]));
1153
972
  const hydratedById=new Map();
1154
973
  const failures=[];
1155
974
  const failedIds=new Set();
1156
- if(bodySearch&&!searchTermMatch){
1157
- const phrase=normalizedSearchText(queryValue);
1158
- const tokens=searchTokens(queryValue);
975
+ if(bodySearch){
976
+ const phrase=normalizedDocumentSearchText(queryValue);
977
+ const tokens=documentSearchTokens(queryValue);
1159
978
  for(const record of this.#manifest.documents.slice(0,scanLimit)){
1160
979
  let hydrated;
1161
980
  try{
@@ -1168,7 +987,7 @@ export default class StaticDocumentCatalog{
1168
987
  failedIds.add(record.id);
1169
988
  continue;
1170
989
  }
1171
- const score=bodyScore(hydrated.text,phrase,tokens);
990
+ const score=scoreDocumentBody(hydrated.text,phrase,tokens);
1172
991
  if(!score)continue;
1173
992
  const existing=candidates.get(record.id);
1174
993
  candidates.set(record.id,Object.freeze({
@@ -1181,7 +1000,7 @@ export default class StaticDocumentCatalog{
1181
1000
  const matches=[...candidates.values()]
1182
1001
  .sort((left,right)=>
1183
1002
  right.score-left.score
1184
- ||compareText(normalizedSearchText(left.title),normalizedSearchText(right.title))
1003
+ ||compareText(normalizedDocumentSearchText(left.title),normalizedDocumentSearchText(right.title))
1185
1004
  ||compareText(left.id,right.id)
1186
1005
  )
1187
1006
  .slice(0,Math.min(limit,this.#limits.maxResults));
@@ -1210,7 +1029,7 @@ export default class StaticDocumentCatalog{
1210
1029
  const remaining=maxCharacters-text.length-budgetHeading.length-footer.length;
1211
1030
  if(remaining<=0){truncated=true;break;}
1212
1031
  const allowed=Math.min(maxDocumentCharacters,remaining);
1213
- const excerpt=contextExcerpt(hydrated.text,queryValue,allowed,{relevant:bodySearch});
1032
+ const excerpt=documentContextExcerpt(hydrated.text,queryValue,allowed,{relevant:bodySearch});
1214
1033
  const heading=contextHeading(match,excerpt);
1215
1034
  text+=heading+excerpt.text+footer;
1216
1035
  truncated=truncated||excerpt.truncated;
@@ -28,7 +28,7 @@
28
28
  "const": "arcane-os"
29
29
  },
30
30
  "version": {
31
- "const": "0.1.2"
31
+ "const": "0.2.1"
32
32
  }
33
33
  }
34
34
  },
@@ -42,7 +42,8 @@
42
42
  ],
43
43
  "properties": {
44
44
  "manifest": {
45
- "const": "node_modules/arcane-os/runtime/ARCANE_RUNTIME_RELEASE.json"
45
+ "type": "string",
46
+ "pattern": "^node_modules/(?:@[a-z0-9][a-z0-9._-]*/)?[a-z0-9][a-z0-9._-]*/runtime/ARCANE_RUNTIME_RELEASE\\.json$"
46
47
  },
47
48
  "contentSha256": {
48
49
  "$ref": "#/$defs/sha256"
@@ -66,19 +67,22 @@
66
67
  ],
67
68
  "properties": {
68
69
  "manifest": {
69
- "const": "node_modules/arcane-os/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json"
70
+ "type": "string",
71
+ "pattern": "^node_modules/(?:@[a-z0-9][a-z0-9._-]*/)?[a-z0-9][a-z0-9._-]*/browser-runtime/ARCANE_SDK_BROWSER_RELEASE\\.json$"
70
72
  },
71
73
  "manifestSha256": {
72
- "const": "88395493b411fd5461fbb2bb065ae2b745f6d1672f796583fd248ec97f71f4f7"
74
+ "type": "string",
75
+ "pattern": "^[a-f0-9]{64}$"
73
76
  },
74
77
  "contentSha256": {
75
- "const": "5e03f45a732db51cb5a2b2193cc79ecda34501d07a9b2e82e794e5fa37d55d00"
78
+ "type": "string",
79
+ "pattern": "^[a-f0-9]{64}$"
76
80
  },
77
81
  "builder": {
78
82
  "const": "arcane-sdk-browser-runtime-v1"
79
83
  },
80
84
  "sdkVersion": {
81
- "const": "0.1.2"
85
+ "const": "0.2.1"
82
86
  },
83
87
  "source": {
84
88
  "type": "object",
package/src/cli/main.mjs CHANGED
@@ -11,6 +11,7 @@ const VALUE_OPTIONS=new Set([
11
11
  'display-name',
12
12
  'workspace',
13
13
  'app',
14
+ 'sdk-runtime-source',
14
15
  'arcane-root',
15
16
  'host',
16
17
  'port',
@@ -40,7 +41,7 @@ Usage:
40
41
  ${CLI_NAME} init [id] [--workspace <directory>] [--display-name <name>] [--target <target>]
41
42
  ${CLI_NAME} doctor [--workspace <directory>] [--arcane-root <directory>]
42
43
  ${CLI_NAME} import-map [--workspace <directory>] [--app <id>]
43
- ${CLI_NAME} dev [--app <id>] [--host 127.0.0.1] [--port 8000]
44
+ ${CLI_NAME} dev [--app <id>] [--host 127.0.0.1] [--port 8000] [--sdk-runtime-source <sdk-root>]
44
45
  ${CLI_NAME} test [--app <id>] [--scope app]
45
46
  ${CLI_NAME} test --scope shared --test-file <repo-relative.test.mjs>
46
47
  ${CLI_NAME} check [--app <id>] [--scope app] [--skip-tests]
@@ -57,6 +58,9 @@ Usage:
57
58
  ${CLI_NAME} targets
58
59
  ${CLI_NAME} repo status|pull|push
59
60
 
61
+ Development:
62
+ --sdk-runtime-source <sdk-root> Dev-only live SDK checkout; omitted preserves the workspace runtime mode.
63
+
60
64
  Global:
61
65
  --workspace <directory> Select an external or integrated Arcane workspace.
62
66
  --output human|json|ndjson Select output framing (default: human).
@@ -188,6 +192,9 @@ function operationOptions(command,parsed,cwd){
188
192
  if(values.artifact!==undefined&&!['bundle','verify-bundle'].includes(command)){
189
193
  usage('--artifact is supported only by bundle and verify-bundle.');
190
194
  }
195
+ if(values['sdk-runtime-source']!==undefined&&command!=='dev'){
196
+ usage('--sdk-runtime-source is supported only by dev.');
197
+ }
191
198
  if(flags.has('overwrite')&&command!=='bundle'){
192
199
  usage('--overwrite is supported only by bundle.');
193
200
  }
@@ -230,7 +237,10 @@ function operationOptions(command,parsed,cwd){
230
237
  return {
231
238
  ...common,
232
239
  host:values.host??'127.0.0.1',
233
- port:readPort(values.port,8000)
240
+ port:readPort(values.port,8000),
241
+ ...(values['sdk-runtime-source']===undefined?{}:{
242
+ sdkRuntimeSourceRoot:path.resolve(cwd,values['sdk-runtime-source'])
243
+ })
234
244
  };
235
245
  }
236
246
  if(command==='test'){
@@ -458,6 +468,8 @@ function serverSummary(result){
458
468
  host:result.host,
459
469
  port:result.port,
460
470
  url:result.url,
471
+ ...(result.runtimeMode?{runtimeMode:result.runtimeMode}:{}),
472
+ ...(result.runtime?{runtime:result.runtime}:{}),
461
473
  ...(result.verified?{verified:result.verified}:{})
462
474
  };
463
475
  }
package/src/constants.mjs CHANGED
@@ -14,7 +14,7 @@ export const ARCANE_PROTOCOL='arcane/1';
14
14
  export const CLI_EVENT_PROTOCOL='arcane-cli-events/1';
15
15
  export const TARGET_ADAPTER_PROTOCOL='arcane-target-adapter/1';
16
16
  export const ARCANE_MACHINE_BUNDLE_VERSION='0.8.12';
17
- export const ARCANE_UPSTREAM_COMMIT='567ad110bf57a1c2d4a3daa22ae93716cc5f4d7e';
17
+ export const ARCANE_UPSTREAM_COMMIT='c540014afe69f14cf5ae60493b7295f36dbcec64';
18
18
  export const ARCANE_UPSTREAM_REPOSITORY='https://github.com/TheWizardNexus/ARCANE-OS.git';
19
19
 
20
20
  export const SDK_ROOT=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');