arcane-os 0.5.12 → 0.5.14

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 +27 -0
  2. package/browser-runtime/ai/browser-wasm-llm-provider.mjs +11 -10
  3. package/browser-runtime/ai/browser-wllama-runtime.mjs +2 -1
  4. package/browser-runtime/ai/model-controller.mjs +6 -5
  5. package/browser-runtime/ai/speech-worker-client.mjs +45 -3
  6. package/browser-runtime/event-manager.mjs +2 -1
  7. package/browser-runtime/logging.mjs +58 -0
  8. package/docs/reference/README.md +8 -7
  9. package/docs/reference/ai/browser-speech.md +46 -1
  10. package/docs/reference/asset-versioning.md +69 -0
  11. package/docs/reference/inventory/package-api.json +30 -2
  12. package/docs/reference/runtime-modules.md +18 -0
  13. package/docs/reference/sdk-api.md +94 -8
  14. package/package.json +3 -2
  15. package/runtime/arcane/components/app-bar.html +3 -1
  16. package/runtime/arcane/components/calculator.html +1 -1
  17. package/runtime/arcane/components/chart.html +2 -7
  18. package/runtime/arcane/components/chat.html +22 -20
  19. package/runtime/arcane/components/dashboard-config.html +6 -9
  20. package/runtime/arcane/components/data-maintenance.html +4 -2
  21. package/runtime/arcane/components/data-view.html +3 -1
  22. package/runtime/arcane/components/directory-picker.html +3 -1
  23. package/runtime/arcane/components/file-manager.html +17 -15
  24. package/runtime/arcane/components/header.html +5 -3
  25. package/runtime/arcane/components/markdown-document.html +4 -7
  26. package/runtime/arcane/components/markdown-editor.html +6 -9
  27. package/runtime/arcane/components/media-embed.html +1 -1
  28. package/runtime/arcane/components/modal.html +3 -1
  29. package/runtime/arcane/components/screen-capture.html +4 -2
  30. package/runtime/arcane/components/speech.html +10 -8
  31. package/runtime/arcane/components/table.html +3 -1
  32. package/runtime/arcane/components/voice-transcription.html +12 -15
  33. package/runtime/arcane/entities/Chat.js +5 -4
  34. package/runtime/arcane/entities/User.js +2 -1
  35. package/runtime/arcane/modules/AI.js +442 -292
  36. package/runtime/arcane/modules/AIProviderRuntime.js +359 -82
  37. package/runtime/arcane/modules/CommunicationAppController.js +2 -1
  38. package/runtime/arcane/modules/ComponentContracts.js +3 -2
  39. package/runtime/arcane/modules/ConversationTimebox.js +2 -1
  40. package/runtime/arcane/modules/DBOPFS.js +5 -4
  41. package/runtime/arcane/modules/Errors.js +3 -14
  42. package/runtime/arcane/modules/HTMLImport.js +188 -16
  43. package/runtime/arcane/modules/LocalAIReadinessController.js +2 -1
  44. package/runtime/arcane/modules/MD.js +3 -2
  45. package/runtime/arcane/modules/MailOutbox.mjs +2 -1
  46. package/runtime/arcane/modules/PersistentAIChatSession.js +2 -1
  47. package/runtime/arcane/modules/ScreenCapture.js +2 -1
  48. package/runtime/arcane/modules/ThemeBootstrap.js +3 -2
  49. package/runtime/arcane/modules/ToolCallRouter.js +2 -1
  50. package/src/dev-server.mjs +72 -5
  51. package/src/import-map.mjs +603 -16
  52. package/src/installed-sdk-runtime.mjs +1 -0
  53. package/src/packager/core.mjs +60 -1
  54. package/src/workspace-runtime.mjs +19 -7
@@ -343,6 +343,8 @@
343
343
  <html-import id="deleteModal" class="modal" href="./arcane/components/modal.html?v=13"></html-import>
344
344
 
345
345
  <script type="module">
346
+ const {arcaneLogging}=await import('arcane-os/logging');
347
+
346
348
  import('../modules/DBOPFS.js');
347
349
  //importing Document at the end of the file to avoid blocking;
348
350
 
@@ -461,7 +463,7 @@
461
463
  ()=>uploadFiles().catch(
462
464
  error=>{
463
465
  if(!destroyed){
464
- console.error('Unable to upload files:',error);
466
+ arcaneLogging.error('Unable to upload files:',error);
465
467
  }
466
468
  }
467
469
  ),
