arcane-os 0.3.4 → 0.3.5
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 +12 -0
- package/README.md +7 -7
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +315 -119
- package/browser-runtime/ai/model-controller.mjs +439 -95
- package/package.json +1 -1
- package/runtime/arcane/components/assistant-panel.html +2 -1
- package/runtime/arcane/components/chat.html +466 -206
- package/runtime/arcane/components/speech.html +33 -13
- package/runtime/arcane/components/voice-transcription.html +27 -3
- package/runtime/arcane/entities/Chat.js +165 -97
- package/runtime/arcane/entities/IntentEnvelope.js +52 -118
- package/runtime/arcane/entities/TWiNPolicyDecision.js +33 -130
- package/runtime/arcane/entities/User.js +38 -44
- package/runtime/arcane/modules/AI.js +569 -302
- package/runtime/arcane/modules/AIProviderRuntime.js +765 -135
- package/runtime/arcane/modules/AIRuntimeState.js +22 -24
- package/runtime/arcane/modules/ApiModelDatabase.js +54 -48
- package/runtime/arcane/modules/CaseEvidenceIndexer.js +6 -10
- package/runtime/arcane/modules/CommunicationHub.js +90 -94
- package/runtime/arcane/modules/ComponentContracts.js +34 -9
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +77 -77
- package/runtime/arcane/modules/ConversationTimebox.js +76 -104
- package/runtime/arcane/modules/DBLS.js +14 -12
- package/runtime/arcane/modules/DBOPFS.js +20 -15
- package/runtime/arcane/modules/Errors.js +196 -436
- package/runtime/arcane/modules/HTMLImport.js +49 -32
- package/runtime/arcane/modules/Ollama.js +16 -14
- package/runtime/arcane/modules/PersistentAIChatSession.js +174 -93
- package/runtime/arcane/modules/RecordReviewStore.js +40 -35
- package/runtime/arcane/modules/TerminalClient.js +12 -14
- package/runtime/arcane/modules/ThemeBootstrap.js +7 -7
- package/runtime/arcane/modules/ThemeManager.js +5 -5
- package/runtime/arcane/modules/TimeGuard.js +5 -65
- package/runtime/arcane/modules/WaitForComponent.js +43 -40
- package/src/installed-sdk-runtime.mjs +11 -1
|
@@ -65,6 +65,15 @@ function createComponentFragment(html,resolvedHref){
|
|
|
65
65
|
return template.content;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
function resolveRelativeDynamicImports(source,baseHref){
|
|
69
|
+
return source.replace(
|
|
70
|
+
/\bimport\s*\(\s*(['"])(\.{1,2}\/[^'"]+)\1\s*\)/gu,
|
|
71
|
+
function resolveDynamicImport(_match,_quote,specifier){
|
|
72
|
+
return `import(${JSON.stringify(new URL(specifier,baseHref).href)})`;
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
68
77
|
function samePropertyDescriptor(left,right){
|
|
69
78
|
if(!left||!right)return left===right;
|
|
70
79
|
return left.configurable===right.configurable
|
|
@@ -77,7 +86,7 @@ function samePropertyDescriptor(left,right){
|
|
|
77
86
|
|
|
78
87
|
class HTMLImport extends HTMLElement {
|
|
79
88
|
#connectionGeneration=0;
|
|
80
|
-
#eventOwner=
|
|
89
|
+
#eventOwner={kind:'html-import-lifecycle-owner'};
|
|
81
90
|
#events;
|
|
82
91
|
#importedDestroy=null;
|
|
83
92
|
#loadController=null;
|
|
@@ -93,10 +102,10 @@ class HTMLImport extends HTMLElement {
|
|
|
93
102
|
#createEvents(){
|
|
94
103
|
this.#events=createArcaneEventSource(this.#eventOwner,{
|
|
95
104
|
source:'html-import',
|
|
96
|
-
eventTypes:
|
|
105
|
+
eventTypes:[
|
|
97
106
|
'html-import-error',
|
|
98
107
|
'html-import-ready'
|
|
99
|
-
]
|
|
108
|
+
]
|
|
100
109
|
});
|
|
101
110
|
return this.#events;
|
|
102
111
|
}
|
|
@@ -128,17 +137,11 @@ class HTMLImport extends HTMLElement {
|
|
|
128
137
|
}
|
|
129
138
|
|
|
130
139
|
try{
|
|
131
|
-
const
|
|
132
|
-
const resolvedURL=new URL(href,baseURL);
|
|
140
|
+
const resolvedURL=new URL(href,document.baseURI);
|
|
133
141
|
resolvedHref=resolvedURL.href;
|
|
134
|
-
if(resolvedURL.origin!==baseURL.origin){
|
|
135
|
-
throw new Error('HTML imports must use a same-origin URL.');
|
|
136
|
-
}
|
|
137
142
|
const response=await fetch(resolvedURL.href,{
|
|
138
143
|
cache:'default',
|
|
139
|
-
credentials:'same-origin',
|
|
140
144
|
method:'GET',
|
|
141
|
-
redirect:'error',
|
|
142
145
|
signal:controller.signal
|
|
143
146
|
});
|
|
144
147
|
if(!this.#isCurrentConnection(generation,controller))return;
|
|
@@ -149,19 +152,19 @@ class HTMLImport extends HTMLElement {
|
|
|
149
152
|
return;
|
|
150
153
|
}
|
|
151
154
|
console.error('Error loading HTML component:',err);
|
|
152
|
-
const detail=
|
|
155
|
+
const detail={
|
|
153
156
|
code:'HTML_IMPORT_FAILED',
|
|
154
157
|
href,
|
|
155
158
|
message:'The component could not be loaded.',
|
|
156
159
|
reason:'component-import-rejected',
|
|
157
160
|
resolvedHref
|
|
158
|
-
}
|
|
161
|
+
};
|
|
159
162
|
const {occurrence}=this.#events.dispatch(
|
|
160
163
|
'html-import-error',
|
|
161
164
|
detail,
|
|
162
165
|
{
|
|
163
166
|
operationId,
|
|
164
|
-
publicDetail:
|
|
167
|
+
publicDetail:{code:detail.code,reason:detail.reason}
|
|
165
168
|
}
|
|
166
169
|
);
|
|
167
170
|
projectArcaneDOMEvent(this,occurrence,{
|
|
@@ -200,18 +203,18 @@ class HTMLImport extends HTMLElement {
|
|
|
200
203
|
#reportImportedDestroyError(error,{events,href,operationId}){
|
|
201
204
|
console.error('Error destroying imported HTML component:',error);
|
|
202
205
|
if(!events||events.disposed)return;
|
|
203
|
-
const detail=
|
|
206
|
+
const detail={
|
|
204
207
|
code:'HTML_IMPORT_IMPORTED_COMPONENT_DESTROY_REJECTED',
|
|
205
208
|
href,
|
|
206
209
|
message:'The imported component could not be destroyed.',
|
|
207
210
|
reason:'imported-component-destroy-rejected'
|
|
208
|
-
}
|
|
211
|
+
};
|
|
209
212
|
const {occurrence}=events.dispatch(
|
|
210
213
|
'html-import-error',
|
|
211
214
|
detail,
|
|
212
215
|
{
|
|
213
216
|
operationId,
|
|
214
|
-
publicDetail:
|
|
217
|
+
publicDetail:{code:detail.code,reason:detail.reason}
|
|
215
218
|
}
|
|
216
219
|
);
|
|
217
220
|
projectArcaneDOMEvent(this,occurrence,{
|
|
@@ -272,9 +275,10 @@ class HTMLImport extends HTMLElement {
|
|
|
272
275
|
if(!this.#isCurrentConnection(generation,controller))return false;
|
|
273
276
|
await this.#destroyImportedHost();
|
|
274
277
|
if(!this.#isCurrentConnection(generation,controller))return false;
|
|
275
|
-
|
|
278
|
+
const contentBaseHref=response.url||resolvedHref;
|
|
279
|
+
this.shadowRoot.replaceChildren(createComponentFragment(html,contentBaseHref));
|
|
276
280
|
|
|
277
|
-
await this.#executeScripts();
|
|
281
|
+
await this.#executeScripts(contentBaseHref,generation,controller);
|
|
278
282
|
if(!this.#isCurrentConnection(generation,controller)){
|
|
279
283
|
await this.#destroyImportedHost();
|
|
280
284
|
return false;
|
|
@@ -283,8 +287,8 @@ class HTMLImport extends HTMLElement {
|
|
|
283
287
|
this.ready=true;
|
|
284
288
|
const {occurrence}=this.#events.dispatch(
|
|
285
289
|
'html-import-ready',
|
|
286
|
-
|
|
287
|
-
{operationId,publicDetail:
|
|
290
|
+
{href,resolvedHref},
|
|
291
|
+
{operationId,publicDetail:{ready:true}}
|
|
288
292
|
);
|
|
289
293
|
projectArcaneDOMEvent(this,occurrence,{
|
|
290
294
|
bubbles:true,
|
|
@@ -293,36 +297,49 @@ class HTMLImport extends HTMLElement {
|
|
|
293
297
|
return true;
|
|
294
298
|
}
|
|
295
299
|
|
|
296
|
-
async #executeScripts() {
|
|
300
|
+
async #executeScripts(contentBaseHref,generation,controller) {
|
|
297
301
|
const scripts = Array.from(this.shadowRoot.querySelectorAll('script'));
|
|
298
302
|
const previousDescriptor=Object.getOwnPropertyDescriptor(this,'destroy')??null;
|
|
299
303
|
const previousDestroy=this.destroy;
|
|
300
304
|
try{
|
|
301
305
|
for(const script of scripts){
|
|
302
|
-
if
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
306
|
+
if(!this.#isCurrentConnection(generation,controller))return;
|
|
307
|
+
let source=script.textContent||'';
|
|
308
|
+
let sourceBaseHref=contentBaseHref;
|
|
309
|
+
const scriptSource=script.getAttribute('src');
|
|
310
|
+
if(scriptSource!==null){
|
|
311
|
+
const requestedScriptHref=new URL(scriptSource,contentBaseHref).href;
|
|
312
|
+
const response=await fetch(requestedScriptHref,{
|
|
313
|
+
cache:'default',
|
|
314
|
+
method:'GET',
|
|
315
|
+
signal:controller.signal
|
|
316
|
+
});
|
|
317
|
+
if(!response.ok){
|
|
318
|
+
throw new Error(`HTML import script request failed with status ${response.status}.`);
|
|
319
|
+
}
|
|
320
|
+
source=await response.text();
|
|
321
|
+
sourceBaseHref=response.url||requestedScriptHref;
|
|
322
|
+
if(!this.#isCurrentConnection(generation,controller))return;
|
|
307
323
|
}
|
|
308
324
|
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
return `import(${JSON.stringify(new URL(specifier,import.meta.url).href)})`;
|
|
313
|
-
}
|
|
325
|
+
const executableSource=resolveRelativeDynamicImports(
|
|
326
|
+
source,
|
|
327
|
+
sourceBaseHref
|
|
314
328
|
);
|
|
315
329
|
const executable=document.createElement('script');
|
|
316
330
|
const hostToken=`html-import-${Date.now()}-${htmlImportScriptId++}`;
|
|
317
331
|
|
|
318
332
|
executable.dataset.arcaneHostToken=hostToken;
|
|
319
|
-
executable.textContent=`(()=>{const registry=globalThis[Symbol.for('arcane.html-import.hosts')];const token=document.currentScript&&document.currentScript.dataset.arcaneHostToken;const binding=registry instanceof Map&&token?registry.get(token):null;if(!binding?.host)throw new Error('HTML import host binding is unavailable.');binding.promise=(async function(){${
|
|
333
|
+
executable.textContent=`(()=>{const registry=globalThis[Symbol.for('arcane.html-import.hosts')];const token=document.currentScript&&document.currentScript.dataset.arcaneHostToken;const binding=registry instanceof Map&&token?registry.get(token):null;if(!binding?.host)throw new Error('HTML import host binding is unavailable.');binding.promise=(async function(){${executableSource}}).call(binding.host);})()`;
|
|
320
334
|
script.parentNode.removeChild(script);
|
|
321
335
|
|
|
322
336
|
const binding={host:this,promise:null};
|
|
323
337
|
htmlImportHostRegistry.set(hostToken,binding);
|
|
324
338
|
try{
|
|
325
339
|
document.head.appendChild(executable);
|
|
340
|
+
if(!binding.promise||typeof binding.promise.then!=='function'){
|
|
341
|
+
throw new Error('The HTML import script did not start.');
|
|
342
|
+
}
|
|
326
343
|
await binding.promise;
|
|
327
344
|
}finally{
|
|
328
345
|
executable.remove();
|
|
@@ -9,12 +9,14 @@ import {
|
|
|
9
9
|
|
|
10
10
|
const PUBLISH_OLLAMA_READY=Symbol('publish-ollama-ready');
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
const ollamaEventTypes={
|
|
13
13
|
ready:'arcane-ollama-ready'
|
|
14
|
-
}
|
|
15
|
-
|
|
14
|
+
};
|
|
15
|
+
const ollamaReasons={
|
|
16
16
|
ready:'ollama-module-ready'
|
|
17
|
-
}
|
|
17
|
+
};
|
|
18
|
+
export const OLLAMA_EVENT_TYPES={...ollamaEventTypes};
|
|
19
|
+
export const OLLAMA_REASONS={...ollamaReasons};
|
|
18
20
|
|
|
19
21
|
function api(){
|
|
20
22
|
const client=globalThis.Arcane?.ollama
|
|
@@ -29,7 +31,7 @@ function api(){
|
|
|
29
31
|
export class Ollama{
|
|
30
32
|
#events=createArcaneEventSource(this,{
|
|
31
33
|
source:'ollama',
|
|
32
|
-
eventTypes:Object.
|
|
34
|
+
eventTypes:Object.values(ollamaEventTypes)
|
|
33
35
|
})
|
|
34
36
|
|
|
35
37
|
version(){ return api().version() }
|
|
@@ -59,13 +61,13 @@ export class Ollama{
|
|
|
59
61
|
const version=String(
|
|
60
62
|
typeof response==='string' ? response : response?.version||''
|
|
61
63
|
).trim()||null
|
|
62
|
-
return
|
|
64
|
+
return {ready:true,version,errorCode:null}
|
|
63
65
|
}catch(error){
|
|
64
|
-
return
|
|
66
|
+
return {
|
|
65
67
|
ready:false,
|
|
66
68
|
version:null,
|
|
67
69
|
errorCode:String(error?.code||'OLLAMA_UNAVAILABLE')
|
|
68
|
-
}
|
|
70
|
+
}
|
|
69
71
|
}
|
|
70
72
|
}
|
|
71
73
|
|
|
@@ -84,13 +86,13 @@ export class Ollama{
|
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
[PUBLISH_OLLAMA_READY](){
|
|
87
|
-
const reason=
|
|
89
|
+
const reason=ollamaReasons.ready;
|
|
88
90
|
const {occurrence}=this.#events.dispatch(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
ollamaEventTypes.ready,
|
|
92
|
+
{ollama:this,reason},
|
|
91
93
|
{
|
|
92
94
|
operationId:`${this.#events.instanceId}:ready:1`,
|
|
93
|
-
publicDetail:
|
|
95
|
+
publicDetail:{ready:true,reason}
|
|
94
96
|
}
|
|
95
97
|
)
|
|
96
98
|
if(typeof globalThis.CustomEvent==='function'
|
|
@@ -100,10 +102,10 @@ export class Ollama{
|
|
|
100
102
|
}
|
|
101
103
|
}
|
|
102
104
|
|
|
103
|
-
export const ollama=
|
|
105
|
+
export const ollama=new Ollama()
|
|
104
106
|
export default ollama
|
|
105
107
|
|
|
106
108
|
if(!Object.prototype.hasOwnProperty.call(globalThis,'arcaneOllama')){
|
|
107
|
-
Object.defineProperty(globalThis,'arcaneOllama',{ value:ollama,enumerable:true,configurable:
|
|
109
|
+
Object.defineProperty(globalThis,'arcaneOllama',{ value:ollama,enumerable:true,configurable:true,writable:true })
|
|
108
110
|
}
|
|
109
111
|
ollama[PUBLISH_OLLAMA_READY]()
|