arcane-os 0.56.0 → 0.58.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 (75) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +6 -2
  3. package/browser-runtime/ai/core-local.mjs +306 -0
  4. package/browser-runtime/ai/core-onnx.mjs +96 -0
  5. package/browser-runtime/ai/onnx-tensors.mjs +85 -0
  6. package/browser-runtime/core/client.mjs +151 -16
  7. package/docs/architecture.md +5 -2
  8. package/docs/platform-targets.md +30 -13
  9. package/docs/reference/README.md +38 -3
  10. package/docs/reference/availability-and-normalization.md +9 -6
  11. package/docs/reference/cli.md +29 -9
  12. package/docs/reference/core-client.md +80 -0
  13. package/docs/reference/core-native-packaging.md +304 -12
  14. package/docs/reference/core-preferences.md +49 -0
  15. package/docs/reference/diarization.md +206 -0
  16. package/docs/reference/git-text-snapshot.md +104 -0
  17. package/docs/reference/inventory/package-api.json +330 -22
  18. package/docs/reference/local-ai.md +331 -0
  19. package/docs/reference/protocols.md +97 -20
  20. package/docs/reference/pwa.md +5 -2
  21. package/docs/reference/runtime-modules.md +6 -5
  22. package/docs/reference/sdk-api.md +611 -63
  23. package/package.json +15 -3
  24. package/runtime/arcane/modules/LocalAIReadiness.js +3 -1
  25. package/schemas/arcane-app.schema.json +55 -1
  26. package/schemas/arcane-package.schema.json +44 -0
  27. package/schemas/native-build-plan.schema.json +27 -1
  28. package/schemas/target-adapter.schema.json +2 -0
  29. package/src/app-descriptor.mjs +18 -2
  30. package/src/cli/main.mjs +20 -4
  31. package/src/constants.mjs +2 -0
  32. package/src/core/host.mjs +23 -0
  33. package/src/core/hosts/macos/ArcaneCoreProcess.h +85 -0
  34. package/src/core/hosts/macos/ArcaneCoreProcess.m +357 -0
  35. package/src/core/hosts/macos/ArcaneHost.h +86 -0
  36. package/src/core/hosts/macos/ArcaneHost.m +455 -0
  37. package/src/core/hosts/macos/ArcaneLauncher.m +432 -0
  38. package/src/core/hosts/windows/ArcaneCoreProcess.cs +3 -3
  39. package/src/core/hosts/windows/ArcaneHost.cs +695 -0
  40. package/src/core/hosts/windows/ArcaneHost.manifest +22 -0
  41. package/src/core/hosts/windows/ArcaneLauncher.cs +239 -0
  42. package/src/core/services/local-ai.mjs +621 -0
  43. package/src/core/services/packaged-web.mjs +89 -0
  44. package/src/core/services/preferences.mjs +201 -0
  45. package/src/core-classic-source.mjs +2 -2
  46. package/src/dev-server.mjs +9 -5
  47. package/src/diarization/build.mjs +35 -0
  48. package/src/diarization/index.mjs +432 -0
  49. package/src/diarization/native/CMakeLists.txt +9 -0
  50. package/src/diarization/native/main.cpp +269 -0
  51. package/src/diarization/service.mjs +129 -0
  52. package/src/git-text-snapshot.mjs +265 -0
  53. package/src/import-map.mjs +2 -0
  54. package/src/index.mjs +1 -0
  55. package/src/local-ai/archive.mjs +52 -0
  56. package/src/local-ai/config.mjs +62 -0
  57. package/src/local-ai/dev.mjs +390 -0
  58. package/src/local-ai/discover.mjs +71 -0
  59. package/src/local-ai/http.mjs +106 -0
  60. package/src/local-ai/install.mjs +459 -0
  61. package/src/local-ai/onnx-worker.mjs +85 -0
  62. package/src/local-ai/onnx.mjs +368 -0
  63. package/src/local-ai/server.mjs +262 -0
  64. package/src/native/macos-provider.mjs +291 -0
  65. package/src/native/portable-layout.mjs +37 -4
  66. package/src/native/portable-provider.mjs +44 -8
  67. package/src/native/windows-provider.mjs +262 -0
  68. package/src/native-plan.mjs +9 -1
  69. package/src/native-provider-loader.mjs +10 -2
  70. package/src/packager/core.mjs +6 -2
  71. package/src/process.mjs +184 -20
  72. package/src/scaffold.mjs +1 -1
  73. package/src/targets/index.mjs +11 -1
  74. package/src/templates/workspace-template.mjs +6 -5
  75. package/src/toolchain.mjs +33 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-os",