@@ -481,7 +483,7 @@
481
483
  openDirectory(directoryElement.dataset.directory).catch(
482
484
  error=>{
483
485
  if(!destroyed){
484
- console.error('Unable to open directory:',error);
486
+ arcaneLogging.error('Unable to open directory:',error);
485
487
  }
486
488
  }
487
489
  );
@@ -825,8 +827,8 @@
825
827
  icon.className='tree-entry-icon';
826
828
  icon.alt='';
827
829
  icon.src=entry.kind==='directory'
828
- ?'./arcane/img/folder.svg'
829
- :'./arcane/img/doc.svg';
830
+ ?new URL('./arcane/img/folder.svg',document.baseURI).href
831
+ :new URL('./arcane/img/doc.svg',document.baseURI).href;
830
832
  name.className='tree-entry-name';
831
833
  name.innerText=entry.name;
832
834
  count.className='tree-file-count';
@@ -1205,7 +1207,7 @@
1205
1207
  false,
1206
1208
  nextOperationId('open-error')
1207
1209
  );
1208
- console.error('Unable to open file:',error);
1210
+ arcaneLogging.error('Unable to open file:',error);
1209
1211
  }
1210
1212
  return false;
1211
1213
  }
@@ -1404,14 +1406,14 @@
1404
1406
  deleteButton.innerText='Delete File';
1405
1407
  deleteIcon.alt='';
1406
1408
  deleteIcon.className='action-icon';
1407
- deleteIcon.src='./arcane/img/trash.svg';
1409
+ deleteIcon.src=new URL('./arcane/img/trash.svg',document.baseURI).href;
1408
1410
  deleteButton.prepend(deleteIcon);
1409
1411
  deleteButton.addEventListener(
1410
1412
  'click',
1411
1413
  ()=>confirmDelete(directory,fileName,true).catch(
1412
1414
  error=>{
1413
1415
  if(!destroyed){
1414
- console.error('Unable to delete file:',error);
1416
+ arcaneLogging.error('Unable to delete file:',error);
1415
1417
  }
1416
1418
  }
1417
1419
  ),
@@ -1455,7 +1457,7 @@
1455
1457
  }catch(error){
1456
1458
  if(!destroyed&&generation===fileOpenGeneration){
1457
1459
  status.innerText='Unable to open this file.';
1458
- console.error('Unable to open file:',error);
1460
+ arcaneLogging.error('Unable to open file:',error);
1459
1461
  }
1460
1462
  return false;
1461
1463
  }
@@ -1610,7 +1612,7 @@
1610
1612
 
1611
1613
  fileIcon.alt='';
1612
1614
  fileIcon.className='icon file-icon';
1613
- fileIcon.src='./arcane/img/doc.svg';
1615
+ fileIcon.src=new URL('./arcane/img/doc.svg',document.baseURI).href;
1614
1616
  fileDetails.className='file-details';
1615
1617
  fileLabel.className='file-name';
1616
1618
  fileLabel.innerText=fileName;
@@ -1633,7 +1635,7 @@
1633
1635
 
1634
1636
  deleteIcon.alt='';
1635
1637
  deleteIcon.className='action-icon';
1636
- deleteIcon.src='./arcane/img/trash.svg';
1638
+ deleteIcon.src=new URL('./arcane/img/trash.svg',document.baseURI).href;
1637
1639
 
1638
1640
  openButton.addEventListener(
1639
1641
  'click',
@@ -1649,7 +1651,7 @@
1649
1651
  }
1650
1652
 
1651
1653
  openFile(directory,fileName).catch(
1652
- error=>console.error('Unable to open file:',error)
1654
+ error=>arcaneLogging.error('Unable to open file:',error)
1653
1655
  );
1654
1656
  },
1655
1657
  {signal:lifecycleController.signal}
@@ -1662,7 +1664,7 @@
1662
1664
  }
1663
1665
 
1664
1666
  confirmDelete(directory,fileName).catch(
1665
- error=>console.error('Unable to delete file:',error)
1667
+ error=>arcaneLogging.error('Unable to delete file:',error)
1666
1668
  );
1667
1669
  },
1668
1670
  {signal:lifecycleController.signal}
@@ -1747,7 +1749,7 @@
1747
1749
  message.innerText=`Unable to delete ${fileName}.`;
1748
1750
  cancelButton.disabled=false;
1749
1751
  deleteButton.disabled=false;
1750
- console.error('Unable to delete file:',error);
1752
+ arcaneLogging.error('Unable to delete file:',error);
1751
1753
  }
1752
1754
  }
1753
1755
  },
@@ -1850,7 +1852,7 @@
1850
1852
  }catch(error){
1851
1853
  if(!destroyed){
1852
1854
  initialized=false;
1853
- console.error('Unable to initialize file manager:',error);
1855
+ arcaneLogging.error('Unable to initialize file manager:',error);
1854
1856
  }
1855
1857
  }
