arcane-os 0.67.0 → 0.68.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 +19 -0
- package/README.md +1 -1
- package/docs/reference/README.md +5 -0
- package/docs/reference/availability-and-normalization.md +1 -0
- package/docs/reference/core-runtime.md +14 -0
- package/docs/reference/inventory/package-api.json +54 -12
- package/docs/reference/inventory/runtime-components.json +2 -1
- package/docs/reference/inventory/runtime-modules.json +3 -3
- package/docs/reference/runtime-components.md +62 -5
- package/docs/reference/runtime-modules.md +44 -7
- package/docs/reference/sdk-api.md +174 -7
- package/package.json +1 -1
- package/runtime/arcane/components/theme-switcher.html +112 -13
- package/runtime/arcane/modules/PreferenceStore.js +18 -13
- package/runtime/arcane/modules/SystemAppearance.js +24 -6
- package/src/core/runtime.mjs +15 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.68.0
|
|
4
|
+
|
|
5
|
+
- Add per-instance theme-switcher `configure({modes,labels})` and initial
|
|
6
|
+
`data-modes` / `data-system-label` presentation. Applications can select
|
|
7
|
+
Light / Dark / System with complete readable labels while the default
|
|
8
|
+
Auto / Light / Dark / Skin choices remain unchanged. Preserve selected,
|
|
9
|
+
disabled and keyboard-focus states with wrapping based on component space.
|
|
10
|
+
- Distinguish a wholly absent Core namespace from a missing method in a
|
|
11
|
+
registered service. Retain `METHOD_NOT_ALLOWED` and add exact `method`,
|
|
12
|
+
`namespace` and `reason` lookup metadata; genuine handler errors remain intact.
|
|
13
|
+
- Let the default preference adapter complete single operations through its
|
|
14
|
+
existing app-scoped local store only after an exact absent preferences
|
|
15
|
+
namespace response, retaining cancellation, disposal and full values.
|
|
16
|
+
An advertised rejected atomic batch is never retried as serial writes.
|
|
17
|
+
- Treat an exactly absent optional appearance namespace as unsupported, keeping
|
|
18
|
+
the original diagnostic. Preserve partial-service and genuine errors, the
|
|
19
|
+
existing theme persistence order, native window theming and app-owned host
|
|
20
|
+
preferences. No OS-wide appearance change, migration or dependency is added.
|
|
21
|
+
|
|
3
22
|
## 0.67.0
|
|
4
23
|
|
|
5
24
|
- Add native Laya FP32 typed decisions through `arcane-os/local-ai/decisions`
|
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ selected SDK projection or an explicit live SDK source mount. Both profiles
|
|
|
20
20
|
share the theme, packaging, event, cancellation,
|
|
21
21
|
and browser run contracts while retaining their selected application layout.
|
|
22
22
|
|
|
23
|
-
This checkout defines the `0.
|
|
23
|
+
This checkout defines the `0.68.0` SDK contract. Development applications declare
|
|
24
24
|
`arcane-os` as `latest` and retain their lockfile. Exact SDK pins begin when Roshi
|
|
25
25
|
designates a production build. Follow [Consumer updates](docs/consumer-updates.md)
|
|
26
26
|
to refresh and compare the installed SDK and lockfile with the published channel;
|
package/docs/reference/README.md
CHANGED
|
@@ -54,6 +54,7 @@ alone does not make bare module names resolve in a browser.
|
|
|
54
54
|
| Connect a browser to one Core transport | [Core browser client](core-client.md) |
|
|
55
55
|
| Cancel one Core speech synthesis request without changing its payload | [Speech request lifetime](core-client.md#events-and-request-lifetime) and [Core facade](sdk-api.md#createcorefacade) |
|
|
56
56
|
| Compose native Core dispatch, service lifecycle, and stdio hosting | [Native Core runtime](core-runtime.md) |
|
|
57
|
+
| Reuse dependency-ready native services without a renderer | [Core service composition](core-runtime.md#native-service-composition) and [existing ONNX owner](local-ai.md#native-service-owners) |
|
|
57
58
|
| Compose application Core services during source development, independently of local AI | [Development Core services](core-development.md) |
|
|
58
59
|
| Own an explicitly selected native Codex App Server session | [Codex App Server](codex-app-server.md) |
|
|
59
60
|
| Expose application-owned tools and static resources through Node STDIO | [MCP STDIO server](mcp-stdio.md) |
|
|
@@ -66,12 +67,14 @@ alone does not make bare module names resolve in a browser.
|
|
|
66
67
|
| Select the optional Intel NPU encoder with independent CUDA or CPU decoding | [Intel NPU Whisper](../guides/native-whisper-openvino.md) |
|
|
67
68
|
| Edit an original PNG with a complete prompt and explicit strength | [Local image editing](local-image-editing.md) |
|
|
68
69
|
| Project complete stored model files into native working files | [Model assets through Core](model-assets.md) |
|
|
70
|
+
| Prepare selected upstream model members in native services | [Native preparation and retained lifetime](model-assets.md#native-ownership) |
|
|
69
71
|
| Retain a Nemotron model and diarize caller-fed audio streams | [Native speaker diarization](diarization.md) |
|
|
70
72
|
| Persist application-selected preferences through Core | [Core preferences service](core-preferences.md) |
|
|
71
73
|
| Read complete selected Git text without changing a checkout | [Git text snapshots](git-text-snapshot.md) |
|
|
72
74
|
| Own a native working checkout under per-user ArcaneData/Repos | [Native repository workspaces](core-repositories.md) |
|
|
73
75
|
| Read Git identity defaults or select child-only author and credential hints | [Git identity configuration](core-repositories.md#git-identity-configuration) |
|
|
74
76
|
| Write, commit and push complete selected repository text | [Selected-text repository writing](core-repositories.md#write-commit-and-push-selected-text) |
|
|
77
|
+
| Observe existing checkout configuration and capture an explicit remote/ref | [Repository configuration and selected targets](core-repositories.md#existing-checkout-configuration-and-selected-targets) |
|
|
75
78
|
| Build an installed-SDK portable Core payload | [Portable Core packaging](core-native-packaging.md) |
|
|
76
79
|
| Pass host-selected state defaults and unchanged explicit launch values to services | [Launch-time locations](core-native-packaging.md#launch-time-locations) |
|
|
77
80
|
| Build a Windows executable without an OS checkout | [Windows executable packaging](core-native-packaging.md#windows-executable) |
|
|
@@ -79,6 +82,7 @@ alone does not make bare module names resolve in a browser.
|
|
|
79
82
|
| Subscribe to native events | [Arcane event reference](core/arcane-events.md) |
|
|
80
83
|
| Use provider-neutral AI lifecycle, chat, speech, persistence, or document context | [Normalized AI](#normalized-ai) |
|
|
81
84
|
| Choose a normalized typed browser decision surface | [Browser typed decisions](ai/browser-decisions.md) |
|
|
85
|
+
| Score complete typed options with native Laya FP32 | [Native typed decisions](native-decisions.md) |
|
|
82
86
|
| Run a caller-selected local LLM in the browser | [Browser-WASM local AI](ai/browser-wasm.md) |
|
|
83
87
|
| Run caller-selected Whisper/Kokoro, native browser recognition/voices or cloud TTS | [Browser speech providers](ai/browser-speech.md) |
|
|
84
88
|
| Send TWiN chat, System One state/questions or image requests | [TWiN Cloud guide](ai/twin-cloud.md) |
|
|
@@ -239,6 +243,7 @@ Ollama, Wllama, Whisper, Kokoro, native, or cloud transport:
|
|
|
239
243
|
| Run application-selected native llama.cpp/Ollama chat | [`arcane-os/ai/core-local`, `arcane-os/core/local-ai`](local-ai.md) | Explicit Core connection and selected native runtimes; installation, availability and loaded-model readiness remain distinct. |
|
|
240
244
|
| Transcribe complete recordings with a retained native Whisper model | [`arcane-os/local-ai/whisper`](local-whisper.md) and [Core speech](native-speech.md) | Matching native helper, Whisper libraries, decoder and selected model; Windows defaults and explicit other-platform distributions have distinct preparation requirements. |
|
|
241
245
|
| Run a local ONNX graph with named tensors | [`arcane-os/local-ai/onnx`, `arcane-os/ai/core-onnx`](local-ai.md#native-onnx-sessions) | Retained native workers; browser access requires an available Core ONNX service. |
|
|
246
|
+
| Score typed options without a renderer | [`arcane-os/local-ai/decisions`, `arcane-os/core/decisions`](native-decisions.md) | Explicit native Laya FP32 activation using the existing ONNX owner; complete scores and outputs, joined Worker cleanup. |
|
|
242
247
|
| Generate local images from complete prompts and selected model resources | [`arcane-os/local-ai/image`, `arcane-os/ai/core-image`](local-image-generation.md) | Prepared native image runtime; browser access requires its Core service. CPU Windows/Linux and Mac Metal/CPU paths have distinct actual host requirements. |
|
|
243
248
|
| Supply complete stored model members to a native engine | [`arcane-os/ai/core-model-assets`, `arcane-os/core/model-assets`](model-assets.md) | Available Core service; DBOPFS originals stay authoritative while native owners retain working files. |
|
|
244
249
|
| Run caller-selected Whisper/Kokoro locally | [`arcane-os/ai/browser-speech`](ai/browser-speech.md) | Browser with DBOPFS, Web Locks, Workers and selected upstream sources; automatic WebNN NPU, WebGPU, then WASM loading, or an explicit backend. |
|
|
@@ -74,6 +74,7 @@ where listed. See [native output and host requirements](core-native-packaging.md
|
|
|
74
74
|
| Share one native WebSocket by exact URI and ordered protocols | `arcane-os/websocket-client` | **Node** and **Browser**, using the host's native `WebSocket` | The selected upstream `ws-share` instance owns the connection pool and global observation. Native socket messages and events remain unchanged; there is no reconnect, heartbeat, application envelope, storage, or fallback. |
|
|
75
75
|
| Build browser UI and app-local behavior | `/arcane/modules/*.js`, shared entities, and components | **Browser**; many modules also run inside every native renderer | Pure modules own their result contracts. Modules that call `Arcane` inherit the bridge boundary described below. |
|
|
76
76
|
| Score caller-supplied typed options with Laya or Julia | `arcane-os/ai/browser-decisions` | **Browser** only; caller-selected upstream runtime/model and backend | Typed decisions retain complete rows and return typed values, scores, probabilities, and diagnostics in caller order. This surface is separate from chat and speech and does not silently change model, precision, backend, or family. |
|
|
77
|
+
| Score complete typed options with native Laya FP32 | [`arcane-os/local-ai/decisions`, `arcane-os/core/decisions`](native-decisions.md) | **Node** Windows/Linux/macOS with selected ONNX Runtime and model; Android needs host adaptation | Reuses the existing native ONNX owner and a tokenizer Worker, with explicit load and joined cleanup. Preserves separate state/question/options/type, original rows, raw scores and complete graph outputs. GPU preference attempts actual advertised providers before CPU; provider configuration does not prove physical acceleration. No renderer, chat provider or automatic persistence is required. |
|
|
77
78
|
| Select and observe independent LLM/STT/TTS roles | `/arcane/modules/AIProviderRuntime.js` and `AIRuntimeState.js` | **Cross-host** controller/state; registered providers retain their own host requirements | Required/projected provider members, route/configuration records, and status fields; per-role lifecycle, cancellation, stream cleanup, sticky state, and startup barriers are normalized. `localOnly` creates no fallback. |
|
|
78
79
|
| Run a caller-selected local LLM entirely in a browser renderer | `arcane-os/ai/browser-wasm` through `createArcaneAI()` | **Browser** only; secure context, WebAssembly, and OPFS/DBOPFS; full WebGPU offload by default or explicit CPU with `gpuLayers:0` | The public AI API module normalizes multi-model lifecycle, status, complete all-choice streaming, cancellation, exact ordered structural tool-call visibility, and session persistence. Model sources are canonical ordered file descriptors; licenses and model choice remain application policy. |
|
|
79
80
|
| Run caller-selected Whisper or Kokoro in a browser renderer | `arcane-os/ai/browser-speech` registered with `AIProviderRuntime` | **Browser** only; DBOPFS, Web Locks, Workers, Fetch/object URLs, and a caller-supplied self-contained runtime/model closure are required | Independent provider/2 lifecycle and status, with `auto`, `webnn-npu`, `webgpu`, or `wasm` execution. Whisper owns one Worker/session; Kokoro defaults to four and accepts one through four. Complete model/runtime selection, offline behavior, cancellation, Worker teardown, and request/result shapes are normalized. No runtime/model content or cloud fallback is supplied. |
|
|
@@ -123,6 +123,20 @@ The shared `arcane-os/core/contracts` module owns `CORE_PROTOCOL` (`arcane/1`),
|
|
|
123
123
|
availability errors remain observable; unavailable services are not replaced
|
|
124
124
|
with browser behavior.
|
|
125
125
|
|
|
126
|
+
A request with no registered handler retains code `METHOD_NOT_ALLOWED` and
|
|
127
|
+
adds the exact `method`, its first dotted `namespace`, and a `reason`.
|
|
128
|
+
`core-namespace-unavailable` means the dispatcher has neither a service with
|
|
129
|
+
that name nor any registered method in that namespace. Otherwise the reason is
|
|
130
|
+
`core-method-unavailable`; the built-in `system`, `app`, and `version`
|
|
131
|
+
namespaces also count as present. This is a dispatch lookup result before any
|
|
132
|
+
handler or permission decision, not a capability-discovery call. A read-only
|
|
133
|
+
or partially registered service therefore never appears wholly absent.
|
|
134
|
+
Handler/startup/permission errors remain unchanged and acquire none of these
|
|
135
|
+
lookup markers. Generic or older `METHOD_NOT_ALLOWED` errors do not establish
|
|
136
|
+
namespace absence. An optional browser adapter may recognize the exact absent
|
|
137
|
+
namespace and method according to its own documented contract; the dispatcher
|
|
138
|
+
does not select or create another implementation.
|
|
139
|
+
|
|
126
140
|
Events have `{protocol, type:'event', event, data, time}`:
|
|
127
141
|
|
|
128
142
|
- `core.ready`: the dispatcher is connected; service/model readiness is separate.
|
|
@@ -1,17 +1,59 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"sdkVersion": "0.
|
|
3
|
+
"sdkVersion": "0.67.0",
|
|
4
4
|
"environment": {
|
|
5
5
|
"runtime": "Node.js for Node entrypoints; browser for browser-only entrypoints",
|
|
6
6
|
"minimumVersion": "22.23.2 for Node entrypoints",
|
|
7
7
|
"moduleSystem": "ESM"
|
|
8
8
|
},
|
|
9
|
-
"memberCount":
|
|
9
|
+
"memberCount": 293,
|
|
10
10
|
"runtimeSubpathPatterns": {
|
|
11
11
|
"arcane-os/modules/*": "./runtime/arcane/modules/*",
|
|
12
12
|
"arcane-os/entities/*": "./runtime/arcane/entities/*"
|
|
13
13
|
},
|
|
14
14
|
"members": [
|
|
15
|
+
{
|
|
16
|
+
"id": "local-ai-decisions:createNativeDecisionModel",
|
|
17
|
+
"name": "createNativeDecisionModel",
|
|
18
|
+
"displayName": "createNativeDecisionModel()",
|
|
19
|
+
"kind": "function",
|
|
20
|
+
"signature": "createNativeDecisionModel({onnx,modelAssets,workingDirectory,paths,model='onnx-community/laya-typed-decisions-ONNX',revision='main',dtype='fp32',sessionOptions,executionPreference='gpu',signal}={})",
|
|
21
|
+
"entrypoints": ["arcane-os/local-ai/decisions"],
|
|
22
|
+
"primaryImport": "arcane-os/local-ai/decisions",
|
|
23
|
+
"group": "Native typed decisions",
|
|
24
|
+
"summary": "Explicit native Laya FP32 option scoring through an existing ONNX owner and a tokenizer Worker.",
|
|
25
|
+
"availability": "Node on Windows/Linux/macOS with selected ONNX Runtime and model files; Android needs host adaptation",
|
|
26
|
+
"protocol": "Shared browser/native decision encoding with native named tensor results",
|
|
27
|
+
"normalization": "Returns load/evaluate/classify/current/status/subscribe/unload/dispose; preserves complete separate state/question/options/type and original rows, raw scores and every graph output. Explicit load prepares selected upstream files or uses caller-owned paths; GPU preference attempts advertised providers then CPU. Cancellation retires the shared activation; files remain retained through actual ONNX and tokenizer Worker exit. No chat history or duplicate inference engine."
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "core-decisions:createNativeDecisionService",
|
|
31
|
+
"name": "createNativeDecisionService",
|
|
32
|
+
"displayName": "createNativeDecisionService()",
|
|
33
|
+
"kind": "function",
|
|
34
|
+
"signature": "createNativeDecisionService(configuration={}, {appRoot=process.cwd()}={})",
|
|
35
|
+
"entrypoints": ["arcane-os/core/decisions"],
|
|
36
|
+
"primaryImport": "arcane-os/core/decisions",
|
|
37
|
+
"group": "Native typed decisions",
|
|
38
|
+
"summary": "Renderer-independent native Laya service reusing the registered local-AI and model-assets owners.",
|
|
39
|
+
"availability": "Node Core with selected native ONNX and model files",
|
|
40
|
+
"protocol": "arcane/1 decisions.status/load/evaluate/unload and decisions.state",
|
|
41
|
+
"normalization": "Registration starts no model or tokenizer. Explicit load obtains dependency-ready same-process owners and reacquires getONNXRuntime after recovery. Native load/evaluate/classify/current/subscribe/unload/dispose preserve complete results; RPC uses the existing tensor codec. Unload has accepted service lifetime; host shutdown cancels request-lifetime load/evaluation."
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": "core-decisions:default",
|
|
45
|
+
"name": "default",
|
|
46
|
+
"displayName": "createNativeDecisionService default export",
|
|
47
|
+
"kind": "function",
|
|
48
|
+
"signature": "default as createNativeDecisionService",
|
|
49
|
+
"entrypoints": ["arcane-os/core/decisions"],
|
|
50
|
+
"primaryImport": "arcane-os/core/decisions",
|
|
51
|
+
"group": "Native typed decisions",
|
|
52
|
+
"summary": "Default binding for the same native decision Core service factory.",
|
|
53
|
+
"availability": "Node Core runtime",
|
|
54
|
+
"protocol": "arcane/1 service definition",
|
|
55
|
+
"normalization": "Binding identity equals the named createNativeDecisionService export"
|
|
56
|
+
},
|
|
15
57
|
{
|
|
16
58
|
"id": "local-ai-whisper:createWhisperRuntime",
|
|
17
59
|
"name": "createWhisperRuntime",
|
|
@@ -227,14 +269,14 @@
|
|
|
227
269
|
"name": "createCoreImageRuntime",
|
|
228
270
|
"displayName": "createCoreImageRuntime()",
|
|
229
271
|
"kind": "function",
|
|
230
|
-
"signature": "createCoreImageRuntime({client
|
|
272
|
+
"signature": "createCoreImageRuntime({client,signal,onEvent}={})",
|
|
231
273
|
"entrypoints": ["arcane-os/ai/core-image"],
|
|
232
274
|
"primaryImport": "arcane-os/ai/core-image",
|
|
233
275
|
"group": "Core local images",
|
|
234
276
|
"summary": "Uses an available Core image service for generation and original-PNG editing with synchronous Thinking acknowledgement, lifecycle replay and complete PNG Blobs.",
|
|
235
277
|
"availability": "Browser/native WebView with an available Core image service; construction opens no connection or model",
|
|
236
278
|
"protocol": "arcane/1 image.status/load/generate/edit/unload and image.state/progress",
|
|
237
|
-
"normalization": "Returns load/generate/edit/unload/inspect/current/subscribe/close;
|
|
279
|
+
"normalization": "Returns load/generate/edit/unload/inspect/current/subscribe/close; omitted client follows installation/replacement/retirement, explicit client including null remains fixed. Retirement cancels owned work and clears readiness; late old-client output is suppressed. Edit preserves the complete original PNG Blob/File through transport with explicit strength; timeoutMs is zero, close cancels only this accessor and explicit unload owns the shared model"
|
|
238
280
|
},
|
|
239
281
|
{
|
|
240
282
|
"id": "core-image-service:createLocalImageService",
|
|
@@ -290,7 +332,7 @@
|
|
|
290
332
|
"summary": "Owns selected native working-file projections and engine retain handles while original stored model files remain unchanged.",
|
|
291
333
|
"availability": "Node Core with an application-selected working directory",
|
|
292
334
|
"protocol": "arcane/1 modelAssets.open/write/complete/release/status and modelAssets.state",
|
|
293
|
-
"normalization": "Returns current/retain/dispose and Core service lifecycle
|
|
335
|
+
"normalization": "Returns current/prepare/retain/release/dispose and Core service lifecycle. Explicit prepare({id,workingDirectory,members:[{path,url}],signal,onProgress}) streams complete upstream members through the existing file owner and reports file/phase progress. release(id) relinquishes preparation ownership; cancellation and cleanup join fetches/writes. Native retains survive until actual engine release before deleting only the owned working projection. Startup downloads nothing."
|
|
294
336
|
},
|
|
295
337
|
{
|
|
296
338
|
"id": "core-model-assets-service:default",
|
|
@@ -318,21 +360,21 @@
|
|
|
318
360
|
"summary": "Owns explicitly loaded ONNX graphs and complete named tensor inference in retained native workers.",
|
|
319
361
|
"availability": "Node on Windows/Linux/macOS x64/arm64 with prepared onnxruntime-node; Android needs host adaptation",
|
|
320
362
|
"protocol": "Per-session worker lifecycle with structured-clone tensors and replaying state",
|
|
321
|
-
"normalization": "Returns load/run/unload/current/subscribe/close; explicit
|
|
363
|
+
"normalization": "Returns load/run/unload/current/subscribe/close; load accepts executionPreference gpu for advertised provider creation attempts then CPU, while explicit sessionOptions.executionProviders takes precedence. Complete execution diagnostics distinguish configured providers from physical acceleration. stopping revokes new runs while exited records actual Worker exit; recoverable run errors preserve the session. Cleanup joins exit and output delivery even when termination fails."
|
|
322
364
|
},
|
|
323
365
|
{
|
|
324
366
|
"id": "core-onnx:createCoreONNXRuntime",
|
|
325
367
|
"name": "createCoreONNXRuntime",
|
|
326
368
|
"displayName": "createCoreONNXRuntime()",
|
|
327
369
|
"kind": "function",
|
|
328
|
-
"signature": "createCoreONNXRuntime({client
|
|
370
|
+
"signature": "createCoreONNXRuntime({client}={})",
|
|
329
371
|
"entrypoints": ["arcane-os/ai/core-onnx"],
|
|
330
372
|
"primaryImport": "arcane-os/ai/core-onnx",
|
|
331
373
|
"group": "Core local AI",
|
|
332
374
|
"summary": "Accesses local system ONNX through an existing Core client with complete tensor transport.",
|
|
333
375
|
"availability": "Browser with available Core ONNX service; construction installs no runtime or model",
|
|
334
376
|
"protocol": "arcane/1 onnx.status/load/run/unload and localai.state",
|
|
335
|
-
"normalization": "Returns load/run/unload/inspect/current/subscribe/close;
|
|
377
|
+
"normalization": "Returns load/run/unload/inspect/current/subscribe/close; omitted client follows late installation/replacement/retirement and reads current status, while explicit client including null stays fixed. Retirement clears readiness and cancels owned work; late old-client results are suppressed. Preserves typed and string tensors; close removes subscriptions and cancels requests without closing shared Core or implicitly unloading shared models"
|
|
336
378
|
},
|
|
337
379
|
{
|
|
338
380
|
"id": "root:createGitTextSnapshot",
|
|
@@ -409,14 +451,14 @@
|
|
|
409
451
|
"name": "createCoreLocalAIProvider",
|
|
410
452
|
"displayName": "createCoreLocalAIProvider()",
|
|
411
453
|
"kind": "function",
|
|
412
|
-
"signature": "createCoreLocalAIProvider({client
|
|
454
|
+
"signature": "createCoreLocalAIProvider({client,id='llama.cpp'}={})",
|
|
413
455
|
"entrypoints": ["arcane-os/ai/core-local"],
|
|
414
456
|
"primaryImport": "arcane-os/ai/core-local",
|
|
415
457
|
"group": "Core local AI",
|
|
416
458
|
"summary": "Browser llama.cpp provider through an explicitly connected Core, with application-owned model selection and complete response streaming.",
|
|
417
459
|
"availability": "Browser with an available Core local AI service; construction installs no runtime or model",
|
|
418
460
|
"protocol": "arcane-ai-provider/2 LLM lifecycle over arcane/1",
|
|
419
|
-
"normalization": "Preserves complete payloads and original parsed chunks; waits for the exact requested model and cancels on observed readiness loss"
|
|
461
|
+
"normalization": "Preserves complete payloads and original parsed chunks; waits for the exact requested model and cancels on observed readiness loss. Omitted client follows installation/replacement/retirement; explicit client including null stays fixed. Inspect reports load capability separately from loaded readiness; disposal releases only an actually retained selection through its captured client. Provider/2 role state reconciles at existing operation boundaries, not through an idle state subscription."
|
|
420
462
|
},
|
|
421
463
|
{
|
|
422
464
|
"id": "core-local-ai:createLocalAIService",
|
|
@@ -430,7 +472,7 @@
|
|
|
430
472
|
"summary": "Composes selected native llama.cpp, Ollama and ONNX engines as a Core service with retained process/worker ownership and model lifecycle.",
|
|
431
473
|
"availability": "Node with selected upstream runtime distributions or available configured system services",
|
|
432
474
|
"protocol": "arcane/1 methods and events; llama.cpp OpenAI HTTP/SSE, Ollama native HTTP/NDJSON and ONNX tensor transport",
|
|
433
|
-
"normalization": "Application-owned runtime and model requirements; optional prepare supplies installed records during this service startup;
|
|
475
|
+
"normalization": "Application-owned runtime and model requirements; optional prepare supplies installed records during this service startup. getONNXRuntime() returns the actual prepared ONNX owner for native composition after context.getService('local-ai'); callers reacquire after recovery and retain the acquired handle for cleanup. llama.status/models observe without starting or restarting an engine. Independent services, complete responses and exact owned-process cleanup remain unchanged."
|
|
434
476
|
},
|
|
435
477
|
{
|
|
436
478
|
"id": "core-local-ai:default",
|
|
@@ -4276,7 +4318,7 @@
|
|
|
4276
4318
|
"summary": "Creates an app-neutral Core dispatcher with explicit services, request lifetimes, events and graceful drain.",
|
|
4277
4319
|
"availability": "Node on Windows, Linux and macOS native hosts; Android requires its host adaptation",
|
|
4278
4320
|
"protocol": "arcane/1 dispatcher and service lifecycle",
|
|
4279
|
-
"normalization": "Starts services independently,
|
|
4321
|
+
"normalization": "Starts services independently; runtime.getService(name) and context.getService(name) return the same registered object after only its shared startup, without a renderer or global barrier. Lookup is readiness, not a lifetime lease; new lookups reject during shutdown. Preserves complete results/errors, cancels request-lifetime work and drains accepted service work; runtime.replay publishes current dispatcher/service state without restart and preserves reentrant lifecycle publication order"
|
|
4280
4322
|
},
|
|
4281
4323
|
{
|
|
4282
4324
|
"id": "core-stdio:encodeCoreFrame",
|
|
@@ -967,8 +967,9 @@
|
|
|
967
967
|
{
|
|
968
968
|
"file": "runtime/arcane/components/theme-switcher.html",
|
|
969
969
|
"name": "theme-switcher.html",
|
|
970
|
-
"purpose": "Selects and refreshes system, light, dark, or custom theme mode.",
|
|
970
|
+
"purpose": "Selects and refreshes system, light, dark, or custom theme mode with per-instance choices and labels.",
|
|
971
971
|
"methods": [
|
|
972
|
+
"configure()",
|
|
972
973
|
"setMode()",
|
|
973
974
|
"refresh()"
|
|
974
975
|
],
|
|
@@ -1083,7 +1083,7 @@
|
|
|
1083
1083
|
"summary": "Loads and updates schema-defined app preferences through native storage with a narrow browser fallback.",
|
|
1084
1084
|
"availability": "Browser/native hybrid",
|
|
1085
1085
|
"protocol": "Arcane.preferences or app-scoped localStorage + per-realm globalThis.arcaneEvents authority",
|
|
1086
|
-
"normalization": "Complete
|
|
1086
|
+
"normalization": "Complete values and operation context retained; the default adapter recognizes only exact missing preferences namespace/matching method or existing Android unsupported capability before selecting existing app-scoped localStorage. Single operations retry once after disposal/cancellation checks; partial-service and genuine failures reject unchanged. An advertised rejected batch is never retried serially, and its original rejection is preserved before later local operations.",
|
|
1087
1087
|
"surface": "Event/error constants, default `PreferenceStore`, re-exported `Preference`/schema; load/set/setAll/reset APIs, required adapter get/set/delete plus optional setMany, state-free EventTarget/on compatibility, and `dispose()`."
|
|
1088
1088
|
},
|
|
1089
1089
|
{
|
|
@@ -1291,10 +1291,10 @@
|
|
|
1291
1291
|
"exports": [
|
|
1292
1292
|
"default"
|
|
1293
1293
|
],
|
|
1294
|
-
"summary": "Reads or applies native appearance, returning an explicit unsupported
|
|
1294
|
+
"summary": "Reads or applies native appearance, returning an explicit unsupported result when the bridge or optional namespace is absent.",
|
|
1295
1295
|
"availability": "Browser/native hybrid",
|
|
1296
1296
|
"protocol": "Arcane.appearance",
|
|
1297
|
-
"normalization": "Absent bridge
|
|
1297
|
+
"normalization": "Absent bridge keeps its browser result. Exact missing appearance namespace/matching method returns supported:false with the complete original diagnostic; no platform guess or cached absence. Partial-method, permission, transport, cancellation and other genuine errors reject unchanged; available() is callable bridge presence only.",
|
|
1298
1298
|
"surface": "default `SystemAppearance`; `available()`, `current()`, `apply()`."
|
|
1299
1299
|
},
|
|
1300
1300
|
{
|
|
@@ -112,7 +112,7 @@ snapshot remains owned until the browser's `afterprint` event.
|
|
|
112
112
|
| [`task-progress.html`](#task-progresshtml) | Runs and displays a task list with started/change/complete/error state. | `configure()`<br>`setTasks()`<br>`updateTask()`<br>`runTasks()`<br>`clear()`<br>`destroy()` | `task-progress-ready`<br>`task-progress-started`<br>`task-progress-change`<br>`task-progress-complete`<br>`task-progress-error` | Task state normalized; injected task results mixed |
|
|
113
113
|
| [`terminal-workspace.html`](#terminal-workspacehtml) | Presents multiple terminal sessions, output, active selection, theme, and terminal actions. | `configure()`<br>`addSession()`<br>`removeSession()`<br>`activateSession()`<br>`append()`<br>`clear()`<br>`setState()`<br>`setTheme()`<br>`focus()`<br>`destroy()` | `terminal-workspace-ready`<br>`terminal-submit`<br>`terminal-interrupt`<br>`terminal-clear`<br>`terminal-session-new`<br>`terminal-session-close`<br>`terminal-session-select`<br>`terminal-settings` | UI/session state normalized; native command results supplied externally |
|
|
114
114
|
| [`theme-editor.html`](#theme-editorhtml) | Edits, previews, saves, and resets semantic custom theme tokens. | `configure()`<br>`getTheme()`<br>`setTheme()`<br>`setBusy()`<br>`setStatus()`<br>`destroy()` | `theme-editor-ready`<br>`theme-preview`<br>`theme-save`<br>`theme-reset` | Fully normalized Theme values |
|
|
115
|
-
| [`theme-switcher.html`](#theme-switcherhtml) | Selects and refreshes system, light, dark, or custom theme mode. | `setMode()`<br>`refresh()` | No component-specific event | Preference/native appearance behavior mixed; no component-ready contract |
|
|
115
|
+
| [`theme-switcher.html`](#theme-switcherhtml) | Selects and refreshes system, light, dark, or custom theme mode with per-instance choices and labels. | `configure()`<br>`setMode()`<br>`refresh()` | No component-specific event | Preference/native appearance behavior mixed; no component-ready contract |
|
|
116
116
|
| [`unified-inbox.html`](#unified-inboxhtml) | Displays provider-neutral communication threads with active/loading state. | `configure()`<br>`setThreads()`<br>`setActive()`<br>`setLoading()`<br>`destroy()` | `unified-inbox-ready`<br>`inbox-refresh`<br>`thread-select` | DOM-normalized |
|
|
117
117
|
| [`voice-transcription.html`](#voice-transcriptionhtml) | Records manual clips or optional continuous microphone audio with pause/periodic segments, ordered transcription and saves, retained failures, and complete transcript delivery. | `configure()`<br>`requestSTTActivation()`<br>`startRecording()`<br>`stopRecording()`<br>`retryTranscription()`<br>`cancelRecording()`<br>`save()`<br>`completeTranscription()/complete()`<br>`clear()`<br>`reset()`<br>`destroy()` | `voice-transcription-ready`<br>`voice-transcription-state`<br>`voice-transcription-segment`<br>`voice-transcription-empty`<br>`voice-transcription-error`<br>`voice-transcription-change`<br>`voice-transcription-complete`<br>`speech-transcription-complete`<br>`speech-transcription-cancelled`<br>`speech-stt-activation-request`<br>`speech-stt-activation-error` | Sticky STT readiness, capture/queue lifecycle, retry, cancellation, and complete state/text are normalized; media/provider behavior remains external |
|
|
118
118
|
| [`weather-widget.html`](#weather-widgethtml) | Displays normalized current and daily weather with refresh intent. | `setWeather()`<br>`clear()`<br>`destroy()` | `weather-widget-ready`<br>`weather-refresh` | Display normalized; provider supplied externally |
|
|
@@ -2015,11 +2015,61 @@ Shared dependencies: [`Theme.js`](runtime-entities.md#themejs).
|
|
|
2015
2015
|
|
|
2016
2016
|
### Overview
|
|
2017
2017
|
|
|
2018
|
-
Selects and refreshes system, light, dark, or custom theme mode.
|
|
2018
|
+
Selects and refreshes system, light, dark, or custom theme mode. Native buttons
|
|
2019
|
+
retain complete readable labels and wrap when their component runs out of room,
|
|
2020
|
+
independently of viewport width. Each button has a `2.75rem` minimum target in
|
|
2021
|
+
both dimensions. Selected buttons retain `aria-pressed` and an inset outline;
|
|
2022
|
+
disabled choices and keyboard focus have distinct presentation.
|
|
2019
2023
|
|
|
2020
2024
|
### Public surface
|
|
2021
2025
|
|
|
2022
|
-
Methods/properties: `setMode()`, `refresh()`.
|
|
2026
|
+
Methods/properties: `configure(options)`, `setMode(mode='system')`, `refresh()`.
|
|
2027
|
+
|
|
2028
|
+
`configure({modes,labels})` changes only this component's presentation:
|
|
2029
|
+
|
|
2030
|
+
- `modes` is an ordered array of the available identifiers `system`, `light`,
|
|
2031
|
+
`dark`, and `custom`. It selects both visible choices and DOM/keyboard order.
|
|
2032
|
+
Omitted `modes` retains the current presentation; an empty array displays no
|
|
2033
|
+
choices. Unknown or repeated identifiers throw `TypeError` before changing
|
|
2034
|
+
the presentation.
|
|
2035
|
+
- `labels` is a partial record of complete string labels keyed by those mode
|
|
2036
|
+
identifiers. Omitted labels keep their current text. Text is assigned through
|
|
2037
|
+
`textContent`, never interpreted as markup or reduced to initials. A label for
|
|
2038
|
+
a built-in mode that is not a string throws `TypeError`.
|
|
2039
|
+
- The return value is `{modes,labels}` containing independent mutable copies of
|
|
2040
|
+
the current presentation. Later changes to supplied/returned records do not
|
|
2041
|
+
reconfigure the component.
|
|
2042
|
+
|
|
2043
|
+
Label-only and unchanged-order configuration retain the existing buttons in
|
|
2044
|
+
place. An actual reorder restores keyboard focus to the previously focused
|
|
2045
|
+
button when that choice remains visible and enabled, without scrolling.
|
|
2046
|
+
|
|
2047
|
+
The default remains Auto / Light / Dark / Skin, using identifiers
|
|
2048
|
+
`system`, `light`, `dark`, and `custom`. A caller may omit Skin or change Auto's
|
|
2049
|
+
label to System without removing custom-theme support from other instances.
|
|
2050
|
+
Configuration never changes preferences, activates a theme, or replaces the
|
|
2051
|
+
current selected mode. If the active mode is omitted, no visible button claims
|
|
2052
|
+
to be selected. Restoring that choice restores its existing pressed and disabled
|
|
2053
|
+
state. Skin remains disabled until the manager has a saved custom theme.
|
|
2054
|
+
|
|
2055
|
+
For the initial presentation, `data-modes` accepts whitespace-separated mode
|
|
2056
|
+
identifiers and `data-system-label` supplies the complete system-mode label.
|
|
2057
|
+
These attributes are read once before the asynchronous ThemeManager import and
|
|
2058
|
+
preference refresh, so initial choices do not wait for `html-import-ready`.
|
|
2059
|
+
Use `configure()` after that event for subsequent presentation changes;
|
|
2060
|
+
changing these attributes later does not reconfigure an existing instance.
|
|
2061
|
+
|
|
2062
|
+
`setMode()` updates pressed state and the host's `data-mode` only. `refresh()`
|
|
2063
|
+
loads the existing ThemeManager state, updates selection and Skin availability,
|
|
2064
|
+
and resolves with the complete manager state. Clicking a choice uses the same
|
|
2065
|
+
manager persistence/activation operation; buttons remain disabled while that
|
|
2066
|
+
operation is pending. Presentation configuration preserves that pending state.
|
|
2067
|
+
|
|
2068
|
+
The host inherits text color. Existing `--app-bar-border` (falling back to
|
|
2069
|
+
`--border-color`), `--app-bar-accent` (then `--secondary-color`),
|
|
2070
|
+
`--app-bar-active-text` (then `--primary-color`), and `--focus-color` overrides
|
|
2071
|
+
remain supported. Applications own their palette and surrounding placement;
|
|
2072
|
+
the component adds no application-specific palette or settings section.
|
|
2023
2073
|
|
|
2024
2074
|
This fragment declares no component-specific readiness or action event; use the loader's `html-import-ready` only to know that import execution completed.
|
|
2025
2075
|
|
|
@@ -2033,11 +2083,18 @@ Shared dependencies: [`ThemeManager.js`](runtime-modules.md#thememanagerjs).
|
|
|
2033
2083
|
|
|
2034
2084
|
```html
|
|
2035
2085
|
<html-import
|
|
2036
|
-
id="theme-switcher
|
|
2037
|
-
href="/arcane/components/theme-switcher.html"
|
|
2086
|
+
id="theme-switcher"
|
|
2087
|
+
href="/node_modules/arcane-os/runtime/arcane/components/theme-switcher.html"
|
|
2088
|
+
data-modes="light dark system"
|
|
2089
|
+
data-system-label="System">
|
|
2038
2090
|
</html-import>
|
|
2039
2091
|
```
|
|
2040
2092
|
|
|
2093
|
+
This instance displays Light / Dark / System in that order. An instance without
|
|
2094
|
+
the two configuration attributes retains all four default choices. Both use
|
|
2095
|
+
the existing shared preference owner; presentation does not create a new store
|
|
2096
|
+
or migrate saved themes.
|
|
2097
|
+
|
|
2041
2098
|
## unified-inbox.html
|
|
2042
2099
|
|
|
2043
2100
|
### Overview
|
|
@@ -120,7 +120,7 @@ own asynchronous work, cancellation, and backpressure.
|
|
|
120
120
|
| [`OllamaSettings.js`](#ollamasettingsjs) | esm | Defines complete runtime/service preference schemas and deterministic Arcane brain alias names. | Cross-host | Fully normalized settings/name contract. |
|
|
121
121
|
| [`OpenMeteoWeatherProvider.js`](#openmeteoweatherproviderjs) | esm | Searches and loads Open-Meteo data into complete mutable Arcane weather entities. | Browser / native WebView / server with fetch + cloud | Provider data normalized to mutable entities; transport errors mixed. |
|
|
122
122
|
| [`PersistentAIChatSession.js`](#persistentaichatsessionjs) | esm | Adds explicit retained-history/memory policy to complete configured chat without changing DBOPFS or ChatEntity semantics. | Browser / native WebView with DBOPFS and configured chat | Retained context commits atomically; `persist:false` turns are one-operation-only. |
|
|
123
|
-
| [`PreferenceStore.js`](#preferencestorejs) | esm | Loads and updates schema-defined app preferences through native storage with a narrow browser fallback. | Browser/native hybrid | Complete
|
|
123
|
+
| [`PreferenceStore.js`](#preferencestorejs) | esm | Loads and updates schema-defined app preferences through native storage with a narrow browser fallback. | Browser/native hybrid | Complete values and operation context retained; exact optional namespace absence or existing Android unsupported capability selects the existing local adapter; partial-service and genuine failures remain errors; an advertised rejected batch is never retried serially. |
|
|
124
124
|
| [`PreparedSpeech.js`](#preparedspeechjs) | esm | Owns detached ordered preparation, semantic audio reuse, and per-caller cancellation behind AI.prepareTTS. | Browser / native WebView with injected synthesis and optional DBOPFS | Complete original inputs, ordered audio metadata, durable reuse, and observable preparation results. |
|
|
125
125
|
| [`PrintView.js`](#printviewjs) | esm | Prints current rendered content and title through one document-owned print lifecycle. | Browser / supported native WebView print implementation | Complete rendered snapshot, preparation cancellation, resource lifetime, and honest request result. |
|
|
126
126
|
| [`QRCode.min.js`](#qrcodeminjs) | classic-script | Vendored QRCode generator for DOM, canvas, SVG, and image output. | Browser vendor script | Vendor-native. |
|
|
@@ -134,7 +134,7 @@ own asynchronous work, cancellation, and backpressure.
|
|
|
134
134
|
| [`ScreenCapture.js`](#screencapturejs) | esm | Captures a display surface as image, video, or GIF with explicit lifecycle events. | Browser / native WebView | State/events normalized; permission and codec errors mixed. |
|
|
135
135
|
| [`SpeechPlayback.js`](#speechplaybackjs) | esm | Admits complete speech segments to a capacity-advertising provider immediately, retains serialized native/custom lookahead, and plays every result in exact indexed order. | Browser + native bridge | Stored part text stays exact; the outbound speech-input copy receives automatic formatting-mark cleanup; provider/media failures remain mixed. |
|
|
136
136
|
| [`StaticDocumentCatalog.js`](#staticdocumentcatalogjs) | esm | Loads a positive static document inventory with cache, search, and complete context. | Browser / native WebView / server with fetch | Mutable complete catalog/content normalization; malformed data and transport failures remain visible. |
|
|
137
|
-
| [`SystemAppearance.js`](#systemappearancejs) | esm | Reads or applies native appearance, returning an explicit unsupported
|
|
137
|
+
| [`SystemAppearance.js`](#systemappearancejs) | esm | Reads or applies native appearance, returning an explicit unsupported result when the bridge or optional namespace is absent. | Browser/native hybrid | Exact absent optional namespace normalized with its complete error; partial-method and genuine native errors preserved. |
|
|
138
138
|
| [`SystemPlatformPresentation.js`](#systemplatformpresentationjs) | classic-script | Maps kernel names to presentation labels/classes without granting platform authority. | Browser / native WebView classic script | Fully normalized presentation only. |
|
|
139
139
|
| [`SystemToolRegistry.js`](#systemtoolregistryjs) | esm | Registers validated command builders and constructs command strings without executing them. | Cross-host | Fully normalized definitions/quoting. |
|
|
140
140
|
| [`TerminalClient.js`](#terminalclientjs) | esm | Maps native terminal sessions and Arcane events into an EventTarget client. | Native bridge | Client events/state normalized; native result/error mixed. |
|
|
@@ -3475,9 +3475,31 @@ Exact exports: `PREFERENCE_STORE_ERROR_CODES`,
|
|
|
3475
3475
|
|
|
3476
3476
|
**Browser/native hybrid.** Complete ordinary values and returned snapshots remain
|
|
3477
3477
|
mutable after schema normalization. Non-Android
|
|
3478
|
-
`Arcane.preferences.setMany()` supplies the optional atomic batch.
|
|
3479
|
-
|
|
3480
|
-
|
|
3478
|
+
`Arcane.preferences.setMany()` supplies the optional atomic batch. The default
|
|
3479
|
+
adapter uses the existing app-scoped localStorage owner when there is no native
|
|
3480
|
+
preferences facade, on the existing Android route, or after either the existing
|
|
3481
|
+
`ANDROID_CAPABILITY_UNSUPPORTED` error or an exact Core lookup error:
|
|
3482
|
+
`code:'METHOD_NOT_ALLOWED'`, `reason:'core-namespace-unavailable'`,
|
|
3483
|
+
`namespace:'preferences'`, and `method:'preferences.<current operation>'`.
|
|
3484
|
+
This marker proves the entire optional namespace was absent before dispatch.
|
|
3485
|
+
A missing method in a partial/read-only service, an older unmarked error,
|
|
3486
|
+
permission denial, persistence failure, transport error, or cancellation never
|
|
3487
|
+
selects local storage. Explicit caller adapters retain their own behavior.
|
|
3488
|
+
|
|
3489
|
+
For `get`, `set`, and `delete`, that positively absent namespace retries the
|
|
3490
|
+
same operation once through the existing local adapter, then keeps that adapter
|
|
3491
|
+
for the store's later operations. Complete arguments and the existing
|
|
3492
|
+
`{operationId,signal}` context are retained. Disposal and caller cancellation
|
|
3493
|
+
are checked before selecting or invoking the local adapter, so a late native
|
|
3494
|
+
absence result cannot start a cancelled local write. No data location, schema,
|
|
3495
|
+
saved value, or migration is introduced.
|
|
3496
|
+
|
|
3497
|
+
An in-flight advertised `setMany` batch is never downgraded to serial writes
|
|
3498
|
+
after rejection. Exact namespace absence selects the local adapter for later
|
|
3499
|
+
operations and preserves that batch's original rejection with no local write.
|
|
3500
|
+
ThemeManager's first Light/Dark/System choice uses two ordinary `set` calls,
|
|
3501
|
+
not a batch: both may complete through the existing local owner before the
|
|
3502
|
+
selected theme is applied. Its persistence-first ordering is unchanged.
|
|
3481
3503
|
If cancellation settles after a native batch was dispatched, reload the store to
|
|
3482
3504
|
reconcile any atomic host commit that completed before cancellation. Transport:
|
|
3483
3505
|
Arcane.preferences or app-scoped localStorage. [Deep protocol details](protocols.md).
|
|
@@ -4064,7 +4086,8 @@ console.log(Object.keys(module));
|
|
|
4064
4086
|
|
|
4065
4087
|
### Overview
|
|
4066
4088
|
|
|
4067
|
-
Reads or applies native appearance, returning an explicit unsupported
|
|
4089
|
+
Reads or applies native appearance, returning an explicit unsupported result
|
|
4090
|
+
when the bridge or its optional namespace is absent.
|
|
4068
4091
|
|
|
4069
4092
|
### Public surface
|
|
4070
4093
|
|
|
@@ -4074,7 +4097,21 @@ Exact exports: `default`.
|
|
|
4074
4097
|
|
|
4075
4098
|
### Availability and normalization
|
|
4076
4099
|
|
|
4077
|
-
**Browser/native hybrid.**
|
|
4100
|
+
**Browser/native hybrid.** No bridge or callable method retains the existing
|
|
4101
|
+
`{supported:false,platform:'browser'}` result. A callable facade is not proof of
|
|
4102
|
+
an installed service: `available()` reports callable `apply` presence only.
|
|
4103
|
+
`current()` and `apply()` recognize only a matching Core
|
|
4104
|
+
`METHOD_NOT_ALLOWED` error with `reason:'core-namespace-unavailable'`,
|
|
4105
|
+
`namespace:'appearance'`, and the exact requested method. They return
|
|
4106
|
+
`{supported:false,reason:'core-namespace-unavailable',error}`, retaining the
|
|
4107
|
+
complete original error for diagnostics and making no platform or native
|
|
4108
|
+
application claim. Absence is not cached, so later service registration can
|
|
4109
|
+
serve the next operation. Partial-method absence, unmarked permission errors,
|
|
4110
|
+
transport/cancellation failures and all other native errors reject unchanged.
|
|
4111
|
+
Native success values and existing appearance input normalization remain
|
|
4112
|
+
unchanged. ThemeManager may therefore complete a browser color-scheme change
|
|
4113
|
+
when native appearance is explicitly unsupported, while genuine failures stay
|
|
4114
|
+
observable. Transport: Arcane.appearance. [Deep protocol details](protocols.md).
|
|
4078
4115
|
|
|
4079
4116
|
### Example
|
|
4080
4117
|
|
|
@@ -69,6 +69,8 @@ runtime layouts.
|
|
|
69
69
|
| `arcane-os/core/local-ai` | Native llama.cpp, Ollama and ONNX Core service, model readiness, complete responses and owned lifecycle. See [local AI through Core](local-ai.md). |
|
|
70
70
|
| `arcane-os/local-ai` | Official runtime installation and native artifact bundling for selected llama.cpp/Ollama/ONNX/image requirements and NeMo libraries. |
|
|
71
71
|
| `arcane-os/local-ai/onnx` | Retained native ONNX worker sessions with explicit graph loading and complete tensor inference. |
|
|
72
|
+
| `arcane-os/local-ai/decisions` | Explicit native Laya FP32 decisions using the existing ONNX owner and a tokenizer Worker. |
|
|
73
|
+
| `arcane-os/core/decisions` | Renderer-independent typed-decision service composed with existing local-AI and model-assets owners. |
|
|
72
74
|
| `arcane-os/ai/core-onnx` | Optional browser access to system ONNX through an existing Core connection. |
|
|
73
75
|
| `arcane-os/local-ai/image` | Retained native stable-diffusion.cpp context, complete PNG generation and owned worker lifetime. |
|
|
74
76
|
| `arcane-os/ai/core-image` | Browser image lifecycle and complete PNG Blobs through an available Core service. |
|
|
@@ -169,6 +171,9 @@ The remaining data-only subpaths are eight JSON Schemas and package metadata.
|
|
|
169
171
|
| `acceptWebSocket()` | function | `arcane-os`, `arcane-os/websocket` | WebSocket protocol | Node; browser-native client interoperability |
|
|
170
172
|
| `WS` | class | `arcane-os`, `arcane-os/websocket-client` | Shared WebSocket clients | Node and native-WebSocket browser hosts |
|
|
171
173
|
| `createBrowserDecisionModel()` | function | `arcane-os/ai/browser-decisions` | Browser typed decisions | Browser module Workers and the caller-selected inference backend |
|
|
174
|
+
| `createNativeDecisionModel()` | function | `arcane-os/local-ai/decisions` | Native typed decisions | Node with an existing native ONNX owner and selected Laya FP32 files |
|
|
175
|
+
| `createNativeDecisionService()` | function | `arcane-os/core/decisions` | Native typed decisions | Node Core with existing local-AI and model-assets services |
|
|
176
|
+
| `createNativeDecisionService default export` | function | `arcane-os/core/decisions` | Native typed decisions | Same native decision service factory |
|
|
172
177
|
| `fetchRequest()` | function | `arcane-os/ai/twin-cloud` | TWiN Cloud requests | Node and Browser; remote HTTPS provider |
|
|
173
178
|
| `fetchSystemOneRequest()` | function | `arcane-os/ai/twin-cloud` | TWiN Cloud state-and-questions requests | Node and Browser; remote HTTPS provider |
|
|
174
179
|
| `generateImages()` | function | `arcane-os/ai/twin-cloud` | TWiN Cloud image generation | Node and Browser with Fetch and Blob; remote HTTPS provider |
|
|
@@ -7297,9 +7302,18 @@ createCoreRuntime({application, version, services=[]}={})
|
|
|
7297
7302
|
```
|
|
7298
7303
|
|
|
7299
7304
|
Import it from `arcane-os/core/runtime`. The runtime exposes `current()`,
|
|
7300
|
-
`subscribe()`, `onFrame()`, `emit()`, `registerService()`, `start()`, `handle()`
|
|
7305
|
+
`subscribe()`, `onFrame()`, `emit()`, `registerService()`, `getService()`, `start()`, `handle()`
|
|
7301
7306
|
and idempotent `close()`.
|
|
7302
7307
|
|
|
7308
|
+
`await runtime.getService(name)` and service `context.getService(name)` return
|
|
7309
|
+
the actual registered service after its shared startup. They wait for that
|
|
7310
|
+
dependency alone, may start it before `runtime.start()`, and add no renderer or
|
|
7311
|
+
all-service barrier. Unknown services reject with `CORE_SERVICE_UNAVAILABLE`;
|
|
7312
|
+
new lookups during shutdown reject with `CORE_CLOSING`. Startup failures retain
|
|
7313
|
+
their original error. This is readiness, not a lifetime lease: retain acquired
|
|
7314
|
+
native handles for their actual cleanup rather than looking them up during
|
|
7315
|
+
disposal. See [native service composition](core-runtime.md#native-service-composition).
|
|
7316
|
+
|
|
7303
7317
|
Services start independently. Request-lifetime work receives cooperative
|
|
7304
7318
|
cancellation; accepted `lifetime:'service'` work survives renderer cancellation.
|
|
7305
7319
|
Shutdown stops admission, waits accepted responses, then runs each service's
|
|
@@ -8011,7 +8025,7 @@ Construction selects no model and installs no runtime or transport.
|
|
|
8011
8025
|
### Signature and result
|
|
8012
8026
|
|
|
8013
8027
|
```text
|
|
8014
|
-
createCoreLocalAIProvider({client
|
|
8028
|
+
createCoreLocalAIProvider({client,id='llama.cpp'}={})
|
|
8015
8029
|
```
|
|
8016
8030
|
|
|
8017
8031
|
Import it from `arcane-os/ai/core-local`. The provider implements
|
|
@@ -8023,6 +8037,16 @@ payloads and parsed streaming chunks, and cancel on observed readiness loss.
|
|
|
8023
8037
|
Missing Core reports unavailability; it does not choose a browser or cloud route.
|
|
8024
8038
|
Dispose/unregister at the caller's owning lifecycle boundary.
|
|
8025
8039
|
|
|
8040
|
+
Omitted `client` follows late installation, replacement and retirement through
|
|
8041
|
+
the shared Core installation subscription. An explicit client, including
|
|
8042
|
+
`null`, remains fixed. Replacement revokes readiness and cancels owned work;
|
|
8043
|
+
late results cannot restore it. `inspect()` distinguishes explicit load
|
|
8044
|
+
capability from loaded readiness, while `status()` remains observational.
|
|
8045
|
+
Disposal releases only an actually retained selection through its captured
|
|
8046
|
+
client, so never-loaded and already-unloaded providers send no native unload.
|
|
8047
|
+
The provider/2 runtime reconciles status at its operation boundaries; this
|
|
8048
|
+
does not add an idle role-state subscription.
|
|
8049
|
+
|
|
8026
8050
|
```javascript
|
|
8027
8051
|
import {createCoreLocalAIProvider} from 'arcane-os/ai/core-local';
|
|
8028
8052
|
import {getAIProviderRuntime} from 'arcane-os/ai-provider-runtime';
|
|
@@ -8055,6 +8079,13 @@ resolved installed runtime records. It returns a Core service definition with
|
|
|
8055
8079
|
existing Core lifecycle. Shutdown cancels owned work and joins owned processes;
|
|
8056
8080
|
an already running external service remains under its external owner.
|
|
8057
8081
|
|
|
8082
|
+
After `await context.getService('local-ai')`, `service.getONNXRuntime()` returns
|
|
8083
|
+
that service's actual prepared ONNX owner. It creates no engine and rejects
|
|
8084
|
+
unavailable or closing access. Reacquire on each explicit load after recovery;
|
|
8085
|
+
retain the returned handle for cleanup. Core shutdown cancels request-lifetime
|
|
8086
|
+
work, and independent services dispose concurrently. See
|
|
8087
|
+
[native service owners](local-ai.md#native-service-owners).
|
|
8088
|
+
|
|
8058
8089
|
Optional `prepare({signal,onEvent})` supplies resolved runtime records during
|
|
8059
8090
|
this service's startup. Only operations depending on that service wait for its
|
|
8060
8091
|
preparation; the development listener and independently composed image/model
|
|
@@ -8064,7 +8095,10 @@ requirements. The managed development and native entrypoints separate them.
|
|
|
8064
8095
|
|
|
8065
8096
|
The service provides `localai.status`, explicit `localai.services.recover`,
|
|
8066
8097
|
`llama.status/models/load/unload/chat`, `onnx.status/load/run/unload`, and the documented native Ollama methods.
|
|
8067
|
-
`localai.state` reports runtime/model changes. `llama.
|
|
8098
|
+
`localai.state` reports runtime/model changes. `llama.status` and `llama.models`
|
|
8099
|
+
observe current state without starting, restarting or waiting for an engine.
|
|
8100
|
+
Explicit load retains startup and exact catalog-membership checks.
|
|
8101
|
+
`llama.chunk` and `ollama.chunk`
|
|
8068
8102
|
carry original parsed chunks with `streamId`; terminal responses remain complete.
|
|
8069
8103
|
There is no background health polling or implicit model choice.
|
|
8070
8104
|
|
|
@@ -8081,7 +8115,7 @@ and [native bundling](local-ai.md#native-bundling).
|
|
|
8081
8115
|
|
|
8082
8116
|
`createONNXRuntime({modulePath,signal?,onEvent?})` from `arcane-os/local-ai/onnx`
|
|
8083
8117
|
owns retained native ONNX sessions in workers. It exposes `load({id,model,
|
|
8084
|
-
sessionOptions?,signal?})`, `run({id,feeds,fetches?,runOptions?,signal?})`,
|
|
8118
|
+
sessionOptions?,executionPreference?,signal?})`, `run({id,feeds,fetches?,runOptions?,signal?})`,
|
|
8085
8119
|
`unload({id,signal?})`, `current()`, replaying `subscribe(listener)` and `close()`.
|
|
8086
8120
|
The direct model path is absolute. Complete typed tensor records use
|
|
8087
8121
|
`{type,dims,data}`; callers own the actual graph's inputs and preprocessing.
|
|
@@ -8091,11 +8125,22 @@ before replacement. Independent sessions run concurrently; same-session work
|
|
|
8091
8125
|
waits at that session's loading/execution boundary. Queued cancellation removes
|
|
8092
8126
|
that request; active cancellation retires the affected worker and suppresses
|
|
8093
8127
|
its response. Native code can delay termination; cleanup waits for actual exit.
|
|
8128
|
+
`current().sessions[].stopping` revokes new-run availability at terminal
|
|
8129
|
+
shutdown; `exited` records actual Worker exit. A recoverable run error leaves
|
|
8130
|
+
the loaded session usable. Unload joins exit and output delivery even when a
|
|
8131
|
+
termination request fails, preserving the complete cleanup error.
|
|
8132
|
+
|
|
8133
|
+
The generic load defaults to CPU. `executionPreference:'gpu'` tries advertised
|
|
8134
|
+
CUDA, TensorRT, DirectML, CoreML and WebGPU session creation before CPU.
|
|
8135
|
+
Explicit `sessionOptions.executionProviders` takes precedence unchanged.
|
|
8136
|
+
The complete `execution` record reports discovery, provider attempts and
|
|
8137
|
+
fallback; successful creation establishes configuration, not physical GPU
|
|
8138
|
+
execution. Inference is never replayed on a different provider after failure.
|
|
8094
8139
|
See [complete signatures, readiness, cancellation and usage](local-ai.md#native-onnx-sessions).
|
|
8095
8140
|
|
|
8096
8141
|
## createCoreONNXRuntime()
|
|
8097
8142
|
|
|
8098
|
-
`createCoreONNXRuntime({client
|
|
8143
|
+
`createCoreONNXRuntime({client}={})` from
|
|
8099
8144
|
`arcane-os/ai/core-onnx` accesses an available Core ONNX service. Its `load`,
|
|
8100
8145
|
`run`, and `unload` mirror the native session selection and accept `signal` and
|
|
8101
8146
|
`timeoutMs` (default `0`). Relative model paths resolve at Core's `appRoot`.
|
|
@@ -8103,7 +8148,11 @@ The accessor owns complete tensor transport encoding/decoding, `inspect()`,
|
|
|
8103
8148
|
`current()`, replaying `subscribe(listener)` and `close()`. Closing cancels this
|
|
8104
8149
|
accessor's requests and subscriptions; unloading shared models is explicit.
|
|
8105
8150
|
Construction installs no runtime and opens no transport. Existing browser
|
|
8106
|
-
ONNX/Wllama remain independent.
|
|
8151
|
+
ONNX/Wllama remain independent. Omitted `client` follows late installation and
|
|
8152
|
+
reads each installed connection's current status; explicit clients, including
|
|
8153
|
+
`null`, remain fixed. Retirement or replacement clears readiness and cancels
|
|
8154
|
+
owned work, with late old-client results suppressed. Close also removes the
|
|
8155
|
+
installation subscription. See [Core and browser usage](local-ai.md#onnx-through-core-and-the-browser).
|
|
8107
8156
|
|
|
8108
8157
|
## createImageRuntime()
|
|
8109
8158
|
|
|
@@ -8143,12 +8192,18 @@ browser accessor's detach-only ownership below. See the
|
|
|
8143
8192
|
|
|
8144
8193
|
## createCoreImageRuntime()
|
|
8145
8194
|
|
|
8146
|
-
`createCoreImageRuntime({client
|
|
8195
|
+
`createCoreImageRuntime({client,signal?,onEvent?})`
|
|
8147
8196
|
from `arcane-os/ai/core-image` returns immediately with `load`, `generate`, `edit`,
|
|
8148
8197
|
`unload`, `inspect`, `current`, `subscribe` and `close`. It subscribes before
|
|
8149
8198
|
requesting an initial status snapshot so newer lifecycle events win. It opens
|
|
8150
8199
|
no connection and installs or selects no model.
|
|
8151
8200
|
|
|
8201
|
+
Omitted `client` follows late Core installation, replacement and retirement;
|
|
8202
|
+
an explicit client, including `null`, remains fixed. Each installed client is
|
|
8203
|
+
observed before its status request. Retirement cancels owned work and removes
|
|
8204
|
+
old readiness; late results cannot restore it. Close removes both service and
|
|
8205
|
+
installation subscriptions without closing the shared client or model.
|
|
8206
|
+
|
|
8152
8207
|
`load({model,context?,assetProjectionId?,resourcePaths?,signal?})` and
|
|
8153
8208
|
`generate({model,prompt,parameters?,assetProjectionId?,resourcePaths?,signal?,
|
|
8154
8209
|
onProgress?})` use the selected Core service. Generation acknowledges with
|
|
@@ -8445,6 +8500,14 @@ directory and complete member files.
|
|
|
8445
8500
|
|
|
8446
8501
|
`current()` returns `{closing,projections}`. `retain(id)` accepts a completed
|
|
8447
8502
|
projection and returns `{id,directory,members,release}` for a native owner.
|
|
8503
|
+
Native `prepare({id,workingDirectory,members,signal,onProgress})` accepts
|
|
8504
|
+
ordered `{path,url}` members and returns their ready projection. Explicit calls
|
|
8505
|
+
stream complete upstream responses through the same file owner; startup
|
|
8506
|
+
downloads nothing. Independent members transfer concurrently and progress
|
|
8507
|
+
reports phases and completed files. `release(id)` relinquishes preparation
|
|
8508
|
+
ownership; cancellation, release and disposal join fetches and writes before
|
|
8509
|
+
cleanup. Native retain handles keep completed files alive until actual engine
|
|
8510
|
+
release. See [native preparation](model-assets.md#native-ownership).
|
|
8448
8511
|
`dispose()` releases preparation ownership and joins file writes, closes and
|
|
8449
8512
|
all native retain lifetimes before cleanup. The native owner releases its
|
|
8450
8513
|
handle only after its actual context/worker use ends. Original stored model
|
|
@@ -9106,6 +9169,110 @@ See the [mounting contract](pwa.md#mountpwainstallprompt) and
|
|
|
9106
9169
|
[component reference](runtime-components.md#pwa-installhtml). The browser owns
|
|
9107
9170
|
native installation eligibility and URL-bar promotion.
|
|
9108
9171
|
|
|
9172
|
+
## createNativeDecisionModel()
|
|
9173
|
+
|
|
9174
|
+
### Overview
|
|
9175
|
+
|
|
9176
|
+
Runs explicitly selected Laya FP32 option scoring through an existing native
|
|
9177
|
+
ONNX owner, with tokenization in a Node Worker. It creates no second inference
|
|
9178
|
+
engine and starts no model download at construction.
|
|
9179
|
+
|
|
9180
|
+
### Signature and result
|
|
9181
|
+
|
|
9182
|
+
```text
|
|
9183
|
+
createNativeDecisionModel({onnx,modelAssets,workingDirectory,paths,model='onnx-community/laya-typed-decisions-ONNX',revision='main',dtype='fp32',sessionOptions,executionPreference='gpu',signal}={})
|
|
9184
|
+
```
|
|
9185
|
+
|
|
9186
|
+
Import from `arcane-os/local-ai/decisions`. Supply the existing `onnx` owner and
|
|
9187
|
+
either `modelAssets` plus `workingDirectory`, or native `paths` for the model,
|
|
9188
|
+
tokenizer and tokenizer configuration. The selected graph requires FP32. The
|
|
9189
|
+
handle exposes `load`, `evaluate`, `classify`, `current`, `status`, `subscribe`,
|
|
9190
|
+
`unload` and terminal `dispose`; `classify` aliases `evaluate` and `status`
|
|
9191
|
+
aliases `current`.
|
|
9192
|
+
|
|
9193
|
+
`evaluate(rows,{signal,runOptions})` preserves each complete `state`, `question`,
|
|
9194
|
+
`options` and optional `type` separately. It returns `{decisions,outputs}` with
|
|
9195
|
+
original rows, typed values, raw logits, unrounded probabilities and every
|
|
9196
|
+
named tensor output. It requires a loading or loaded activation. Cancellation
|
|
9197
|
+
retires the shared activation and joins its actual ONNX/tokenizer lifetime;
|
|
9198
|
+
working files remain retained until both Workers exit. Ordinary invalid rows
|
|
9199
|
+
leave a healthy session and sibling evaluations intact.
|
|
9200
|
+
|
|
9201
|
+
### Availability and normalization
|
|
9202
|
+
|
|
9203
|
+
**Node on Windows, Linux and macOS with the selected ONNX Runtime; Android needs
|
|
9204
|
+
host adaptation.** GPU preference attempts actual advertised providers before
|
|
9205
|
+
CPU fallback; accepted configuration does not prove GPU node execution. Model
|
|
9206
|
+
selection, unchanged payloads, scoring interpretation and persistence remain
|
|
9207
|
+
application-owned. Complete lifecycle, errors and paths are documented in
|
|
9208
|
+
[native typed decisions](native-decisions.md).
|
|
9209
|
+
|
|
9210
|
+
### Example
|
|
9211
|
+
|
|
9212
|
+
```javascript
|
|
9213
|
+
import {createNativeDecisionModel} from 'arcane-os/local-ai/decisions';
|
|
9214
|
+
|
|
9215
|
+
function createMoonChefDecisions({onnx, paths}) {
|
|
9216
|
+
return createNativeDecisionModel({onnx, paths});
|
|
9217
|
+
}
|
|
9218
|
+
```
|
|
9219
|
+
|
|
9220
|
+
The caller explicitly loads the returned model before evaluation and unloads
|
|
9221
|
+
or disposes it at its owning boundary; defining this function downloads nothing.
|
|
9222
|
+
|
|
9223
|
+
## createNativeDecisionService()
|
|
9224
|
+
|
|
9225
|
+
### Overview
|
|
9226
|
+
|
|
9227
|
+
Composes the same native decision model into an existing Core runtime without
|
|
9228
|
+
a renderer. The factory starts no inference, tokenizer or model preparation.
|
|
9229
|
+
|
|
9230
|
+
### Signature and result
|
|
9231
|
+
|
|
9232
|
+
```text
|
|
9233
|
+
createNativeDecisionService(configuration={}, {appRoot=process.cwd()}={})
|
|
9234
|
+
```
|
|
9235
|
+
|
|
9236
|
+
Import from `arcane-os/core/decisions`. Configuration selects the model options
|
|
9237
|
+
above and an optional service `name` (default `decisions`); relative supplied
|
|
9238
|
+
`paths` resolve from `appRoot`. Explicit load obtains the registered local-AI
|
|
9239
|
+
and, when needed, model-assets owners through `context.getService`, then
|
|
9240
|
+
reacquires `getONNXRuntime()` after any recovery. Native members are `load`,
|
|
9241
|
+
`evaluate`, `classify`, `current`, `subscribe`, `unload`, `dispose` and Core
|
|
9242
|
+
`start(context)`.
|
|
9243
|
+
|
|
9244
|
+
RPC exposes `decisions.status`, `decisions.load`, `decisions.evaluate` and
|
|
9245
|
+
`decisions.unload`. Evaluation accepts `{rows,runOptions?}` and returns complete
|
|
9246
|
+
`{decisions,outputs}` using the existing tensor codec at the JSON boundary.
|
|
9247
|
+
`decisions.state` and replaying `subscribe(listener,{emitCurrent:true,signal})`
|
|
9248
|
+
report lifecycle. Unload is accepted service-lifetime cleanup; host shutdown
|
|
9249
|
+
still cancels request-lifetime load/evaluation.
|
|
9250
|
+
|
|
9251
|
+
### Availability and normalization
|
|
9252
|
+
|
|
9253
|
+
**Node Core with an existing local-AI ONNX service and selected model files.**
|
|
9254
|
+
Registration does not wait for all services or open another host. Original
|
|
9255
|
+
inputs, complete outputs, failures and cleanup semantics match the native
|
|
9256
|
+
model. See [composition and example](native-decisions.md#compose-with-existing-core-services).
|
|
9257
|
+
|
|
9258
|
+
### Example
|
|
9259
|
+
|
|
9260
|
+
```javascript
|
|
9261
|
+
import {createNativeDecisionService} from 'arcane-os/core/decisions';
|
|
9262
|
+
|
|
9263
|
+
const decisions = createNativeDecisionService({
|
|
9264
|
+
model: 'onnx-community/laya-typed-decisions-ONNX',
|
|
9265
|
+
dtype: 'fp32',
|
|
9266
|
+
workingDirectory: '.models/laya'
|
|
9267
|
+
});
|
|
9268
|
+
// Add decisions to the application's existing Core services; load explicitly.
|
|
9269
|
+
```
|
|
9270
|
+
|
|
9271
|
+
## createNativeDecisionService default export
|
|
9272
|
+
|
|
9273
|
+
The default export from `arcane-os/core/decisions` is exactly the named
|
|
9274
|
+
`createNativeDecisionService` factory, with the same arguments and lifecycle.
|
|
9275
|
+
|
|
9109
9276
|
## createBrowserDecisionModel()
|
|
9110
9277
|
|
|
9111
9278
|
### Overview
|
package/package.json
CHANGED
|
@@ -1,11 +1,62 @@
|
|
|
1
1
|
<style>
|
|
2
|
-
:host{
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
:host {
|
|
3
|
+
display:inline-block;
|
|
4
|
+
min-inline-size:0;
|
|
5
|
+
max-inline-size:100%;
|
|
6
|
+
color:inherit;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.switcher {
|
|
10
|
+
display:flex;
|
|
11
|
+
flex-wrap:wrap;
|
|
12
|
+
align-items:center;
|
|
13
|
+
gap:.15rem;
|
|
14
|
+
box-sizing:border-box;
|
|
15
|
+
max-inline-size:100%;
|
|
16
|
+
padding:.2rem;
|
|
17
|
+
border:1px solid var(--app-bar-border,var(--border-color,rgba(255,255,255,.25)));
|
|
18
|
+
border-radius:1.6rem;
|
|
19
|
+
background:color-mix(in srgb,currentColor 8%,transparent);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
button {
|
|
23
|
+
appearance:none;
|
|
24
|
+
flex:1 0 auto;
|
|
25
|
+
box-sizing:border-box;
|
|
26
|
+
min-inline-size:2.75rem;
|
|
27
|
+
max-inline-size:100%;
|
|
28
|
+
min-block-size:2.75rem;
|
|
29
|
+
padding:.5rem .75rem;
|
|
30
|
+
border:0;
|
|
31
|
+
border-radius:1.4rem;
|
|
32
|
+
background:transparent;
|
|
33
|
+
color:inherit;
|
|
34
|
+
cursor:pointer;
|
|
35
|
+
font:700 .875rem/1.25 system-ui,sans-serif;
|
|
36
|
+
text-align:center;
|
|
37
|
+
white-space:normal;
|
|
38
|
+
overflow-wrap:anywhere;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
button:hover:not(:disabled) {
|
|
42
|
+
background:color-mix(in srgb,currentColor 14%,transparent);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
button[aria-pressed="true"] {
|
|
46
|
+
background:var(--app-bar-accent,var(--secondary-color,rgb(196,154,82)));
|
|
47
|
+
color:var(--app-bar-active-text,var(--primary-color,rgb(23,34,56)));
|
|
48
|
+
box-shadow:inset 0 0 0 .1rem currentColor;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
button:disabled {
|
|
52
|
+
cursor:not-allowed;
|
|
53
|
+
opacity:.55;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
button:focus-visible {
|
|
57
|
+
outline:.18rem solid var(--focus-color,currentColor);
|
|
58
|
+
outline-offset:.12rem;
|
|
59
|
+
}
|
|
9
60
|
</style>
|
|
10
61
|
<div class="switcher" role="group" aria-label="Color scheme">
|
|
11
62
|
<button type="button" data-scheme="system" aria-pressed="false" title="Use device theme">Auto</button>
|
|
@@ -16,31 +67,79 @@
|
|
|
16
67
|
<script type="module">
|
|
17
68
|
const host=this;
|
|
18
69
|
const root=host.shadowRoot;
|
|
70
|
+
const group=root.querySelector('.switcher');
|
|
19
71
|
const buttons=Array.from(root.querySelectorAll('[data-scheme]'));
|
|
72
|
+
let modes=buttons.map(function scheme(button){return button.dataset.scheme;});
|
|
73
|
+
let labels=Object.fromEntries(buttons.map(function label(button){
|
|
74
|
+
return [button.dataset.scheme,button.textContent];
|
|
75
|
+
}));
|
|
76
|
+
let busy=false;
|
|
77
|
+
|
|
78
|
+
host.configure=configure;
|
|
79
|
+
configure({
|
|
80
|
+
modes:host.dataset.modes===undefined?modes:host.dataset.modes.split(/\s+/u).filter(Boolean),
|
|
81
|
+
labels:host.dataset.systemLabel===undefined?{}:{system:host.dataset.systemLabel}
|
|
82
|
+
});
|
|
83
|
+
|
|
20
84
|
const {default:ThemeManager}=await import('../modules/ThemeManager.js');
|
|
21
85
|
const manager=new ThemeManager();
|
|
22
86
|
|
|
23
87
|
host.setMode=setMode;
|
|
24
88
|
host.refresh=refresh;
|
|
25
|
-
|
|
89
|
+
group.addEventListener('click',async function selectScheme(event){
|
|
26
90
|
const button=event.target.closest('[data-scheme]');
|
|
27
|
-
if(!button) return;
|
|
91
|
+
if(!button||button.disabled) return;
|
|
28
92
|
setBusy(true);
|
|
29
93
|
try{
|
|
30
94
|
const state=button.dataset.scheme==='custom'?await manager.activateCustom():await manager.setScheme(button.dataset.scheme);
|
|
31
95
|
setMode(state.mode);setCustomAvailable(Boolean(state.theme));
|
|
32
96
|
}finally{setBusy(false);setCustomAvailable(Boolean(manager.customTheme));}
|
|
33
97
|
});
|
|
34
|
-
globalThis.addEventListener('arcane-theme-change',()
|
|
98
|
+
globalThis.addEventListener('arcane-theme-change',function themeChanged(){
|
|
99
|
+
refresh().catch(function refreshRejected(){});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
function configure(options={}){
|
|
103
|
+
const nextModes=options.modes===undefined?modes:[...options.modes];
|
|
104
|
+
const nextLabels={...labels,...options.labels};
|
|
105
|
+
const visible=[];
|
|
106
|
+
for(const mode of nextModes){
|
|
107
|
+
const button=buttons.find(function matchingScheme(candidate){return candidate.dataset.scheme===mode;});
|
|
108
|
+
if(!button) throw new TypeError(`Unknown theme-switcher mode: ${mode}`);
|
|
109
|
+
if(visible.includes(button)) throw new TypeError(`Repeated theme-switcher mode: ${mode}`);
|
|
110
|
+
visible.push(button);
|
|
111
|
+
}
|
|
112
|
+
for(const button of buttons){
|
|
113
|
+
const label=nextLabels[button.dataset.scheme];
|
|
114
|
+
if(typeof label!=='string') throw new TypeError('Theme-switcher labels must be strings.');
|
|
115
|
+
}
|
|
116
|
+
modes=nextModes;
|
|
117
|
+
labels=nextLabels;
|
|
118
|
+
for(const button of buttons) button.textContent=labels[button.dataset.scheme];
|
|
119
|
+
const reordered=group.children.length!==visible.length||visible.some(function moved(button,index){
|
|
120
|
+
return group.children[index]!==button;
|
|
121
|
+
});
|
|
122
|
+
if(reordered){
|
|
123
|
+
const focused=root.activeElement;
|
|
124
|
+
group.replaceChildren(...visible);
|
|
125
|
+
if(visible.includes(focused)&&!focused.disabled) focused.focus({preventScroll:true});
|
|
126
|
+
}
|
|
127
|
+
return {modes:[...modes],labels:{...labels}};
|
|
128
|
+
}
|
|
35
129
|
|
|
36
130
|
function setMode(mode='system'){
|
|
37
131
|
for(const button of buttons) button.setAttribute('aria-pressed',String(button.dataset.scheme===mode));
|
|
38
132
|
host.dataset.mode=mode;
|
|
39
133
|
return mode;
|
|
40
134
|
}
|
|
41
|
-
function setBusy(value){
|
|
42
|
-
|
|
135
|
+
function setBusy(value){
|
|
136
|
+
busy=Boolean(value);
|
|
137
|
+
for(const button of buttons) button.disabled=busy;
|
|
138
|
+
}
|
|
139
|
+
function setCustomAvailable(value){
|
|
140
|
+
buttons.find(function customScheme(button){return button.dataset.scheme==='custom';}).disabled=busy||!value;
|
|
141
|
+
}
|
|
43
142
|
async function refresh(){const state=await manager.load();setMode(state.mode);setCustomAvailable(Boolean(state.theme));return state;}
|
|
44
143
|
|
|
45
|
-
refresh().catch(()
|
|
144
|
+
refresh().catch(function refreshRejected(){setMode('system');});
|
|
46
145
|
</script>
|
|
@@ -153,21 +153,26 @@ function nativeAdapter(){
|
|
|
153
153
|
return preferences;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
function isUnsupportedNativeAdapter(error){
|
|
157
|
-
return error?.code==='ANDROID_CAPABILITY_UNSUPPORTED'
|
|
156
|
+
function isUnsupportedNativeAdapter(error,method){
|
|
157
|
+
return error?.code==='ANDROID_CAPABILITY_UNSUPPORTED'
|
|
158
|
+
||(error?.code==='METHOD_NOT_ALLOWED'
|
|
159
|
+
&&error.reason==='core-namespace-unavailable'
|
|
160
|
+
&&error.namespace==='preferences'
|
|
161
|
+
&&error.method===`preferences.${method}`);
|
|
158
162
|
}
|
|
159
163
|
|
|
160
|
-
function preferenceAdapter(){
|
|
164
|
+
function preferenceAdapter(assertActive){
|
|
161
165
|
const local=localAdapter('arcane.preferences');
|
|
162
166
|
if(is.function(globalThis.arcaneAndroid?.postMessage)) return local;
|
|
163
167
|
const native=nativeAdapter();
|
|
164
168
|
if(!native) return local;
|
|
165
169
|
let active=native;
|
|
166
|
-
async function call(method,args){
|
|
170
|
+
async function call(method,args,context){
|
|
167
171
|
try{
|
|
168
172
|
return await active[method](...args);
|
|
169
173
|
}catch(error){
|
|
170
|
-
if(active!==native||!isUnsupportedNativeAdapter(error)) throw error;
|
|
174
|
+
if(active!==native||!isUnsupportedNativeAdapter(error,method)) throw error;
|
|
175
|
+
assertActive(context?.signal);
|
|
171
176
|
active=local;
|
|
172
177
|
delete adapter.setMany;
|
|
173
178
|
if(!is.function(active[method])) throw error;
|
|
@@ -175,19 +180,19 @@ function preferenceAdapter(){
|
|
|
175
180
|
}
|
|
176
181
|
}
|
|
177
182
|
const adapter={
|
|
178
|
-
async get(key){
|
|
179
|
-
return call('get',[key]);
|
|
183
|
+
async get(key,context){
|
|
184
|
+
return call('get',[key,context],context);
|
|
180
185
|
},
|
|
181
|
-
async set(key,value){
|
|
182
|
-
return call('set',[key,value]);
|
|
186
|
+
async set(key,value,context){
|
|
187
|
+
return call('set',[key,value,context],context);
|
|
183
188
|
},
|
|
184
|
-
async delete(key){
|
|
185
|
-
return call('delete',[key]);
|
|
189
|
+
async delete(key,context){
|
|
190
|
+
return call('delete',[key,context],context);
|
|
186
191
|
}
|
|
187
192
|
};
|
|
188
193
|
if(is.function(native.setMany)){
|
|
189
194
|
adapter.setMany=async function setMany(entries,context){
|
|
190
|
-
return call('setMany',[entries,context]);
|
|
195
|
+
return call('setMany',[entries,context],context);
|
|
191
196
|
};
|
|
192
197
|
}
|
|
193
198
|
return adapter;
|
|
@@ -204,7 +209,7 @@ export default class PreferenceStore extends EventTarget{
|
|
|
204
209
|
super();
|
|
205
210
|
this.namespace=String(namespace||'arcane');
|
|
206
211
|
this.schema=preferenceSchema(schema);
|
|
207
|
-
this.adapter=validateAdapter(adapter||preferenceAdapter());
|
|
212
|
+
this.adapter=validateAdapter(adapter||preferenceAdapter(this.#assertOperationActive.bind(this)));
|
|
208
213
|
this.values=this.defaults();
|
|
209
214
|
this.#events=createArcaneEventSource(
|
|
210
215
|
this,
|
|
@@ -8,16 +8,34 @@ export default class SystemAppearance{
|
|
|
8
8
|
|
|
9
9
|
async current(){
|
|
10
10
|
if(!this.api||!is.function(this.api.current)) return {supported:false,platform:'browser'};
|
|
11
|
-
|
|
11
|
+
try{
|
|
12
|
+
return await this.api.current();
|
|
13
|
+
}catch(error){
|
|
14
|
+
return unsupportedNamespace(error,'current');
|
|
15
|
+
}
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
async apply(input={}){
|
|
15
19
|
if(!this.available()) return {supported:false,platform:'browser'};
|
|
16
20
|
const scheme=['system','light','dark'].includes(input.scheme)?input.scheme:'system';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
try{
|
|
22
|
+
return await this.api.apply({
|
|
23
|
+
scheme,
|
|
24
|
+
captionColor:scheme==='system'?null:input.captionColor||null,
|
|
25
|
+
textColor:scheme==='system'?null:input.textColor||null
|
|
26
|
+
});
|
|
27
|
+
}catch(error){
|
|
28
|
+
return unsupportedNamespace(error,'apply');
|
|
29
|
+
}
|
|
22
30
|
}
|
|
23
31
|
}
|
|
32
|
+
|
|
33
|
+
function unsupportedNamespace(error,method){
|
|
34
|
+
if(error?.code==='METHOD_NOT_ALLOWED'
|
|
35
|
+
&&error.reason==='core-namespace-unavailable'
|
|
36
|
+
&&error.namespace==='appearance'
|
|
37
|
+
&&error.method===`appearance.${method}`){
|
|
38
|
+
return {supported:false,reason:'core-namespace-unavailable',error};
|
|
39
|
+
}
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
package/src/core/runtime.mjs
CHANGED
|
@@ -267,7 +267,21 @@ class CoreRuntime {
|
|
|
267
267
|
|
|
268
268
|
#request(frame) {
|
|
269
269
|
const registration = this.#methods.get(frame.method);
|
|
270
|
-
if (!registration)
|
|
270
|
+
if (!registration) {
|
|
271
|
+
const namespace = frame.method.split('.')[0];
|
|
272
|
+
const prefix = `${namespace}.`;
|
|
273
|
+
const namespacePresent = this.#services.has(namespace)
|
|
274
|
+
|| [...this.#methods.keys(), 'system.ping', 'app.current', 'version.current'].some(
|
|
275
|
+
function inNamespace(method) { return method.startsWith(prefix); }
|
|
276
|
+
);
|
|
277
|
+
throw new CoreError({
|
|
278
|
+
code: 'METHOD_NOT_ALLOWED',
|
|
279
|
+
message: `Core does not expose ${frame.method}.`,
|
|
280
|
+
reason: namespacePresent ? 'core-method-unavailable' : 'core-namespace-unavailable',
|
|
281
|
+
namespace,
|
|
282
|
+
method: frame.method
|
|
283
|
+
});
|
|
284
|
+
}
|
|
271
285
|
const {service, handle, lifetime} = registration;
|
|
272
286
|
const controller = new AbortController();
|
|
273
287
|
const request = {id: frame.id, method: frame.method, lifetime, controller, task: null};
|