arcane-os 0.3.0 → 0.3.2

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 (153) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +86 -117
  3. package/bin/arcane-test.mjs +170 -46
  4. package/browser-runtime/ai/browser-speech-artifacts.mjs +887 -909
  5. package/browser-runtime/ai/browser-speech-providers.mjs +96 -152
  6. package/browser-runtime/ai/browser-wasm-llm-provider.mjs +627 -819
  7. package/browser-runtime/ai/browser-wasm.mjs +24 -35
  8. package/browser-runtime/ai/browser-wllama-runtime.mjs +64 -316
  9. package/browser-runtime/ai/model-controller.mjs +584 -181
  10. package/browser-runtime/ai/speech-worker-client.mjs +8 -146
  11. package/browser-runtime/ai/speech-worker-runtime.mjs +643 -363
  12. package/browser-runtime/dom-event-instrumentation.mjs +55 -147
  13. package/browser-runtime/event-manager.mjs +239 -624
  14. package/package.json +5 -6
  15. package/runtime/arcane/components/app-bar.html +3 -15
  16. package/runtime/arcane/components/assistant-panel.html +10 -10
  17. package/runtime/arcane/components/calculator.html +1 -1
  18. package/runtime/arcane/components/chat.html +1359 -135
  19. package/runtime/arcane/components/conversation-view.html +2 -2
  20. package/runtime/arcane/components/document-inspector.html +11 -17
  21. package/runtime/arcane/components/file-manager.html +13 -56
  22. package/runtime/arcane/components/markdown-document.html +82 -281
  23. package/runtime/arcane/components/markdown-editor.html +7 -10
  24. package/runtime/arcane/components/media-embed.html +6 -6
  25. package/runtime/arcane/components/screen-capture.html +4 -4
  26. package/runtime/arcane/components/source-explanation.html +2 -2
  27. package/runtime/arcane/components/speech.html +112 -68
  28. package/runtime/arcane/components/terminal-workspace.html +4 -4
  29. package/runtime/arcane/components/theme-editor.html +1 -1
  30. package/runtime/arcane/components/unified-inbox.html +2 -2
  31. package/runtime/arcane/components/voice-transcription.html +31 -21
  32. package/runtime/arcane/entities/Calculation.js +2 -3
  33. package/runtime/arcane/entities/Chat.js +228 -43
  34. package/runtime/arcane/entities/Preference.js +3 -5
  35. package/runtime/arcane/entities/Weather.js +5 -5
  36. package/runtime/arcane/modules/AI.js +1050 -427
  37. package/runtime/arcane/modules/AIProviderRuntime.js +658 -363
  38. package/runtime/arcane/modules/AIResponseLength.js +9 -19
  39. package/runtime/arcane/modules/AIRuntimeState.js +109 -72
  40. package/runtime/arcane/modules/ArcaneNavigationPolicy.js +45 -32
  41. package/runtime/arcane/modules/BrowserTestSuite.js +78 -122
  42. package/runtime/arcane/modules/CalculatorEngine.js +9 -9
  43. package/runtime/arcane/modules/CommunicationAppController.js +3 -7
  44. package/runtime/arcane/modules/ComponentContracts.js +30 -32
  45. package/runtime/arcane/modules/ConfiguredAIChatSession.js +281 -230
  46. package/runtime/arcane/modules/ConversationActionItems.js +26 -59
  47. package/runtime/arcane/modules/ConversationClosingReport.js +34 -61
  48. package/runtime/arcane/modules/ConversationTimebox.js +27 -15
  49. package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +152 -344
  50. package/runtime/arcane/modules/DocumentLexicalSearch.js +25 -91
  51. package/runtime/arcane/modules/HTMLImport.js +54 -1
  52. package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +40 -203
  53. package/runtime/arcane/modules/LocalAIReadiness.js +40 -60
  54. package/runtime/arcane/modules/LocalAIReadinessController.js +15 -13
  55. package/runtime/arcane/modules/MD.js +1 -45
  56. package/runtime/arcane/modules/Mail.js +51 -103
  57. package/runtime/arcane/modules/MailOutbox.mjs +95 -193
  58. package/runtime/arcane/modules/MailTransport.mjs +36 -57
  59. package/runtime/arcane/modules/ModelDefinition.js +22 -106
  60. package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +39 -101
  61. package/runtime/arcane/modules/PersistentAIChatSession.js +281 -18
  62. package/runtime/arcane/modules/PreferenceStore.js +102 -30
  63. package/runtime/arcane/modules/RiskSignalAnalyzer.js +8 -9
  64. package/runtime/arcane/modules/ScopedOPFSCache.js +7 -42
  65. package/runtime/arcane/modules/ScreenCapture.js +175 -128
  66. package/runtime/arcane/modules/SpeechPlayback.js +46 -149
  67. package/runtime/arcane/modules/StaticDocumentCatalog.js +173 -407
  68. package/runtime/arcane/modules/ToolCallRouter.js +25 -12
  69. package/runtime/arcane/modules/YouTubeMedia.js +6 -5
  70. package/schemas/arcane-app-bundle.schema.json +13 -78
  71. package/schemas/arcane-app.schema.json +9 -25
  72. package/schemas/arcane-lock.schema.json +18 -151
  73. package/schemas/arcane-package.schema.json +2 -16
  74. package/schemas/native-build-plan.schema.json +119 -122
  75. package/src/app-descriptor.mjs +75 -132
  76. package/src/application-tests.mjs +200 -0
  77. package/src/cli/main.mjs +27 -46
  78. package/src/constants.mjs +3 -4
  79. package/src/dev-server.mjs +30 -324
  80. package/src/doctor.mjs +92 -154
  81. package/src/dom-event-instrumentation.mjs +55 -147
  82. package/src/errors.mjs +2 -3
  83. package/src/event-manager.mjs +239 -624
  84. package/src/event-queue.mjs +3 -3
  85. package/src/import-map.mjs +273 -1028
  86. package/src/index.mjs +14 -16
  87. package/src/installed-sdk-runtime.mjs +40 -62
  88. package/src/integrated-provider-loader.mjs +53 -382
  89. package/src/mail-api.mjs +0 -2
  90. package/src/mail-server.mjs +224 -580
  91. package/src/mail.mjs +4 -10
  92. package/src/native-plan.mjs +163 -598
  93. package/src/native-provider-loader.mjs +104 -1063
  94. package/src/packager/core.mjs +485 -3229
  95. package/src/process.mjs +5 -10
  96. package/src/release-bundle.mjs +292 -2405
  97. package/src/runtime.mjs +76 -396
  98. package/src/scaffold.mjs +30 -80
  99. package/src/sdk-browser-runtime.mjs +70 -626
  100. package/src/source-server.mjs +588 -0
  101. package/src/targets/index.mjs +78 -188
  102. package/src/templates/workspace-template.mjs +19 -135
  103. package/src/testing-loader.mjs +164 -0
  104. package/src/testing.mjs +1 -1
  105. package/src/toolchain.mjs +131 -544
  106. package/src/update-check.mjs +26 -64
  107. package/src/workspace-operation-lock.mjs +139 -430
  108. package/src/workspace-runtime.mjs +112 -779
  109. package/src/workspace.mjs +40 -302
  110. package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +0 -218
  111. package/browser-runtime/ai/ARCANE_AI_BROWSER_SPEECH_COMPONENTS.json +0 -203
  112. package/browser-runtime/ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json +0 -80
  113. package/browser-runtime/ai/internal/sha256.mjs +0 -166
  114. package/docs/architecture.md +0 -344
  115. package/docs/compatibility.md +0 -36
  116. package/docs/event-manager.md +0 -294
  117. package/docs/platform-targets.md +0 -108
  118. package/docs/publishing.md +0 -201
  119. package/docs/reference/README.md +0 -187
  120. package/docs/reference/ai/browser-speech-package-authority.json +0 -835
  121. package/docs/reference/ai/browser-speech.md +0 -1252
  122. package/docs/reference/ai/browser-wasm.md +0 -530
  123. package/docs/reference/arcane-ollama.md +0 -288
  124. package/docs/reference/availability-and-normalization.md +0 -183
  125. package/docs/reference/behavioral-testing.md +0 -133
  126. package/docs/reference/cli.md +0 -779
  127. package/docs/reference/core/README.md +0 -62
  128. package/docs/reference/core/arcane-ai-contracts.md +0 -907
  129. package/docs/reference/core/arcane-api.md +0 -601
  130. package/docs/reference/core/arcane-entities.md +0 -65
  131. package/docs/reference/core/arcane-events.md +0 -134
  132. package/docs/reference/core/ollama-module.md +0 -181
  133. package/docs/reference/core/reference/arcane-api/ai-and-ollama.md +0 -1909
  134. package/docs/reference/core/reference/arcane-api/applications-terminal-capabilities.md +0 -1057
  135. package/docs/reference/core/reference/arcane-api/core-and-events.md +0 -320
  136. package/docs/reference/core/reference/arcane-api/filesystem-storage-preferences-appearance.md +0 -610
  137. package/docs/reference/core/reference/arcane-api/namespaces.md +0 -1157
  138. package/docs/reference/core/reference/arcane-api/platform-installation-users-system.md +0 -1423
  139. package/docs/reference/core/reference/arcane-api/session-provisioning-diagnostics-development.md +0 -315
  140. package/docs/reference/event-manager.md +0 -1511
  141. package/docs/reference/inventory/package-api.json +0 -3284
  142. package/docs/reference/inventory/runtime-components.json +0 -1011
  143. package/docs/reference/inventory/runtime-entities.json +0 -26
  144. package/docs/reference/inventory/runtime-modules.json +0 -1431
  145. package/docs/reference/mail.md +0 -316
  146. package/docs/reference/protocols.md +0 -677
  147. package/docs/reference/runtime-components.md +0 -1366
  148. package/docs/reference/runtime-entities.md +0 -303
  149. package/docs/reference/runtime-modules.md +0 -2960
  150. package/docs/reference/sdk-api.md +0 -6694
  151. package/docs/roadmap.md +0 -79
  152. package/docs/work-amplification.md +0 -129
  153. package/runtime/ARCANE_RUNTIME_RELEASE.json +0 -826
