arcane-os 0.68.0 → 0.70.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +9 -4
  3. package/browser-runtime/ai/browser-decisions.mjs +46 -2
  4. package/browser-runtime/ai/browser-speech-artifacts.mjs +58 -62
  5. package/browser-runtime/ai/browser-speech-providers.mjs +8 -3
  6. package/browser-runtime/ai/browser-wasm-llm-provider.mjs +76 -164
  7. package/browser-runtime/ai/dbopfs-model-parts.mjs +344 -0
  8. package/browser-runtime/ai/dbopfs-model-resources.mjs +190 -0
  9. package/browser-runtime/ai/decision-runtime.mjs +17 -1
  10. package/browser-runtime/ai/decision-worker.mjs +21 -1
  11. package/browser-runtime/ai/model-resource-bridge.mjs +231 -0
  12. package/browser-runtime/ai/speech-worker-client.mjs +68 -28
  13. package/browser-runtime/ai/speech-worker-runtime.mjs +212 -97
  14. package/browser-runtime/core/contracts.mjs +1 -1
  15. package/docs/reference/README.md +2 -0
  16. package/docs/reference/ai/browser-decisions.md +57 -3
  17. package/docs/reference/ai/browser-speech.md +94 -26
  18. package/docs/reference/ai/browser-wasm.md +28 -20
  19. package/docs/reference/core-native-packaging.md +54 -0
  20. package/docs/reference/core-runtime.md +9 -0
  21. package/docs/reference/core-shared-host.md +190 -0
  22. package/docs/reference/inventory/package-api.json +3 -3
  23. package/docs/reference/inventory/runtime-modules.json +3 -3
  24. package/docs/reference/runtime-components.md +4 -2
  25. package/docs/reference/runtime-modules.md +120 -20
  26. package/docs/reference/sdk-api.md +64 -30
  27. package/package.json +2 -2
  28. package/runtime/arcane/components/theme-switcher.html +1 -1
  29. package/runtime/arcane/modules/AI.js +7 -22
  30. package/runtime/arcane/modules/AIProviderRuntime.js +84 -6
  31. package/runtime/arcane/modules/DBOPFS.js +180 -26
  32. package/schemas/arcane-app.schema.json +10 -0
  33. package/src/app-descriptor.mjs +23 -1
  34. package/src/core/host.mjs +2 -0
  35. package/src/core/hosts/windows/ArcaneHost.cs +46 -0
  36. package/src/core/hosts/windows/ArcaneLauncher.cs +21 -0
  37. package/src/core/runtime.mjs +9 -4
  38. package/src/core/services/packaged-web.mjs +8 -1
  39. package/src/core/shared-host.mjs +500 -0
  40. package/src/native/portable-layout.mjs +66 -34
  41. package/src/native/portable-provider.mjs +1 -0
@@ -9,6 +9,7 @@ const is = new Is(false);
9
9
  export const SDK_ROOT = fileURLToPath(new URL('../../', import.meta.url));