1856
1858
  }
@@ -1933,7 +1935,7 @@
1933
1935
  directory.dataset.directory=tableName;
1934
1936
  folder.className='file folder';
1935
1937
  folderIcon.className='icon';
1936
- folderIcon.src='./arcane/img/folder.svg';
1938
+ folderIcon.src=new URL('./arcane/img/folder.svg',document.baseURI).href;
1937
1939
  folderName.innerText=tableName;
1938
1940
  fileCount.className='file-count';
1939
1941
  fileCount.innerText=`${files.length} ${files.length===1?'file':'files'}`;
@@ -78,6 +78,8 @@
78
78
  </header>
79
79
 
80
80
  <script type="module">
81
+ const {arcaneLogging}=await import('arcane-os/logging');
82
+
81
83
  import('../entities/User.js');
82
84
 
83
85
  const host=this;
@@ -123,17 +125,17 @@
123
125
  if (skin) {
124
126
  document.body.className = skin;
125
127
  } else {
126
- console.log('No saved skin found. Using default.');
128
+ arcaneLogging.log('No saved skin found. Using default.');
127
129
  }
128
130
  } catch (err) {
129
- console.error('Failed to set global saved skin', err);
131
+ arcaneLogging.error('Failed to set global saved skin', err);
130
132
  }
131
133
  }
132
134
 
133
135
  // Check if user can connect to the internet (make sure the cloud can be reached)
134
136
  async function checkInternet() {
135
137
  const online = navigator.onLine;
136
- console.log(`Internet status: ${online ? 'Online' : 'Offline'}`);
138
+ arcaneLogging.log(`Internet status: ${online ? 'Online' : 'Offline'}`);
137
139
  host.shadowRoot.querySelector('.internet-status')
138
140
  .classList
139
141
  .toggle('online', online);
@@ -211,15 +211,12 @@
211
211
  </section>
212
212
 
213
213
  <script type="module">
214
+ const {arcaneLogging}=await import('arcane-os/logging');
215
+
214
216
  const host=this;
215
217
  host.ready=false;
216
218
 
217
- const componentURL=new URL(
218
- host.getAttribute('href')||'./arcane/components/markdown-document.html',
219
- document.baseURI
220
- );
221
- const moduleURL=name=>new URL(`../modules/${name}`,componentURL).href;
222
- const {default:MD}=await import(moduleURL('MD.js?v=2'));
219
+ const {default:MD}=await import('../modules/MD.js?v=2');
223
220
  const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
224
221
  const events=createArcaneEventSource(host,{source:'arcane.component.markdown-document',eventTypes:['markdown-document-state','markdown-document-empty','markdown-document-error','markdown-document-loading','markdown-document-rendered','markdown-document-navigate','markdown-document-ready']});
225
222
  const lifecycleController=new AbortController();
@@ -888,7 +885,7 @@
888
885
  Promise.resolve(options.onNavigate(detail,{signal:lifecycleController.signal,operationId})).catch(
889
886
  error=>{
890
887
  if(!destroyed){
891
- console.error('Markdown document navigation callback failed.',error);
888
+ arcaneLogging.error('Markdown document navigation callback failed.',error);
892
889
  }
893
890
  }
894
891
  );
@@ -74,17 +74,14 @@
74
74
  </section>
75
75
 
76
76
  <script type="module">
77
+ const {arcaneLogging}=await import('arcane-os/logging');
78
+
77
79
  const host=this;
78
- const componentURL=new URL(
79
- host.getAttribute('href')||'./arcane/components/markdown-editor.html',
80
- document.baseURI
81
- );
82
- const moduleURL=name=>new URL(`../modules/${name}`,componentURL).href;
83
- const {default:MD}=await import(moduleURL('MD.js?v=2'));
80
+ const {default:MD}=await import('../modules/MD.js?v=2');
84
81
  const {
85
82
  applyMarkdownFormat,
86
83
  normalizeMarkdownOptions
87
- }=await import(moduleURL('ComponentContracts.js'));
84
+ }=await import('../modules/ComponentContracts.js');
88
85
  const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
89
86
  const events=createArcaneEventSource(host,{source:'arcane.component.markdown-editor',eventTypes:['markdown-editor-change','markdown-editor-saved','markdown-editor-ready']});
90
87
  const lifecycleController=new AbortController();
@@ -234,7 +231,7 @@
234
231
  emit('markdown-editor-change',detail,detail);