3
- "version": "0.56.0",
3
+ "version": "0.58.0",
4
4
  "description": "Arcane OS JavaScript SDK, project-local CLI, browser runtime, and repository-portable application packager.",
5
5
  "type": "module",
6
6
  "main": "./src/index.mjs",
@@ -39,6 +39,8 @@
39
39
  "./speech-playback": "./runtime/arcane/modules/SpeechPlayback.js",
40
40
  "./speech-text": "./browser-runtime/speech-text.mjs",
41
41
  "./ai/browser-wasm": "./browser-runtime/ai/browser-wasm.mjs",
42
+ "./ai/core-local": "./browser-runtime/ai/core-local.mjs",
43
+ "./ai/core-onnx": "./browser-runtime/ai/core-onnx.mjs",
42
44
  "./ai/browser-decisions": "./browser-runtime/ai/browser-decisions.mjs",
43
45
  "./ai/tool-text-stream": "./browser-runtime/ai/tool-text-stream.mjs",
44
46
  "./ai/twin-cloud": "./browser-runtime/ai/twin-cloud.mjs",
@@ -49,12 +51,22 @@
49
51
  "./native": "./src/native-plan.mjs",
50
52
  "./native-provider": "./src/native-provider-loader.mjs",
51
53
  "./native/portable-provider": "./src/native/portable-provider.mjs",
54
+ "./native/windows-provider": "./src/native/windows-provider.mjs",
55
+ "./native/macos-provider": "./src/native/macos-provider.mjs",
52
56
  "./core/client": "./browser-runtime/core/client.mjs",
53
57
  "./core/contracts": "./browser-runtime/core/contracts.mjs",
54
58
  "./core/classic-source": "./src/core-classic-source.mjs",
55
59
  "./core/runtime": "./src/core/runtime.mjs",
56
60
  "./core/stdio": "./src/core/stdio.mjs",
57
61
  "./core/host": "./src/core/host.mjs",
62
+ "./core/packaged-web": "./src/core/services/packaged-web.mjs",
63
+ "./core/preferences": "./src/core/services/preferences.mjs",
64
+ "./core/diarization": "./src/diarization/service.mjs",
65
+ "./core/local-ai": "./src/core/services/local-ai.mjs",
66
+ "./diarization": "./src/diarization/index.mjs",
67
+ "./diarization/build": "./src/diarization/build.mjs",
68
+ "./local-ai": "./src/local-ai/install.mjs",
69
+ "./local-ai/onnx": "./src/local-ai/onnx.mjs",
58
70
  "./integrated-provider": "./src/integrated-provider-loader.mjs",
59
71
  "./packager": "./src/packager/core.mjs",
60
72
  "./release-bundle": "./src/release-bundle.mjs",
@@ -96,8 +108,8 @@
96
108
  "test": "npm run test:unit && npm run test:functional && npm run test:integration && npm run test:regression",
97
109
  "test:release": "node ./bin/arcane-test.mjs test/npm-release.test.mjs",
98
110
  "test:unit": "node ./bin/arcane-test.mjs test/app-descriptor.test.mjs test/app-schema.test.mjs test/app-selection.test.mjs test/contracts.test.mjs test/conversation-closing-report.test.mjs test/doctor.test.mjs test/mail-credentials.test.mjs test/mail-outbox.test.mjs test/mail-public-api.test.mjs test/mail-send.test.mjs test/mail-transport.test.mjs test/targets.test.mjs test/workspace-operation-lock.test.mjs",
