arcane-os 0.1.0-dev.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 +154 -0
- package/COMMERCIAL-LICENSE.md +13 -0
- package/LICENSE +661 -0
- package/NOTICE +70 -0
- package/README.md +448 -0
- package/bin/arcane-test.mjs +741 -0
- package/bin/arcane.mjs +5 -0
- package/docs/architecture.md +234 -0
- package/docs/compatibility.md +36 -0
- package/docs/event-manager.md +166 -0
- package/docs/platform-targets.md +108 -0
- package/docs/publishing.md +203 -0
- package/docs/reference/README.md +117 -0
- package/docs/reference/arcane-ollama.md +288 -0
- package/docs/reference/availability-and-normalization.md +123 -0
- package/docs/reference/behavioral-testing.md +86 -0
- package/docs/reference/cli.md +569 -0
- package/docs/reference/core/README.md +62 -0
- package/docs/reference/core/arcane-ai-contracts.md +873 -0
- package/docs/reference/core/arcane-api.md +601 -0
- package/docs/reference/core/arcane-entities.md +65 -0
- package/docs/reference/core/arcane-events.md +134 -0
- package/docs/reference/core/ollama-module.md +181 -0
- package/docs/reference/core/reference/arcane-api/ai-and-ollama.md +1909 -0
- package/docs/reference/core/reference/arcane-api/applications-terminal-capabilities.md +1057 -0
- package/docs/reference/core/reference/arcane-api/core-and-events.md +320 -0
- package/docs/reference/core/reference/arcane-api/filesystem-storage-preferences-appearance.md +610 -0
- package/docs/reference/core/reference/arcane-api/namespaces.md +1157 -0
- package/docs/reference/core/reference/arcane-api/platform-installation-users-system.md +1423 -0
- package/docs/reference/core/reference/arcane-api/session-provisioning-diagnostics-development.md +315 -0
- package/docs/reference/event-manager.md +957 -0
- package/docs/reference/inventory/package-api.json +2632 -0
- package/docs/reference/inventory/runtime-components.json +934 -0
- package/docs/reference/inventory/runtime-entities.json +26 -0
- package/docs/reference/inventory/runtime-modules.json +1249 -0
- package/docs/reference/protocols.md +242 -0
- package/docs/reference/runtime-components.md +1098 -0
- package/docs/reference/runtime-entities.md +303 -0
- package/docs/reference/runtime-modules.md +2010 -0
- package/docs/reference/sdk-api.md +4901 -0
- package/docs/roadmap.md +79 -0
- package/docs/work-amplification.md +124 -0
- package/node_modules/event-pubsub/CHANGELOG.md +55 -0
- package/node_modules/event-pubsub/MIGRATION.md +70 -0
- package/node_modules/event-pubsub/README.md +363 -0
- package/node_modules/event-pubsub/SECURITY.md +37 -0
- package/node_modules/event-pubsub/index.js +141 -0
- package/node_modules/event-pubsub/licence +21 -0
- package/node_modules/event-pubsub/package.json +59 -0
- package/node_modules/strong-type/README.md +408 -0
- package/node_modules/strong-type/assets/strong-type-header.png +0 -0
- package/node_modules/strong-type/index.js +1151 -0
- package/node_modules/strong-type/licence +21 -0
- package/node_modules/strong-type/node.js +125 -0
- package/node_modules/strong-type/package.json +61 -0
- package/package.json +95 -0
- package/runtime/ARCANE_RUNTIME_RELEASE.json +791 -0
- package/runtime/arcane/components/app-bar.html +468 -0
- package/runtime/arcane/components/assistant-panel.html +715 -0
- package/runtime/arcane/components/calculator.html +8 -0
- package/runtime/arcane/components/chart.html +655 -0
- package/runtime/arcane/components/chat.html +1225 -0
- package/runtime/arcane/components/conversation-view.html +13 -0
- package/runtime/arcane/components/dashboard-config.html +341 -0
- package/runtime/arcane/components/data-maintenance.html +112 -0
- package/runtime/arcane/components/data-view.html +92 -0
- package/runtime/arcane/components/directory-picker.html +197 -0
- package/runtime/arcane/components/document-inspector.html +252 -0
- package/runtime/arcane/components/file-drop.html +264 -0
- package/runtime/arcane/components/file-inspector.html +293 -0
- package/runtime/arcane/components/file-manager.html +1715 -0
- package/runtime/arcane/components/header.html +142 -0
- package/runtime/arcane/components/integration-settings.html +14 -0
- package/runtime/arcane/components/local-ai-status.html +360 -0
- package/runtime/arcane/components/markdown-document.html +1048 -0
- package/runtime/arcane/components/markdown-editor.html +360 -0
- package/runtime/arcane/components/media-embed.html +8 -0
- package/runtime/arcane/components/modal.html +402 -0
- package/runtime/arcane/components/output-panel.html +259 -0
- package/runtime/arcane/components/preferences-form.html +135 -0
- package/runtime/arcane/components/record-timeline.html +105 -0
- package/runtime/arcane/components/relationship-board.html +116 -0
- package/runtime/arcane/components/screen-capture.html +8 -0
- package/runtime/arcane/components/source-code-viewer.html +441 -0
- package/runtime/arcane/components/source-explanation.html +124 -0
- package/runtime/arcane/components/speech.html +365 -0
- package/runtime/arcane/components/summary-strip.html +177 -0
- package/runtime/arcane/components/table.html +77 -0
- package/runtime/arcane/components/task-progress.html +282 -0
- package/runtime/arcane/components/terminal-workspace.html +65 -0
- package/runtime/arcane/components/theme-editor.html +41 -0
- package/runtime/arcane/components/theme-switcher.html +46 -0
- package/runtime/arcane/components/unified-inbox.html +20 -0
- package/runtime/arcane/components/voice-transcription.html +476 -0
- package/runtime/arcane/components/weather-widget.html +8 -0
- package/runtime/arcane/components/web-navigator.html +239 -0
- package/runtime/arcane/css/communications.css +1 -0
- package/runtime/arcane/css/dashboard-config.css +45 -0
- package/runtime/arcane/css/document-site.css +981 -0
- package/runtime/arcane/css/layout.css +438 -0
- package/runtime/arcane/css/primitives.css +321 -0
- package/runtime/arcane/css/theme.css +112 -0
- package/runtime/arcane/css/utility-workspace.css +1 -0
- package/runtime/arcane/entities/ApiModelRecord.js +20 -0
- package/runtime/arcane/entities/Calculation.js +13 -0
- package/runtime/arcane/entities/Chat.js +581 -0
- package/runtime/arcane/entities/CommunicationMessage.js +29 -0
- package/runtime/arcane/entities/CommunicationThread.js +21 -0
- package/runtime/arcane/entities/Document.js +10 -0
- package/runtime/arcane/entities/File.js +143 -0
- package/runtime/arcane/entities/Image.js +135 -0
- package/runtime/arcane/entities/IntentEnvelope.js +834 -0
- package/runtime/arcane/entities/Preference.js +83 -0
- package/runtime/arcane/entities/TWiNPolicyDecision.js +1092 -0
- package/runtime/arcane/entities/TerminalSession.js +46 -0
- package/runtime/arcane/entities/Theme.js +107 -0
- package/runtime/arcane/entities/User.js +1046 -0
- package/runtime/arcane/entities/Weather.js +23 -0
- package/runtime/arcane/img/arcane-os-everywhere.png +0 -0
- package/runtime/arcane/img/arrow-left.png +0 -0
- package/runtime/arcane/img/arrow-right.png +0 -0
- package/runtime/arcane/img/doc.svg +5 -0
- package/runtime/arcane/img/folder.svg +4 -0
- package/runtime/arcane/img/image.svg +5 -0
- package/runtime/arcane/img/refresh.png +0 -0
- package/runtime/arcane/img/send.svg +9 -0
- package/runtime/arcane/img/trash.svg +5 -0
- package/runtime/arcane/img/upload.svg +5 -0
- package/runtime/arcane/modules/AI.js +2048 -0
- package/runtime/arcane/modules/AIPreferenceRuntime.js +32 -0
- package/runtime/arcane/modules/AIPreferenceTuple.js +92 -0
- package/runtime/arcane/modules/AIResponseLength.js +42 -0
- package/runtime/arcane/modules/AIResponseURLPolicy.js +626 -0
- package/runtime/arcane/modules/AnsiText.js +53 -0
- package/runtime/arcane/modules/ApiModelDatabase.js +25 -0
- package/runtime/arcane/modules/AppDataScope.js +245 -0
- package/runtime/arcane/modules/AppearancePreferences.js +28 -0
- package/runtime/arcane/modules/ArcaneCommunicationBridge.js +22 -0
- package/runtime/arcane/modules/ArcaneNavigationPolicy.js +135 -0
- package/runtime/arcane/modules/ArcaneNetworkPolicy.js +255 -0
- package/runtime/arcane/modules/AsyncBoundary.js +161 -0
- package/runtime/arcane/modules/BrowserTestSuite.js +326 -0
- package/runtime/arcane/modules/CalculatorEngine.js +20 -0
- package/runtime/arcane/modules/CaseEvidenceIndexer.js +134 -0
- package/runtime/arcane/modules/ChartLibrary.js +35 -0
- package/runtime/arcane/modules/ChatRecords.js +13 -0
- package/runtime/arcane/modules/CommunicationAppController.js +43 -0
- package/runtime/arcane/modules/CommunicationHub.js +16 -0
- package/runtime/arcane/modules/CommunicationPreferences.js +13 -0
- package/runtime/arcane/modules/CommunicationProviderRegistry.js +16 -0
- package/runtime/arcane/modules/ComponentContracts.js +586 -0
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +288 -0
- package/runtime/arcane/modules/ConversationActionItems.js +488 -0
- package/runtime/arcane/modules/ConversationClosingReport.js +274 -0
- package/runtime/arcane/modules/ConversationTimebox.js +527 -0
- package/runtime/arcane/modules/CoreLocalModelCatalog.js +255 -0
- package/runtime/arcane/modules/DBLS.js +171 -0
- package/runtime/arcane/modules/DBOPFS.js +1154 -0
- package/runtime/arcane/modules/DBOPFSWorker.js +116 -0
- package/runtime/arcane/modules/DataMaintenance.js +91 -0
- package/runtime/arcane/modules/DevelopmentWorkspace.js +74 -0
- package/runtime/arcane/modules/DirectoryPicker.js +109 -0
- package/runtime/arcane/modules/DocumentNavigation.js +223 -0
- package/runtime/arcane/modules/Errors.js +1025 -0
- package/runtime/arcane/modules/GifEncoder.js +29 -0
- package/runtime/arcane/modules/HTMLImport.js +114 -0
- package/runtime/arcane/modules/InMemoryCommunicationProvider.js +14 -0
- package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +275 -0
- package/runtime/arcane/modules/LocalAIReadiness.js +870 -0
- package/runtime/arcane/modules/LocalAIReadinessController.js +156 -0
- package/runtime/arcane/modules/MD.js +111 -0
- package/runtime/arcane/modules/Mail.js +352 -0
- package/runtime/arcane/modules/MailTransport.mjs +180 -0
- package/runtime/arcane/modules/Marked.min.js +71 -0
- package/runtime/arcane/modules/MemoryRecords.js +44 -0
- package/runtime/arcane/modules/MessageAdvisory.js +38 -0
- package/runtime/arcane/modules/ModelDefinition.js +189 -0
- package/runtime/arcane/modules/Ollama.js +74 -0
- package/runtime/arcane/modules/OllamaModelIdentifier.js +21 -0
- package/runtime/arcane/modules/OllamaSettings.js +24 -0
- package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +14 -0
- package/runtime/arcane/modules/PreferenceStore.js +109 -0
- package/runtime/arcane/modules/QRCode.min.js +1 -0
- package/runtime/arcane/modules/Questionnaire.js +61 -0
- package/runtime/arcane/modules/RecordLinkIndex.js +24 -0
- package/runtime/arcane/modules/RecordPassageIndex.js +222 -0
- package/runtime/arcane/modules/RecordReviewStore.js +94 -0
- package/runtime/arcane/modules/RevocableProjectionLedger.js +1623 -0
- package/runtime/arcane/modules/RiskSignalAnalyzer.js +37 -0
- package/runtime/arcane/modules/ScamRiskPolicy.js +62 -0
- package/runtime/arcane/modules/ScopedOPFSCache.js +183 -0
- package/runtime/arcane/modules/ScreenCapture.js +20 -0
- package/runtime/arcane/modules/SpeechPlayback.js +581 -0
- package/runtime/arcane/modules/StaticDocumentCatalog.js +1248 -0
- package/runtime/arcane/modules/SystemAppearance.js +20 -0
- package/runtime/arcane/modules/SystemPlatformPresentation.js +51 -0
- package/runtime/arcane/modules/SystemToolRegistry.js +28 -0
- package/runtime/arcane/modules/TerminalClient.js +52 -0
- package/runtime/arcane/modules/TerminalCommandRegistry.js +50 -0
- package/runtime/arcane/modules/ThemeBootstrap.js +26 -0
- package/runtime/arcane/modules/ThemeManager.js +131 -0
- package/runtime/arcane/modules/TimeGuard.js +149 -0
- package/runtime/arcane/modules/ToolCallRouter.js +83 -0
- package/runtime/arcane/modules/WaitForComponent.js +102 -0
- package/runtime/arcane/modules/YouTubeMedia.js +16 -0
- package/runtime/arcane/modules/uPlot.LICENSE.txt +21 -0
- package/runtime/arcane/modules/uPlot.iife.min.js +2 -0
- package/runtime/arcane/modules/uPlot.min.css +1 -0
- package/runtime/arcane/security/arcane-network-policy.json +6 -0
- package/runtime/strong-type/index.js +352 -0
- package/runtime/strong-type/licence +21 -0
- package/runtime/strong-type/package.json +45 -0
- package/schemas/arcane-app-bundle.schema.json +125 -0
- package/schemas/arcane-app.schema.json +329 -0
- package/schemas/arcane-lock.schema.json +86 -0
- package/schemas/arcane-package.schema.json +224 -0
- package/schemas/cli-event.schema.json +122 -0
- package/schemas/event-stack.schema.json +152 -0
- package/schemas/native-build-plan.schema.json +176 -0
- package/schemas/target-adapter.schema.json +117 -0
- package/src/app-descriptor.mjs +500 -0
- package/src/cli/main.mjs +561 -0
- package/src/constants.mjs +31 -0
- package/src/dev-server.mjs +718 -0
- package/src/doctor.mjs +315 -0
- package/src/dom-event-instrumentation.mjs +594 -0
- package/src/errors.mjs +75 -0
- package/src/event-manager.mjs +1342 -0
- package/src/event-queue.mjs +138 -0
- package/src/events.mjs +219 -0
- package/src/index.mjs +177 -0
- package/src/integrated-provider-loader.mjs +432 -0
- package/src/native-plan.mjs +698 -0
- package/src/native-provider-loader.mjs +1126 -0
- package/src/packager/core.mjs +2691 -0
- package/src/process.mjs +353 -0
- package/src/release-bundle.mjs +2523 -0
- package/src/repository.mjs +90 -0
- package/src/runtime.mjs +452 -0
- package/src/scaffold.mjs +380 -0
- package/src/targets/index.mjs +436 -0
- package/src/templates/assets/app-icon.png +0 -0
- package/src/templates/workspace-template.mjs +388 -0
- package/src/testing-loader.mjs +9 -0
- package/src/testing.mjs +427 -0
- package/src/toolchain.mjs +1335 -0
- package/src/update-check.mjs +307 -0
- package/src/workspace.mjs +449 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const ascii=value=>Array.from(value,char=>char.charCodeAt(0));
|
|
2
|
+
const word=value=>[value&255,(value>>8)&255];
|
|
3
|
+
|
|
4
|
+
function palette(){const bytes=[];for(let index=0;index<256;index++){bytes.push(((index>>5)&7)*255/7,((index>>2)&7)*255/7,(index&3)*255/3)}return bytes.map(Math.round)}
|
|
5
|
+
function indexPixels(data){const result=new Uint8Array(data.length/4);for(let offset=0,index=0;offset<data.length;offset+=4,index++)result[index]=((data[offset]>>5)<<5)|((data[offset+1]>>5)<<2)|(data[offset+2]>>6);return result;}
|
|
6
|
+
|
|
7
|
+
function lzw(indices){
|
|
8
|
+
const clear=256,end=257,bytes=[];let bits=0,bitCount=0,codeSize=9,next=258,table=new Map();
|
|
9
|
+
const write=code=>{bits|=code<<bitCount;bitCount+=codeSize;while(bitCount>=8){bytes.push(bits&255);bits>>>=8;bitCount-=8}};
|
|
10
|
+
const reset=()=>{table=new Map();codeSize=9;next=258};write(clear);let prefix=indices[0]??0;
|
|
11
|
+
for(let position=1;position<indices.length;position++){
|
|
12
|
+
const symbol=indices[position],key=`${prefix},${symbol}`;
|
|
13
|
+
if(table.has(key)){prefix=table.get(key);continue}
|
|
14
|
+
write(prefix);
|
|
15
|
+
if(next<4096){table.set(key,next++);if(next===(1<<codeSize)&&codeSize<12)codeSize++}
|
|
16
|
+
else{write(clear);reset()}
|
|
17
|
+
prefix=symbol;
|
|
18
|
+
}
|
|
19
|
+
write(prefix);write(end);if(bitCount)bytes.push(bits&255);return bytes;
|
|
20
|
+
}
|
|
21
|
+
function blocks(data){const result=[];for(let index=0;index<data.length;index+=255){const block=data.slice(index,index+255);result.push(block.length,...block)}result.push(0);return result;}
|
|
22
|
+
|
|
23
|
+
export default class GifEncoder{
|
|
24
|
+
constructor(width,height,{loop=0}={}){this.width=Math.max(1,Math.trunc(width));this.height=Math.max(1,Math.trunc(height));this.loop=Math.max(0,Math.trunc(loop));this.frames=[];}
|
|
25
|
+
addFrame(imageData,{delay=250}={}){if(imageData.width!==this.width||imageData.height!==this.height)throw new RangeError('GIF frame dimensions must match the encoder.');this.frames.push({pixels:indexPixels(imageData.data),delay:Math.max(2,Math.round(delay/10))});return this.frames.length;}
|
|
26
|
+
encode(){if(!this.frames.length)throw new Error('A GIF requires at least one frame.');const bytes=[...ascii('GIF89a'),...word(this.width),...word(this.height),0xF7,0,0,...palette(),0x21,0xFF,0x0B,...ascii('NETSCAPE2.0'),0x03,0x01,...word(this.loop),0];for(const frame of this.frames){bytes.push(0x21,0xF9,0x04,0x04,...word(frame.delay),0,0,0x2C,0,0,0,0,...word(this.width),...word(this.height),0,8,...blocks(lzw(frame.pixels)))}bytes.push(0x3B);return new Blob([new Uint8Array(bytes)],{type:'image/gif'});}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export {indexPixels,lzw};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
const htmlImportHostRegistryKey=Symbol.for('arcane.html-import.hosts');
|
|
2
|
+
const htmlImportHostRegistry=globalThis[htmlImportHostRegistryKey] instanceof Map
|
|
3
|
+
?globalThis[htmlImportHostRegistryKey]
|
|
4
|
+
:new Map();
|
|
5
|
+
|
|
6
|
+
globalThis[htmlImportHostRegistryKey]=htmlImportHostRegistry;
|
|
7
|
+
|
|
8
|
+
let htmlImportScriptId=0;
|
|
9
|
+
|
|
10
|
+
class HTMLImport extends HTMLElement {
|
|
11
|
+
ready=false;
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
super();
|
|
15
|
+
this.attachShadow({ mode: 'open' });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async connectedCallback() {
|
|
19
|
+
this.ready=false;
|
|
20
|
+
const href=this.getAttribute('href');
|
|
21
|
+
let resolvedHref='';
|
|
22
|
+
if(!href){
|
|
23
|
+
console.log('no href provided for html-import tag',this);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
try{
|
|
28
|
+
const baseURL=new URL(document.baseURI);
|
|
29
|
+
const resolvedURL=new URL(href,baseURL);
|
|
30
|
+
resolvedHref=resolvedURL.href;
|
|
31
|
+
if(resolvedURL.origin!==baseURL.origin){
|
|
32
|
+
throw new Error('HTML imports must use a same-origin URL.');
|
|
33
|
+
}
|
|
34
|
+
const response=await fetch(resolvedURL.href,{
|
|
35
|
+
cache:'default',
|
|
36
|
+
credentials:'same-origin',
|
|
37
|
+
method:'GET',
|
|
38
|
+
redirect:'error'
|
|
39
|
+
});
|
|
40
|
+
await this.#loadHTML(href,resolvedHref,response);
|
|
41
|
+
}catch(err){
|
|
42
|
+
console.error('Error loading HTML component:',err);
|
|
43
|
+
this.dispatchEvent(new CustomEvent('html-import-error',{
|
|
44
|
+
bubbles:true,
|
|
45
|
+
composed:true,
|
|
46
|
+
detail:{
|
|
47
|
+
code:'HTML_IMPORT_FAILED',
|
|
48
|
+
href,
|
|
49
|
+
message:'The component could not be loaded.',
|
|
50
|
+
resolvedHref
|
|
51
|
+
}
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async #loadHTML(href,resolvedHref,response){
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const html = await response.text();
|
|
62
|
+
this.shadowRoot.innerHTML = html;
|
|
63
|
+
|
|
64
|
+
await this.#executeScripts();
|
|
65
|
+
|
|
66
|
+
this.ready=true;
|
|
67
|
+
this.dispatchEvent(new CustomEvent('html-import-ready',{
|
|
68
|
+
bubbles:true,
|
|
69
|
+
composed:true,
|
|
70
|
+
detail:{href,resolvedHref}
|
|
71
|
+
}));
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async #executeScripts() {
|
|
76
|
+
const scripts = Array.from(this.shadowRoot.querySelectorAll('script'));
|
|
77
|
+
for(const script of scripts){
|
|
78
|
+
if (script.src) {
|
|
79
|
+
console.error('ONLY INLINE SCRIPTS SUPPORTED AT THIS TIME FOR SECURITY REASONS');
|
|
80
|
+
console.warn('script src path will need to be limited to ./{text}.js, ../{text}.js), or acceptable sub folders. This can be complex.');
|
|
81
|
+
return;
|
|
82
|
+
//newScript.src = script.src;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const source=(script.textContent||'').replace(
|
|
86
|
+
/\bimport\s*\(\s*(['"])(\.{1,2}\/[^'"]+)\1\s*\)/g,
|
|
87
|
+
(_match,_quote,specifier)=>{
|
|
88
|
+
return `import(${JSON.stringify(new URL(specifier,import.meta.url).href)})`;
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
const executable=document.createElement('script');
|
|
92
|
+
const hostToken=`html-import-${Date.now()}-${htmlImportScriptId++}`;
|
|
93
|
+
|
|
94
|
+
executable.dataset.arcaneHostToken=hostToken;
|
|
95
|
+
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(){${source}}).call(binding.host);})()`;
|
|
96
|
+
script.parentNode.removeChild(script);
|
|
97
|
+
|
|
98
|
+
const binding={host:this,promise:null};
|
|
99
|
+
htmlImportHostRegistry.set(hostToken,binding);
|
|
100
|
+
try{
|
|
101
|
+
document.head.appendChild(executable);
|
|
102
|
+
await binding.promise;
|
|
103
|
+
}finally{
|
|
104
|
+
executable.remove();
|
|
105
|
+
htmlImportHostRegistry.delete(hostToken);
|
|
106
|
+
delete executable.dataset.arcaneHostToken;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
customElements.define('html-import', HTMLImport);
|
|
113
|
+
|
|
114
|
+
export default HTMLImport;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import CommunicationMessage from '../entities/CommunicationMessage.js';
|
|
2
|
+
import CommunicationThread from '../entities/CommunicationThread.js';
|
|
3
|
+
|
|
4
|
+
export default class InMemoryCommunicationProvider{
|
|
5
|
+
constructor({id='demo-provider',label='Demo provider',channels=['other'],threads=[],messages={}}={}){
|
|
6
|
+
this.id=String(id);this.label=String(label);this.channels=Object.freeze(Array.from(channels,String));
|
|
7
|
+
this.threadRecords=Array.from(threads,value=>value instanceof CommunicationThread?value:new CommunicationThread({...value,providerId:this.id}));
|
|
8
|
+
this.messageRecords=new Map(Object.entries(messages).map(([threadId,values])=>[threadId,Array.from(values,item=>item instanceof CommunicationMessage?item:new CommunicationMessage({...item,threadId,providerId:this.id}))]));
|
|
9
|
+
this.sequence=0;
|
|
10
|
+
}
|
|
11
|
+
async listThreads(){return this.threadRecords.map(thread=>new CommunicationThread(thread.toJSON()));}
|
|
12
|
+
async getMessages(threadId){return Array.from(this.messageRecords.get(String(threadId))||[],message=>new CommunicationMessage(message.toJSON()));}
|
|
13
|
+
async send({threadId,channel='other',body,recipients=[]}={}){const id=`demo-outbound-${++this.sequence}`,records=this.messageRecords.get(String(threadId))||[],latest=records.reduce((value,item)=>Math.max(value,new Date(item.timestamp).valueOf()),0),timestamp=new Date(Math.max(Date.now(),latest+1)).toISOString(),message=new CommunicationMessage({id,threadId,providerId:this.id,channel,direction:'outbound',body,recipients,timestamp,status:'sent'});records.push(message);this.messageRecords.set(String(threadId),records);return new CommunicationMessage(message.toJSON());}
|
|
14
|
+
}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
const MODEL_EVIDENCE_KEYS=Object.freeze([
|
|
2
|
+
'id',
|
|
3
|
+
'name',
|
|
4
|
+
'provider',
|
|
5
|
+
'digest',
|
|
6
|
+
'sizeBytes',
|
|
7
|
+
'modifiedAt'
|
|
8
|
+
]);
|
|
9
|
+
const RUN_REQUEST_KEYS=Object.freeze([
|
|
10
|
+
'model',
|
|
11
|
+
'prompt',
|
|
12
|
+
'systemPrompt',
|
|
13
|
+
'options',
|
|
14
|
+
'expectedModel'
|
|
15
|
+
]);
|
|
16
|
+
const RUN_REQUEST_OPTIONAL_KEYS=Object.freeze(['onPhase','think']);
|
|
17
|
+
const THINK_LEVELS=Object.freeze(['low','medium','high']);
|
|
18
|
+
const SENTENCE_BOUNDARY=/[.!?]+(?:["'\u2019\u201d)\]}]+)?(?=\s|$)/gu;
|
|
19
|
+
const WORD_OR_NUMBER=/[\p{L}\p{N}]/u;
|
|
20
|
+
|
|
21
|
+
function codedError(code,message,ErrorType=Error){
|
|
22
|
+
const error=new ErrorType(message);
|
|
23
|
+
error.code=code;
|
|
24
|
+
return error;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function isPlainRecord(value){
|
|
28
|
+
return Boolean(value)
|
|
29
|
+
&&typeof value==='object'
|
|
30
|
+
&&!Array.isArray(value)
|
|
31
|
+
&&Object.getPrototypeOf(value)===Object.prototype;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function hasExactKeys(value,required,optional=[]){
|
|
35
|
+
if(!isPlainRecord(value)){
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
const requiredSet=new Set(required);
|
|
39
|
+
const allowed=new Set([...required,...optional]);
|
|
40
|
+
const keys=Object.keys(value);
|
|
41
|
+
return required.every(function requiredKey(key){return Object.hasOwn(value,key);})
|
|
42
|
+
&&keys.every(function allowedKey(key){return allowed.has(key);})
|
|
43
|
+
&&keys.filter(function requiredKey(key){return requiredSet.has(key);}).length===required.length;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function exactTimestamp(value){
|
|
47
|
+
if(typeof value!=='string'){
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const milliseconds=Date.parse(value);
|
|
51
|
+
if(!Number.isFinite(milliseconds)||new Date(milliseconds).toISOString()!==value){
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
return milliseconds;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function validModifiedAt(value){
|
|
58
|
+
return value===null||(typeof value==='string'&&Number.isFinite(Date.parse(value)));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function validateExpectedModel(model,expectedModel){
|
|
62
|
+
const valid=typeof model==='string'
|
|
63
|
+
&&model.length>0
|
|
64
|
+
&&model===model.trim()
|
|
65
|
+
&&hasExactKeys(expectedModel,MODEL_EVIDENCE_KEYS)
|
|
66
|
+
&&expectedModel.id===model
|
|
67
|
+
&&expectedModel.name===model
|
|
68
|
+
&&expectedModel.provider==='ollama'
|
|
69
|
+
&&/^[a-f0-9]{64}$/i.test(expectedModel.digest)
|
|
70
|
+
&&Number.isSafeInteger(expectedModel.sizeBytes)
|
|
71
|
+
&&expectedModel.sizeBytes>0
|
|
72
|
+
&&validModifiedAt(expectedModel.modifiedAt);
|
|
73
|
+
if(!valid){
|
|
74
|
+
throw codedError(
|
|
75
|
+
'INVALID_ISOLATED_MODEL_RUNNER_REQUEST',
|
|
76
|
+
'The isolated-model request requires exact authoritative model evidence.',
|
|
77
|
+
TypeError
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function sameModelEvidence(actual,expected){
|
|
83
|
+
return hasExactKeys(actual,MODEL_EVIDENCE_KEYS)
|
|
84
|
+
&&MODEL_EVIDENCE_KEYS.every(function matchingField(field){
|
|
85
|
+
return actual[field]===expected[field];
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function validDefaults(value){
|
|
90
|
+
return hasExactKeys(value,['systemPromptPresent','messageCount'])
|
|
91
|
+
&&value.systemPromptPresent===false
|
|
92
|
+
&&value.messageCount===0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function invalidProof(message){
|
|
96
|
+
throw codedError(
|
|
97
|
+
'ARCANE_ISOLATED_MODEL_PROOF_INVALID',
|
|
98
|
+
message||'Arcane Core returned an invalid isolated-model proof.'
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function validateInspection(result,expectedModel,contextTokens){
|
|
103
|
+
if(!hasExactKeys(result,['schemaVersion','model','defaults','admission'])
|
|
104
|
+
||result.schemaVersion!==1
|
|
105
|
+
||!sameModelEvidence(result.model,expectedModel)
|
|
106
|
+
||!validDefaults(result.defaults)
|
|
107
|
+
||!isPlainRecord(result.admission)
|
|
108
|
+
||result.admission.admitted!==true
|
|
109
|
+
||result.admission.contextTokens!==contextTokens){
|
|
110
|
+
invalidProof('Arcane Core returned an invalid isolated-model inspection proof.');
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function validateAbsenceProof(value){
|
|
116
|
+
return hasExactKeys(value,['absent','observedAt','polls'])
|
|
117
|
+
&&value.absent===true
|
|
118
|
+
&&exactTimestamp(value.observedAt)!==null
|
|
119
|
+
&&Number.isSafeInteger(value.polls)
|
|
120
|
+
&&value.polls>0;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function validateIsolation(value){
|
|
124
|
+
if(!hasExactKeys(value,['pre','post','keepAlive','messageCount','defaults'])
|
|
125
|
+
||!validateAbsenceProof(value.pre)
|
|
126
|
+
||!validateAbsenceProof(value.post)
|
|
127
|
+
||exactTimestamp(value.pre.observedAt)>exactTimestamp(value.post.observedAt)
|
|
128
|
+
||value.keepAlive!==0
|
|
129
|
+
||value.messageCount!==2
|
|
130
|
+
||!validDefaults(value.defaults)){
|
|
131
|
+
invalidProof('Arcane Core did not prove the required isolated-model lifecycle.');
|
|
132
|
+
}
|
|
133
|
+
return value;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function validateRunResult(result,expectedModel){
|
|
137
|
+
if(!hasExactKeys(result,[
|
|
138
|
+
'schemaVersion',
|
|
139
|
+
'model',
|
|
140
|
+
'answer',
|
|
141
|
+
'startedAt',
|
|
142
|
+
'completedAt',
|
|
143
|
+
'elapsedMs',
|
|
144
|
+
'isolation'
|
|
145
|
+
])
|
|
146
|
+
||result.schemaVersion!==1
|
|
147
|
+
||!sameModelEvidence(result.model,expectedModel)
|
|
148
|
+
||typeof result.answer!=='string'){
|
|
149
|
+
invalidProof('Arcane Core returned an invalid isolated-model response.');
|
|
150
|
+
}
|
|
151
|
+
const started=exactTimestamp(result.startedAt);
|
|
152
|
+
const completed=exactTimestamp(result.completedAt);
|
|
153
|
+
if(started===null
|
|
154
|
+
||completed===null
|
|
155
|
+
||completed<started
|
|
156
|
+
||!Number.isFinite(result.elapsedMs)
|
|
157
|
+
||result.elapsedMs<0){
|
|
158
|
+
invalidProof('Arcane Core returned invalid isolated-model timing evidence.');
|
|
159
|
+
}
|
|
160
|
+
validateIsolation(result.isolation);
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Counts terminal sentence-punctuation groups and one final unpunctuated
|
|
166
|
+
* fragment. The heuristic is deliberately deterministic and never rewrites
|
|
167
|
+
* the response it observes.
|
|
168
|
+
*/
|
|
169
|
+
function countSentences(value){
|
|
170
|
+
if(typeof value!=='string'){
|
|
171
|
+
throw new TypeError('Sentence counting requires a string.');
|
|
172
|
+
}
|
|
173
|
+
const text=value.trim();
|
|
174
|
+
if(!text){
|
|
175
|
+
return 0;
|
|
176
|
+
}
|
|
177
|
+
let count=0;
|
|
178
|
+
let consumed=0;
|
|
179
|
+
SENTENCE_BOUNDARY.lastIndex=0;
|
|
180
|
+
for(const match of text.matchAll(SENTENCE_BOUNDARY)){
|
|
181
|
+
count+=1;
|
|
182
|
+
consumed=Number(match.index)+match[0].length;
|
|
183
|
+
}
|
|
184
|
+
const trailing=text.slice(consumed).trim();
|
|
185
|
+
if(trailing&&(count===0||WORD_OR_NUMBER.test(trailing))){
|
|
186
|
+
count+=1;
|
|
187
|
+
}
|
|
188
|
+
return count;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function requireLocalAI(localAI){
|
|
192
|
+
if(!localAI
|
|
193
|
+
||typeof localAI.inspectIsolatedModel!=='function'
|
|
194
|
+
||typeof localAI.runIsolatedQuestion!=='function'){
|
|
195
|
+
throw codedError(
|
|
196
|
+
'ARCANE_ISOLATED_MODEL_API_UNAVAILABLE',
|
|
197
|
+
'The Arcane isolated-model API is unavailable. Open this application through a compatible Arcane OS host.'
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
return localAI;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
class IsolatedModelQuestionRunner{
|
|
204
|
+
constructor({localAI,maxSentences=5}={}){
|
|
205
|
+
if(!Number.isSafeInteger(maxSentences)||maxSentences<1||maxSentences>100){
|
|
206
|
+
throw new RangeError('maxSentences must be an integer from 1 through 100.');
|
|
207
|
+
}
|
|
208
|
+
this.localAI=requireLocalAI(localAI);
|
|
209
|
+
this.maxSentences=maxSentences;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async inspectModel(model,expectedModel,contextTokens){
|
|
213
|
+
validateExpectedModel(model,expectedModel);
|
|
214
|
+
if(!Number.isSafeInteger(contextTokens)||contextTokens<1024||contextTokens>262144){
|
|
215
|
+
throw codedError(
|
|
216
|
+
'INVALID_ISOLATED_MODEL_RUNNER_REQUEST',
|
|
217
|
+
'The isolated-model inspection requires a context from 1,024 through 262,144 tokens.',
|
|
218
|
+
RangeError
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
const result=await this.localAI.inspectIsolatedModel({model,expectedModel,contextTokens});
|
|
222
|
+
return validateInspection(result,expectedModel,contextTokens);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async runQuestion(input={}){
|
|
226
|
+
if(!hasExactKeys(input,RUN_REQUEST_KEYS,RUN_REQUEST_OPTIONAL_KEYS)){
|
|
227
|
+
throw codedError(
|
|
228
|
+
'INVALID_ISOLATED_MODEL_RUNNER_REQUEST',
|
|
229
|
+
'The isolated-model question request has unsupported or missing fields.',
|
|
230
|
+
TypeError
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
const {model,prompt,systemPrompt,options,think,expectedModel,onPhase}=input;
|
|
234
|
+
const hasThink=Object.hasOwn(input,'think');
|
|
235
|
+
validateExpectedModel(model,expectedModel);
|
|
236
|
+
if(typeof prompt!=='string'
|
|
237
|
+
||typeof systemPrompt!=='string'
|
|
238
|
+
||!isPlainRecord(options)
|
|
239
|
+
||(hasThink&&!THINK_LEVELS.includes(think))
|
|
240
|
+
||(onPhase!==undefined&&typeof onPhase!=='function')){
|
|
241
|
+
throw codedError(
|
|
242
|
+
'INVALID_ISOLATED_MODEL_RUNNER_REQUEST',
|
|
243
|
+
'The isolated-model question request contains invalid values.',
|
|
244
|
+
TypeError
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
const request={
|
|
248
|
+
model,
|
|
249
|
+
prompt,
|
|
250
|
+
systemPrompt,
|
|
251
|
+
options,
|
|
252
|
+
...(hasThink?{think}:{}),
|
|
253
|
+
expectedModel
|
|
254
|
+
};
|
|
255
|
+
const streamOptions=onPhase===undefined?{}:{onPhase};
|
|
256
|
+
const result=validateRunResult(
|
|
257
|
+
await this.localAI.runIsolatedQuestion(request,streamOptions),
|
|
258
|
+
expectedModel
|
|
259
|
+
);
|
|
260
|
+
const sentenceCount=countSentences(result.answer);
|
|
261
|
+
return Object.freeze({
|
|
262
|
+
answer:result.answer,
|
|
263
|
+
startedAt:result.startedAt,
|
|
264
|
+
completedAt:result.completedAt,
|
|
265
|
+
elapsedMs:result.elapsedMs,
|
|
266
|
+
isolation:result.isolation,
|
|
267
|
+
model:result.model,
|
|
268
|
+
sentenceCount,
|
|
269
|
+
sentenceLimitExceeded:sentenceCount>this.maxSentences
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export {IsolatedModelQuestionRunner,countSentences};
|
|
275
|
+
export default IsolatedModelQuestionRunner;
|