235
232
  if(options.onChange){
236
233
  Promise.resolve(options.onChange(detail)).catch(
237
- error=>console.error('Markdown change callback failed:',error)
234
+ error=>arcaneLogging.error('Markdown change callback failed:',error)
238
235
  );
239
236
  }
240
237
  }
@@ -334,7 +331,7 @@
334
331
  return false;
335
332
  }
336
333
  status.innerText=options.labels.saveError;
337
- console.error('Unable to save Markdown content:',error);
334
+ arcaneLogging.error('Unable to save Markdown content:',error);
338
335
  return false;
339
336
  }finally{
340
337
  if(saveController===controller){
@@ -1,7 +1,7 @@
1
1
  <link rel="stylesheet" href="./arcane/css/theme.css?v=1"><link rel="stylesheet" href="./arcane/css/primitives.css?v=1">
2
2
  <style>:host{display:block}.player-shell{display:grid;gap:var(--arcane-space-4)}.loader{display:flex;gap:var(--arcane-space-2)}.loader input{min-width:0;width:100%}.player{aspect-ratio:16/9;display:grid;place-items:center;background:var(--arcane-surface-muted);border:1px solid var(--arcane-border);border-radius:var(--arcane-radius-large)}iframe{width:100%;height:100%;border:0}.empty{text-align:center;color:var(--arcane-muted);padding:var(--arcane-space-5)}.footer{align-items:center;display:flex;gap:var(--arcane-space-3);justify-content:space-between}.status{margin:0;color:var(--arcane-muted)}@media(max-width:36rem){.loader,.footer{align-items:stretch;flex-direction:column}}</style>
3
3
  <section class="player-shell"><form id="loader" class="loader"><label class="visually-hidden" for="mediaUrl">Video or playlist address</label><input id="mediaUrl" type="text" inputmode="url" autocomplete="off" spellcheck="false" placeholder="Paste a YouTube video or playlist URL"><button class="arcane-button" type="submit">Play</button></form><div class="player"><div id="empty" class="empty"><strong>Choose something to play</strong><p>Paste a YouTube or YouTube Music video or playlist address.</p></div><iframe id="frame" title="Embedded media player" hidden allow="autoplay; encrypted-media; picture-in-picture; fullscreen" allowfullscreen></iframe></div><div class="footer"><p id="status" class="status" role="status" aria-live="polite">Nothing loaded.</p><button id="platform" class="arcane-button arcane-button--secondary" type="button">Open platform</button></div></section>
4
- <script type="module">const host=this,root=host.shadowRoot,form=root.querySelector('#loader'),input=root.querySelector('#mediaUrl'),frame=root.querySelector('#frame'),empty=root.querySelector('#empty'),status=root.querySelector('#status');const componentURL=new URL(host.getAttribute('href')||'./arcane/components/media-embed.html',document.baseURI);const {parseYouTubeMedia,youtubeEmbedUrl}=await import(new URL('../modules/YouTubeMedia.js',componentURL));const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');const events=createArcaneEventSource(host,{source:'arcane.component.media-embed',eventTypes:['media-open-platform','media-load','media-error','media-embed-ready']}),lifecycleController=new AbortController();let platformUrl='https://www.youtube.com/',privacyEnhanced=false,destroyed=false,operationSequence=0;
4
+ <script type="module">const host=this,root=host.shadowRoot,form=root.querySelector('#loader'),input=root.querySelector('#mediaUrl'),frame=root.querySelector('#frame'),empty=root.querySelector('#empty'),status=root.querySelector('#status');const {parseYouTubeMedia,youtubeEmbedUrl}=await import('../modules/YouTubeMedia.js');const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');const events=createArcaneEventSource(host,{source:'arcane.component.media-embed',eventTypes:['media-open-platform','media-load','media-error','media-embed-ready']}),lifecycleController=new AbortController();let platformUrl='https://www.youtube.com/',privacyEnhanced=false,destroyed=false,operationSequence=0;
5
5
  function nextOperationId(kind){operationSequence+=1;return `${events.descriptor.instanceId}:${kind}:${operationSequence}`}
6
6
  function emit(type,detail={},publicDetail={},operationId=null){if(destroyed)return false;const publication=events.dispatch(type,detail,{publicDetail,operationId});return projectArcaneDOMEvent(host,publication.occurrence,{bubbles:true,composed:true})}
7
7
  host.configure=options=>{if(destroyed)return false;platformUrl=String(options?.platformUrl||platformUrl);if(Object.hasOwn(options||{},'privacyEnhanced'))privacyEnhanced=options.privacyEnhanced===true;if(options?.placeholder)input.placeholder=String(options.placeholder);if(options?.openLabel)root.querySelector('#platform').textContent=String(options.openLabel);if(options?.initialValue){input.value=String(options.initialValue);load(input.value)}return host};host.load=load;host.destroy=destroy;
@@ -156,6 +156,8 @@
156
156
  </dialog>
157
157
 
158
158
  <script type="module">
159
+ const {arcaneLogging}=await import('arcane-os/logging');
160
+
159
161
  const host=this;
160
162
  const shadowRoot=host.shadowRoot;
161
163
  const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
@@ -384,7 +386,7 @@
384
386
  }catch(error){
385
387
  rows[index].row.dataset.status='failed';
386
388
  rows[index].status.innerText='Unable to complete';
387
- console.error(`Unable to complete ${job.name}:`,error);
389
+ arcaneLogging.error(`Unable to complete ${job.name}:`,error);
388
390
  throw error;
389
391
  }
390
392
  }));