99
- "test:functional": "node ./bin/arcane-test.mjs test/ai-request-model.test.mjs test/ai-request-retry.test.mjs test/ai-stream-cancellation.test.mjs test/browser-decisions.test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-gpu-notice.test.mjs test/browser-wasm-download-resume.test.mjs test/chat-input.test.mjs test/chat-stream-speech.test.mjs test/chat-transcript-scroll.test.mjs test/chat-transient-retention.test.mjs test/cli.test.mjs test/continuous-voice-capture.test.mjs test/core-classic-source.test.mjs test/core-client.test.mjs test/core-host.test.mjs test/core-runtime.test.mjs test/core-stdio.test.mjs test/dbopfs-document-library.test.mjs test/dbopfs-png.test.mjs test/dbopfs.test.mjs test/dev-server.test.mjs test/dev-pwa.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/file-preview.test.mjs test/import-map.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/markdown-editor.test.mjs test/markdown-media.test.mjs test/markdown-source-map.test.mjs test/modal.test.mjs test/native-module-packaging.test.mjs test/native-module-resource-references.test.mjs test/packaging.test.mjs test/pwa-packaging.test.mjs test/pwa-client.test.mjs test/pwa-install.test.mjs test/pwa-worker.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/rendered-print.test.mjs test/runtime-api-behavior.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/speech-playback.test.mjs test/site.test.mjs test/theme-manager.test.mjs test/twin-cloud-images.test.mjs test/twin-cloud.test.mjs test/websocket-client-import-map.test.mjs test/websocket.test.mjs test/update-check.test.mjs test/user-explicit-updates.test.mjs",
100
- "test:integration": "node ./bin/arcane-test.mjs test/installed-package-runtime.test.mjs test/root-app-layout.test.mjs test/integrated-shared.test.mjs test/integrated-workspace.test.mjs test/mail-browser.test.mjs test/native-plan.test.mjs test/native-portable-provider.test.mjs test/native-provider-loader.test.mjs test/npm-release.test.mjs test/release-bundle.test.mjs test/release-capability-smoke.test.mjs test/shared-payload-batch.test.mjs test/tarball.test.mjs test/browser-wasm-cpu.test.mjs test/wllama-webgpu-runtime.test.mjs",
111
+ "test:functional": "node ./bin/arcane-test.mjs test/ai-request-model.test.mjs test/ai-request-retry.test.mjs test/ai-stream-cancellation.test.mjs test/browser-decisions.test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-gpu-notice.test.mjs test/browser-wasm-download-resume.test.mjs test/chat-input.test.mjs test/chat-stream-speech.test.mjs test/chat-transcript-scroll.test.mjs test/chat-transient-retention.test.mjs test/cli.test.mjs test/continuous-voice-capture.test.mjs test/core-classic-source.test.mjs test/core-client.test.mjs test/core-host.test.mjs test/core-packaged-web.test.mjs test/core-runtime.test.mjs test/core-stdio.test.mjs test/dbopfs-document-library.test.mjs test/dbopfs-png.test.mjs test/dbopfs.test.mjs test/dev-server.test.mjs test/dev-pwa.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/file-preview.test.mjs test/import-map.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/markdown-editor.test.mjs test/markdown-media.test.mjs test/markdown-source-map.test.mjs test/modal.test.mjs test/native-module-packaging.test.mjs test/native-module-resource-references.test.mjs test/packaging.test.mjs test/pwa-packaging.test.mjs test/pwa-client.test.mjs test/pwa-install.test.mjs test/pwa-worker.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/rendered-print.test.mjs test/runtime-api-behavior.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/speech-playback.test.mjs test/site.test.mjs test/theme-manager.test.mjs test/twin-cloud-images.test.mjs test/twin-cloud.test.mjs test/websocket-client-import-map.test.mjs test/websocket.test.mjs test/update-check.test.mjs test/user-explicit-updates.test.mjs",
112
+ "test:integration": "node ./bin/arcane-test.mjs test/installed-package-runtime.test.mjs test/root-app-layout.test.mjs test/integrated-shared.test.mjs test/integrated-workspace.test.mjs test/mail-browser.test.mjs test/native-macos-provider.test.mjs test/native-plan.test.mjs test/native-portable-provider.test.mjs test/native-provider-loader.test.mjs test/npm-release.test.mjs test/release-bundle.test.mjs test/release-capability-smoke.test.mjs test/shared-payload-batch.test.mjs test/tarball.test.mjs test/browser-wasm-cpu.test.mjs test/wllama-webgpu-runtime.test.mjs",
101
113
  "test:regression": "node ./bin/arcane-test.mjs test/channel-workflows.test.mjs test/html-import-registration.test.mjs test/html-import-packaged-script.test.mjs test/logging-regression.test.mjs test/markdown-speech.test.mjs test/prepared-speech.test.mjs test/native-provider-generation.test.mjs test/speech-queue-regression.test.mjs test/testing.test.mjs test/test-sets.test.mjs",
102
114
  "check": "node tools/check-source.mjs && npm test",
103
115
  "check:release": "node tools/check-source.mjs --package-only && npm run test:release",
@@ -555,7 +555,9 @@ async function probeRequiredServices({
555
555
  arcane,
556
556
  requirements.llm.model
557
557
  )
558
- :unavailableBrowserOllama()
558
+ :is.function(arcane?.localAI?.status)
559
+ ?probeNativeOllama(arcane,requirements.llm.model)
560
+ :unavailableBrowserOllama()
559
561
  :null,
560
562
  requiresSpeech
561
563
  ?mode==='native'
@@ -119,6 +119,19 @@
119
119
  "oneOf": [{ "$ref": "#/$defs/rasterIcon" }, { "type": "null" }]
120
120
  },
121
121
  "order": { "type": "integer", "minimum": 0 },
