arcane-os 0.1.1 → 0.2.0
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 +17 -0
- package/NOTICE +5 -3
- package/README.md +73 -24
- package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +67 -18
- package/browser-runtime/ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json +16 -5
- package/browser-runtime/ai/browser-kokoro-worker.mjs +3 -0
- package/browser-runtime/ai/browser-speech-artifacts.mjs +1108 -0
- package/browser-runtime/ai/browser-speech-providers.mjs +475 -0
- package/browser-runtime/ai/browser-speech.mjs +9 -0
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +1537 -167
- package/browser-runtime/ai/browser-wasm.mjs +46 -1
- package/browser-runtime/ai/browser-whisper-worker.mjs +3 -0
- package/browser-runtime/ai/browser-wllama-runtime.mjs +677 -132
- package/browser-runtime/ai/model-controller.mjs +138 -12
- package/browser-runtime/ai/speech-worker-client.mjs +207 -0
- package/browser-runtime/ai/speech-worker-runtime.mjs +516 -0
- package/browser-runtime/ai/wllama/index.mjs +389 -0
- package/docs/architecture.md +132 -22
- package/docs/reference/README.md +8 -5
- package/docs/reference/ai/browser-wasm.md +394 -0
- package/docs/reference/availability-and-normalization.md +31 -0
- package/docs/reference/behavioral-testing.md +21 -0
- package/docs/reference/cli.md +4 -4
- package/docs/reference/inventory/package-api.json +84 -4
- package/docs/reference/protocols.md +9 -8
- package/docs/reference/sdk-api.md +238 -4
- package/docs/work-amplification.md +8 -4
- package/package.json +7 -3
- package/runtime/ARCANE_RUNTIME_RELEASE.json +50 -20
- package/runtime/arcane/components/chat.html +280 -62
- package/runtime/arcane/components/speech.html +1113 -265
- package/runtime/arcane/entities/Chat.js +246 -43
- package/runtime/arcane/modules/AI.js +713 -162
- package/runtime/arcane/modules/AIProviderRuntime.js +2289 -0
- package/runtime/arcane/modules/AIRuntimeState.js +872 -0
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +293 -27
- package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +682 -0
- package/runtime/arcane/modules/DocumentLexicalSearch.js +292 -0
- package/runtime/arcane/modules/PersistentAIChatSession.js +268 -0
- package/runtime/arcane/modules/StaticDocumentCatalog.js +25 -206
- package/schemas/arcane-lock.schema.json +6 -4
- package/src/cli/main.mjs +14 -2
- package/src/constants.mjs +1 -1
- package/src/dev-server.mjs +246 -14
- package/src/doctor.mjs +1 -1
- package/src/import-map.mjs +59 -1
- package/src/packager/core.mjs +2 -2
- package/src/runtime.mjs +14 -4
- package/src/sdk-browser-runtime.mjs +28 -75
- package/src/templates/workspace-template.mjs +4 -4
- package/src/toolchain.mjs +3 -0
- package/src/workspace-runtime.mjs +1 -1
- package/src/workspace.mjs +1 -1
package/src/dev-server.mjs
CHANGED
|
@@ -17,6 +17,7 @@ import {verifyRuntime} from './runtime.mjs';
|
|
|
17
17
|
import {verifySdkBrowserRuntime} from './sdk-browser-runtime.mjs';
|
|
18
18
|
import {resolveWorkspace} from './workspace.mjs';
|
|
19
19
|
import {createEventQueue} from './event-queue.mjs';
|
|
20
|
+
import {SDK_NAME,SDK_VERSION} from './constants.mjs';
|
|
20
21
|
|
|
21
22
|
const MIME_TYPES=new Map([
|
|
22
23
|
['.css','text/css; charset=utf-8'],
|
|
@@ -31,6 +32,7 @@ const MIME_TYPES=new Map([
|
|
|
31
32
|
['.png','image/png'],
|
|
32
33
|
['.svg','image/svg+xml; charset=utf-8'],
|
|
33
34
|
['.txt','text/plain; charset=utf-8'],
|
|
35
|
+
['.wasm','application/wasm'],
|
|
34
36
|
['.webp','image/webp'],
|
|
35
37
|
['.woff','font/woff'],
|
|
36
38
|
['.woff2','font/woff2']
|
|
@@ -43,6 +45,17 @@ const SESSION_COOKIE='Arcane-Dev-Session';
|
|
|
43
45
|
const PRIVATE_SOURCE_SEGMENTS=new Set([
|
|
44
46
|
'arcane-app.json','arcane-package.json','test','tests','scripts','node_modules','dist','local'
|
|
45
47
|
]);
|
|
48
|
+
const SDK_RUNTIME_SOURCE_PROTOCOL='arcane-sdk-runtime-source/1';
|
|
49
|
+
const SDK_RUNTIME_SOURCE_ARCANE_ROOTS=new Set([
|
|
50
|
+
'components','css','entities','img','modules','security'
|
|
51
|
+
]);
|
|
52
|
+
const SDK_RUNTIME_SOURCE_PRIVATE_SEGMENTS=new Set([
|
|
53
|
+
'node_modules','.git','.hg','.svn','cvs'
|
|
54
|
+
]);
|
|
55
|
+
const SDK_RUNTIME_SOURCE_PRIVATE_MANIFESTS=new Set([
|
|
56
|
+
'arcane-app.json','arcane-package.json','arcane.lock.json',
|
|
57
|
+
'arcane_app_release.json','arcane_runtime_release.json','arcane_sdk_browser_release.json'
|
|
58
|
+
]);
|
|
46
59
|
|
|
47
60
|
// This server is a loopback-only development host, not a production policy
|
|
48
61
|
// boundary. The bundled runtime currently needs inline component execution,
|
|
@@ -51,7 +64,7 @@ const PRIVATE_SOURCE_SEGMENTS=new Set([
|
|
|
51
64
|
// development CSP from being exposed as a general network service.
|
|
52
65
|
const DEVELOPMENT_CSP=[
|
|
53
66
|
"default-src 'self'",
|
|
54
|
-
"script-src 'self' 'unsafe-inline'",
|
|
67
|
+
"script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval'",
|
|
55
68
|
"style-src 'self' 'unsafe-inline'",
|
|
56
69
|
"img-src 'self' data: blob: http: https:",
|
|
57
70
|
"font-src 'self' data:",
|
|
@@ -138,6 +151,173 @@ function inventoryKey(value){
|
|
|
138
151
|
return process.platform==='win32'?value.toLowerCase():value;
|
|
139
152
|
}
|
|
140
153
|
|
|
154
|
+
function canonicalLocationKey(value){
|
|
155
|
+
return inventoryKey(path.resolve(value));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function pathIsWithin(root,candidate){
|
|
159
|
+
const relative=path.relative(root,candidate);
|
|
160
|
+
return relative===''||(!path.isAbsolute(relative)&&relative!=='..'
|
|
161
|
+
&&!relative.startsWith(`..${path.sep}`));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function pathsOverlap(left,right){
|
|
165
|
+
return pathIsWithin(left,right)||pathIsWithin(right,left);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function canonicalRealDirectory(requested,label){
|
|
169
|
+
let info;
|
|
170
|
+
try{
|
|
171
|
+
info=await lstat(requested);
|
|
172
|
+
}catch{
|
|
173
|
+
fail(`${label} must be an existing real directory.`,'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
174
|
+
}
|
|
175
|
+
if(info.isSymbolicLink()||!info.isDirectory()){
|
|
176
|
+
fail(`${label} must be an existing real directory.`,'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
177
|
+
}
|
|
178
|
+
let canonical;
|
|
179
|
+
try{
|
|
180
|
+
canonical=await realpath(requested);
|
|
181
|
+
}catch{
|
|
182
|
+
fail(`${label} could not be resolved as a real directory.`,'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
183
|
+
}
|
|
184
|
+
if(canonicalLocationKey(canonical)!==canonicalLocationKey(requested)){
|
|
185
|
+
fail(`${label} must not contain a symlink or reparse-point escape.`,'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
186
|
+
}
|
|
187
|
+
return canonical;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function sdkRuntimeSourcePathAllowed(relative,{arcaneRoot=false}={}){
|
|
191
|
+
if(relative.length===0)return false;
|
|
192
|
+
const normalized=relative.map(function normalizeRuntimeSourceSegment(segment){
|
|
193
|
+
return segment.normalize('NFC').toLowerCase();
|
|
194
|
+
});
|
|
195
|
+
if(normalized.some(function runtimeSourceSegmentIsPrivate(segment){
|
|
196
|
+
return segment.startsWith('.')||SDK_RUNTIME_SOURCE_PRIVATE_SEGMENTS.has(segment)
|
|
197
|
+
||SDK_RUNTIME_SOURCE_PRIVATE_MANIFESTS.has(segment);
|
|
198
|
+
}))return false;
|
|
199
|
+
return !arcaneRoot||SDK_RUNTIME_SOURCE_ARCANE_ROOTS.has(normalized[0]);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function sdkArcaneSourcePathAllowed(relative){
|
|
203
|
+
return sdkRuntimeSourcePathAllowed(relative,{arcaneRoot:true});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function sdkDependencySourcePathAllowed(relative){
|
|
207
|
+
return sdkRuntimeSourcePathAllowed(relative);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function sdkBrowserSourcePathAllowed(relative){
|
|
211
|
+
return sdkRuntimeSourcePathAllowed(relative);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async function emitRuntimeSourceEvent(onEvent,event){
|
|
215
|
+
if(typeof onEvent==='function')await onEvent(event);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async function verifySdkRuntimeSourceRoot(sourceRoot,workspaceRoot,appId,{signal,onEvent}={}){
|
|
219
|
+
throwIfAborted(signal);
|
|
220
|
+
if(typeof sourceRoot!=='string'||!sourceRoot.trim()){
|
|
221
|
+
fail('sdkRuntimeSourceRoot must name an Arcane SDK directory.',
|
|
222
|
+
'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
223
|
+
}
|
|
224
|
+
const requestedRoot=path.resolve(sourceRoot);
|
|
225
|
+
await emitRuntimeSourceEvent(onEvent,{
|
|
226
|
+
type:'runtime.source.mount.started',
|
|
227
|
+
appId,
|
|
228
|
+
requestedRoot,
|
|
229
|
+
target:'browser'
|
|
230
|
+
});
|
|
231
|
+
const canonicalRoot=await canonicalRealDirectory(requestedRoot,'SDK runtime source root');
|
|
232
|
+
const canonicalWorkspaceRoot=await realpath(workspaceRoot);
|
|
233
|
+
if(pathsOverlap(canonicalRoot,canonicalWorkspaceRoot)){
|
|
234
|
+
fail('SDK runtime source root must not overlap the application workspace.',
|
|
235
|
+
'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
let packageFile;
|
|
239
|
+
try{
|
|
240
|
+
packageFile=await openSafeFile(canonicalRoot,['package.json']);
|
|
241
|
+
}catch{
|
|
242
|
+
fail('SDK runtime source package.json must be a readable bounded real file.',
|
|
243
|
+
'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
244
|
+
}
|
|
245
|
+
if(!packageFile){
|
|
246
|
+
fail('SDK runtime source root must contain a real package.json.',
|
|
247
|
+
'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
248
|
+
}
|
|
249
|
+
let packageDocument;
|
|
250
|
+
try{
|
|
251
|
+
packageDocument=JSON.parse(packageFile.bytes.toString('utf8'));
|
|
252
|
+
}catch{
|
|
253
|
+
fail('SDK runtime source package.json must be valid JSON.',
|
|
254
|
+
'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
255
|
+
}
|
|
256
|
+
if(!packageDocument||Array.isArray(packageDocument)||packageDocument.name!==SDK_NAME){
|
|
257
|
+
fail(`SDK runtime source package name must be exactly ${SDK_NAME}.`,
|
|
258
|
+
'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
259
|
+
}
|
|
260
|
+
if(packageDocument.version!==SDK_VERSION){
|
|
261
|
+
fail(
|
|
262
|
+
`SDK runtime source version must exactly match the executing SDK (${SDK_VERSION}).`,
|
|
263
|
+
'ARCANE_DEV_RUNTIME_VERSION_MISMATCH'
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const roots=[
|
|
268
|
+
{
|
|
269
|
+
path:'runtime/arcane',
|
|
270
|
+
prefix:['arcane'],
|
|
271
|
+
allow:sdkArcaneSourcePathAllowed
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
path:'runtime/strong-type',
|
|
275
|
+
prefix:['arcane','dependencies','strong-type'],
|
|
276
|
+
allow:sdkDependencySourcePathAllowed
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
path:'browser-runtime',
|
|
280
|
+
prefix:['arcane','sdk'],
|
|
281
|
+
allow:sdkBrowserSourcePathAllowed
|
|
282
|
+
}
|
|
283
|
+
];
|
|
284
|
+
const mappings=[];
|
|
285
|
+
for(let index=0;index<roots.length;index+=1){
|
|
286
|
+
throwIfAborted(signal);
|
|
287
|
+
const root=roots[index];
|
|
288
|
+
const requested=path.join(canonicalRoot,...root.path.split('/'));
|
|
289
|
+
const canonical=await canonicalRealDirectory(requested,`SDK runtime source ${root.path}`);
|
|
290
|
+
if(!pathIsWithin(canonicalRoot,canonical)){
|
|
291
|
+
fail(`SDK runtime source ${root.path} must remain inside the SDK root.`,
|
|
292
|
+
'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
293
|
+
}
|
|
294
|
+
mappings.push({prefix:root.prefix,root:canonical,allow:root.allow});
|
|
295
|
+
await emitRuntimeSourceEvent(onEvent,{
|
|
296
|
+
type:'runtime.source.mount.progress',
|
|
297
|
+
current:index+1,
|
|
298
|
+
total:roots.length,
|
|
299
|
+
path:root.path
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
const runtime=Object.freeze({
|
|
303
|
+
mode:'sdk-source',
|
|
304
|
+
protocol:SDK_RUNTIME_SOURCE_PROTOCOL,
|
|
305
|
+
sdkVersion:SDK_VERSION,
|
|
306
|
+
mutable:true,
|
|
307
|
+
distributionAuthority:false,
|
|
308
|
+
sourceRoot:canonicalRoot
|
|
309
|
+
});
|
|
310
|
+
await emitRuntimeSourceEvent(onEvent,{
|
|
311
|
+
type:'runtime.source.mount.ready',
|
|
312
|
+
appId,
|
|
313
|
+
canonicalRoot,
|
|
314
|
+
sdkVersion:SDK_VERSION,
|
|
315
|
+
protocol:SDK_RUNTIME_SOURCE_PROTOCOL,
|
|
316
|
+
routeCount:mappings.length
|
|
317
|
+
});
|
|
318
|
+
return {mappings,runtime};
|
|
319
|
+
}
|
|
320
|
+
|
|
141
321
|
function identityMap(identities,prefix=''){
|
|
142
322
|
const normalizedPrefix=prefix?`${prefix}/`:'';
|
|
143
323
|
const result=new Map();
|
|
@@ -345,8 +525,34 @@ function sharedPathAllowed(relative,route){
|
|
|
345
525
|
});
|
|
346
526
|
}
|
|
347
527
|
|
|
348
|
-
async function sourceRoutes(workspaceRoot,appId,{
|
|
528
|
+
async function sourceRoutes(workspaceRoot,appId,{
|
|
529
|
+
workspaceRuntimeReceipt,
|
|
530
|
+
sdkRuntimeSourceRoot,
|
|
531
|
+
signal,
|
|
532
|
+
onEvent
|
|
533
|
+
}){
|
|
349
534
|
const resolved=await resolveWorkspace({workspaceRoot,appId});
|
|
535
|
+
const appMapping={
|
|
536
|
+
prefix:['apps',resolved.appId],
|
|
537
|
+
root:resolved.appRoot,
|
|
538
|
+
allow:relative=>sourcePathAllowed(relative,resolved.app.manifest)
|
|
539
|
+
};
|
|
540
|
+
if(sdkRuntimeSourceRoot!==undefined){
|
|
541
|
+
const sdkSource=await verifySdkRuntimeSourceRoot(
|
|
542
|
+
sdkRuntimeSourceRoot,
|
|
543
|
+
resolved.workspaceRoot,
|
|
544
|
+
resolved.appId,
|
|
545
|
+
{signal,onEvent}
|
|
546
|
+
);
|
|
547
|
+
return {
|
|
548
|
+
workspaceRoot:resolved.workspaceRoot,
|
|
549
|
+
workspaceMode:resolved.config.workspaceMode,
|
|
550
|
+
appId:resolved.appId,
|
|
551
|
+
startPath:`/apps/${resolved.appId}/${resolved.app.manifest.entry}`,
|
|
552
|
+
runtime:sdkSource.runtime,
|
|
553
|
+
mappings:[appMapping,...sdkSource.mappings]
|
|
554
|
+
};
|
|
555
|
+
}
|
|
350
556
|
if(resolved.config.workspaceMode==='integrated'){
|
|
351
557
|
return {
|
|
352
558
|
workspaceRoot:resolved.workspaceRoot,
|
|
@@ -354,11 +560,7 @@ async function sourceRoutes(workspaceRoot,appId,{workspaceRuntimeReceipt,signal}
|
|
|
354
560
|
appId:resolved.appId,
|
|
355
561
|
startPath:`/apps/${resolved.appId}/${resolved.app.manifest.entry}`,
|
|
356
562
|
mappings:[
|
|
357
|
-
|
|
358
|
-
prefix:['apps',resolved.appId],
|
|
359
|
-
root:resolved.appRoot,
|
|
360
|
-
allow:relative=>sourcePathAllowed(relative,resolved.app.manifest)
|
|
361
|
-
},
|
|
563
|
+
appMapping,
|
|
362
564
|
...resolved.config.sharedPayloads['browser-runtime'].map(route=>({
|
|
363
565
|
prefix:route.destination.split('/'),
|
|
364
566
|
root:path.join(resolved.workspaceRoot,...route.source.split('/')),
|
|
@@ -410,11 +612,7 @@ async function sourceRoutes(workspaceRoot,appId,{workspaceRuntimeReceipt,signal}
|
|
|
410
612
|
appId:resolved.appId,
|
|
411
613
|
startPath:`/apps/${resolved.appId}/${resolved.app.manifest.entry}`,
|
|
412
614
|
mappings:[
|
|
413
|
-
|
|
414
|
-
prefix:['apps',resolved.appId],
|
|
415
|
-
root:resolved.appRoot,
|
|
416
|
-
allow:relative=>sourcePathAllowed(relative,resolved.app.manifest)
|
|
417
|
-
},
|
|
615
|
+
appMapping,
|
|
418
616
|
{
|
|
419
617
|
prefix:['arcane'],
|
|
420
618
|
root:runtimeRoot,
|
|
@@ -505,18 +703,33 @@ async function startOwnedDevServer({
|
|
|
505
703
|
port=0,
|
|
506
704
|
signal,
|
|
507
705
|
workspaceRuntimeReceipt,
|
|
706
|
+
sdkRuntimeSourceRoot,
|
|
508
707
|
releaseReceipt
|
|
509
708
|
}={},events,releaseSignal){
|
|
510
709
|
throwIfAborted(signal);
|
|
511
710
|
if(mode!=='source'&&mode!=='packaged')fail(`Unsupported server mode: ${String(mode)}.`,'ARCANE_USAGE');
|
|
711
|
+
if(sdkRuntimeSourceRoot!==undefined&&mode!=='source'){
|
|
712
|
+
fail('sdkRuntimeSourceRoot is supported only in source development mode.','ARCANE_USAGE');
|
|
713
|
+
}
|
|
512
714
|
if(host!=='127.0.0.1'&&host!=='::1'){
|
|
513
715
|
fail('Development server host must be a numeric loopback address (127.0.0.1 or ::1).','ARCANE_POLICY_DENIED');
|
|
514
716
|
}
|
|
515
717
|
if(!Number.isInteger(port)||port<0||port>65535)fail('port must be an integer from 0 through 65535.','ARCANE_USAGE');
|
|
516
|
-
|
|
718
|
+
const requestedRuntimeMode=mode==='source'&&sdkRuntimeSourceRoot!==undefined
|
|
719
|
+
?'sdk-source'
|
|
720
|
+
:null;
|
|
721
|
+
await events.send({
|
|
722
|
+
type:'server.starting',
|
|
723
|
+
mode,
|
|
724
|
+
host,
|
|
725
|
+
port,
|
|
726
|
+
appId,
|
|
727
|
+
...(requestedRuntimeMode?{runtimeMode:requestedRuntimeMode}:{})
|
|
728
|
+
});
|
|
517
729
|
const routeSet=mode==='source'
|
|
518
730
|
?await sourceRoutes(workspaceRoot,appId,{
|
|
519
731
|
workspaceRuntimeReceipt,
|
|
732
|
+
sdkRuntimeSourceRoot,
|
|
520
733
|
signal,
|
|
521
734
|
onEvent:event=>events.send(event)
|
|
522
735
|
})
|
|
@@ -646,6 +859,17 @@ async function startOwnedDevServer({
|
|
|
646
859
|
while(requestTasks.size>0){
|
|
647
860
|
await Promise.allSettled([...requestTasks]);
|
|
648
861
|
}
|
|
862
|
+
if(routeSet.runtime?.mode==='sdk-source'){
|
|
863
|
+
await events.send({
|
|
864
|
+
type:'runtime.source.mount.stopped',
|
|
865
|
+
appId:routeSet.appId,
|
|
866
|
+
reason:events.error||operationalError
|
|
867
|
+
?'failed'
|
|
868
|
+
:signal?.aborted
|
|
869
|
+
?'cancelled'
|
|
870
|
+
:'closed'
|
|
871
|
+
});
|
|
872
|
+
}
|
|
649
873
|
await events.send({
|
|
650
874
|
type:'server.stopped',
|
|
651
875
|
host:address.address,
|
|
@@ -694,6 +918,10 @@ async function startOwnedDevServer({
|
|
|
694
918
|
mode,
|
|
695
919
|
workspaceRoot:routeSet.workspaceRoot,
|
|
696
920
|
appId:routeSet.appId,
|
|
921
|
+
...(routeSet.runtime?{
|
|
922
|
+
runtimeMode:routeSet.runtime.mode,
|
|
923
|
+
runtime:routeSet.runtime
|
|
924
|
+
}:{}),
|
|
697
925
|
host:address.address,
|
|
698
926
|
port:address.port,
|
|
699
927
|
origin,
|
|
@@ -710,7 +938,11 @@ async function startOwnedDevServer({
|
|
|
710
938
|
host:result.host,
|
|
711
939
|
port:result.port,
|
|
712
940
|
url,
|
|
713
|
-
appId:result.appId
|
|
941
|
+
appId:result.appId,
|
|
942
|
+
...(routeSet.runtime?{
|
|
943
|
+
runtimeMode:routeSet.runtime.mode,
|
|
944
|
+
runtime:routeSet.runtime
|
|
945
|
+
}:{})
|
|
714
946
|
});
|
|
715
947
|
throwIfAborted(signal);
|
|
716
948
|
}catch(error){
|
package/src/doctor.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import {runProcess} from './process.mjs';
|
|
|
8
8
|
import {ARCANE_PROTOCOL,SDK_VERSION} from './constants.mjs';
|
|
9
9
|
import {ERROR_CODES,ArcaneError,throwIfAborted} from './errors.mjs';
|
|
10
10
|
|
|
11
|
-
const MINIMUM_NODE=[22,
|
|
11
|
+
const MINIMUM_NODE=[22,23,2];
|
|
12
12
|
const WINDOWS_SERVICE_NAME='ArcaneOllama';
|
|
13
13
|
const WINDOWS_SERVICE_HOST='C:\\Program Files\\Ollama\\ArcaneOllamaService.exe';
|
|
14
14
|
const WINDOWS_SERVICE_COMMAND=`"${WINDOWS_SERVICE_HOST}"`;
|
package/src/import-map.mjs
CHANGED
|
@@ -14,15 +14,26 @@ export const MANAGED_IMPORT_MAP_ATTRIBUTE='data-arcane-import-map';
|
|
|
14
14
|
const JAVASCRIPT_EXTENSION=/\.(?:js|mjs)$/u;
|
|
15
15
|
const NODE_ONLY_MODULE='modules/CaseEvidenceIndexer.js';
|
|
16
16
|
const RUNTIME_STRONG_TYPE_IMPORT='../../node_modules/strong-type/index.js';
|
|
17
|
+
const PERSISTENT_CHAT_IMPORT='#arcane/persistent-ai-chat-session';
|
|
18
|
+
const PERSISTENT_CHAT_MODULE='modules/PersistentAIChatSession.js';
|
|
17
19
|
const SDK_BROWSER_ENTRY='sdk/event-manager.mjs';
|
|
18
20
|
const SDK_BROWSER_AI_ENTRY='sdk/ai/browser-wasm.mjs';
|
|
21
|
+
const SDK_BROWSER_SPEECH_ENTRY='sdk/ai/browser-speech.mjs';
|
|
22
|
+
const SDK_BROWSER_SPEECH_WORKER_RUNTIME='sdk/ai/speech-worker-runtime.mjs';
|
|
19
23
|
const SDK_BROWSER_FILES=Object.freeze([
|
|
20
24
|
'sdk/ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json',
|
|
25
|
+
'sdk/ai/browser-kokoro-worker.mjs',
|
|
26
|
+
'sdk/ai/browser-speech-artifacts.mjs',
|
|
27
|
+
'sdk/ai/browser-speech-providers.mjs',
|
|
28
|
+
SDK_BROWSER_SPEECH_ENTRY,
|
|
21
29
|
'sdk/ai/browser-wasm-llm-provider.mjs',
|
|
22
30
|
SDK_BROWSER_AI_ENTRY,
|
|
31
|
+
'sdk/ai/browser-whisper-worker.mjs',
|
|
23
32
|
'sdk/ai/browser-wllama-runtime.mjs',
|
|
24
33
|
'sdk/ai/internal/sha256.mjs',
|
|
25
34
|
'sdk/ai/model-controller.mjs',
|
|
35
|
+
'sdk/ai/speech-worker-client.mjs',
|
|
36
|
+
SDK_BROWSER_SPEECH_WORKER_RUNTIME,
|
|
26
37
|
'sdk/ai/wllama/LICENCE',
|
|
27
38
|
'sdk/ai/wllama/index.mjs',
|
|
28
39
|
'sdk/ai/wllama/llama.cpp-LICENSE',
|
|
@@ -719,6 +730,14 @@ function nonliteralDynamic(importer,offset){
|
|
|
719
730
|
);
|
|
720
731
|
}
|
|
721
732
|
|
|
733
|
+
function isAuthorizedSpeechRuntimeImport(tokens,index,close,importer){
|
|
734
|
+
if(importer!==SDK_BROWSER_SPEECH_WORKER_RUNTIME||close!==index+5)return false;
|
|
735
|
+
const [entry,dot,moduleUrl]=tokens.slice(index+2,close);
|
|
736
|
+
return entry?.type==='identifier'&&entry.value==='entry'
|
|
737
|
+
&&dot?.value==='.'
|
|
738
|
+
&&moduleUrl?.type==='identifier'&&moduleUrl.value==='moduleUrl';
|
|
739
|
+
}
|
|
740
|
+
|
|
722
741
|
export function scanModuleImports(source,{importer='<module>'}={}){
|
|
723
742
|
if(typeof source!=='string')throw new TypeError('scanModuleImports source must be a string.');
|
|
724
743
|
const tokens=tokenize(source);
|
|
@@ -745,6 +764,11 @@ export function scanModuleImports(source,{importer='<module>'}={}){
|
|
|
745
764
|
||commas.length>2
|
|
746
765
|
||(commas.length===2
|
|
747
766
|
&&(commas[1]!==close-1||commas[1]===commas[0]+1))){
|
|
767
|
+
if(isAuthorizedSpeechRuntimeImport(tokens,index,close,importer)){
|
|
768
|
+
hasModuleSyntax=true;
|
|
769
|
+
index=close;
|
|
770
|
+
continue;
|
|
771
|
+
}
|
|
748
772
|
nonliteralDynamic(importer,current.start);
|
|
749
773
|
}
|
|
750
774
|
hasModuleSyntax=true;
|
|
@@ -811,6 +835,20 @@ function unresolved(importer,specifier,normalizedTarget,reason='is not in the sh
|
|
|
811
835
|
}
|
|
812
836
|
|
|
813
837
|
function resolveImport(importer,specifier,files){
|
|
838
|
+
if(specifier===PERSISTENT_CHAT_IMPORT){
|
|
839
|
+
if(!files.has(PERSISTENT_CHAT_MODULE)){
|
|
840
|
+
unresolved(importer,specifier,PERSISTENT_CHAT_MODULE);
|
|
841
|
+
}
|
|
842
|
+
return {target:PERSISTENT_CHAT_MODULE,persistentChat:true};
|
|
843
|
+
}
|
|
844
|
+
if(specifier.startsWith(PERSISTENT_CHAT_IMPORT)){
|
|
845
|
+
unresolved(
|
|
846
|
+
importer,
|
|
847
|
+
specifier,
|
|
848
|
+
PERSISTENT_CHAT_MODULE,
|
|
849
|
+
'does not match the exact browser import-map key'
|
|
850
|
+
);
|
|
851
|
+
}
|
|
814
852
|
const reachableSpecifier=stripQueryAndHash(specifier);
|
|
815
853
|
if(!reachableSpecifier)unresolved(importer,specifier,'<empty>');
|
|
816
854
|
if(reachableSpecifier.includes('%')){
|
|
@@ -966,9 +1004,13 @@ export async function buildImportMap({files,readFile,signal}={}){
|
|
|
966
1004
|
}
|
|
967
1005
|
const hasSdkBrowserGraph=inventory.has(SDK_BROWSER_ENTRY);
|
|
968
1006
|
const hasSdkAiGraph=inventory.has(SDK_BROWSER_AI_ENTRY);
|
|
1007
|
+
const hasSdkSpeechGraph=inventory.has(SDK_BROWSER_SPEECH_ENTRY);
|
|
969
1008
|
if(hasSdkAiGraph&&!hasSdkBrowserGraph){
|
|
970
1009
|
unresolved(SDK_BROWSER_AI_ENTRY,'<authenticated SDK browser closure>',SDK_BROWSER_ENTRY);
|
|
971
1010
|
}
|
|
1011
|
+
if(hasSdkSpeechGraph&&!hasSdkAiGraph){
|
|
1012
|
+
unresolved(SDK_BROWSER_SPEECH_ENTRY,'<authenticated SDK browser closure>',SDK_BROWSER_AI_ENTRY);
|
|
1013
|
+
}
|
|
972
1014
|
if(hasSdkBrowserGraph){
|
|
973
1015
|
for(const required of SDK_BROWSER_FILES){
|
|
974
1016
|
if(!inventory.has(required)){
|
|
@@ -1016,11 +1058,20 @@ export async function buildImportMap({files,readFile,signal}={}){
|
|
|
1016
1058
|
'arcane-os/ai/browser-wasm',
|
|
1017
1059
|
'./arcane/sdk/ai/browser-wasm.mjs'
|
|
1018
1060
|
);
|
|
1061
|
+
registerSpecifier(
|
|
1062
|
+
namedRegistry,
|
|
1063
|
+
'arcane-os/ai/browser-speech',
|
|
1064
|
+
'./arcane/sdk/ai/browser-speech.mjs'
|
|
1065
|
+
);
|
|
1019
1066
|
}
|
|
1020
1067
|
}
|
|
1021
1068
|
|
|
1022
1069
|
const sdkRoots=hasSdkBrowserGraph
|
|
1023
|
-
?[
|
|
1070
|
+
?[
|
|
1071
|
+
SDK_BROWSER_ENTRY,
|
|
1072
|
+
...(hasSdkAiGraph?[SDK_BROWSER_AI_ENTRY]:[]),
|
|
1073
|
+
...(hasSdkSpeechGraph?[SDK_BROWSER_SPEECH_ENTRY]:[]),
|
|
1074
|
+
]:[];
|
|
1024
1075
|
const queue=[...roots,...sdkRoots];
|
|
1025
1076
|
const reached=new Set();
|
|
1026
1077
|
const entities=new Set();
|
|
@@ -1036,6 +1087,13 @@ export async function buildImportMap({files,readFile,signal}={}){
|
|
|
1036
1087
|
const resolution=resolveImport(importer,imported.specifier,inventory);
|
|
1037
1088
|
if(resolution.runtimeStrongType)usesRuntimeStrongType=true;
|
|
1038
1089
|
if(resolution.eventPubSub)usesEventPubSub=true;
|
|
1090
|
+
if(resolution.persistentChat){
|
|
1091
|
+
registerSpecifier(
|
|
1092
|
+
namedRegistry,
|
|
1093
|
+
PERSISTENT_CHAT_IMPORT,
|
|
1094
|
+
'./arcane/modules/PersistentAIChatSession.js'
|
|
1095
|
+
);
|
|
1096
|
+
}
|
|
1039
1097
|
if(resolution.target.startsWith('entities/'))entities.add(resolution.target);
|
|
1040
1098
|
if(!reached.has(resolution.target))queue.push(resolution.target);
|
|
1041
1099
|
}
|
package/src/packager/core.mjs
CHANGED
|
@@ -1036,7 +1036,7 @@ function packagedRuntimeAuthorities(receipt){
|
|
|
1036
1036
|
||!Number.isSafeInteger(receipt.fileCount)||receipt.fileCount<1
|
|
1037
1037
|
||!Number.isSafeInteger(receipt.totalBytes)||receipt.totalBytes<1
|
|
1038
1038
|
||!SHA256_PATTERN.test(receipt.contentSha256??'')
|
|
1039
|
-
||!isPlainObject(arcane)||arcane.authority!=='arcane-os-
|
|
1039
|
+
||!isPlainObject(arcane)||arcane.authority!=='arcane-os-sdk'
|
|
1040
1040
|
||!SHA256_PATTERN.test(arcane.manifestSha256??'')
|
|
1041
1041
|
||!SHA256_PATTERN.test(arcane.contentSha256??'')
|
|
1042
1042
|
||!isPlainObject(arcane.source)
|
|
@@ -1158,7 +1158,7 @@ async function authenticatePackageRuntimeVerificationState(context,state,{signal
|
|
|
1158
1158
|
});
|
|
1159
1159
|
const workspaceReceipt=snapshot.workspaceRuntimeReceipt;
|
|
1160
1160
|
const expectedArcaneSource={
|
|
1161
|
-
authority:'arcane-os-
|
|
1161
|
+
authority:'arcane-os-sdk',
|
|
1162
1162
|
location:snapshot.runtimeReceipt.canonicalLocation,
|
|
1163
1163
|
manifestSha256:snapshot.runtimeReceipt.manifestSha256,
|
|
1164
1164
|
contentSha256:snapshot.runtimeReceipt.contentSha256,
|
package/src/runtime.mjs
CHANGED
|
@@ -7,6 +7,8 @@ import {SDK_VERSION} from './constants.mjs';
|
|
|
7
7
|
|
|
8
8
|
export const RUNTIME_MANIFEST_NAME='ARCANE_RUNTIME_RELEASE.json';
|
|
9
9
|
const SHA256_PATTERN=/^[a-f0-9]{64}$/;
|
|
10
|
+
const SDK_RUNTIME_REPOSITORY='https://github.com/TheWizardNexus/arcane-os-sdk.git';
|
|
11
|
+
const LEGACY_ARCANE_REPOSITORY='https://github.com/TheWizardNexus/ARCANE-OS.git';
|
|
10
12
|
const READ_ONLY_NO_FOLLOW=FS_CONSTANTS.O_RDONLY|(FS_CONSTANTS.O_NOFOLLOW??0);
|
|
11
13
|
const MAX_VERIFIED_RUNTIME_FILE_BYTES=64*1024*1024;
|
|
12
14
|
const sdkRoot=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
|
|
@@ -59,10 +61,18 @@ function validateRelease(value){
|
|
|
59
61
|
}
|
|
60
62
|
if(value.sdkVersion!==SDK_VERSION)fail('Runtime manifest sdkVersion is incompatible with this SDK.');
|
|
61
63
|
if(!value.source||typeof value.source!=='object'
|
|
62
|
-
||Object.keys(value.source).sort(compareText).join('\0')!=='
|
|
63
|
-
||value.source.
|
|
64
|
-
||
|
|
65
|
-
||value.source.
|
|
64
|
+
||Object.keys(value.source).sort(compareText).join('\0')!=='authority\0legacyProjection\0path\0protocol\0repository'
|
|
65
|
+
||value.source.authority!=='sdk-canonical'
|
|
66
|
+
||value.source.repository!==SDK_RUNTIME_REPOSITORY
|
|
67
|
+
||value.source.path!=='runtime/arcane'
|
|
68
|
+
||value.source.protocol!=='arcane/1'
|
|
69
|
+
||!value.source.legacyProjection
|
|
70
|
+
||typeof value.source.legacyProjection!=='object'
|
|
71
|
+
||Object.keys(value.source.legacyProjection).sort(compareText).join('\0')!=='bundleVersion\0commit\0repository'
|
|
72
|
+
||value.source.legacyProjection.repository!==LEGACY_ARCANE_REPOSITORY
|
|
73
|
+
||typeof value.source.legacyProjection.commit!=='string'
|
|
74
|
+
||!/^[a-f0-9]{40}$/.test(value.source.legacyProjection.commit)
|
|
75
|
+
||value.source.legacyProjection.bundleVersion!=='0.8.12'){
|
|
66
76
|
fail('Runtime manifest source identity is invalid.');
|
|
67
77
|
}
|
|
68
78
|
if(!Array.isArray(value.files)||!Number.isSafeInteger(value.fileCount)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {createHash} from 'node:crypto';
|
|
2
2
|
import {constants as FS_CONSTANTS} from 'node:fs';
|
|
3
|
-
import {lstat,open,readdir,realpath} from 'node:fs/promises';
|
|
3
|
+
import {lstat,open,readFile,readdir,realpath} from 'node:fs/promises';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import {fileURLToPath} from 'node:url';
|
|
6
6
|
import {SDK_VERSION} from './constants.mjs';
|
|
@@ -8,96 +8,49 @@ import {SDK_VERSION} from './constants.mjs';
|
|
|
8
8
|
const MANIFEST_NAME='ARCANE_SDK_BROWSER_RELEASE.json';
|
|
9
9
|
const BUILDER='arcane-sdk-browser-runtime-v1';
|
|
10
10
|
const PROTOCOL='arcane-sdk-browser-runtime/1';
|
|
11
|
-
export const SDK_BROWSER_RUNTIME_MANIFEST_SHA256=
|
|
12
|
-
'33396b3d35322b784929270e7ca0a2a8b31d899c6e77bcb227edc95b37d0ae7d';
|
|
13
|
-
export const SDK_BROWSER_RUNTIME_CONTENT_SHA256=
|
|
14
|
-
'5e03f45a732db51cb5a2b2193cc79ecda34501d07a9b2e82e794e5fa37d55d00';
|
|
15
11
|
const REPOSITORY='https://github.com/TheWizardNexus/arcane-os-sdk.git';
|
|
16
12
|
const SHA256_PATTERN=/^[a-f0-9]{64}$/u;
|
|
17
13
|
const READ_ONLY_NO_FOLLOW=FS_CONSTANTS.O_RDONLY|(FS_CONSTANTS.O_NOFOLLOW??0);
|
|
18
14
|
const MAX_VERIFIED_FILE_BYTES=64*1024*1024;
|
|
19
15
|
const packageRoot=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
|
|
20
16
|
const defaultRoot=path.join(packageRoot,'browser-runtime');
|
|
17
|
+
const canonicalManifestBytes=await readFile(path.join(defaultRoot,MANIFEST_NAME));
|
|
18
|
+
const canonicalRelease=JSON.parse(canonicalManifestBytes.toString('utf8'));
|
|
19
|
+
if(
|
|
20
|
+
canonicalRelease?.schemaVersion!==1
|
|
21
|
+
||canonicalRelease.builder!==BUILDER
|
|
22
|
+
||canonicalRelease.sdkVersion!==SDK_VERSION
|
|
23
|
+
||!SHA256_PATTERN.test(canonicalRelease.contentSha256)
|
|
24
|
+
){
|
|
25
|
+
throw new Error('The canonical SDK browser runtime receipt is invalid.');
|
|
26
|
+
}
|
|
27
|
+
export const SDK_BROWSER_RUNTIME_MANIFEST_SHA256=
|
|
28
|
+
createHash('sha256').update(canonicalManifestBytes).digest('hex');
|
|
29
|
+
export const SDK_BROWSER_RUNTIME_CONTENT_SHA256=canonicalRelease.contentSha256;
|
|
21
30
|
const issuedReceipts=new WeakSet();
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
runtimePolicy:{
|
|
29
|
-
modelAuthorities:'caller-supplied-exact-bytes-and-sha256',
|
|
30
|
-
modelWeightsPacked:false,
|
|
31
|
-
remoteModelHelpers:false,
|
|
32
|
-
compatibilityRuntime:false,
|
|
33
|
-
toolCalls:'structural-only-never-executed'
|
|
34
|
-
},
|
|
35
|
-
components:[
|
|
36
|
-
{
|
|
37
|
-
name:'@wllama/wllama',
|
|
38
|
-
version:'3.6.0',
|
|
39
|
-
licenseSpdx:'MIT',
|
|
40
|
-
sourceRepository:'https://github.com/ngxson/wllama.git',
|
|
41
|
-
sourceRevision:'f16050d8d51a00602c6a2a6b8ac9c09f490eea7f',
|
|
42
|
-
npm:{
|
|
43
|
-
resolved:'https://registry.npmjs.org/@wllama/wllama/-/wllama-3.6.0.tgz',
|
|
44
|
-
integrity:'sha512-NN3ZBXqaaUwGXTQubkNvsCaLPjN2XVa0bVS40OYCE8zquYmRc2W3oHYEgwvuSWWDB8aUqTLyMioySCXNkcnD1w==',
|
|
45
|
-
tarballBytes:5671369,
|
|
46
|
-
tarballSha256:'137c35ceccb4911a9b0ce9b427889f75991654ec6a6d1dd8fabd879b14b07a1b'
|
|
47
|
-
},
|
|
48
|
-
files:[
|
|
49
|
-
{
|
|
50
|
-
role:'runtime-module',
|
|
51
|
-
path:'ai/wllama/index.mjs',
|
|
52
|
-
sourcePath:'node_modules/@wllama/wllama/esm/index.js',
|
|
53
|
-
bytes:373519,
|
|
54
|
-
sha256:'4637e42d636010493a9b274fbbe70bfd8120365da726b1d9e589d85ca84a00d6'
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
role:'runtime-wasm',
|
|
58
|
-
path:'ai/wllama/wllama.wasm',
|
|
59
|
-
sourcePath:'node_modules/@wllama/wllama/esm/wasm/wllama.wasm',
|
|
60
|
-
bytes:8524865,
|
|
61
|
-
sha256:'95c6ff9ef2a03ff2c63bc91db132f0126a0bd0456b272cd8ae2e0f592fb059f6'
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
role:'license',
|
|
65
|
-
path:'ai/wllama/LICENCE',
|
|
66
|
-
sourcePath:'node_modules/@wllama/wllama/LICENCE',
|
|
67
|
-
bytes:1071,
|
|
68
|
-
sha256:'5866e3bd7e3cbd3f7c8bea6efd8a1e7fa7cc8de68c30f428aff7c6584a0fb720'
|
|
69
|
-
}
|
|
70
|
-
]
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
name:'llama.cpp',
|
|
74
|
-
version:'b10454',
|
|
75
|
-
licenseSpdx:'MIT',
|
|
76
|
-
sourceRepository:'https://github.com/ggerganov/llama.cpp.git',
|
|
77
|
-
sourceRevision:'4df29be4f4c3673f428170fda944a5b19f743bb8',
|
|
78
|
-
embeddedBy:'@wllama/wllama@3.6.0',
|
|
79
|
-
files:[
|
|
80
|
-
{
|
|
81
|
-
role:'license',
|
|
82
|
-
path:'ai/wllama/llama.cpp-LICENSE',
|
|
83
|
-
sourceUrl:'https://raw.githubusercontent.com/ggerganov/llama.cpp/4df29be4f4c3673f428170fda944a5b19f743bb8/LICENSE',
|
|
84
|
-
bytes:1078,
|
|
85
|
-
sha256:'94f29bbed6a22c35b992c5c6ebf0e7c92f13b836b90f36f461c9cf2f0f1d010d'
|
|
86
|
-
}
|
|
87
|
-
]
|
|
88
|
-
}
|
|
89
|
-
]
|
|
90
|
-
});
|
|
31
|
+
const canonicalAiComponentsBytes=await readFile(
|
|
32
|
+
path.join(defaultRoot,'ai','ARCANE_AI_BROWSER_WASM_COMPONENTS.json')
|
|
33
|
+
);
|
|
34
|
+
const expectedAiComponents=Object.freeze(
|
|
35
|
+
JSON.parse(canonicalAiComponentsBytes.toString('utf8'))
|
|
36
|
+
);
|
|
91
37
|
|
|
92
38
|
const expectedFiles=Object.freeze([
|
|
93
39
|
['ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json','browser-runtime/ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json','sdk-source-identity'],
|
|
40
|
+
['ai/browser-kokoro-worker.mjs','browser-runtime/ai/browser-kokoro-worker.mjs','sdk-source-identity'],
|
|
41
|
+
['ai/browser-speech-artifacts.mjs','browser-runtime/ai/browser-speech-artifacts.mjs','sdk-source-identity'],
|
|
42
|
+
['ai/browser-speech-providers.mjs','browser-runtime/ai/browser-speech-providers.mjs','sdk-source-identity'],
|
|
43
|
+
['ai/browser-speech.mjs','browser-runtime/ai/browser-speech.mjs','sdk-source-identity'],
|
|
94
44
|
['ai/browser-wasm-llm-provider.mjs','browser-runtime/ai/browser-wasm-llm-provider.mjs','sdk-source-identity'],
|
|
95
45
|
['ai/browser-wasm.mjs','browser-runtime/ai/browser-wasm.mjs','sdk-source-identity'],
|
|
46
|
+
['ai/browser-whisper-worker.mjs','browser-runtime/ai/browser-whisper-worker.mjs','sdk-source-identity'],
|
|
96
47
|
['ai/browser-wllama-runtime.mjs','browser-runtime/ai/browser-wllama-runtime.mjs','sdk-source-identity'],
|
|
97
48
|
['ai/internal/sha256.mjs','browser-runtime/ai/internal/sha256.mjs','sdk-source-identity'],
|
|
98
49
|
['ai/model-controller.mjs','browser-runtime/ai/model-controller.mjs','sdk-source-identity'],
|
|
50
|
+
['ai/speech-worker-client.mjs','browser-runtime/ai/speech-worker-client.mjs','sdk-source-identity'],
|
|
51
|
+
['ai/speech-worker-runtime.mjs','browser-runtime/ai/speech-worker-runtime.mjs','sdk-source-identity'],
|
|
99
52
|
['ai/wllama/LICENCE','node_modules/@wllama/wllama/LICENCE','vendor-package-identity'],
|
|
100
|
-
['ai/wllama/index.mjs','
|
|
53
|
+
['ai/wllama/index.mjs','browser-runtime/ai/wllama/index.mjs','deterministic-derived-vendor'],
|
|
101
54
|
['ai/wllama/llama.cpp-LICENSE','browser-runtime/ai/wllama/llama.cpp-LICENSE','vendor-source-identity'],
|
|
102
55
|
['ai/wllama/wllama.wasm','node_modules/@wllama/wllama/esm/wasm/wllama.wasm','vendor-package-identity'],
|
|
103
56
|
['dependencies/event-pubsub/index.js','node_modules/event-pubsub/index.js','vendor-package-identity'],
|