@@ -1,10 +1,12 @@
1
1
  <link rel="stylesheet" href="./arcane/css/theme.css?v=1"><link rel="stylesheet" href="./arcane/css/primitives.css?v=1">
2
2
  <style>:host{display:block}.capture{display:grid;gap:var(--arcane-space-4)}.actions{display:grid;gap:var(--arcane-space-3);grid-template-columns:repeat(3,minmax(0,1fr))}.action{display:grid;gap:var(--arcane-space-2);padding:var(--arcane-space-4);text-align:left}.action strong{font-size:1.05rem}.action span{color:var(--arcane-muted);font-size:.85rem}.recording{align-items:center;display:flex;gap:var(--arcane-space-3);justify-content:space-between;padding:var(--arcane-space-3);border:1px solid var(--arcane-border);border-radius:var(--arcane-radius-medium)}.preview{display:grid;place-items:center;min-height:16rem;overflow:auto;background:var(--arcane-surface-muted);border:1px solid var(--arcane-border);border-radius:var(--arcane-radius-large)}.preview :where(img,video){display:block}.empty{color:var(--arcane-muted);text-align:center}.status{margin:0;color:var(--arcane-muted)}@media(max-width:44rem){.actions{grid-template-columns:1fr}}</style>
3
3
  <section class="capture"><div class="actions"><button class="action arcane-card" type="button" data-capture="image"><strong>Screenshot</strong><span>Capture the selected display as PNG.</span></button><button class="action arcane-card" type="button" data-capture="video"><strong>Record video</strong><span>Record the selected display in a browser-supported video format.</span></button><button class="action arcane-card" type="button" data-capture="gif"><strong>Record GIF</strong><span>Record the selected display as an animated GIF.</span></button></div><div id="recording" class="recording" hidden><span id="recordingLabel">Recording…</span><button id="stop" class="arcane-button" type="button">Stop recording</button></div><div id="preview" class="preview"><div class="empty"><strong>No capture yet</strong><p>Your capture remains on this device unless you choose to save it.</p></div></div><p id="status" class="status" role="status" aria-live="polite">Choose a capture type. Your browser will ask which display to share.</p></section>
4
- <script type="module">const host=this,root=host.shadowRoot,preview=root.querySelector('#preview'),recording=root.querySelector('#recording'),status=root.querySelector('#status');const componentURL=new URL(host.getAttribute('href')||'./arcane/components/screen-capture.html',document.baseURI);const {default:ScreenCapture}=await import(new URL('../modules/ScreenCapture.js',componentURL));const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');const events=createArcaneEventSource(host,{source:'arcane.component.screen-capture',eventTypes:['screen-capture-result','screen-capture-ready']});const capture=new ScreenCapture(),listeners=new AbortController();let destroyed=false,operationGeneration=0,previewUrl='';
4
+ <script type="module">
5
+ const {arcaneLogging}=await import('arcane-os/logging');
6
+ const host=this,root=host.shadowRoot,preview=root.querySelector('#preview'),recording=root.querySelector('#recording'),status=root.querySelector('#status');const {default:ScreenCapture}=await import('../modules/ScreenCapture.js');const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');const events=createArcaneEventSource(host,{source:'arcane.component.screen-capture',eventTypes:['screen-capture-result','screen-capture-ready']});const capture=new ScreenCapture(),listeners=new AbortController();let destroyed=false,operationGeneration=0,previewUrl='';
5
7
  function emit(type,detail={},publicDetail={},operationId=null){if(destroyed)return false;const publication=events.dispatch(type,detail,{operationId,publicDetail});return projectArcaneDOMEvent(host,publication.occurrence,{bubbles:true,composed:true})}
6
8
  function current(generation){return !destroyed&&generation===operationGeneration}