122
+ "services": {
123
+ "description": "Explicit application-owned Core factory modules from the selected native release. Factories receive authored options first and launch context second.",
124
+ "type": "array",
125
+ "items": {
126
+ "type": "object",
127
+ "required": ["module"],
128
+ "properties": {
129
+ "module": { "$ref": "#/$defs/relativePath" },
130
+ "options": {}
131
+ }
132
+ }
133
+ },
134
+ "localAI": { "$ref": "#/$defs/localAI" },
122
135
  "bundledApps": {
123
136
  "type": "array",
124
137
  "uniqueItems": true,
@@ -167,7 +180,7 @@
167
180
  "minItems": 1,
168
181
  "uniqueItems": true,
169
182
  "items": {
170
- "enum": ["android-arm64", "browser", "linux-arm64", "linux-x64", "portable", "windows-x64"]
183
+ "enum": ["android-arm64", "browser", "linux-arm64", "linux-x64", "macos-arm64", "macos-x64", "portable", "windows-x64"]
171
184
  }
172
185
  }
173
186
  },
@@ -240,6 +253,47 @@
240
253
  }
241
254
  ],
242
255
  "$defs": {
256
+ "localAI": {
257
+ "type": "object",
258
+ "required": ["runtimes"],
259
+ "description": "Required Core AI runtimes. Development ensures selected runtimes locally; native builds bundle their upstream runtime distributions. Model selection remains application-owned.",
260
+ "properties": {
261
+ "runtimes": {
262
+ "type": "array",
263
+ "items": {
264
+ "oneOf": [
265
+ { "enum": ["llama.cpp", "ollama", "onnx"] },
266
+ {
267
+ "type": "object",
268
+ "required": ["id"],
269
+ "properties": {
270
+ "id": { "enum": ["llama.cpp", "ollama", "onnx"] },
271
+ "version": { "type": "string" },
272
+ "url": { "type": "string" }
273
+ }
274
+ }
275
+ ]
276
+ }
277
+ },
278
+ "llamaCpp": {
279
+ "type": "object",
280
+ "properties": {
281
+ "url": { "type": "string" },
282
+ "model": { "type": "string" },
283
+ "modelsDirectory": { "type": "string" },
284
+ "args": { "type": "array", "items": { "type": "string" } }
285
+ }
286
+ },
287
+ "ollama": {
288
+ "type": "object",
289
+ "properties": {
290
+ "url": { "type": "string" },
291
+ "modelsDirectory": { "type": "string" },
292
+ "args": { "type": "array", "items": { "type": "string" } }
293
+ }
294
+ }
295
+ }
296
+ },
243
297
  "pwa": {
244
298
  "type": "object",
245
299
  "additionalProperties": false,
@@ -57,6 +57,9 @@
57
57
  "localAIModelPolicy": {
58
58
  "$ref": "#/$defs/localAIModelPolicy"
59
59
  },
60
+ "localAI": {
61
+ "$ref": "#/$defs/localAI"
62
+ },
60
63
  "pwa": {
61
64
  "$ref": "#/$defs/pwa"
62
65
  },
@@ -144,6 +147,47 @@
144
147
  }
145
148
  ],
146
149
  "$defs": {
150
+ "localAI": {
151
+ "type": "object",
152
+ "required": ["runtimes"],
153
+ "description": "Required Core AI runtimes. Development ensures selected runtimes locally; native builds bundle their upstream runtime distributions. Model selection remains application-owned.",
154
+ "properties": {
155
+ "runtimes": {
156
+ "type": "array",
157
+ "items": {
158
+ "oneOf": [
159
+ { "enum": ["llama.cpp", "ollama", "onnx"] },
160
+ {
161
+ "type": "object",
162
+ "required": ["id"],
163
+ "properties": {
164
+ "id": { "enum": ["llama.cpp", "ollama", "onnx"] },
165
+ "version": { "type": "string" },
166
+ "url": { "type": "string" }
167
+ }
168
+ }
169
+ ]
170
+ }
171
+ },
172
+ "llamaCpp": {
173
+ "type": "object",
174
+ "properties": {
175
+ "url": { "type": "string" },
176
+ "model": { "type": "string" },
177
+ "modelsDirectory": { "type": "string" },
178
+ "args": { "type": "array", "items": { "type": "string" } }
179
+ }
180
+ },
181
+ "ollama": {
182
+ "type": "object",
183
+ "properties": {
184
+ "url": { "type": "string" },
185
+ "modelsDirectory": { "type": "string" },
186
+ "args": { "type": "array", "items": { "type": "string" } }
187
+ }
188
+ }
189
+ }
190
+ },
147
191
  "pwa": {
148
192
  "type": "object",
149
193
  "additionalProperties": false,
@@ -117,7 +117,7 @@
117
117
  {
118
118
  "properties": {
119
119
  "target": { "const": "portable" },
120
- "platform": { "enum": ["windows", "linux"] },
120
+ "platform": { "enum": ["windows", "linux", "macos"] },
121
121
  "architecture": { "enum": ["x64", "arm64"] },
122
122
  "format": { "const": "portable" }
123
123
  }
@@ -163,6 +163,32 @@
163
163
  }
164
164
  ]
165
165
  },