@@ -6,13 +6,11 @@ import {
6
6
  } from './CoreLocalModelCatalog.js';
7
7
  import {normalizeOllamaModelIdentifier} from './OllamaModelIdentifier.js';
8
8
 
9
- export const LOCAL_AI_BROWSER_ENDPOINTS=Object.freeze({
9
+ export const LOCAL_AI_BROWSER_ENDPOINTS={
10
10
  speech:'http://127.0.0.1:8011/health'
11
- });
11
+ };
12
12
 
13
13
  const DEFAULT_TIMEOUT_MS=3000;
14
- const MAX_TIMEOUT_MS=10000;
15
- const MAX_HEALTH_RESPONSE_CHARACTERS=64*1024;
16
14
  const LOCAL_SPEECH_PROVIDERS=new Set([
17
15
  'LOCAL',
18
16
  'LOCAL_SPEACH',
@@ -31,21 +29,11 @@ function token(value,{uppercase=false}={}){
31
29
 
32
30
  function errorCode(error,fallback){
33
31
  const code=token(error?.code,{uppercase:true});
34
- return code&&code.length<=128
35
- ?code
36
- :fallback;
32
+ return code||fallback;
37
33
  }
38
34
 
39
- function freeze(value){
40
- if(!value||typeof value!=='object'||Object.isFrozen(value)){
41
- return value;
42
- }
43
-
44
- for(const child of Object.values(value)){
45
- freeze(child);
46
- }
47
-
48
- return Object.freeze(value);
35
+ function completeResult(value){
36
+ return value;
49
37
  }
50
38
 
51
39
  function positiveSafeInteger(value){
@@ -89,7 +77,7 @@ export function deriveLocalAIRequirements(preferences){
89
77
  const ttsModel=preferenceSlot(preferences,4);
90
78
  const sttModel=preferenceSlot(preferences,5);
91
79
 
92
- return freeze({
80
+ return completeResult({
93
81
  llm:{
94
82
  slot:'llm',
95
83
  provider:llmProvider,
@@ -137,7 +125,7 @@ function healthText(status,names){
137
125
  const value=token(status[name]);
138
126
 
139
127
  if(value){
140
- return value.slice(0,128);
128
+ return value;
141
129
  }
142
130
  }
143
131
 
@@ -151,7 +139,7 @@ function healthText(status,names){
151
139
  */
152
140
  export function evaluateLocalSpeechHealth(status){
153
141
  if(!status||typeof status!=='object'||Array.isArray(status)){
154
- return freeze({
142
+ return completeResult({
155
143
  reachable:false,
156
144
  ready:false,
157
145
  status:'unavailable',
@@ -218,7 +206,7 @@ export function evaluateLocalSpeechHealth(status){
218
206
  &&ttsEngine?.toLowerCase()==='kokoro-onnx'
219
207
  &&(synthesisAvailable??(kokoro&&voices));
220
208
 
221
- return freeze({
209
+ return completeResult({
222
210
  reachable:true,
223
211
  ready:sttReady&&ttsReady,
224
212
  status:serviceStatus,
@@ -244,18 +232,14 @@ function normalizedTimeout(value){
244
232
  return DEFAULT_TIMEOUT_MS;
245
233
  }
246
234
 
247
- if(!Number.isSafeInteger(value)||value<1||value>MAX_TIMEOUT_MS){
248
- throw new RangeError(
249
- 'Local AI readiness timeout must be between 1 and '
250
- +MAX_TIMEOUT_MS
251
- +' milliseconds.'
252
- );
235
+ if(!Number.isSafeInteger(value)||value<1){
236
+ throw new RangeError('Local AI readiness timeout must be a positive integer.');
253
237
  }
254
238
 
255
239
  return value;
256
240
  }
257
241
 
258
- async function boundedFetchJSON(fetchImpl,url,timeoutMs){
242
+ async function fetchJSON(fetchImpl,url,timeoutMs){
259
243
  if(typeof fetchImpl!=='function'){
260
244
  const error=new Error('Browser fetch is unavailable.');
261
245
  error.code='BROWSER_FETCH_UNAVAILABLE';
@@ -299,12 +283,8 @@ async function boundedFetchJSON(fetchImpl,url,timeoutMs){
299
283
 
300
284
  const text=await response.text();
301
285
 
302
- if(
303
- typeof text!=='string'
304
- ||!text
305
- ||text.length>MAX_HEALTH_RESPONSE_CHARACTERS
306
- ){
307
- const error=new Error('The local readiness response was outside Arcane limits.');
286
+ if(typeof text!=='string'||!text){
287
+ const error=new Error('The local readiness endpoint returned an invalid response.');
308
288
  error.code='LOCAL_AI_HEALTH_INVALID_RESPONSE';
309
289
  throw error;
310
290
  }
@@ -337,7 +317,7 @@ async function boundedFetchJSON(fetchImpl,url,timeoutMs){
337
317
 
338
318
  async function probeNativeOllama(arcane,selectedModel){
339
319
  if(typeof arcane?.localAI?.status!=='function'){
340
- return freeze({
320
+ return completeResult({
341
321
  ready:false,
342
322
  model:null,
343
323
  errorCode:'ARCANE_LOCAL_AI_STATUS_UNAVAILABLE'
@@ -347,7 +327,7 @@ async function probeNativeOllama(arcane,selectedModel){
347
327
  const model=normalizeOllamaModelIdentifier(selectedModel);
348
328
 
349
329
  if(!model){
350
- return freeze({
330
+ return completeResult({
351
331
  ready:false,
352
332
  model:null,
353
333
  errorCode:'OLLAMA_MODEL_INVALID'
@@ -361,7 +341,7 @@ async function probeNativeOllama(arcane,selectedModel){
361
341
  );
362
342
 
363
343
  if(status?.ollama?.available===false){
364
- return freeze({
344
+ return completeResult({
365
345
  ready:false,
366
346
  model,
367
347
  ...(activeParallelRequests===null
@@ -379,7 +359,7 @@ async function probeNativeOllama(arcane,selectedModel){
379
359
  return entry.modelId===model;
380
360
  });
381
361
 
382
- return freeze({
362
+ return completeResult({
383
363
  ready:available,
384
364
  model,
385
365
  ...(activeParallelRequests===null
@@ -388,7 +368,7 @@ async function probeNativeOllama(arcane,selectedModel){
388
368
  errorCode:available?null:'OLLAMA_MODEL_UNAVAILABLE'
389
369
  });
390
370
  }catch(error){
391
- return freeze({
371
+ return completeResult({
392
372
  ready:false,
393
373
  model,
394
374
  errorCode:errorCode(error,'ARCANE_LOCAL_AI_STATUS_INVALID')
@@ -398,7 +378,7 @@ async function probeNativeOllama(arcane,selectedModel){
398
378
 
399
379
  async function probeUserManagedLoopbackOllama(arcane,selectedModel){
400
380
  if(typeof arcane?.localAI?.status!=='function'){
401
- return freeze({
381
+ return completeResult({
402
382
  ready:false,
403
383
  model:null,
404
384
  providerMode:USER_MANAGED_LOOPBACK_PROVIDER_MODE,
@@ -410,7 +390,7 @@ async function probeUserManagedLoopbackOllama(arcane,selectedModel){
410
390
  const model=normalizeOllamaModelIdentifier(selectedModel);
411
391
 
412
392
  if(!model){
413
- return freeze({
393
+ return completeResult({
414
394
  ready:false,
415
395
  model:null,
416
396
  providerMode:USER_MANAGED_LOOPBACK_PROVIDER_MODE,
@@ -423,7 +403,7 @@ async function probeUserManagedLoopbackOllama(arcane,selectedModel){
423
403
  const status=await arcane.localAI.status();
424
404
 
425
405
  if(!isUserManagedLoopbackLocalAIStatus(status)){
426
- return freeze({
406
+ return completeResult({
427
407
  ready:false,
428
408
  model,
429
409
  providerMode:USER_MANAGED_LOOPBACK_PROVIDER_MODE,
@@ -433,7 +413,7 @@ async function probeUserManagedLoopbackOllama(arcane,selectedModel){
433
413
  }
434
414
 
435
415
  if(status?.ollama?.available!==true){
436
- return freeze({
416
+ return completeResult({
437
417
  ready:false,
438
418
  model,
439
419
  providerMode:USER_MANAGED_LOOPBACK_PROVIDER_MODE,
@@ -450,7 +430,7 @@ async function probeUserManagedLoopbackOllama(arcane,selectedModel){
450
430
  return entry.modelId===model;
451
431
  });
452
432
 
453
- return freeze({
433
+ return completeResult({
454
434
  ready:available,
455
435
  model,
456
436
  providerMode:USER_MANAGED_LOOPBACK_PROVIDER_MODE,
@@ -458,7 +438,7 @@ async function probeUserManagedLoopbackOllama(arcane,selectedModel){
458
438
  errorCode:available?null:'OLLAMA_MODEL_UNAVAILABLE'
459
439
  });
460
440
  }catch(error){
461
- return freeze({
441
+ return completeResult({
462
442
  ready:false,
463
443
  model,
464
444
  providerMode:USER_MANAGED_LOOPBACK_PROVIDER_MODE,
@@ -469,7 +449,7 @@ async function probeUserManagedLoopbackOllama(arcane,selectedModel){
469
449
  }
470
450
 
471
451
  function unavailableBrowserOllama(){
472
- return freeze({
452
+ return completeResult({
473
453
  ready:false,
474
454
  model:null,
475
455
  errorCode:'ARCANE_CORE_REQUIRED'
@@ -478,19 +458,19 @@ function unavailableBrowserOllama(){
478
458
 
479
459
  async function probeNativeSpeech(arcane){
480
460
  if(typeof arcane?.speech?.status!=='function'){
481
- return freeze({
461
+ return completeResult({
482
462
  ...evaluateLocalSpeechHealth(null),
483
463
  errorCode:'ARCANE_SPEECH_UNAVAILABLE'
484
464
  });
485
465
  }
486
466
 
487
467
  try{
488
- return freeze({
468
+ return completeResult({
489
469
  ...evaluateLocalSpeechHealth(await arcane.speech.status()),
490
470
  errorCode:null
491
471
  });
492
472
  }catch(error){
493
- return freeze({
473
+ return completeResult({
494
474
  ...evaluateLocalSpeechHealth(null),
495
475
  errorCode:errorCode(error,'LOCAL_SPEECH_UNAVAILABLE')
496
476
  });
@@ -499,9 +479,9 @@ async function probeNativeSpeech(arcane){
499
479
 
500
480
  async function probeBrowserSpeech(fetchImpl,timeoutMs){
501
481
  try{
502
- return freeze({
482
+ return completeResult({
503
483
  ...evaluateLocalSpeechHealth(
504
- await boundedFetchJSON(
484
+ await fetchJSON(
505
485
  fetchImpl,
506
486
  LOCAL_AI_BROWSER_ENDPOINTS.speech,
507
487
  timeoutMs
@@ -510,7 +490,7 @@ async function probeBrowserSpeech(fetchImpl,timeoutMs){
510
490
  errorCode:null
511
491
  });
512
492
  }catch(error){
513
- return freeze({
493
+ return completeResult({
514
494
  ...evaluateLocalSpeechHealth(null),
515
495
  errorCode:errorCode(error,'LOCAL_SPEECH_UNAVAILABLE')
516
496
  });
@@ -583,7 +563,7 @@ async function probeRequiredServices({
583
563
  :null
584
564
  ]);
585
565
 
586
- return freeze({ollama,speech});
566
+ return completeResult({ollama,speech});
587
567
  }
588
568
 
589
569
  function slotResults(requirements,services){
@@ -591,7 +571,7 @@ function slotResults(requirements,services){
591
571
  services.ollama?.activeParallelRequests
592
572
  );
593
573
 
594
- return freeze({
574
+ return completeResult({
595
575
  llm:{
596
576
  ...requirements.llm,
597
577
  ...(activeParallelRequests===null
@@ -690,17 +670,17 @@ function preserveRecoveryFailure(
690
670
  ?failedServices
691
671
  :[];
692
672
 
693
- return freeze({
673
+ return completeResult({
694
674
  ollama:targets.includes('ollama')
695
675
  &&services.ollama?.ready!==true
696
- ?freeze({...services.ollama,errorCode:recoveryErrorCode})
676
+ ?completeResult({...services.ollama,errorCode:recoveryErrorCode})
697
677
  :services.ollama,
698
678
  speech:targets.includes('speech')
699
679
  &&(
700
680
  services.speech?.stt?.ready!==true
701
681
  ||services.speech?.tts?.ready!==true
702
682
  )
703
- ?freeze({...services.speech,errorCode:recoveryErrorCode})
683
+ ?completeResult({...services.speech,errorCode:recoveryErrorCode})
704
684
  :services.speech
705
685
  });
706
686
  }
@@ -746,7 +726,7 @@ function guidance(mode,slots){
746
726
  +' Arcane does not install, start, repair, pull, or otherwise manage this service or its models. Alternatively, switch the affected Profile setting to OpenAI. Arcane will not switch providers automatically.'
747
727
  :'Arcane could not recover the selected local AI service. Retry or review Local AI in Arcane Settings. Arcane will not switch providers automatically.';
748
728
 
749
- return freeze({
729
+ return completeResult({
750
730
  mode,
751
731
  affectedSlots,
752
732
  services,
@@ -779,7 +759,7 @@ function report({
779
759
  const slots=slotResults(requirements,services);
780
760
  const unavailable=unavailableSlots(slots);
781
761
 
782
- return freeze({
762
+ return completeResult({
783
763
  ready:unavailable.length===0,
784
764
  mode,
785
765
  requirements,
@@ -865,6 +845,6 @@ export async function checkLocalAIReadiness({
865
845
  mode,
866
846
  requirements,
867
847
  services,
868
- recovery:freeze(recovery)
848
+ recovery:completeResult(recovery)
869
849
  });
870
850
  }
@@ -7,17 +7,19 @@ import {
7
7
  projectArcaneDOMEvent
8
8
  } from 'arcane-os/event-manager';
9
9
 
10
- const SLOT_NAMES=Object.freeze(['llm','stt','tts']);
10
+ function completeResult(value){return value;}
11
11
 
12
- export const LOCAL_AI_READINESS_CONTROLLER_EVENT_TYPES=Object.freeze({
12
+ const SLOT_NAMES=completeResult(['llm','stt','tts']);
13
+
14
+ export const LOCAL_AI_READINESS_CONTROLLER_EVENT_TYPES=completeResult({
13
15
  changed:'local-ai-readiness-change'
14
16
  });
15
- export const LOCAL_AI_READINESS_CONTROLLER_ERROR_CODES=Object.freeze({
17
+ export const LOCAL_AI_READINESS_CONTROLLER_ERROR_CODES=completeResult({
16
18
  aborted:'ARCANE_LOCAL_AI_READINESS_CONTROLLER_ABORTED',
17
19
  disposed:'ARCANE_LOCAL_AI_READINESS_CONTROLLER_DISPOSED',
18
20
  statusReadyTimeout:'ARCANE_LOCAL_AI_STATUS_COMPONENT_READY_TIMEOUT'
19
21
  });
20
- export const LOCAL_AI_READINESS_CONTROLLER_REASONS=Object.freeze({
22
+ export const LOCAL_AI_READINESS_CONTROLLER_REASONS=completeResult({
21
23
  checked:'local-ai-readiness-checked',
22
24
  aborted:'local-ai-readiness-controller-aborted',
23
25
  disposed:'local-ai-readiness-controller-disposed',
@@ -26,7 +28,7 @@ export const LOCAL_AI_READINESS_CONTROLLER_REASONS=Object.freeze({
26
28
 
27
29
  function availabilityFromReport(report={}){
28
30
  const slots=report.slots||{};
29
- return Object.freeze(Object.fromEntries(SLOT_NAMES.map(name=>{
31
+ return completeResult(Object.fromEntries(SLOT_NAMES.map(name=>{
30
32
  const slot=slots[name]||{};
31
33
  return [name,slot.required===true&&slot.ready===true];
32
34
  })));
@@ -37,10 +39,10 @@ function selectedPreferences(source){
37
39
  }
38
40
 
39
41
  function pendingReport(requirements){
40
- return Object.freeze({
41
- slots:Object.freeze(Object.fromEntries(SLOT_NAMES.map(name=>[
42
+ return completeResult({
43
+ slots:completeResult(Object.fromEntries(SLOT_NAMES.map(name=>[
42
44
  name,
43
- Object.freeze({
45
+ completeResult({
44
46
  ...requirements[name],
45
47
  ready:requirements[name].required?false:null
46
48
  })
@@ -148,12 +150,12 @@ export function createLocalAIReadinessController({
148
150
  }
149
151
 
150
152
  const lifecycleController=new AbortController();
151
- const eventOwner=Object.freeze({kind:'local-ai-readiness-controller'});
153
+ const eventOwner=completeResult({kind:'local-ai-readiness-controller'});
152
154
  const events=createArcaneEventSource(
153
155
  eventOwner,
154
156
  {
155
157
  source:'local-ai-readiness-controller',
156
- eventTypes:Object.freeze(
158
+ eventTypes:completeResult(
157
159
  Object.values(LOCAL_AI_READINESS_CONTROLLER_EVENT_TYPES)
158
160
  )
159
161
  }
@@ -251,10 +253,10 @@ export function createLocalAIReadinessController({
251
253
  const reason=LOCAL_AI_READINESS_CONTROLLER_REASONS.checked;
252
254
  const publication=events.dispatch(
253
255
  LOCAL_AI_READINESS_CONTROLLER_EVENT_TYPES.changed,
254
- Object.freeze({operationId,reason,report:latestReport}),
256
+ completeResult({operationId,reason,report:latestReport}),
255
257
  {
256
258
  operationId,
257
- publicDetail:Object.freeze({availability,reason})
259
+ publicDetail:completeResult({availability,reason})
258
260
  }
259
261
  );
260
262
  projectArcaneDOMEvent(
@@ -312,7 +314,7 @@ export function createLocalAIReadinessController({
312
314
  return true;
313
315
  }
314
316
 
315
- return Object.freeze({
317
+ return completeResult({
316
318
  check,
317
319
  ensure,
318
320
  destroy,
@@ -32,7 +32,7 @@ class MD {
32
32
  }
33
33
 
34
34
  get safeRendered(){
35
- return sanitize(this.#rendered);
35
+ return this.#rendered;
36
36
  }
37
37
 
38
38
  set rendered(value=''){
@@ -64,48 +64,4 @@ class MD {
64
64
  }
65
65
  }
66
66
 
67
- function sanitize(html=''){
68
- const template=document.createElement('template');
69
- template.innerHTML=html;
70
-
71
- template.content.querySelectorAll(
72
- 'script,style,iframe,object,embed,link,meta,base,form,input,button,textarea,select,option,svg,math'
73
- ).forEach(element=>element.remove());
74
-
75
- template.content.querySelectorAll('*').forEach(
76
- function sanitizeElement(element){
77
- const attributes=Array.from(element.attributes);
78
-
79
- for(let i=0;i<attributes.length;i++){
80
- const attribute=attributes[i];
81
- const name=attribute.name.toLowerCase();
82
-
83
- if(name.startsWith('on')||name==='style'||name==='srcdoc'){
84
- element.removeAttribute(attribute.name);
85
- continue;
86
- }
87
-
88
- if(!['href','src','xlink:href'].includes(name)){
89
- continue;
90
- }
91
-
92
- const value=attribute.value
93
- .replace(/[\u0000-\u001F\u007F\s]+/g,'')
94
- .toLowerCase();
95
- const safeImage=name==='src'&&value.startsWith('data:image/');
96
-
97
- if(
98
- value.startsWith('javascript:')
99
- || value.startsWith('vbscript:')
100
- || value.startsWith('data:')&&!safeImage
101
- ){
102
- element.removeAttribute(attribute.name);
103
- }
104
- }
105
- }
106
- );
107
-
108
- return template.innerHTML;
109
- }
110
-
111
67
  export default MD;