10
10
  export const CORE_FILES = [
11
11
  'src/core/host.mjs',
12
+ 'src/core/shared-host.mjs',
12
13
  'src/core/runtime.mjs',
13
14
  'src/core/stdio.mjs',
14
15
  'src/event-manager.mjs',
@@ -161,11 +162,11 @@ export function coreEntrySource(application, version, services, {localAI, runtim
161
162
  }) ?? false;
162
163
  const imports = services.map(function serviceImport(service, index) {
163
164
  const specifier = '../app/' + service.module.split('/').map(encodeURIComponent).join('/');
164
- return `import createService${index} from ${JSON.stringify(specifier)};`;
165
+ return {binding: `{default: createService${index}}`, specifier};
165
166
  });
166
167
  // JSON parsing retains authored field names that have object-literal syntax.
167
168
  const definitions = services.map(function serviceDefinition(service, index) {
168
- return ` createService${index}(JSON.parse(${JSON.stringify(JSON.stringify(service.options === undefined ? {} : service.options))}), context)`;
169
+ return ` register(createService${index}(JSON.parse(${JSON.stringify(JSON.stringify(service.options === undefined ? {} : service.options))}), context));`;
169
170
  });
170
171
  if (localAI !== undefined) {
171
172
  const chatConfiguration = {
@@ -175,31 +176,30 @@ export function coreEntrySource(application, version, services, {localAI, runtim
175
176
  return id !== 'stable-diffusion.cpp' && id !== 'whisper.cpp';
176
177
  })
177
178
  };
178
- imports.push("import {createLocalAIService} from 'arcane-os/core/local-ai';");
179
- definitions.push(` createLocalAIService(JSON.parse(${JSON.stringify(JSON.stringify(chatConfiguration))}), context)`);
179
+ imports.push({binding: '{createLocalAIService}', specifier: 'arcane-os/core/local-ai'});
180
+ definitions.push(` register(createLocalAIService(JSON.parse(${JSON.stringify(JSON.stringify(chatConfiguration))}), context));`);
180
181
  }
181
182
  if (modelAssetsSelected) {
182
- imports.push("import {createModelAssetService} from 'arcane-os/core/model-assets';");
183
- definitions.push(' modelAssets');
183
+ imports.push({binding: '{createModelAssetService}', specifier: 'arcane-os/core/model-assets'});
184
184
  }
185
185
  if (imageSelected) {
186
- imports.push("import {createLocalImageService} from 'arcane-os/core/image';");
187
- definitions.push(` createLocalImageService(JSON.parse(${JSON.stringify(JSON.stringify(localAI))}), {...context, modelAssets})`);
186
+ imports.push({binding: '{createLocalImageService}', specifier: 'arcane-os/core/image'});
187
+ definitions.push(` register(createLocalImageService(JSON.parse(${JSON.stringify(JSON.stringify(localAI))}), {...context, modelAssets}));`);
188
188
  }
189
189
  if (whisperSelected) {
190
- imports.push("import path from 'node:path';");
191
- imports.push("import {createSpeechService} from 'arcane-os/core/speech';");
192
- imports.push("import {createWhisperRuntime} from 'arcane-os/local-ai/whisper';");
193
- definitions.push(' createSpeechService({stt, signal: context.signal})');
190
+ imports.push({binding: '{createSpeechService}', specifier: 'arcane-os/core/speech'});
191
+ imports.push({binding: '{createWhisperRuntime}', specifier: 'arcane-os/local-ai/whisper'});
194
192
  }
195
193
  if (packagedWeb) {
196
- imports.push("import {createPackagedWebService} from 'arcane-os/core/packaged-web';");
197
- definitions.push(" createPackagedWebService({artifactRoot: fileURLToPath(new URL('../', import.meta.url))}, context)");
194
+ imports.push({binding: '{createPackagedWebService}', specifier: 'arcane-os/core/packaged-web'});
195
+ definitions.push(" packagedWeb = createPackagedWebService({artifactRoot: fileURLToPath(new URL('../', import.meta.url))}, context);",
196
+ ' register(packagedWeb);');
198
197
  }
199
198
  return [
200
199
  "import {fileURLToPath} from 'node:url';",
201
- "import {readCoreLaunchContext, startCoreHost} from 'arcane-os/core/host';",
202
- ...imports,
200
+ "import path from 'node:path';",
201
+ "import {isSea} from 'node:sea';",
202
+ "import {readCoreLaunchContext, startCoreHost, runSharedCoreHost, startSharedCoreBridge} from 'arcane-os/core/host';",
203
203
  '',
204
204
  ...(localAI === undefined ? [] : [
205
205
  '// Bundled runtime paths are artifact-root-relative POSIX paths.',
@@ -244,30 +244,62 @@ export function coreEntrySource(application, version, services, {localAI, runtim
244
244
  ' ...await readCoreLaunchContext()',
245
245
  '};',
246
246
  '',
247
- ...(modelAssetsSelected ? ['const modelAssets = createModelAssetService({appRoot: context.appRoot});', ''] : []),
247
+ ...(packagedWeb ? ['let packagedWeb;', ''] : []),
248
+ 'async function createServices(register) {',
249
+ ` const [${imports.map(function binding(selection) { return selection.binding; }).join(', ')}] = await Promise.all([`,
250
+ ...imports.map(function importService(selection) { return ` import(${JSON.stringify(selection.specifier)})`; }).map(
251
+ function separateImport(line, index) { return line + (index < imports.length - 1 ? ',' : ''); }
252
+ ),
253
+ ' ]);',
254
+ ...(modelAssetsSelected ? [' const modelAssets = createModelAssetService({appRoot: context.appRoot});', ' register(modelAssets);'] : []),
248
255
  ...(whisperSelected ? [
249
- 'const stt = createWhisperRuntime(',
250
- ' {',
251
- ' runtime: context.runtimes.find(function selectedWhisperRuntime(runtime) {',
252
- " return runtime.id === 'whisper.cpp';",
253
- ' }),',
254
- " temporaryDirectory: path.join(context.stateRoot ?? path.join(context.appRoot, '.arcane'), 'speech', 'whisper'),",
255
- ' onEvent: context.onEvent',
256
- ' }',
257
- ');',
258
- ''
256
+ ' const stt = createWhisperRuntime(',
257
+ ' {',
258
+ ' runtime: context.runtimes.find(function selectedWhisperRuntime(runtime) {',
259
+ " return runtime.id === 'whisper.cpp';",
260
+ ' }),',
261
+ " temporaryDirectory: path.join(context.stateRoot ?? path.join(context.appRoot, '.arcane'), 'speech', 'whisper'),",
262
+ ' onEvent: context.onEvent',
263
+ ' }',
264
+ ' );',
265
+ ' register(createSpeechService({stt, signal: context.signal}));'
259
266
  ] : []),
260
- 'const host = startCoreHost({',
261
- ` application: JSON.parse(${JSON.stringify(JSON.stringify(application))}),`,
262
- ` version: ${JSON.stringify(version)},`,
263
- ` services: [\n${definitions.join(',\n')}\n ]`,
264
- '});',
267
+ ...definitions,
268
+ '}',
269
+ `const application = JSON.parse(${JSON.stringify(JSON.stringify(application))});`,
270
+ `const version = ${JSON.stringify(version)};`,
271
+ 'let host;',
272
+ 'if (context.sharedHost === undefined) {',
273
+ ' const services = [];',
274
+ ' await createServices(function register(service) { services.push(service); });',
275
+ ' host = startCoreHost({application, version, services});',
276
+ "} else if (process.argv.includes('--arcane-core-headless')) {",
277
+ ' host = await runSharedCoreHost({',
278
+ ' endpoint: context.sharedHost.endpoint, application, version,',
279
+ ' configure(runtime) { return createServices(function register(service) { runtime.registerService(service); }); },',
280
+ ...(packagedWeb ? [
281
+ ' getReplayEvents() {',
282
+ ' const current = packagedWeb?.current();',
283
+ " return current ? [{event: 'core.web.ready', data: current}] : [];",
284
+ ' }'
285
+ ] : []),
286
+ ' });',
287
+ '} else {',
288
+ ' host = await startSharedCoreBridge({',
289
+ ' endpoint: context.sharedHost.endpoint,',
290
+ ' start: {',
291
+ ' command: process.execPath,',
292
+ " args: [...(isSea() ? [] : [fileURLToPath(import.meta.url)]), ...process.argv.slice(2), '--arcane-core-headless'],",
293
+ ' logFile: context.sharedHost.logFile',
294
+ ' }',
295
+ ' });',
296
+ '}',
265
297
  '',
266
- 'function closeCore() { host.close(); }',
298
+ 'function closeCore() { host?.close(); }',
267
299
  "process.on('SIGINT', closeCore);",
268
300
  "process.on('SIGTERM', closeCore);",
269
301
  'try {',
270
- ' await host.closed;',
302
+ ' await host?.closed;',
271
303
  '} catch (error) {',
272
304
  " console.error('Arcane Core host failed:', error);",
273
305
  ' process.exitCode = 1;',
@@ -196,6 +196,7 @@ export function createPortableNativeProvider({services, packagedWeb = false, web
196
196
  target,
197
197
  webRoot: 'app',
198
198
  start: release.manifest?.app?.start ?? './index.html',
199
+ ...(appDescriptor.native?.window === undefined ? {} : {window: {...appDescriptor.native.window}}),
199
200
  core: {
200
201
  entry: 'runtime/arcane-core.mjs', transport: 'stdio', protocol: 'arcane/1', services: selectedServices,
201
202
  ...(localAI === undefined ? {} : {localAIRuntimes: bundled.runtimes})