166
+ {
167
+ "allOf": [
168
+ { "$ref": "#/$defs/unsignedTargetRequest" },
169
+ {
170
+ "properties": {
171
+ "target": { "const": "macos-arm64" },
172
+ "platform": { "const": "macos" },
173
+ "architecture": { "const": "arm64" },
174
+ "format": { "const": "app" }
175
+ }
176
+ }
177
+ ]
178
+ },
179
+ {
180
+ "allOf": [
181
+ { "$ref": "#/$defs/unsignedTargetRequest" },
182
+ {
183
+ "properties": {
184
+ "target": { "const": "macos-x64" },
185
+ "platform": { "const": "macos" },
186
+ "architecture": { "const": "x64" },
187
+ "format": { "const": "app" }
188
+ }
189
+ }
190
+ ]
191
+ },
166
192
  {
167
193
  "type": "object",
168
194
  "required": ["target", "platform", "architecture", "format", "signing", "signingProfileId"],
@@ -48,6 +48,7 @@
48
48
  "any",
49
49
  "windows",
50
50
  "linux",
51
+ "macos",
51
52
  "android"
52
53
  ]
53
54
  }
@@ -73,6 +74,7 @@
73
74
  "directory",
74
75
  "portable",
75
76
  "exe",
77
+ "app",
76
78
  "appimage",
77
79
  "deb",
78
80
  "rpm",
@@ -5,6 +5,7 @@ import {readFile, writeFile} from 'node:fs/promises';
5
5
  import path from 'node:path';
6
6
  import {throwIfAborted} from './errors.mjs';
7
7
  import {normalizePwaConfig} from './pwa.mjs';
8
+ import {normalizeLocalAIConfig} from './local-ai/config.mjs';
8
9
  import {
9
10
  ARCANE_MACHINE_BUNDLE_VERSION,
10
11
  ARCANE_PROTOCOL,
@@ -235,7 +236,7 @@ function validateDocumentCatalog(value){
235
236
  }
236
237
 
237
238
  function validateNative(value,appId){
238
- assertOnlyKeys(value,new Set(['type','icon','order','bundledApps','documentCatalog']),'descriptor.native');
239
+ assertOnlyKeys(value,new Set(['type','icon','order','bundledApps','documentCatalog','localAI','services']),'descriptor.native');
239
240
  if(!NATIVE_TYPES.has(value.type))fail('descriptor.native.type is unsupported.');
240
241
  const icon=value.icon===null?null:normalizeRelativePath(value.icon,'descriptor.native.icon');
241
242
  if(!is.integer(value.order)||value.order<0){
@@ -245,11 +246,21 @@ function validateNative(value,appId){
245
246
  pattern:APP_ID_PATTERN
246
247
  });
247
248
  const documentCatalog=validateDocumentCatalog(value.documentCatalog);
249
+ let services;
250
+ if(value.services!==undefined){
251
+ if(!is.array(value.services))fail('descriptor.native.services must be an array.');
252
+ services=value.services.map(function nativeService(service,index){
253
+ if(!isObject(service))fail(`descriptor.native.services[${index}] must be an object.`);
254
+ return {...service,module:normalizeRelativePath(service.module,`descriptor.native.services[${index}].module`)};
255
+ });
256
+ }
248
257
  return completeValue({
249
258
  type:value.type,
250
259
  icon,
251
260
  order:value.order,
252
261
  bundledApps,
262
+ ...(services===undefined?{}:{services}),
263
+ ...(value.localAI===undefined?{}:{localAI:normalizeLocalAIConfig(value.localAI)}),
253
264
  ...(documentCatalog?{documentCatalog}:{})
254
265
  });
255
266
  }
@@ -337,6 +348,7 @@ export function projectPackageManifest(descriptor){
337
348
  mediaOrigins:[...value.security.mediaOrigins]
338
349
  }}:{}),
339
350
  ...(value.package.localAIModelPolicy?{localAIModelPolicy:value.package.localAIModelPolicy}:{}),
351
+ ...(value.native.localAI===undefined?{}:{localAI:value.native.localAI}),
340
352
  ...(value.package.pwa===undefined?{}:{pwa:value.package.pwa}),