7
- function cleanupCaptureStart(originalError=null){const cleanupErrors=[];if(capture.recorder&&capture.recorder.state!=='inactive'){try{capture.recorder.stop()}catch(error){cleanupErrors.push(error)}}try{capture.stopTracks(capture.stream)}catch(error){cleanupErrors.push(error)}try{capture.reset()}catch(error){cleanupErrors.push(error)}for(const error of cleanupErrors)console.error('Error cleaning up rejected screen capture start:',error);return originalError}
9
+ function cleanupCaptureStart(originalError=null){const cleanupErrors=[];if(capture.recorder&&capture.recorder.state!=='inactive'){try{capture.recorder.stop()}catch(error){cleanupErrors.push(error)}}try{capture.stopTracks(capture.stream)}catch(error){cleanupErrors.push(error)}try{capture.reset()}catch(error){cleanupErrors.push(error)}for(const error of cleanupErrors)arcaneLogging.error('Error cleaning up rejected screen capture start:',error);return originalError}
8
10
  async function onCapture(event){const mode=event.target.closest('[data-capture]')?.dataset.capture;if(!mode||destroyed)return;const generation=++operationGeneration;setButtons(true);try{if(mode==='image'){status.textContent='Choose a display to capture…';const result=await capture.captureImage();if(!current(generation))return;showResult(result,generation)}else{status.textContent='Choose a display to record…';if(mode==='video')await capture.startVideo();else await capture.startGif();if(!current(generation)){cleanupCaptureStart();return}recording.hidden=false;root.querySelector('#recordingLabel').textContent=mode==='gif'?'Recording GIF frames…':'Recording video…';status.textContent='Recording. Return here and press Stop when finished.'}}catch(error){const originalError=mode==='image'?error:cleanupCaptureStart(error);if(!current(generation))return;status.textContent=originalError.message;setButtons(false)}}
9
11
  async function onStop(){if(destroyed)return;const generation=operationGeneration;root.querySelector('#stop').disabled=true;status.textContent='Finishing capture…';try{const result=await capture.stop();if(current(generation)&&result)showResult(result,generation)}catch(error){if(current(generation))status.textContent=error.message}finally{if(current(generation)){recording.hidden=true;root.querySelector('#stop').disabled=false;setButtons(false)}}}
10
12
  root.querySelector('.actions').addEventListener('click',onCapture,{signal:listeners.signal});root.querySelector('#stop').addEventListener('click',onStop,{signal:listeners.signal});
@@ -132,6 +132,8 @@
132
132
  <button id="muteButton" type="button" class="mute" aria-pressed="true" aria-label="Voice unavailable" disabled>Voice unavailable</button>
133
133
 
134
134
  <script type="module">
135
+ const {arcaneLogging}=await import('arcane-os/logging');
136
+
135
137
  const completeValue = (value) => value;
136
138
  const {
137
139
  createArcaneEventSource,
@@ -140,7 +142,7 @@
140
142
 
141
143
  void import('../modules/DBLS.js').catch(
142
144
  function reportDBLSImportFailure(error) {
143
- console.error('The shared database runtime could not load.');
145
+ arcaneLogging.error('The shared database runtime could not load.');
144
146
  }
145
147
  );
146
148
  const aiModuleImport = import('../modules/AI.js');
@@ -365,7 +367,7 @@
365
367
  if (destroyed) {
366
368
  return;
367
369
  }
368
- console.error('The shared AI runtime could not load.');
370
+ arcaneLogging.error('The shared AI runtime could not load.');
369
371
  }
370
372
  );
371
373
 
@@ -476,10 +478,10 @@
476
478
  sttRole = snapshot.roles.stt;
477
479
  ttsRole = snapshot.roles.tts;
478
480
  if (sttRole.state === 'error' && previousSTTRole.state !== 'error') {
479
- console.error('Arcane transcription runtime failed.', sttRole.error);
481
+ arcaneLogging.error('Arcane transcription runtime failed.', sttRole.error);
480
482
  }
481
483
  if (ttsRole.state === 'error' && previousTTSRole.state !== 'error') {
482
- console.error('Arcane voice runtime failed.', ttsRole.error);
484
+ arcaneLogging.error('Arcane voice runtime failed.', ttsRole.error);
483
485
  }
484
486
  clearSettledTTSIntent();
485
487
  applyRoleTransitions(previousSTTRole, previousTTSRole);
@@ -1048,7 +1050,7 @@
1048
1050
  `ARCANE_SPEECH_TTS_${action.toUpperCase()}_REJECTED`
1049
1051
  );
1050
1052
  const reason = `tts-${action}-rejected`;
