arcane-os 0.5.16 → 0.5.18
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/CHANGELOG.md +44 -0
- package/README.md +42 -19
- package/bin/arcane-test.mjs +16 -13
- package/browser-runtime/ai/browser-speech-artifacts.mjs +41 -38
- package/browser-runtime/ai/browser-speech-providers.mjs +53 -46
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +127 -124
- package/browser-runtime/ai/browser-wasm.mjs +6 -3
- package/browser-runtime/ai/browser-wllama-runtime.mjs +26 -23
- package/browser-runtime/ai/model-controller.mjs +94 -91
- package/browser-runtime/ai/speech-worker-client.mjs +12 -9
- package/browser-runtime/ai/speech-worker-runtime.mjs +56 -53
- package/browser-runtime/dependencies/strong-type/index.js +207 -82
- package/browser-runtime/dependencies/strong-type/package.json +15 -6
- package/browser-runtime/dom-event-instrumentation.mjs +24 -20
- package/browser-runtime/event-manager.mjs +111 -108
- package/browser-runtime/speech-text.mjs +35 -0
- package/docs/architecture.md +1 -1
- package/docs/reference/README.md +8 -8
- package/docs/reference/ai/browser-speech.md +230 -16
- package/docs/reference/ai/twin-cloud.md +1 -1
- package/docs/reference/availability-and-normalization.md +42 -1
- package/docs/reference/cli.md +1 -1
- package/docs/reference/core/arcane-ai-contracts.md +1 -1
- package/docs/reference/inventory/package-api.json +60 -4
- package/docs/reference/inventory/runtime-components.json +2 -2
- package/docs/reference/inventory/runtime-modules.json +29 -31
- package/docs/reference/protocols.md +17 -13
- package/docs/reference/runtime-components.md +6 -5
- package/docs/reference/runtime-modules.md +212 -70
- package/docs/reference/sdk-api.md +197 -11
- package/examples/wasm-ai-demo/index.html +1 -0
- package/node_modules/event-pubsub/node_modules/strong-type/README.md +408 -0
- package/node_modules/event-pubsub/node_modules/strong-type/assets/strong-type-header.png +0 -0
- package/node_modules/event-pubsub/node_modules/strong-type/index.js +1151 -0
- package/node_modules/event-pubsub/node_modules/strong-type/licence +21 -0
- package/node_modules/event-pubsub/node_modules/strong-type/node.js +125 -0
- package/node_modules/event-pubsub/node_modules/strong-type/package.json +61 -0
- package/node_modules/strong-type/README.md +42 -24
- package/node_modules/strong-type/benchmark/core.js +324 -0
- package/node_modules/strong-type/index.js +207 -82
- package/node_modules/strong-type/package.json +14 -6
- package/package.json +4 -3
- package/runtime/arcane/components/app-bar.html +5 -2
- package/runtime/arcane/components/assistant-panel.html +5 -2
- package/runtime/arcane/components/chart.html +15 -12
- package/runtime/arcane/components/chat.html +118 -141
- package/runtime/arcane/components/dashboard-config.html +6 -3
- package/runtime/arcane/components/data-view.html +4 -1
- package/runtime/arcane/components/directory-picker.html +5 -2
- package/runtime/arcane/components/document-inspector.html +6 -3
- package/runtime/arcane/components/file-drop.html +5 -2
- package/runtime/arcane/components/file-inspector.html +9 -6
- package/runtime/arcane/components/file-manager.html +16 -13
- package/runtime/arcane/components/local-ai-status.html +5 -2
- package/runtime/arcane/components/markdown-document.html +14 -11
- package/runtime/arcane/components/markdown-editor.html +4 -1
- package/runtime/arcane/components/modal.html +4 -1
- package/runtime/arcane/components/output-panel.html +6 -3
- package/runtime/arcane/components/preferences-form.html +4 -1
- package/runtime/arcane/components/record-timeline.html +8 -5
- package/runtime/arcane/components/relationship-board.html +9 -6
- package/runtime/arcane/components/source-code-viewer.html +12 -9
- package/runtime/arcane/components/source-explanation.html +8 -5
- package/runtime/arcane/components/speech.html +24 -21
- package/runtime/arcane/components/summary-strip.html +4 -1
- package/runtime/arcane/components/task-progress.html +6 -3
- package/runtime/arcane/components/terminal-workspace.html +4 -1
- package/runtime/arcane/components/voice-transcription.html +11 -8
- package/runtime/arcane/components/web-navigator.html +5 -2
- package/runtime/arcane/entities/ApiModelRecord.js +5 -2
- package/runtime/arcane/entities/Calculation.js +5 -2
- package/runtime/arcane/entities/Chat.js +33 -33
- package/runtime/arcane/entities/CommunicationMessage.js +4 -1
- package/runtime/arcane/entities/CommunicationThread.js +4 -1
- package/runtime/arcane/entities/File.js +1 -1
- package/runtime/arcane/entities/Image.js +8 -5
- package/runtime/arcane/entities/IntentEnvelope.js +20 -17
- package/runtime/arcane/entities/Preference.js +9 -6
- package/runtime/arcane/entities/Theme.js +5 -2
- package/runtime/arcane/entities/User.js +11 -11
- package/runtime/arcane/entities/Weather.js +5 -2
- package/runtime/arcane/modules/AI.js +503 -187
- package/runtime/arcane/modules/AIPreferenceRuntime.js +5 -2
- package/runtime/arcane/modules/AIPreferenceTuple.js +9 -6
- package/runtime/arcane/modules/AIProviderRuntime.js +117 -92
- package/runtime/arcane/modules/AIResponseURLPolicy.js +148 -62
- package/runtime/arcane/modules/AIRuntimeState.js +29 -26
- package/runtime/arcane/modules/AnsiText.js +4 -1
- package/runtime/arcane/modules/ApiModelDatabase.js +22 -19
- package/runtime/arcane/modules/AppDataScope.js +8 -5
- package/runtime/arcane/modules/ArcaneCommunicationBridge.js +4 -1
- package/runtime/arcane/modules/ArcaneNavigationPolicy.js +8 -5
- package/runtime/arcane/modules/ArcaneNetworkPolicy.js +18 -15
- package/runtime/arcane/modules/AsyncBoundary.js +13 -10
- package/runtime/arcane/modules/BrowserTestSuite.js +19 -16
- package/runtime/arcane/modules/CalculatorEngine.js +5 -2
- package/runtime/arcane/modules/ChatRecords.js +18 -15
- package/runtime/arcane/modules/CommunicationAppController.js +9 -6
- package/runtime/arcane/modules/CommunicationHub.js +9 -6
- package/runtime/arcane/modules/CommunicationPreferences.js +4 -1
- package/runtime/arcane/modules/CommunicationProviderRegistry.js +4 -1
- package/runtime/arcane/modules/ComponentContracts.js +56 -53
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +30 -27
- package/runtime/arcane/modules/ConversationActionItems.js +15 -12
- package/runtime/arcane/modules/ConversationClosingReport.js +11 -8
- package/runtime/arcane/modules/ConversationTimebox.js +28 -25
- package/runtime/arcane/modules/CoreLocalModelCatalog.js +17 -14
- package/runtime/arcane/modules/DBLS.js +7 -4
- package/runtime/arcane/modules/DBOPFS.js +7 -7
- package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +34 -31
- package/runtime/arcane/modules/DevelopmentWorkspace.js +4 -1
- package/runtime/arcane/modules/DirectoryPicker.js +8 -5
- package/runtime/arcane/modules/DocumentLexicalSearch.js +11 -8
- package/runtime/arcane/modules/DocumentNavigation.js +7 -4
- package/runtime/arcane/modules/Errors.js +28 -25
- package/runtime/arcane/modules/HTMLImport.js +7 -4
- package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +15 -12
- package/runtime/arcane/modules/LocalAIReadiness.js +21 -18
- package/runtime/arcane/modules/LocalAIReadinessController.js +6 -3
- package/runtime/arcane/modules/MD.js +1 -1
- package/runtime/arcane/modules/Mail.js +46 -43
- package/runtime/arcane/modules/MailOutbox.mjs +48 -45
- package/runtime/arcane/modules/MailTransport.mjs +29 -26
- package/runtime/arcane/modules/MarkdownSpeech.js +1 -50
- package/runtime/arcane/modules/MemoryRecords.js +7 -4
- package/runtime/arcane/modules/MessageAdvisory.js +6 -3
- package/runtime/arcane/modules/ModelDefinition.js +7 -4
- package/runtime/arcane/modules/Ollama.js +6 -3
- package/runtime/arcane/modules/OllamaModelIdentifier.js +4 -1
- package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +18 -15
- package/runtime/arcane/modules/PersistentAIChatSession.js +33 -30
- package/runtime/arcane/modules/PreferenceStore.js +20 -17
- package/runtime/arcane/modules/PreparedSpeech.js +485 -0
- package/runtime/arcane/modules/Questionnaire.js +6 -3
- package/runtime/arcane/modules/RecordLinkIndex.js +4 -1
- package/runtime/arcane/modules/RecordPassageIndex.js +9 -6
- package/runtime/arcane/modules/RecordReviewStore.js +12 -9
- package/runtime/arcane/modules/RiskSignalAnalyzer.js +4 -1
- package/runtime/arcane/modules/ScopedOPFSCache.js +6 -3
- package/runtime/arcane/modules/ScreenCapture.js +20 -17
- package/runtime/arcane/modules/SpeechPlayback.js +61 -28
- package/runtime/arcane/modules/StaticDocumentCatalog.js +33 -30
- package/runtime/arcane/modules/SystemAppearance.js +5 -2
- package/runtime/arcane/modules/SystemToolRegistry.js +6 -3
- package/runtime/arcane/modules/TerminalClient.js +14 -11
- package/runtime/arcane/modules/TerminalCommandRegistry.js +4 -1
- package/runtime/arcane/modules/ThemeBootstrap.js +9 -6
- package/runtime/arcane/modules/ThemeManager.js +5 -2
- package/runtime/arcane/modules/TimeGuard.js +1 -1
- package/runtime/arcane/modules/ToolCallRouter.js +11 -8
- package/runtime/arcane/modules/WaitForComponent.js +19 -16
- package/runtime/arcane/modules/YouTubeMedia.js +4 -1
- package/runtime/strong-type/index.js +1276 -352
- package/runtime/strong-type/package.json +69 -45
- package/src/app-descriptor.mjs +17 -14
- package/src/application-tests.mjs +4 -1
- package/src/cli/main.mjs +8 -5
- package/src/constants.mjs +4 -1
- package/src/dev-server.mjs +8 -5
- package/src/doctor.mjs +5 -2
- package/src/dom-event-instrumentation.mjs +24 -20
- package/src/errors.mjs +7 -3
- package/src/event-manager.mjs +111 -108
- package/src/event-queue.mjs +8 -5
- package/src/events.mjs +12 -9
- package/src/import-map.mjs +36 -27
- package/src/installed-sdk-runtime.mjs +4 -1
- package/src/integrated-provider-loader.mjs +9 -6
- package/src/mail-credentials.mjs +16 -13
- package/src/mail-server.mjs +53 -50
- package/src/mail.mjs +18 -15
- package/src/native-plan.mjs +12 -9
- package/src/native-provider-loader.mjs +7 -4
- package/src/packager/core.mjs +18 -15
- package/src/process.mjs +6 -3
- package/src/release-bundle.mjs +14 -11
- package/src/runtime.mjs +4 -1
- package/src/scaffold.mjs +9 -6
- package/src/sdk-browser-runtime.mjs +4 -1
- package/src/source-server.mjs +17 -14
- package/src/targets/index.mjs +5 -2
- package/src/templates/workspace-template.mjs +13 -6
- package/src/testing-loader.mjs +7 -4
- package/src/testing.mjs +10 -7
- package/src/toolchain.mjs +13 -10
- package/src/update-check.mjs +9 -6
- package/src/workspace-operation-lock.mjs +14 -11
- package/src/workspace-runtime.mjs +4 -1
- package/src/workspace.mjs +17 -14
- package/runtime/arcane/modules/AIResponseLength.js +0 -32
|
@@ -177,6 +177,9 @@
|
|
|
177
177
|
</section>
|
|
178
178
|
|
|
179
179
|
<script type="module">
|
|
180
|
+
const {default:Is}=await import('strong-type');
|
|
181
|
+
const is=new Is(false);
|
|
182
|
+
|
|
180
183
|
const host=this;
|
|
181
184
|
host.ready=false;
|
|
182
185
|
const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
|
|
@@ -244,7 +247,7 @@
|
|
|
244
247
|
|
|
245
248
|
function normalizedText(value,label,{optional=false}={}){
|
|
246
249
|
if(optional&&(value===undefined||value===null||value===''))return '';
|
|
247
|
-
if(
|
|
250
|
+
if(!is.string(value)||!value.trim()||/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/.test(value)){
|
|
248
251
|
throw new TypeError(`${label} must be text.`);
|
|
249
252
|
}
|
|
250
253
|
return value.trim();
|
|
@@ -266,11 +269,11 @@
|
|
|
266
269
|
}
|
|
267
270
|
|
|
268
271
|
function normalizeOptions(input={},previous=defaultOptions){
|
|
269
|
-
if(!input
|
|
272
|
+
if(!input||!is.object(input)||is.array(input)){
|
|
270
273
|
throw new TypeError('Source viewer options must be an object.');
|
|
271
274
|
}
|
|
272
275
|
const labelInput=input.labels===undefined?{}:input.labels;
|
|
273
|
-
if(!labelInput
|
|
276
|
+
if(!labelInput||!is.object(labelInput)||is.array(labelInput)){
|
|
274
277
|
throw new TypeError('Source viewer labels must be an object.');
|
|
275
278
|
}
|
|
276
279
|
const labels={...previous.labels};
|
|
@@ -283,7 +286,7 @@
|
|
|
283
286
|
}
|
|
284
287
|
|
|
285
288
|
function normalizeRenderOptions(input={}){
|
|
286
|
-
if(!input
|
|
289
|
+
if(!input||!is.object(input)||is.array(input)){
|
|
287
290
|
throw new TypeError('Source render options must be an object.');
|
|
288
291
|
}
|
|
289
292
|
return {
|
|
@@ -306,10 +309,10 @@
|
|
|
306
309
|
const sequence=++loadSequence;
|
|
307
310
|
transition('loading');
|
|
308
311
|
try{
|
|
309
|
-
const pending=
|
|
312
|
+
const pending=is.function(source)?source():source;
|
|
310
313
|
const result=await pending;
|
|
311
314
|
if(destroyed||sequence!==loadSequence)return false;
|
|
312
|
-
if(result&&
|
|
315
|
+
if(result&&is.object(result)&&!is.array(result)){
|
|
313
316
|
return renderSource(result.text??result.value??'',{
|
|
314
317
|
...renderOptions,
|
|
315
318
|
...result
|
|
@@ -334,7 +337,7 @@
|
|
|
334
337
|
}
|
|
335
338
|
|
|
336
339
|
function renderSource(text='',renderOptions={}){
|
|
337
|
-
if(
|
|
340
|
+
if(!is.string(text))throw new TypeError('Source content must be a string.');
|
|
338
341
|
const metadata=normalizeRenderOptions(renderOptions);
|
|
339
342
|
const lines=text.replace(/\r\n?/g,'\n').split('\n');
|
|
340
343
|
|
|
@@ -398,7 +401,7 @@
|
|
|
398
401
|
|
|
399
402
|
function focusLine(value){
|
|
400
403
|
const line=Number(value);
|
|
401
|
-
if(!
|
|
404
|
+
if(!is.integer(line)||line<1||line>current.lineCount)return false;
|
|
402
405
|
const target=sourceLines.querySelector(`[data-line="${line}"]`);
|
|
403
406
|
if(!target)return false;
|
|
404
407
|
target.focus({preventScroll:true});
|
|
@@ -433,7 +436,7 @@
|
|
|
433
436
|
state:`source-code-viewer-${state}`,
|
|
434
437
|
reason,
|
|
435
438
|
...(state==='error'?{
|
|
436
|
-
code:
|
|
439
|
+
code:is.string(error?.code)
|
|
437
440
|
?error.code
|
|
438
441
|
:'ARCANE_SOURCE_CODE_VIEWER_RENDER_REJECTED'
|
|
439
442
|
}:{})
|
|
@@ -42,6 +42,9 @@
|
|
|
42
42
|
</section>
|
|
43
43
|
|
|
44
44
|
<script type="module">
|
|
45
|
+
const {default:Is}=await import('strong-type');
|
|
46
|
+
const is=new Is(false);
|
|
47
|
+
|
|
45
48
|
const host=this; const root=host.shadowRoot;
|
|
46
49
|
const title=root.querySelector('[data-title]'); const assessment=root.querySelector('[data-assessment]'); const badges=root.querySelector('[data-badges]');
|
|
47
50
|
const elements=root.querySelector('[data-elements]'); const application=root.querySelector('[data-application]'); const limitations=root.querySelector('[data-limitations]'); const nextSteps=root.querySelector('[data-next-steps]');
|
|
@@ -73,7 +76,7 @@
|
|
|
73
76
|
}
|
|
74
77
|
function list(target,values=[],emptyLabel){
|
|
75
78
|
target.replaceChildren();
|
|
76
|
-
for(const value of
|
|
79
|
+
for(const value of is.array(values)?values:[]){const item=document.createElement('li'); item.textContent=String(value); target.append(item);}
|
|
77
80
|
if(!target.children.length){const item=document.createElement('li'); item.textContent=emptyLabel; target.append(item);}
|
|
78
81
|
}
|
|
79
82
|
function sameOrigin(value=''){
|
|
@@ -81,8 +84,8 @@
|
|
|
81
84
|
}
|
|
82
85
|
|
|
83
86
|
function showFinding(value={},config={}){
|
|
84
|
-
finding=value&&
|
|
85
|
-
sources=
|
|
87
|
+
finding=value&&is.object(value)?value:null; if(!finding) throw new TypeError('A finding is required.');
|
|
88
|
+
sources=is.array(finding.sources)?finding.sources:[];
|
|
86
89
|
title.textContent=String(finding.label||'Investigative lead'); assessment.textContent=String(finding.assessment||finding.conclusion||'Human review is required before reliance.');
|
|
87
90
|
badges.replaceChildren();
|
|
88
91
|
for(const value of [finding.allegedActorLabel?`Alleged actor: ${finding.allegedActorLabel}`:'Actor not assigned',finding.kind||'Investigative lead',finding.confidence?`${finding.confidence} confidence`:'Confidence not assigned']){const badge=document.createElement('span'); badge.className='badge'; badge.textContent=value; badges.append(badge);}
|
|
@@ -99,7 +102,7 @@
|
|
|
99
102
|
originalPicker.replaceChildren(...sources.flatMap((source,index)=>{if(!source?.pdfUrl)return[];const item=document.createElement('option');item.value=String(index);item.textContent=`${source.recordId||'Source'}${source.page?` — PDF page ${source.page}`:''}`;return[item];})); originalPicker.disabled=!originalPicker.options.length;
|
|
100
103
|
original.hidden=true; original.removeAttribute('src'); originalLabel.textContent='Select a cited excerpt to inspect the original source page.';
|
|
101
104
|
options(actor,config.actorOptions||[]); options(disposition,config.dispositionOptions||[]); options(confidence,config.confidenceOptions||[]);
|
|
102
|
-
const review=finding.review&&
|
|
105
|
+
const review=finding.review&&is.object(finding.review)?finding.review:{};
|
|
103
106
|
actor.value=String(review.classification||finding.allegedActor||'unassigned'); disposition.value=String(review.status||'unassessed'); confidence.value=String(review.attributes?.confidence||finding.confidence||'unassigned'); notes.value=String(review.notes||''); saveState.textContent='';
|
|
104
107
|
if(!actor.value&&actor.options.length) actor.selectedIndex=0; if(!disposition.value&&disposition.options.length) disposition.selectedIndex=0; if(!confidence.value&&confidence.options.length) confidence.selectedIndex=0;
|
|
105
108
|
const requestedSourceId=String(config.initialSourceId||'');
|
|
@@ -111,7 +114,7 @@
|
|
|
111
114
|
}
|
|
112
115
|
|
|
113
116
|
function selectSource(value=0){
|
|
114
|
-
const index=
|
|
117
|
+
const index=is.integer(value)?value:sources.findIndex(source=>String(source?.id||'')===String(value||''));
|
|
115
118
|
if(index<0||!sources[index]?.pdfUrl) return false;
|
|
116
119
|
showSource(index); return true;
|
|
117
120
|
}
|
|
@@ -132,6 +132,9 @@
|
|
|
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 {default:Is}=await import('strong-type');
|
|
136
|
+
const is=new Is(false);
|
|
137
|
+
|
|
135
138
|
const {arcaneLogging}=await import('arcane-os/logging');
|
|
136
139
|
|
|
137
140
|
const completeValue = (value) => value;
|
|
@@ -251,10 +254,10 @@
|
|
|
251
254
|
let causeCode = '';
|
|
252
255
|
let message = '';
|
|
253
256
|
try {
|
|
254
|
-
causeCode =
|
|
257
|
+
causeCode = is.string(error?.code)
|
|
255
258
|
? error.code
|
|
256
259
|
: '';
|
|
257
|
-
message =
|
|
260
|
+
message = is.string(error?.message)
|
|
258
261
|
? error.message
|
|
259
262
|
: '';
|
|
260
263
|
} catch {}
|
|
@@ -293,7 +296,7 @@
|
|
|
293
296
|
return String(reason || 'stt-transcription-cancelled');
|
|
294
297
|
}
|
|
295
298
|
|
|
296
|
-
const initialMutedWasHydrated =
|
|
299
|
+
const initialMutedWasHydrated = is.boolean(host.initialMuted);
|
|
297
300
|
host.initialMuted = initialMutedWasHydrated ? host.initialMuted : true;
|
|
298
301
|
host.muted = true;
|
|
299
302
|
host.configure = configure;
|
|
@@ -400,9 +403,9 @@
|
|
|
400
403
|
}
|
|
401
404
|
|
|
402
405
|
function selectedRole(role) {
|
|
403
|
-
return
|
|
406
|
+
return is.string(role?.providerId)
|
|
404
407
|
&& role.providerId.length > 0
|
|
405
|
-
&&
|
|
408
|
+
&& is.string(role?.modelId)
|
|
406
409
|
&& role.modelId.length > 0;
|
|
407
410
|
}
|
|
408
411
|
|
|
@@ -411,7 +414,7 @@
|
|
|
411
414
|
return host;
|
|
412
415
|
}
|
|
413
416
|
if (Object.prototype.hasOwnProperty.call(options, 'initialMuted')) {
|
|
414
|
-
const configuredMuted =
|
|
417
|
+
const configuredMuted = is.boolean(options.initialMuted)
|
|
415
418
|
? options.initialMuted
|
|
416
419
|
: true;
|
|
417
420
|
host.initialMuted = configuredMuted;
|
|
@@ -445,7 +448,7 @@
|
|
|
445
448
|
if (destroyed) {
|
|
446
449
|
return host;
|
|
447
450
|
}
|
|
448
|
-
if (
|
|
451
|
+
if (!is.boolean(muted)) {
|
|
449
452
|
throw new TypeError('muted must be boolean');
|
|
450
453
|
}
|
|
451
454
|
|
|
@@ -545,8 +548,8 @@
|
|
|
545
548
|
function renderControls() {
|
|
546
549
|
const transcriptionReady = sttRole.state === 'ready';
|
|
547
550
|
const microphoneReady = host.availability.microphone
|
|
548
|
-
&&
|
|
549
|
-
&&
|
|
551
|
+
&& is.function(globalThis.MediaRecorder)
|
|
552
|
+
&& is.function(navigator.mediaDevices?.getUserMedia);
|
|
550
553
|
const activationVisible = sttActivationController.visible;
|
|
551
554
|
recordButton.hidden = activationVisible;
|
|
552
555
|
recordButton.disabled = !transcriptionReady
|
|
@@ -611,9 +614,9 @@
|
|
|
611
614
|
}
|
|
612
615
|
|
|
613
616
|
function renderTTSControl() {
|
|
614
|
-
const providerSelected =
|
|
617
|
+
const providerSelected = is.string(ttsRole.providerId)
|
|
615
618
|
&& ttsRole.providerId.length > 0
|
|
616
|
-
&&
|
|
619
|
+
&& is.string(ttsRole.modelId)
|
|
617
620
|
&& ttsRole.modelId.length > 0;
|
|
618
621
|
let disabled = destroyed;
|
|
619
622
|
let label = host.muted ? 'Unmute' : 'Mute';
|
|
@@ -730,10 +733,10 @@
|
|
|
730
733
|
function visibleErrorMessage(error, fallback) {
|
|
731
734
|
try {
|
|
732
735
|
if (error?.userSafe === true) {
|
|
733
|
-
const message =
|
|
736
|
+
const message = is.string(error.userMessage)
|
|
734
737
|
? error.userMessage
|
|
735
738
|
: error.message;
|
|
736
|
-
if (
|
|
739
|
+
if (is.string(message) && message.trim()) {
|
|
737
740
|
return message;
|
|
738
741
|
}
|
|
739
742
|
}
|
|
@@ -912,9 +915,9 @@
|
|
|
912
915
|
) {
|
|
913
916
|
return false;
|
|
914
917
|
}
|
|
915
|
-
const providerSelected =
|
|
918
|
+
const providerSelected = is.string(ttsRole.providerId)
|
|
916
919
|
&& ttsRole.providerId.length > 0
|
|
917
|
-
&&
|
|
920
|
+
&& is.string(ttsRole.modelId)
|
|
918
921
|
&& ttsRole.modelId.length > 0;
|
|
919
922
|
const canRequestLoad = ttsRole.state === 'ready'
|
|
920
923
|
|| (
|
|
@@ -995,7 +998,7 @@
|
|
|
995
998
|
: action;
|
|
996
999
|
let lifecycle;
|
|
997
1000
|
try {
|
|
998
|
-
if (
|
|
1001
|
+
if (is.function(globalThis.ai?.setSpeechMuted)) {
|
|
999
1002
|
lifecycle = globalThis.ai.setSpeechMuted(action === 'unload');
|
|
1000
1003
|
} else {
|
|
1001
1004
|
lifecycle = requestAIRuntimeIntent(
|
|
@@ -1162,7 +1165,7 @@
|
|
|
1162
1165
|
|
|
1163
1166
|
function resumeTTSPlayback() {
|
|
1164
1167
|
const aiRuntime = globalThis.ai;
|
|
1165
|
-
if (!aiRuntime ||
|
|
1168
|
+
if (!aiRuntime || !is.function(aiRuntime.resumeAudio)) {
|
|
1166
1169
|
return;
|
|
1167
1170
|
}
|
|
1168
1171
|
|
|
@@ -1196,8 +1199,8 @@
|
|
|
1196
1199
|
|| sttRole.state !== 'ready'
|
|
1197
1200
|
|| sttRole.busy
|
|
1198
1201
|
|| !host.availability.microphone
|
|
1199
|
-
||
|
|
1200
|
-
||
|
|
1202
|
+
|| !is.function(globalThis.MediaRecorder)
|
|
1203
|
+
|| !is.function(navigator.mediaDevices?.getUserMedia)
|
|
1201
1204
|
|| recordingRequested
|
|
1202
1205
|
|| captureSession
|
|
1203
1206
|
|| transcriptionActive
|
|
@@ -1473,7 +1476,7 @@
|
|
|
1473
1476
|
);
|
|
1474
1477
|
return false;
|
|
1475
1478
|
}
|
|
1476
|
-
if (
|
|
1479
|
+
if (!is.function(aiRuntime?.fetchSTT)) {
|
|
1477
1480
|
const error = new Error('The selected transcription service is unavailable.');
|
|
1478
1481
|
error.code = 'ARCANE_SPEECH_STT_RUNTIME_METHOD_UNAVAILABLE';
|
|
1479
1482
|
throw error;
|
|
@@ -1490,7 +1493,7 @@
|
|
|
1490
1493
|
) {
|
|
1491
1494
|
return false;
|
|
1492
1495
|
}
|
|
1493
|
-
if (
|
|
1496
|
+
if (!is.string(transcription)) {
|
|
1494
1497
|
throw new TypeError('The selected transcription service returned invalid text.');
|
|
1495
1498
|
}
|
|
1496
1499
|
|
|
@@ -38,6 +38,9 @@
|
|
|
38
38
|
</section>
|
|
39
39
|
|
|
40
40
|
<script type="module">
|
|
41
|
+
const {default:Is}=await import('strong-type');
|
|
42
|
+
const is=new Is(false);
|
|
43
|
+
|
|
41
44
|
const host=this;
|
|
42
45
|
const root=host.shadowRoot;
|
|
43
46
|
const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
|
|
@@ -89,7 +92,7 @@
|
|
|
89
92
|
}
|
|
90
93
|
|
|
91
94
|
function updateItem(id,update={}){
|
|
92
|
-
const index=
|
|
95
|
+
const index=is.number(id)?id:items.findIndex(item=>item.id===`${id}`);
|
|
93
96
|
if(index<0||index>=items.length){
|
|
94
97
|
return null;
|
|
95
98
|
}
|
|
@@ -45,6 +45,9 @@
|
|
|
45
45
|
</section>
|
|
46
46
|
|
|
47
47
|
<script type="module">
|
|
48
|
+
const {default:Is}=await import('strong-type');
|
|
49
|
+
const is=new Is(false);
|
|
50
|
+
|
|
48
51
|
const host=this;
|
|
49
52
|
const root=host.shadowRoot;
|
|
50
53
|
const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
|
|
@@ -135,7 +138,7 @@
|
|
|
135
138
|
|
|
136
139
|
function updateTask(id,update={}){
|
|
137
140
|
if(destroyed)return null;
|
|
138
|
-
const index=
|
|
141
|
+
const index=is.number(id)?id:tasks.findIndex(task=>task.id===`${id}`);
|
|
139
142
|
if(index<0||index>=tasks.length){
|
|
140
143
|
return null;
|
|
141
144
|
}
|
|
@@ -203,7 +206,7 @@
|
|
|
203
206
|
if(running){
|
|
204
207
|
return activeRun;
|
|
205
208
|
}
|
|
206
|
-
const runnable=Array.from(jobs||[]).filter(job=>job&&
|
|
209
|
+
const runnable=Array.from(jobs||[]).filter(job=>job&&is.function(job.task));
|
|
207
210
|
if(!runnable.length){
|
|
208
211
|
setTasks([]);
|
|
209
212
|
return [];
|
|
@@ -244,7 +247,7 @@
|
|
|
244
247
|
'task-progress-error',
|
|
245
248
|
{error,id:tasks[index]?.id,index,task:{...tasks[index]}},
|
|
246
249
|
{
|
|
247
|
-
code:
|
|
250
|
+
code:is.string(error?.code)
|
|
248
251
|
?error.code
|
|
249
252
|
:'ARCANE_TASK_EXECUTION_REJECTED',
|
|
250
253
|
index,
|
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
<form class="prompt" id="prompt"><label class="prompt-label" id="promptLabel" for="input">arcane ❯</label><textarea class="input" id="input" rows="1" autocomplete="off" autocapitalize="off" spellcheck="false" placeholder="Enter a command"></textarea></form>
|
|
27
27
|
</section>
|
|
28
28
|
<script type="module">
|
|
29
|
+
const {default:Is}=await import('strong-type');
|
|
30
|
+
const is=new Is(false);
|
|
31
|
+
|
|
29
32
|
const {parseAnsi,stripAnsi}=await import('../modules/AnsiText.js');
|
|
30
33
|
const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
|
|
31
34
|
const host=this,root=host.shadowRoot;
|
|
@@ -62,7 +65,7 @@
|
|
|
62
65
|
function renderText(row,text,term){const clean=stripAnsi(text);if(!term){for(const token of parseAnsi(text)){const span=document.createElement('span');span.textContent=token.text;const classes=[];if(token.style.bold)classes.push('ansi-bold');if(token.style.dim)classes.push('ansi-dim');if(token.style.italic)classes.push('ansi-italic');if(token.style.underline)classes.push('ansi-underline');if(token.style.foreground&&!token.style.foreground.startsWith('index-'))classes.push(`ansi-${token.style.foreground}`);span.className=classes.join(' ');row.append(span);}return;}let cursor=0,index=clean.toLowerCase().indexOf(term);while(index>=0){row.append(document.createTextNode(clean.slice(cursor,index)));const mark=document.createElement('mark');mark.textContent=clean.slice(index,index+term.length);row.append(mark);cursor=index+term.length;index=clean.toLowerCase().indexOf(term,cursor);}row.append(document.createTextNode(clean.slice(cursor)));}
|
|
63
66
|
function toggleSearch(force){search.hidden=force===undefined?!search.hidden:!force;if(!search.hidden)search.focus();else{search.value='';render();input.focus();}}
|
|
64
67
|
function resizeInput(){input.style.height='auto';input.style.height=`${Math.min(input.scrollHeight,160)}px`;}
|
|
65
|
-
function emit(type,detail={}){if(destroyed)return false;const operationId=`${events.instanceId}:${type}:${(++eventOperationSequence).toString(36)}`;const publication=events.dispatch(type,detail,{operationId,publicDetail:{hasSession:Boolean(detail.sessionId),lineLength:
|
|
68
|
+
function emit(type,detail={}){if(destroyed)return false;const operationId=`${events.instanceId}:${type}:${(++eventOperationSequence).toString(36)}`;const publication=events.dispatch(type,detail,{operationId,publicDetail:{hasSession:Boolean(detail.sessionId),lineLength:is.string(detail.line)?detail.line.length:0,historyCount:is.array(detail.history)?detail.history.length:0,reason:type}});return projectArcaneDOMEvent(host,publication.occurrence,{bubbles:true,composed:true});}
|
|
66
69
|
function destroy(){if(destroyed)return false;destroyed=true;host.ready=false;for(const id of ['find','clear','interrupt','settings','copy'])root.querySelector(`#${id}`).onclick=null;events.dispose();return true;}
|
|
67
70
|
emit('terminal-workspace-ready');
|
|
68
71
|
</script>
|
|
@@ -60,6 +60,9 @@
|
|
|
60
60
|
</section>
|
|
61
61
|
|
|
62
62
|
<script type="module">
|
|
63
|
+
const {default:Is}=await import('strong-type');
|
|
64
|
+
const is=new Is(false);
|
|
65
|
+
|
|
63
66
|
const {arcaneLogging}=await import('arcane-os/logging');
|
|
64
67
|
|
|
65
68
|
const completeValue=(value)=>value;
|
|
@@ -302,7 +305,7 @@
|
|
|
302
305
|
return false;
|
|
303
306
|
}
|
|
304
307
|
if(
|
|
305
|
-
|
|
308
|
+
is.undefined(globalThis.MediaRecorder)
|
|
306
309
|
||!navigator.mediaDevices?.getUserMedia
|
|
307
310
|
){
|
|
308
311
|
setState('error',options.messages.unsupported);
|
|
@@ -468,7 +471,7 @@
|
|
|
468
471
|
||destroyed){
|
|
469
472
|
return false;
|
|
470
473
|
}
|
|
471
|
-
const segment=
|
|
474
|
+
const segment=is.string(result)?result:'';
|
|
472
475
|
if(segment.length===0){
|
|
473
476
|
setState('idle',options.messages.noSpeech);
|
|
474
477
|
return false;
|
|
@@ -483,7 +486,7 @@
|
|
|
483
486
|
|
|
484
487
|
if(options.persist){
|
|
485
488
|
const save=options.onSave||(
|
|
486
|
-
|
|
489
|
+
is.function(host.save)?host.save.bind(host):null
|
|
487
490
|
);
|
|
488
491
|
if(!save){
|
|
489
492
|
setState('error',options.messages.saveError);
|
|
@@ -594,10 +597,10 @@
|
|
|
594
597
|
if(options.transcribe){
|
|
595
598
|
return options.transcribe(file,context);
|
|
596
599
|
}
|
|
597
|
-
if(
|
|
600
|
+
if(!is.function(globalThis.ai?.fetchSTT)){
|
|
598
601
|
await import('../modules/AI.js');
|
|
599
602
|
}
|
|
600
|
-
if(
|
|
603
|
+
if(!is.function(globalThis.ai?.fetchSTT)){
|
|
601
604
|
const error=new Error('Speech transcription is not configured.');
|
|
602
605
|
error.code='ARCANE_VOICE_TRANSCRIPTION_STT_RUNTIME_METHOD_UNAVAILABLE';
|
|
603
606
|
throw error;
|
|
@@ -646,7 +649,7 @@
|
|
|
646
649
|
const generation=sessionGeneration;
|
|
647
650
|
const completionTranscript=transcript;
|
|
648
651
|
const complete=options.onComplete||(
|
|
649
|
-
|
|
652
|
+
is.function(host.complete)?host.complete.bind(host):null
|
|
650
653
|
);
|
|
651
654
|
setState('completing',options.messages.completing,{
|
|
652
655
|
beginOperation:'completion'
|
|
@@ -963,10 +966,10 @@
|
|
|
963
966
|
function visibleErrorMessage(error,fallback){
|
|
964
967
|
try{
|
|
965
968
|
if(error?.userSafe===true){
|
|
966
|
-
const message=
|
|
969
|
+
const message=is.string(error.userMessage)
|
|
967
970
|
?error.userMessage
|
|
968
971
|
:error.message;
|
|
969
|
-
if(
|
|
972
|
+
if(is.string(message)&&message.trim()){
|
|
970
973
|
return message;
|
|
971
974
|
}
|
|
972
975
|
}
|
|
@@ -59,6 +59,9 @@ button{min-width:2.5rem}
|
|
|
59
59
|
<p id="status" class="status" role="status" aria-live="polite">Enter an address. Some sites block embedded viewing; use Open externally when needed.</p>
|
|
60
60
|
</section>
|
|
61
61
|
<script type="module">
|
|
62
|
+
const {default:Is}=await import('strong-type');
|
|
63
|
+
const is=new Is(false);
|
|
64
|
+
|
|
62
65
|
const host=this;
|
|
63
66
|
const root=host.shadowRoot;
|
|
64
67
|
const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
|
|
@@ -128,7 +131,7 @@ async function evaluate(url,intent){
|
|
|
128
131
|
}
|
|
129
132
|
try{
|
|
130
133
|
const decision=await navigationGuard(url,{intent});
|
|
131
|
-
if(!decision
|
|
134
|
+
if(!decision||!is.object(decision)||!is.boolean(decision.blocked)){
|
|
132
135
|
throw new TypeError('Navigation policy returned an invalid decision.');
|
|
133
136
|
}
|
|
134
137
|
return decision;
|
|
@@ -230,7 +233,7 @@ function move(amount){
|
|
|
230
233
|
function configure(options){
|
|
231
234
|
if(destroyed)return false;
|
|
232
235
|
if(options?.homeUrl)homeUrl=normalize(options.homeUrl);
|
|
233
|
-
navigationGuard=
|
|
236
|
+
navigationGuard=is.function(options?.navigationGuard)?options.navigationGuard:null;
|
|
234
237
|
if(options?.initialUrl)ownNavigation(navigate(options.initialUrl));
|
|
235
238
|
else updateButtons();
|
|
236
239
|
return host;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
const is=new Is(false);
|
|
3
|
+
|
|
1
4
|
function deepFreeze(value){
|
|
2
|
-
if(!value
|
|
5
|
+
if(!value||!is.object(value)||Object.isFrozen(value)) return value;
|
|
3
6
|
for(const child of Object.values(value)) deepFreeze(child);
|
|
4
7
|
return Object.freeze(value);
|
|
5
8
|
}
|
|
@@ -9,7 +12,7 @@ export default class ApiModelRecord{
|
|
|
9
12
|
const url=new URL(String(endpoint||''));
|
|
10
13
|
if(!['http:','https:'].includes(url.protocol)) throw new TypeError('API model endpoints must use HTTP or HTTPS.');
|
|
11
14
|
const instant=new Date(fetchedAt);
|
|
12
|
-
if(
|
|
15
|
+
if(is.NaN(instant.valueOf())) throw new TypeError('API model fetch time is invalid.');
|
|
13
16
|
this.endpoint=url.href;
|
|
14
17
|
this.fetchedAt=instant.toISOString();
|
|
15
18
|
this.metadata=deepFreeze({...metadata});
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
const is=new Is(false);
|
|
3
|
+
|
|
1
4
|
export default class Calculation{
|
|
2
5
|
constructor({expression,result,createdAt=new Date()}={}){
|
|
3
6
|
this.expression=String(expression??'');
|
|
4
7
|
if(!this.expression.trim()) throw new TypeError('Calculation expressions must contain text.');
|
|
5
8
|
this.result=Number(result);
|
|
6
|
-
if(!
|
|
9
|
+
if(!is.finite(this.result)) throw new RangeError('Calculation result must be finite.');
|
|
7
10
|
const instant=new Date(createdAt);
|
|
8
|
-
if(
|
|
11
|
+
if(is.NaN(instant.valueOf())) throw new TypeError('Calculation time is invalid.');
|
|
9
12
|
this.createdAt=instant.toISOString();
|
|
10
13
|
}
|
|
11
14
|
toJSON(){return {...this};}
|