341
353
  include:[...value.package.include],
342
354
  exclude:[...value.package.exclude],
@@ -382,6 +394,8 @@ export function projectNativeDescriptor(descriptor,{source}={}){
382
394
  }}:{}),
383
395
  ...(value.native.bundledApps.length?{bundledApps:[...value.native.bundledApps]}:{}),
384
396
  ...(value.native.documentCatalog?{documentCatalog:value.native.documentCatalog}:{}),
397
+ ...(value.native.services===undefined?{}:{services:value.native.services}),
398
+ ...(value.native.localAI===undefined?{}:{localAI:value.native.localAI}),
385
399
  include:[...value.package.include]
386
400
  };
387
401
  }
@@ -425,6 +439,8 @@ function synthesizedDescriptor(packageManifest,nativeDescriptor){
425
439
  icon:native.icon??null,
426
440
  order:is.integer(native.order)?native.order:100,
427
441
  bundledApps:[...(native.bundledApps??[])],
442
+ ...(native.services===undefined?{}:{services:native.services}),
443
+ ...((packageManifest.localAI??native.localAI)===undefined?{}:{localAI:packageManifest.localAI??native.localAI}),
428
444
  ...(native.documentCatalog?{documentCatalog:native.documentCatalog}:{})
429
445
  },
430
446
  requirements:{
@@ -433,7 +449,7 @@ function synthesizedDescriptor(packageManifest,nativeDescriptor){
433
449
  features:[]
434
450
  },
435
451
  targets:nativeDescriptor!==undefined
436
- ?['android-arm64','browser','linux-arm64','linux-x64','portable','windows-x64']
452
+ ?['android-arm64','browser','linux-arm64','linux-x64','macos-arm64','macos-x64','portable','windows-x64']
437
453
  :['browser']
438
454
  },{appId:packageManifest.id});
439
455
  }