1051
- console.error(`Arcane voice ${action} request failed.`, error);
1053
+ arcaneLogging.error(`Arcane voice ${action} request failed.`, error);
1052
1054
  dispatchSpeechEvent(
1053
1055
  'speech-tts-lifecycle-error',
1054
1056
  {
@@ -1113,7 +1115,7 @@
1113
1115
  tone: 'error'
1114
1116
  };
1115
1117
  const errorFields = publicSpeechErrorFields(error, failure.code);
1116
- console.error(`Arcane ${normalizedBoundary} speech operation failed.`, error);
1118
+ arcaneLogging.error(`Arcane ${normalizedBoundary} speech operation failed.`, error);
1117
1119
  dispatchSpeechEvent(
1118
1120
  'speech-synthesis-error',
1119
1121
  {
@@ -1535,7 +1537,7 @@
1535
1537
  'ARCANE_SPEECH_STT_TRANSCRIPTION_REQUEST_REJECTED'
1536
1538
  );
1537
1539
  const reason = 'stt-transcription-rejected';
1538
- console.error('Arcane speech transcription failed.', error);
1540
+ arcaneLogging.error('Arcane speech transcription failed.', error);
1539
1541
  dispatchSpeechEvent(
1540
1542
  'speech-transcription-error',
1541
1543
  {
@@ -1642,7 +1644,7 @@
1642
1644
  if (session.audioContext.state !== 'closed') {
1643
1645
  void session.audioContext.close().catch(
1644
1646
  function reportAudioContextCloseFailure(error) {
1645
- console.warn('The microphone audio context could not close.');
1647
+ arcaneLogging.warn('The microphone audio context could not close.');
1646
1648
  }
1647
1649
  );
1648
1650
  }
@@ -17,6 +17,8 @@
17
17
  </table>
18
18
 
19
19
  <script type="module">
20
+ const {arcaneLogging}=await import('arcane-os/logging');
21
+
20
22
  const host = this;
21
23
  const shadowRoot=this.shadowRoot;
22
24
  const {createArcaneEventSource,projectArcaneDOMEvent}=
@@ -68,7 +70,7 @@
68
70
  tableBody.innerHTML = '';
69
71
 
70
72
  tableArray.forEach(
71
- (row)=>{ console.log('row',row);
73
+ (row)=>{ arcaneLogging.log('row',row);
72
74
  const tr = tableBody.insertRow();
73
75
  row.forEach(
74
76
  (cellValue)=>{
@@ -60,6 +60,8 @@
60
60
  </section>
61
61
 
62
62
  <script type="module">
63
+ const {arcaneLogging}=await import('arcane-os/logging');
64
+
63
65
  const completeValue=(value)=>value;
64
66
  const {
65
67
  createArcaneEventSource,
@@ -84,21 +86,16 @@
84
86
  ]
85
87
  }
86
88
  );
87
- const componentURL=new URL(
88
- host.getAttribute('href')||'./arcane/components/voice-transcription.html',
89
- document.baseURI
90
- );
91
- const moduleURL=name=>new URL(`../modules/${name}`,componentURL).href;
92
- const {default:MD}=await import(moduleURL('MD.js?v=2'));
89
+ const {default:MD}=await import('../modules/MD.js?v=2');
93
90
  const {
94
91
  appendTranscription,
95
92
  createSTTActivationController,
96
93
  normalizeVoiceOptions
97
- }=await import(moduleURL('ComponentContracts.js'));
94
+ }=await import('../modules/ComponentContracts.js');
98
95
  const {
99
96
  requestAIRuntimeIntent,
100
97
  subscribeAIRuntimeState
101
- }=await import(moduleURL('AIRuntimeState.js'));
98
+ }=await import('../modules/AIRuntimeState.js');
102
99
  const description=host.shadowRoot.querySelector('#description');
103
100
  const transcriptElement=host.shadowRoot.querySelector('#transcript');
104
101
  const status=host.shadowRoot.querySelector('#status');
@@ -352,7 +349,7 @@
352
349
  return false;
353
350
  }
354
351
  releaseMicrophone();
355
- console.error('Unable to start recording:',error);
352
+ arcaneLogging.error('Unable to start recording:',error);
356
353
  setState('error',options.messages.startError);
357
354
  return false;
358
355
  }
@@ -502,7 +499,7 @@
502
499
  if(!isCurrentVoiceOperation(generation,'saving')){
503
500
  return false;
504
501
  }
505
- console.error('Unable to save transcription:',error);
502
+ arcaneLogging.error('Unable to save transcription:',error);
506
503
  setState('error',options.messages.saveError);
507
504
  return false;
508
505
  }
@@ -531,7 +528,7 @@
531
528
  );
532
529
  return false;
533
530
  }