package/src/cli/main.mjs CHANGED
@@ -16,6 +16,7 @@ const VALUE_OPTIONS=new Set([
16
16
  'app',
17
17
  'apps-root',
18
18
  'sdk-runtime-source',
19
+ 'local-ai',
19
20
  'arcane-root',
20
21
  'host',
21
22
  'port',
@@ -66,7 +67,7 @@ Usage:
66
67
  ${CLI_NAME} upgrade [--workspace <directory>] [--app <id>]
67
68
  ${CLI_NAME} doctor [--workspace <directory>] [--arcane-root <directory>]
68
69
  ${CLI_NAME} import-map [--workspace <directory>] [--app <id>]
69
- ${CLI_NAME} dev [--app <id>] [--public] [--http | --https] [--cert <pem>] [--key <pem>] [--host <address>] [--port 8000] [--http-port 0] [--sdk-runtime-source <sdk-root>]
70
+ ${CLI_NAME} dev [--app <id>] [--public] [--http | --https] [--cert <pem>] [--key <pem>] [--host <address>] [--port 8000] [--http-port 0] [--sdk-runtime-source <sdk-root>] [--local-ai llama.cpp,ollama,onnx]
70
71
  ${CLI_NAME} test [--app <id>] [--scope app]
71
72
  ${CLI_NAME} test --scope shared --test-file <repo-relative.test.mjs>
72
73
  ${CLI_NAME} check [--app <id>] [--scope app] [--skip-tests]
@@ -97,6 +98,7 @@ Development:
97
98
  --host <address> Override the bind address; takes precedence over --public.
98
99
  --http-port <port> Browser dev/run HTTP redirect port; 0 selects an available port (default).
99
100
  --sdk-runtime-source <sdk-root> Dev-only live SDK checkout; omitted preserves the workspace runtime mode.
101
+ --local-ai <runtimes> Add required Core runtimes to app config and ensure them for development.
100
102
 
101
103
  Global:
102
104
  --workspace <directory> Select an external or integrated Arcane workspace.
@@ -450,6 +452,9 @@ function operationOptions(command,parsed,cwd){
450
452
  if(values['sdk-runtime-source']!==undefined&&command!=='dev'){
451
453
  usage('--sdk-runtime-source is supported only by dev.');
452
454
  }
455
+ if(values['local-ai']!==undefined&&command!=='dev'){
456
+ usage('--local-ai is supported only by dev.');
457
+ }
453
458
  if(flags.has('public')&&command!=='dev'){
454
459
  usage('--public is supported only by dev.');
455
460
  }
@@ -546,6 +551,7 @@ function operationOptions(command,parsed,cwd){
546
551
  ...browserServerOptions,
547
552
  host:values.host??(flags.has('public')?'0.0.0.0':'127.0.0.1'),
548
553
  port:readPort(values.port,8000),
554
+ ...(values['local-ai']===undefined?{}:{localAI:values['local-ai']}),
549
555
  ...(values['sdk-runtime-source']===undefined?{}:{
550
556
  sdkRuntimeSourceRoot:path.resolve(cwd,values['sdk-runtime-source'])
551
557
  })
@@ -732,6 +738,16 @@ function operationOptions(command,parsed,cwd){
732
738
  }
733
739
 
734
740
  const NATIVE_REQUESTS={
741
+ 'macos-arm64':{
742
+ platform:'macos',architecture:'arm64',defaultFormat:'app',formats:new Set(['app']),
743
+ defaultSigning:'unsigned-local-test',defaultProfileId:null,
744
+ signingModes:new Set(['unsigned-local-test'])
745
+ },
746
+ 'macos-x64':{
747
+ platform:'macos',architecture:'x64',defaultFormat:'app',formats:new Set(['app']),
748
+ defaultSigning:'unsigned-local-test',defaultProfileId:null,
749
+ signingModes:new Set(['unsigned-local-test'])
750
+ },
735
751
  'windows-x64':{
736
752
  platform:'windows',architecture:'x64',defaultFormat:'exe',formats:new Set(['exe']),
737
753
  defaultSigning:'unsigned-local-test',defaultProfileId:null,
@@ -755,9 +771,9 @@ const NATIVE_REQUESTS={
755
771
  };
756
772
 
757
773
  function portableRequestDefinition(){
758
- const platform=process.platform==='win32'?'windows':process.platform;
774
+ const platform=process.platform==='win32'?'windows':process.platform==='darwin'?'macos':process.platform;
759
775
  const architecture=process.arch==='x64'?'x64':process.arch==='arm64'?'arm64':process.arch;
760
- if(!['windows','linux'].includes(platform)||!['x64','arm64'].includes(architecture)){
776
+ if(!['windows','linux','macos'].includes(platform)||!['x64','arm64'].includes(architecture)){
761
777
  throw new ArcaneError(
762
778
  ERROR_CODES.targetUnavailable,
763
779
  `The portable native provider does not support ${process.platform}/${process.arch}.`
@@ -811,7 +827,7 @@ async function pairNativeProvider(command,options,loadProvider,{signal,onEvent}=
811
827
  usage(`${command} requires one native target.`);
812
828
  }
813
829
  const targetRequest=createNativeTargetRequest(options);
814
- if(!options.arcaneRoot&&options.target!=='portable'){
830
+ if(!options.arcaneRoot&&!['portable','windows-x64','macos-arm64','macos-x64'].includes(options.target)){
815
831
  usage(`${command} for target ${options.target} requires --arcane-root <directory>.`);
816
832
  }
817
833
  const loaded=await loadProvider({
package/src/constants.mjs CHANGED
@@ -27,6 +27,8 @@ export const TARGET_IDS=[
27
27
  'browser',
28
28
  'portable',
29
29
  'windows-x64',
30
+ 'macos-arm64',
31
+ 'macos-x64',
30
32
  'linux-x64',
31
33
  'linux-arm64',
32
34
  'android-arm64'
package/src/core/host.mjs CHANGED
@@ -1,6 +1,29 @@
1
+ import {readFile} from 'node:fs/promises';
2
+ import Is from 'strong-type';
1
3
  import {createCoreRuntime} from './runtime.mjs';
2
4
  import {startCoreStdio} from './stdio.mjs';
3
5
 
6
+ const is = new Is(false);
7
+
8
+ /**
9
+ * Read only the explicitly supplied --arcane-launch-config filename.
10
+ * Return the complete JSON object for the service factories' second argument;
11
+ * field meanings belong to the launch owner and individual services.
12
+ */
13
+ export async function readCoreLaunchContext({argv = process.argv.slice(2)} = {}) {
14
+ const flag = argv.indexOf('--arcane-launch-config');
15
+ if (flag === -1) return {};
16
+ const filename = argv[flag + 1];
17
+ if (filename === undefined || filename === '') {
18
+ throw new TypeError('--arcane-launch-config requires a filename.');
19
+ }
20
+ const context = JSON.parse(await readFile(filename, 'utf8'));
21
+ if (context === null || !is.object(context) || is.array(context)) {
22
+ throw new TypeError('Core launch configuration must be a JSON object.');
23
+ }
24
+ return context;
25
+ }
26
+
4
27
  /** Compose app services with the shared dispatcher and draining transport. */
5
28
  export function startCoreHost({application, version, services = [], input, output, onError, signal} = {}) {
6
29
  const runtime = createCoreRuntime({application, version, services});
@@ -0,0 +1,85 @@
1
+ #import <Foundation/Foundation.h>
2
+
3
+ NS_ASSUME_NONNULL_BEGIN
4
+
5
+ @class ArcaneCoreProcess;
6
+
7
+ typedef NS_ENUM(NSUInteger, ArcaneCoreOutputStream) {
8
+ ArcaneCoreStandardOutput,
9
+ ArcaneCoreStandardError
10
+ };
11
+
12
+ /**
13
+ * Callbacks run on process-owned background queues. Each output stream retains
14
+ * its order; different streams, writes and exit observation can be concurrent.
15
+ * Marshal UI work at the host. Callbacks must return normally and must not wait
16
+ * for another callback or for completion. The process retains its delegate
17
+ * through didCompleteWithErrors, then releases it.
18
+ *
19
+ * receivedOutputData delivers every unmodified stdout/stderr chunk. Stdout
20
+ * includes framing; receivedFrameData additionally delivers each complete
21
+ * opaque JSON body. No payload is decoded, parsed or rewritten here. Following
22
+ * a framing error, raw stdout continues to EOF without guessing a new boundary.
23
+ */
24
+ @protocol ArcaneCoreProcessDelegate <NSObject>
25
+ - (void)coreProcess:(ArcaneCoreProcess *)process didLaunch:(pid_t)processIdentifier;
26
+ - (void)coreProcess:(ArcaneCoreProcess *)process receivedFrameData:(NSData *)data;
27
+ - (void)coreProcess:(ArcaneCoreProcess *)process receivedOutputData:(NSData *)data
28
+ stream:(ArcaneCoreOutputStream)stream;
29
+ - (void)coreProcess:(ArcaneCoreProcess *)process didEncounterError:(NSError *)error;
30
+ - (void)coreProcess:(ArcaneCoreProcess *)process didExitWithStatus:(int)status
31
+ reason:(NSTaskTerminationReason)reason;
32
+ /**
33
+ * Last callback: launch/exit observation, accepted writes and both streams have
34
+ * settled, successfully or with reported errors. Launch failure has no exit
35
+ * callback; an exit-observation failure is not proof that the child exited.
36
+ */
37
+ - (void)coreProcess:(ArcaneCoreProcess *)process didCompleteWithErrors:(NSArray<NSError *> *)errors;
38
+ @end
39
+
40
+ /**
41
+ * Foundation-only ownership of one explicit Core executable and framed pipes.
42
+ * Compile with Objective-C ARC and blocks; no third-party runtime is linked.
43
+ */
44
+ API_AVAILABLE(macos(11.0))
45
+ @interface ArcaneCoreProcess : NSObject
46
+
47
+ /**
48
+ * Starts asynchronously without shell execution, PATH lookup, environment
49
+ * mutation or a foreground wait. Arguments exclude argv[0]; the selected child
50
+ * inherits the host environment. Launch failure is reported through the
51
+ * delegate and completion. Callbacks can begin before this method returns.
52
+ */
53
+ + (instancetype)startExecutableURL:(NSURL *)executableURL
54
+ arguments:(NSArray<NSString *> *)arguments
55
+ workingDirectoryURL:(NSURL *)workingDirectoryURL
56
+ delegate:(id<ArcaneCoreProcessDelegate>)delegate;
57
+
58
+ /** Zero until a successful launch; the original child PID remains after exit. */
59
+ @property(nonatomic, readonly) pid_t processIdentifier;
60
+
61
+ /**
62
+ * Copies and queues the complete opaque JSON body. YES accepts the write and
63
+ * calls completion exactly once on the input queue. nil completion-error means
64
+ * the full frame reached child stdin, not that Core accepted or completed its
65
+ * operation. NO supplies a synchronous error and never calls completion.
66
+ * A partial/failed write is never retried. Payload length is transport framing
67
+ * only, never an application limit or policy.
68
+ */
69
+ - (BOOL)sendJSONData:(NSData *)data
70
+ completion:(void (^)(NSError * _Nullable error))completion
71
+ error:(NSError * _Nullable * _Nullable)error;
72
+
73
+ /**
74
+ * Idempotent and nonblocking: reject new sends, finish accepted writes, then
75
+ * close stdin. Keep reading stdout/stderr and observe child exit. There is no
76
+ * forced termination or deadline. Accepted service work can outlive a renderer;
77
+ * renderer cancellation belongs to the public Core control protocol.
78
+ */
79
+ - (void)closeInput;
80
+
81
+ - (instancetype)init NS_UNAVAILABLE;
82
+ + (instancetype)new NS_UNAVAILABLE;
83
+ @end
84
+
85
+ NS_ASSUME_NONNULL_END