534
- console.error('Unable to transcribe recording:',error);
531
+ arcaneLogging.error('Unable to transcribe recording:',error);
535
532
  setState('error',options.messages.transcribeError);
536
533
  return false;
537
534
  }finally{
@@ -598,7 +595,7 @@
598
595
  return options.transcribe(file,context);
599
596
  }
600
597
  if(typeof globalThis.ai?.fetchSTT!=='function'){
601
- await import(moduleURL('AI.js'));
598
+ await import('../modules/AI.js');
602
599
  }
603
600
  if(typeof globalThis.ai?.fetchSTT!=='function'){
604
601
  const error=new Error('Speech transcription is not configured.');
@@ -639,7 +636,7 @@
639
636
  function recordingError(event){
640
637
  setState('error',options.messages.interrupted);
641
638
  releaseMicrophone();
642
- console.error('Audio recorder error:',event.error||event);
639
+ arcaneLogging.error('Audio recorder error:',event.error||event);
643
640
  }
644
641
 
645
642
  async function completeStream(){
@@ -684,7 +681,7 @@
684
681
  if(!isCurrentVoiceOperation(generation,'completing')){
685
682
  return false;
686
683
  }
687
- console.error('Unable to complete transcription:',error);
684
+ arcaneLogging.error('Unable to complete transcription:',error);
688
685
  setState('error',options.messages.completeError);
689
686
  return false;
690
687
  }
@@ -827,7 +824,7 @@
827
824
  const previousRole=sttRole;
828
825
  sttRole=snapshot.roles.stt;
829
826
  if(sttRole.state==='error'&&previousRole.state!=='error'){
830
- console.error('Arcane transcription runtime failed.',sttRole.error);
827
+ arcaneLogging.error('Arcane transcription runtime failed.',sttRole.error);
831
828
  }
832
829
  sttActivationController.synchronize(sttRole);
833
830
  if(previousRole.state==='ready'&&sttRole.state!=='ready'){
@@ -1,3 +1,4 @@
1
+ import { arcaneLogging } from 'arcane-os/logging';
1
2
  import Is from '../../node_modules/strong-type/index.js';
2
3
  import '../modules/DBOPFS.js';
3
4
  import '../modules/AI.js';
@@ -114,7 +115,7 @@ function structuralToolMessage(call){
114
115
  function storedStructuralToolCalls(value){
115
116
  if(value===undefined) return [];
116
117
  if(!Array.isArray(value)){
117
- console.error('Arcane stored assistant tool calls were not an array and were not retained.');
118
+ arcaneLogging.error('Arcane stored assistant tool calls were not an array and were not retained.');
118
119
  return [];
119
120
  }
120
121
  const result=[];
@@ -122,7 +123,7 @@ function storedStructuralToolCalls(value){
122
123
  try{
123
124
  result.push(copyToolCalls([call])[0]);
124
125
  }catch(error){
125
- console.error(
126
+ arcaneLogging.error(
126
127
  `Arcane stored assistant tool call ${index+1} had no usable user-facing message and was not retained.`,
127
128
  error
128
129
  );
@@ -840,7 +841,7 @@ class ChatEntity{
840
841
  try{
841
842
  return JSON.parse(row);
842
843
  }catch(error){
843
- console.error(
844
+ arcaneLogging.error(
844
845
  `Arcane saved chat row ${index+1} could not be parsed.`,
845
846
  error,
846
847
  row
@@ -951,7 +952,7 @@ ${JSON.stringify(transcript)}`
951
952
  .map(message=>copyCompleteValue(message));
952
953
  const queued=this.#memoryQueue.then(()=>this.#writeMemory(snapshot,request));
953
954
  this.#memoryQueue=queued.catch(()=>{
954
- console.warn('Unable to update chat memory.');
955
+ arcaneLogging.warn('Unable to update chat memory.');
955
956
  return false;
956
957
  });
957
958
  return this.#memoryQueue;
@@ -1,3 +1,4 @@
1
+ import { arcaneLogging } from 'arcane-os/logging';
1
2
  import Is from '../../node_modules/strong-type/index.js';
2
3
  import DBLS from '../modules/DBLS.js';
3
4
  import {
@@ -818,7 +819,7 @@ class UserEntity {
818
819
  try {
819
820
  this[key] = src[key];
820
821
  } catch(e){
821
- console.warn(`UserEntity.explicit setter skipping invalid field ${key}: ${e.message}`);
822
+ arcaneLogging.warn(`UserEntity.explicit setter skipping invalid field ${key}: ${e.message}`);
822
823
  }
823
824
  }
824
825