arcane-os 0.52.1 → 0.54.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 (39) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/NOTICE +4 -1
  3. package/README.md +1 -1
  4. package/bin/arcane-test.mjs +2 -1
  5. package/browser-runtime/ai/browser-decisions.mjs +405 -0
  6. package/browser-runtime/ai/decision-runtime.mjs +281 -0
  7. package/browser-runtime/ai/decision-worker.mjs +67 -0
  8. package/browser-runtime/dependencies/event-pubsub/dependencies/strong-type/index.js +1151 -0
  9. package/browser-runtime/dependencies/event-pubsub/dependencies/strong-type/licence +21 -0
  10. package/browser-runtime/dependencies/event-pubsub/dependencies/strong-type/package.json +61 -0
  11. package/browser-runtime/dependencies/event-pubsub/index.js +2 -2
  12. package/browser-runtime/dependencies/event-pubsub/package.json +11 -4
  13. package/browser-runtime/dependencies/ws-share/WS.js +128 -0
  14. package/browser-runtime/dependencies/ws-share/licence.md +27 -0
  15. package/browser-runtime/dependencies/ws-share/package.json +64 -0
  16. package/browser-runtime/websocket-client.mjs +1 -0
  17. package/docs/event-manager.md +7 -4
  18. package/docs/reference/ai/browser-decisions.md +184 -0
  19. package/docs/reference/inventory/package-api.json +44 -2
  20. package/docs/reference/inventory/runtime-modules.json +17 -4
  21. package/docs/reference/protocols.md +76 -1
  22. package/docs/reference/runtime-modules.md +45 -2
  23. package/docs/reference/sdk-api.md +280 -6
  24. package/docs/reference/websocket-client.md +132 -0
  25. package/node_modules/event-pubsub/CHANGELOG.md +12 -1
  26. package/node_modules/event-pubsub/MIGRATION.md +8 -5
  27. package/node_modules/event-pubsub/README.md +75 -19
  28. package/node_modules/event-pubsub/SECURITY.md +3 -3
  29. package/node_modules/event-pubsub/index.js +2 -2
  30. package/node_modules/event-pubsub/package.json +11 -4
  31. package/package.json +9 -5
  32. package/runtime/arcane/modules/HTMLImport.js +81 -26
  33. package/runtime/arcane/modules/HTMLImportScript.js +3 -0
  34. package/src/import-map.mjs +416 -59
  35. package/src/index.mjs +2 -0
  36. package/src/packager/core.mjs +24 -6
  37. package/src/packager/native-modules.mjs +458 -0
  38. package/src/testing-loader.mjs +41 -20
  39. package/src/websocket.mjs +479 -0
@@ -8,9 +8,9 @@
8
8
  "sdkVersion": "0.51.1",
9
9
  "protocol": "arcane/1"
10
10
  },
11
- "artifactCount": 92,
12
- "javascriptArtifactCount": 90,
13
- "esmExportCount": 372,
11
+ "artifactCount": 93,
12
+ "javascriptArtifactCount": 91,
13
+ "esmExportCount": 373,
14
14
  "artifacts": [
15
15
  {
16
16
  "file": "runtime/arcane/modules/AI.js",
@@ -719,12 +719,25 @@
719
719
  "exports": [
720
720
  "default"
721
721
  ],
722
- "summary": "Defines the same-origin `<html-import>` loader with open shadow root, inline script execution, and readiness/error events.",
722
+ "summary": "Defines the same-origin `<html-import>` loader with open shadow root, inline or packaged external script execution, and readiness/error events.",
723
723
  "availability": "Browser / native WebView",
724
724
  "protocol": "Same-origin fetch + DOM",
725
725
  "normalization": "Public error detail normalized; fetch/DOM failure preserved.",
726
726
  "surface": "default `HTMLImport`; registers `html-import`; `connectedCallback()` and `ready`."
727
727
  },
728
+ {
729
+ "file": "runtime/arcane/modules/HTMLImportScript.js",
730
+ "name": "HTMLImportScript.js",
731
+ "kind": "esm",
732
+ "exports": [
733
+ "createHTMLImportScript"
734
+ ],
735
+ "summary": "Renders the complete classic-script host wrapper shared by HTMLImport and native-module packaging.",
736
+ "availability": "Cross-host",
737
+ "protocol": "In-process only",
738
+ "normalization": "Complete source retained with a terminating newline before the wrapper closes.",
739
+ "surface": "`createHTMLImportScript(source)` returns the script text without executing it."
740
+ },
728
741
  {
729
742
  "file": "runtime/arcane/modules/InMemoryCommunicationProvider.js",
730
743
  "name": "InMemoryCommunicationProvider.js",
@@ -174,6 +174,69 @@ output must remain separate; a conflicting native assembly fails before it
174
174
  packages any app. App launch paths, resource URLs, and enabled PWA
175
175
  representations retain their package-relative layout.
176
176
 
177
+ ## Native-module package output
178
+
179
+ The public `packageApp` operation accepts `moduleFormat:'native'`. Omission, or
180
+ `'import-map'`, retains ordinary browser output. Optional operation-level
181
+ `outputDirectory` overrides only this invocation's destination; `verifyApp`
182
+ accepts that same override. Configuration, source layout, app identity, storage
183
+ scope and previously generated sibling outputs remain unchanged.
184
+
185
+ The native transformation runs in the selected package stage after application
186
+ adapter work, before the final inventory and any enabled PWA artifacts. It uses
187
+ the existing selected document/runtime records and shared lexical/HTML owners.
188
+ Each selected document supplies its saved maps and authored base. Native mode
189
+ uses the static layout with map declarations before executable scripts; it does
190
+ not reproduce late-map insertion or its already-resolved-module timing rules.
191
+ Exact keys, longest matching prefixes and most-specific importer scopes resolve to package
192
+ URLs, including URL aliases used by direct installed-SDK layouts. Static
193
+ imports, re-exports, string-literal dynamic imports and string-literal
194
+ `import.meta.resolve()` become native relative references. Query strings and
195
+ fragments retain their meaning. Equivalent graphs share output modules;
196
+ documents whose maps resolve differently receive distinct context files beside
197
+ the original module, including when their graphs contain cycles.
198
+
199
+ Selected document import-map elements are consumed in the output only.
200
+ Executable inline document scripts move into complete external files while
201
+ their script elements retain position, type and effective scheduling. The
202
+ packager removes ineffective `async`/`defer` attributes only from formerly inline
203
+ classic scripts, whose external form otherwise would activate those attributes.
204
+ Module scripts and already-external document scripts retain their attributes.
205
+ Imported component scripts use one canonical classic wrapper, with an explicit
206
+ `data-arcane-packaged-script` marker consumed by `HTMLImport`. That path loads
207
+ the external script directly and retains per-instance host binding, ordered
208
+ asynchronous completion, cancellation, teardown and ready/error events. Ordinary
209
+ browser components keep their existing inline path. Application documents not
210
+ selected for document processing remain unchanged unless they are explicitly
211
+ loaded as components.
212
+
213
+ The selected payload is preserved in full, including runtime files, assets,
214
+ workers and licenses. Graph processing follows each document's executable and
215
+ resource references, including literal URLs to selected shared component HTML.
216
+ It does not assign an unused shared file to another document's map. Unreferenced
217
+ selected files retain their complete content. Referenced scripts, component HTML
218
+ and stylesheets are processed at their existing owners; resource URLs are rebased
219
+ for deployment under a directory such as `app/`. The operation adds generated scripts to the
220
+ complete release inventory. It does not bundle, prune, minify or rewrite
221
+ application prose, data or saved history. The existing stage replacement
222
+ preserves prior output if packaging fails or is cancelled.
223
+
224
+ This is a static module/script packaging capability, not a replacement browser
225
+ or a runtime import-map interpreter. Computed import expressions remain authored;
226
+ applications supply native-resolvable URLs for runtime-selected imports. It
227
+ does not convert event-handler attributes, dynamically evaluated source, or
228
+ provider-created executable blobs. An inline document script beneath an authored
229
+ remote effective base cannot address a package-local generated file; native mode
230
+ reports that incompatible transformation and preserves the original output.
231
+ Already-external scripts retain their remote-base behavior. Remote modules/providers
232
+ and WebAssembly still depend on their actual host capabilities. Resolving package references is
233
+ distinct from executing the complete application on Chromium or another host.
234
+
235
+ For an extension, select `browserPwa:false` for that artifact and place the
236
+ complete SDK-produced app beneath the app-owned extension root. The application
237
+ owns its manifest, toolbar/background launcher and permissions. Ordinary browser
238
+ PWA configuration and generated browser output remain independently available.
239
+
177
240
  ## Installed-package browser routes
178
241
 
179
242
  An external application can serve and package its installed SDK directly,
@@ -413,7 +476,7 @@ renaming any preceding entry changes the physical contract.
413
476
 
414
477
  The map derives its complete entries from the selected runtime graph;
415
478
  application source imports do not select a fixed entry count. The operation
416
- result reports `imports`, `documentCount`, and `excludedModules`; reached-file
479
+ result reports `imports`, optional dependency `scopes`, `documentCount`, and `excludedModules`; reached-file
417
480
  traversal remains internal. The
418
481
  managed graph exposes `arcane-os/event-manager`, `arcane-os/ai/browser-wasm`,
419
482
  `arcane-os/ai/browser-speech`, `arcane-os/preference-store`, and
@@ -425,6 +488,8 @@ The focused physical targets remain stable when their bindings are reached:
425
488
  | Browser specifier | Physical target |
426
489
  | --- | --- |
427
490
  | `arcane-os/event-manager` | `./arcane/sdk/event-manager.mjs` |
491
+ | `arcane-os/websocket-client` | `./arcane/sdk/websocket-client.mjs` |
492
+ | `ws-share` | `./arcane/sdk/dependencies/ws-share/WS.js` |
428
493
  | `arcane-os/ai/browser-wasm` | `./arcane/sdk/ai/browser-wasm.mjs` |
429
494
  | `arcane-os/ai/browser-speech` | `./arcane/sdk/ai/browser-speech.mjs` |
430
495
  | `arcane-os/speech-text` | `./arcane/sdk/speech-text.mjs` |
@@ -434,6 +499,16 @@ The focused physical targets remain stable when their bindings are reached:
434
499
  | `strong-type` | `./arcane/dependencies/strong-type/index.js` |
435
500
  | `./node_modules/strong-type/index.js` | `./arcane/dependencies/strong-type/index.js` |
436
501
 
502
+ When the selected runtime contains event-pubsub's own dependency projection,
503
+ the `./arcane/sdk/dependencies/event-pubsub/` scope maps `strong-type` to
504
+ `./arcane/sdk/dependencies/event-pubsub/dependencies/strong-type/index.js`.
505
+ This keeps its published 2.0.0 selection separate from the global SDK 2.0.1
506
+ binding. Scope keys and targets follow installed-package and document-base
507
+ translation together. Older inventories without that nested projection retain
508
+ their existing map shape. Internal managed test contexts accept and preserve
509
+ optional `scopes` alongside `imports`; their loader selects the most-specific
510
+ matching importer scope before the global map.
511
+
437
512
  Direct installed routes translate these targets to their actual npm destinations,
438
513
  including aliases. There is no `arcane-os` package-root mapping or catch-all
439
514
  `arcane/` prefix. Classic scripts, workers, stylesheets, and other
@@ -98,7 +98,8 @@ own asynchronous work, cancellation, and backpressure.
98
98
  | [`DocumentNavigation.js`](#documentnavigationjs) | esm | Binds document navigation, filtering, history, current-item reveal, and load initialization. | Browser / native WebView | Normalized filter/navigation state; DOM effects preserved. |
99
99
  | [`Errors.js`](#errorsjs) | esm | Normalizes global errors/rejections, assigns occurrence identifiers, persists a complete ledger, and performs complete delivery. | Browser / native WebView hybrid | Incident records normalized; storage/mail failures isolated. |
100
100
  | [`GifEncoder.js`](#gifencoderjs) | esm | Encodes indexed frames into a complete animated GIF using palette mapping and LZW. | Cross-host | Normalized complete binary output. |
101
- | [`HTMLImport.js`](#htmlimportjs) | esm | Defines the same-origin `<html-import>` loader with open shadow root, inline script execution, and readiness/error events. | Browser / native WebView | Public error detail normalized; fetch/DOM failure preserved. |
101
+ | [`HTMLImport.js`](#htmlimportjs) | esm | Defines the same-origin `<html-import>` loader with open shadow root, inline or packaged external script execution, and readiness/error events. | Browser / native WebView | Public error detail normalized; fetch/DOM failure preserved. |
102
+ | [`HTMLImportScript.js`](#htmlimportscriptjs) | esm | Renders the complete classic-script host wrapper shared by HTMLImport and native-module packaging. | Cross-host | Complete source retained with a terminating newline before the wrapper closes. |
102
103
  | [`InMemoryCommunicationProvider.js`](#inmemorycommunicationproviderjs) | esm | Implements deterministic in-memory thread/message/send behavior for demos and tests. | Cross-host | Normalized communication entities. |
103
104
  | [`IsolatedModelQuestionRunner.js`](#isolatedmodelquestionrunnerjs) | esm | Inspects one selected model and runs one isolated question while preserving the complete answer. | Native bridge or injected provider | Normalized model/result and coded errors. |
104
105
  | [`LocalAIReadiness.js`](#localaireadinessjs) | esm | Derives selected AI requirements and returns a complete readiness/recovery report across browser, desktop, and Android modes. | Browser/native hybrid | Fully normalized report and stable error codes; browsers never probe Ollama. |
@@ -2500,7 +2501,7 @@ console.log(Object.keys(module));
2500
2501
 
2501
2502
  ### Overview
2502
2503
 
2503
- Defines the same-origin `<html-import>` loader with open shadow root, inline script execution, and readiness/error events.
2504
+ Defines the same-origin `<html-import>` loader with open shadow root, inline or packaged external script execution, and readiness/error events.
2504
2505
 
2505
2506
  ### Public surface
2506
2507
 
@@ -2520,6 +2521,14 @@ Local component resources use stable URLs. The loader removes retired SDK-owned
2520
2521
  including caller-owned `v` fields, and fragments remain intact. External resource
2521
2522
  URLs retain their complete query. Ordinary HTTP conditional caching is unchanged.
2522
2523
 
2524
+ Native-module packages mark component scripts with `data-arcane-packaged-script`
2525
+ and an external `src`. The loader executes those files through a real classic
2526
+ script element instead of fetching their text for inline execution. Each host
2527
+ receives its own invocation, `this` binding, ordered initialization, readiness
2528
+ and error events, cancellation, and imported `destroy()` restoration. Independent
2529
+ component hosts remain concurrent. Ordinary unmarked components retain their
2530
+ existing inline/fetched-script path.
2531
+
2523
2532
  Exact exports: `default`.
2524
2533
 
2525
2534
  ### Availability and normalization
@@ -2534,6 +2543,40 @@ import * as module from '/arcane/modules/HTMLImport.js';
2534
2543
  console.log(Object.keys(module));
2535
2544
  ```
2536
2545
 
2546
+ ## HTMLImportScript.js
2547
+
2548
+ ### Overview
2549
+
2550
+ Renders the complete classic-script host wrapper shared by HTMLImport and
2551
+ native-module packaging. Rendering returns source text; it does not execute it
2552
+ or access the DOM.
2553
+
2554
+ ### Public surface
2555
+
2556
+ `createHTMLImportScript(source)` returns the complete source inside the loader's
2557
+ async host-bound initializer. A newline separates the authored ending from the
2558
+ wrapper closure, including when the body ends in a line comment. At execution,
2559
+ the wrapper uses the current script's host token and the HTMLImport-owned
2560
+ registry, then exposes the initializer promise to that host's loader.
2561
+
2562
+ Exact exports: `createHTMLImportScript`.
2563
+
2564
+ ### Availability and normalization
2565
+
2566
+ **Cross-host.** Complete source retained with a terminating newline before the
2567
+ wrapper closes. Transport: In-process only. [Deep protocol details](protocols.md).
2568
+
2569
+ ### Example
2570
+
2571
+ ```javascript
2572
+ import {createHTMLImportScript} from 'arcane-os/modules/HTMLImportScript.js';
2573
+
2574
+ const source=createHTMLImportScript('this.textContent="The moon burglar arrived.";');
2575
+ ```
2576
+
2577
+ Application packaging normally calls `packageApp({moduleFormat:'native', ...})`
2578
+ instead of assembling or executing component wrappers itself.
2579
+
2537
2580
  ## InMemoryCommunicationProvider.js
2538
2581
 
2539
2582
  ### Overview
@@ -2,9 +2,10 @@
2
2
 
3
3
  The npm package exposes a Node.js ESM control plane, the portable
4
4
  `arcane-os/event-manager`, `arcane-os/logging`, `arcane-os/mail`,
5
- `arcane-os/preference-store`, `arcane-os/speech-playback`,
5
+ `arcane-os/preference-store`, `arcane-os/speech-playback`, `arcane-os/websocket-client`,
6
6
  `arcane-os/speech-text`, `arcane-os/ai/tool-text-stream`, `arcane-os/ai/twin-cloud`, and `arcane-os/browser-device` entrypoints, and the browser-only
7
- `arcane-os/pwa` and `arcane-os/ai/browser-wasm` entrypoints. The
7
+ `arcane-os/pwa`, `arcane-os/ai/browser-wasm`, and
8
+ `arcane-os/ai/browser-decisions` entrypoints. The
8
9
  `arcane-os/ai/browser-speech` entrypoint includes local and native browser
9
10
  providers plus a cloud TTS adapter usable in Node with Fetch and Blob.
10
11
  The `arcane-os/modules/<filename>` and `arcane-os/entities/<filename>` paths
@@ -41,6 +42,8 @@ runtime layouts.
41
42
  | `arcane-os` | Complete high-level SDK surface. |
42
43
  | `arcane-os/toolchain` | Headless application operations. |
43
44
  | `arcane-os/events` | CLI/event reporter. |
45
+ | `arcane-os/websocket` | Node HTTP/1.1 WebSocket Upgrade, complete messages and accepted connection lifecycle. |
46
+ | `arcane-os/websocket-client` | Shared native client `WS`, one managed-connection observer and current connection snapshots through published ws-share. |
44
47
  | `arcane-os/testing` | Isolated test registration and execution. |
45
48
  | `arcane-os/targets` | Target adapters and dispatch. |
46
49
  | `arcane-os/native` | Native plan and builder protocol. |
@@ -73,6 +76,7 @@ runtime layouts.
73
76
  | `arcane-os/browser-device` | Synchronous mobile or desktop identity hints for application-owned settings. |
74
77
  | `arcane-os/pwa` | Nonblocking PWA registration, worker updates, native installation state and a dismissible installation component. |
75
78
  | `arcane-os/ai/browser-wasm` | Caller-selected browser-local Wllama inference, complete DBOPFS model storage, streaming, cancellation, and structural tool-call results. |
79
+ | `arcane-os/ai/browser-decisions` | Explicit-load Laya FP16 and Julia-1 FP32 typed decisions through the shared Transformers.js Worker owner. |
76
80
  | `arcane-os/ai/tool-text-stream` | Shared selected tool-argument text observer for provider integration. |
77
81
  | `arcane-os/ai/twin-cloud` | Stateless chat, System One state/questions and image generation with explicit key/model, complete results and operation-specific retry/cancellation. |
78
82
  | `arcane-os/ai/browser-speech` | Caller-selected Whisper/Kokoro, native browser recognition/synthesis, cloud TTS, upstream assets, role lifecycle and cancellation. |
@@ -130,6 +134,9 @@ The remaining data-only subpaths are eight JSON Schemas and package metadata.
130
134
 
131
135
  | Member | Kind | Import | Group | Availability |
132
136
  | --- | --- | --- | --- | --- |
137
+ | `acceptWebSocket()` | function | `arcane-os`, `arcane-os/websocket` | WebSocket protocol | Node; browser-native client interoperability |
138
+ | `WS` | class | `arcane-os`, `arcane-os/websocket-client` | Shared WebSocket clients | Node and native-WebSocket browser hosts |
139
+ | `createBrowserDecisionModel()` | function | `arcane-os/ai/browser-decisions` | Browser typed decisions | Browser module Workers and the caller-selected inference backend |
133
140
  | `fetchRequest()` | function | `arcane-os/ai/twin-cloud` | TWiN Cloud requests | Node and Browser; remote HTTPS provider |
134
141
  | `fetchSystemOneRequest()` | function | `arcane-os/ai/twin-cloud` | TWiN Cloud state-and-questions requests | Node and Browser; remote HTTPS provider |
135
142
  | `generateImages()` | function | `arcane-os/ai/twin-cloud` | TWiN Cloud image generation | Node and Browser with Fetch and Blob; remote HTTPS provider |
@@ -866,6 +873,42 @@ The package preserves the complete selected content, applying the documented
866
873
  asset-version and enabled browser-PWA transformations to resource references.
867
874
  Malformed configuration or descriptors fail while preserving the prior output.
868
875
 
876
+ `moduleFormat` defaults to `'import-map'`, preserving the ordinary browser
877
+ package. Select `'native'` to resolve saved document import maps into native
878
+ module URLs in the package stage and emit executable inline scripts as external
879
+ files. Static imports, re-exports, string-literal dynamic imports and
880
+ string-literal `import.meta.resolve()` retain exact/prefix/scoped mappings.
881
+ Imported HTML components use the shared `HTMLImport` externally executable
882
+ script path, retaining their host binding and asynchronous lifecycle. No
883
+ application-owned module loader is needed. Source HTML, saved data and the
884
+ ordinary browser output remain unchanged. See
885
+ [native-module package output](protocols.md#native-module-package-output)
886
+ for resource handling and the static transformation boundary.
887
+
888
+ An operation may override `outputDirectory` without changing the saved app
889
+ configuration. For example, package a complete application beneath an
890
+ application-owned extension manifest and launcher:
891
+
892
+ ```javascript
893
+ const release = await packageApp({
894
+ workspaceRoot,
895
+ appId: 'moon-dashboard',
896
+ outputDirectory: 'dist/extension/app',
897
+ moduleFormat: 'native',
898
+ browserPwa: false
899
+ });
900
+ ```
901
+
902
+ The override uses the same workspace-relative destination and staged replacement
903
+ rules as the saved field. It replaces only `dist/extension/app`, leaving its
904
+ extension-root siblings and an existing browser output intact. `browserPwa:false`
905
+ omits generated PWA artifacts for this invocation; it does not change the app's
906
+ saved PWA configuration. The app owns extension metadata, permissions and toolbar
907
+ launch behavior. This API builds the application directory, not an extension
908
+ manifest or an operating-system launcher. Native-mode dry runs report selected
909
+ input files; generated script/context files are included in the completed
910
+ package's full returned inventory.
911
+
869
912
  The app's optional schema-1 `outputDirectory` selects the final
870
913
  workspace-relative destination. For example, `"ai"` emits directly into
871
914
  `<workspace>/ai`; omission retains `dist/<app-id>`. The selected directory is
@@ -1149,11 +1192,14 @@ Authenticates one existing browser app release through the low-level packager AP
1149
1192
  ### Signature and result
1150
1193
 
1151
1194
  ```text
1152
- async verifyApp({workspaceRoot, appId, signal, onEvent})
1195
+ async verifyApp({workspaceRoot, appId, outputDirectory, signal, onEvent})
1153
1196
  ```
1154
1197
 
1155
1198
  Import it from `arcane-os` or `arcane-os/packager`. The signature above states whether settlement is synchronous or promise-based. The overview and owning group define result authority, side effects, callbacks, events, cancellation, and lifecycle.
1156
1199
 
1200
+ Optional `outputDirectory` selects the same workspace-relative override accepted
1201
+ by `packageApp`, without changing the app's saved destination.
1202
+
1157
1203
  ### Availability and normalization
1158
1204
 
1159
1205
  **Node.** Normalized SDK validation with complete canonical archive and release content. Deep protocol: [SDK packager and deterministic bundle contract](protocols.md).
@@ -1302,14 +1348,16 @@ The resolved result contains:
1302
1348
  runtimeRoot,
1303
1349
  documentPaths,
1304
1350
  documentCount,
1305
- documents: [{path, filePath, imports}],
1351
+ documents: [{path, filePath, imports, scopes?}],
1306
1352
  committed: true
1307
1353
  }
1308
1354
  ```
1309
1355
 
1310
1356
  `documentPaths` and each `filePath` are absolute filesystem paths. Each `path`
1311
- is relative to `documentRoot`; `imports` is the complete map rendered for that
1312
- document. The operation inventories the runtime once, builds the shared map
1357
+ is relative to `documentRoot`; `imports` contains the global bindings rendered
1358
+ for that document. Optional `scopes` contains dependency-specific bindings;
1359
+ scope URLs and their targets are rebased with the same document base as global
1360
+ imports. The operation inventories the runtime once, builds the shared map
1313
1361
  once, and reads the selected documents with up to four concurrent readers.
1314
1362
  It renders every document before writing any of them, then writes in selected
1315
1363
  order. `committed: true` means all selected writes completed; the batch is not
@@ -3753,6 +3801,171 @@ async function useselectApp(...arguments_) {
3753
3801
  }
3754
3802
  ```
3755
3803
 
3804
+ ## WS
3805
+
3806
+ Import `WS` as the default or named binding from `arcane-os/websocket-client`,
3807
+ or as a named binding from the Node root `arcane-os`. `new WS(uri,protocols?)`
3808
+ returns the exact native socket from published ws-share, sharing a connecting
3809
+ or open socket for the same exact URI string and ordered protocol list.
3810
+ `await WS.observe()` exposes one event-pubsub observer with
3811
+ `created`/`open`/`error`/`close` lifecycle records; `WS.getConnections()` returns
3812
+ current managed-connection snapshots. Each physical connection has its own ID,
3813
+ including replacements at the same address.
3814
+
3815
+ The [shared-client guide](websocket-client.md) covers complete record fields,
3816
+ subscribe-then-snapshot ordering, listener cleanup, shared close ownership,
3817
+ native per-socket behavior and the per-loaded-module/realm boundary. This
3818
+ client entry does not change the server-side `acceptWebSocket` contract.
3819
+
3820
+ ## acceptWebSocket()
3821
+
3822
+ ### Overview
3823
+
3824
+ Accepts one caller-selected RFC6455 HTTP/1.1 Upgrade using Node's native
3825
+ duplex stream. The caller owns HTTP routing, TLS, listeners, application
3826
+ messages and shutdown. Use the raw `server` returned by `startDevServer`, or
3827
+ the public `.server` / `.secureServer` of `node-http-server`. There is no
3828
+ listener creation, default port, application envelope, message persistence,
3829
+ client sharing, reconnect loop or third-party WebSocket runtime.
3830
+
3831
+ Clients may use native `WebSocket` directly or the separate shared
3832
+ [`WS` client](websocket-client.md). Node's global `WebSocket` is also a client,
3833
+ not a server. This server adapter supports version 13 over an
3834
+ HTTP/1.1 `upgrade` event, including HTTP/1.1 negotiated on an HTTPS listener.
3835
+ It does not implement HTTP/2 extended CONNECT or negotiate extensions such as
3836
+ compression. TLS setup remains with the existing server owner.
3837
+
3838
+ ### Signature, modes, and result
3839
+
3840
+ ```text
3841
+ acceptWebSocket({request,socket,head,protocol,signal})
3842
+ ```
3843
+
3844
+ Import from `arcane-os/websocket` or `arcane-os`. Supply the exact `request`,
3845
+ `socket` and `head` from the selected Node `upgrade` event. Do not substitute
3846
+ `request.socket` for that event's stream. `head` defaults to an empty buffer.
3847
+ Optional `protocol` is one exact client-offered token; the default empty string
3848
+ selects no subprotocol. A browser that offers subprotocols expects one to be
3849
+ selected. Optional `signal` owns this connection's lifetime.
3850
+
3851
+ The synchronous result is a native `EventTarget` with:
3852
+
3853
+ | Member | Contract |
3854
+ | --- | --- |
3855
+ | `readyState` | `1` open, `2` closing, `3` closed. Acceptance queues the handshake before any messages. |
3856
+ | `protocol` | Selected subprotocol, or the empty string. |
3857
+ | `send(data)` | `Promise<void>` for a complete string, `ArrayBuffer`, or view. A view sends only its selected region. Input is snapshotted at submission; writes stay in submission order. The promise waits for the native write callback and any required drain; it is not a peer/application acknowledgement. |
3858
+ | `close(code=1000,reason='')` | Starts the close handshake after already accepted sends; returns `closed`. Repeated calls return the same promise. A peer Close rejects unsent application messages and retains the close reply. |
3859
+ | `terminate(reason?)` | Destroys only this connection's stream immediately, rejects pending sends and returns `closed`. An optional reason is reported as an error. |
3860
+ | `closed` | Resolves once the stream closes to `{code,reason,wasClean,error}`. It never rejects. Code/reason come from the peer Close; without one, code is `1006`. An empty peer Close reports `1005`. `wasClean` requires both close frames and no recorded failure. |
3861
+
3862
+ Register listeners synchronously after acceptance. The handshake write and
3863
+ initial `head` processing begin in a microtask so those listeners receive
3864
+ buffered messages. `head` is processed once, before later stream chunks.
3865
+
3866
+ | Native event | Payload |
3867
+ | --- | --- |
3868
+ | `message` | `MessageEvent.data`: complete text as a string, or complete binary as `Uint8Array`. Fragment boundaries never replace message boundaries. |
3869
+ | `error` | `CustomEvent.detail`: the complete original transport Error or coded protocol/abort Error. |
3870
+ | `close` | `CustomEvent.detail`: the same result as `closed`. |
3871
+
3872
+ These are transport-local native events, not an application bus or retained
3873
+ event history. Native `EventTarget` owns listener exceptions; an async listener
3874
+ must observe its own promises. Listen for errors or inspect `closed.error`.
3875
+ Ping receives a matching Pong internally; Pong is not an application message.
3876
+ Text decoding preserves a leading U+FEFF and validates UTF-8 across the complete
3877
+ fragmented message. Binary data is never interpreted or wrapped as JSON.
3878
+
3879
+ ### Errors and cancellation
3880
+
3881
+ Before changing the socket, an invalid handshake throws
3882
+ `ARCANE_WEBSOCKET_HANDSHAKE_INVALID` with `statusCode:400,headers:{}`;
3883
+ an unsupported WebSocket version throws `ARCANE_WEBSOCKET_VERSION_UNSUPPORTED`
3884
+ with `statusCode:426` and `headers:{'Sec-WebSocket-Version':'13'}`. The host
3885
+ owns sending that HTTP response and ending the rejected stream. Invalid socket,
3886
+ data or close arguments report `TypeError` / `RangeError`; a failed `send`
3887
+ rejects its promise without changing the payload.
3888
+ An unpaired UTF-16 surrogate cannot be represented as UTF-8: sending such text
3889
+ rejects with `ARCANE_WEBSOCKET_TEXT_INVALID`, and using it as a close reason
3890
+ throws that error before changing connection state. Valid strings remain exact.
3891
+
3892
+ After acceptance, invalid framing reports `ARCANE_WEBSOCKET_PROTOCOL_INVALID`
3893
+ and close status `1002`; invalid text reports `ARCANE_WEBSOCKET_TEXT_INVALID`
3894
+ and `1007`. Complete platform errors remain observable. Framing lengths,
3895
+ masking, the handshake's SHA-1 accept calculation and control-frame bounds are
3896
+ RFC transport requirements only. There are no application message limits,
3897
+ byte progress, content identities, or optional security controls.
3898
+
3899
+ A pre-aborted signal throws before taking ownership. Later abort destroys the
3900
+ stream with an `AbortError` coded `ARCANE_WEBSOCKET_ABORTED`, preserving the
3901
+ signal reason as its cause. Closing rejects new sends with
3902
+ `ARCANE_WEBSOCKET_CONNECTION_CLOSED` (or the existing failure).
3903
+ No timer silently terminates a slow close handshake; use the caller's signal or
3904
+ `terminate()` when that owner decides to stop. Server listener closure alone,
3905
+ including Node `closeAllConnections()`, does not own upgraded sockets. Track
3906
+ connections or provide a shared lifetime signal, then await their `closed`
3907
+ promises separately. None of this changes chat storage or `persist:false`.
3908
+
3909
+ ### Example
3910
+
3911
+ This example attaches to an already-owned listener and returns a separate
3912
+ connection cleanup function. Its route and echo policy belong to the caller.
3913
+ Call it with `publicServer.server`, `publicServer.secureServer`, or an SDK
3914
+ development server's returned `server`; it creates no additional HTTP server.
3915
+
3916
+ ```javascript
3917
+ import {acceptWebSocket} from 'arcane-os/websocket';
3918
+
3919
+ function attachEcho(server,signal){
3920
+ const connections=new Set();
3921
+ function upgrade(request,socket,head){
3922
+ if(request.url!=='/socket'){
3923
+ socket.end('HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n');
3924
+ return;
3925
+ }
3926
+ let connection;
3927
+ try{connection=acceptWebSocket({request,socket,head,signal});}
3928
+ catch(error){
3929
+ console.error(error);
3930
+ const status=error.statusCode??400;
3931
+ const version=status===426?'Sec-WebSocket-Version: 13\r\n':'';
3932
+ socket.end(`HTTP/1.1 ${status} Upgrade rejected\r\n${version}Connection: close\r\n\r\n`);
3933
+ return;
3934
+ }
3935
+ connections.add(connection);
3936
+ connection.addEventListener('error',function failed(event){console.error(event.detail);});
3937
+ connection.addEventListener('message',function echo(event){
3938
+ connection.send(event.data).catch(function sendFailed(error){console.error(error);});
3939
+ });
3940
+ connection.addEventListener('close',function remove(){connections.delete(connection);});
3941
+ }
3942
+ server.on('upgrade',upgrade);
3943
+ return async function detach(){
3944
+ server.off('upgrade',upgrade);
3945
+ await Promise.all([...connections].map(function stop(connection){return connection.terminate();}));
3946
+ };
3947
+ }
3948
+
3949
+ // In browser code, after the host has selected its ws: or wss: URL:
3950
+ function connectEcho(url){
3951
+ const client=new WebSocket(url);
3952
+ client.addEventListener('open',function greet(){client.send('The moon needs a coffee break.');});
3953
+ client.addEventListener('message',function received(event){console.log(event.data);});
3954
+ return client;
3955
+ }
3956
+ ```
3957
+
3958
+ Protocol references: [RFC6455](https://www.rfc-editor.org/rfc/rfc6455.html),
3959
+ [Node upgrade event](https://nodejs.org/api/http.html#event-upgrade), and
3960
+ [native browser WebSocket](https://websockets.spec.whatwg.org/).
3961
+ Work is connection-local and linear in actual framing/content. Input is
3962
+ assembled once per complete message; advertised lengths do not preallocate
3963
+ payloads. Outbound framing snapshots each submitted message and uses native
3964
+ writable backpressure. Callers await `send` when producing a sustained stream.
3965
+ There is no history scan, app loop, diagnostic payload store or automatic retry.
3966
+ The authored `test/websocket.test.mjs` fixtures cover this boundary; source
3967
+ inspection is distinct from executing them or verifying a browser deployment.
3968
+
3756
3969
  ## startDevServer()
3757
3970
 
3758
3971
  ### Overview
@@ -6669,6 +6882,67 @@ See the [mounting contract](pwa.md#mountpwainstallprompt) and
6669
6882
  [component reference](runtime-components.md#pwa-installhtml). The browser owns
6670
6883
  native installation eligibility and URL-bar promotion.
6671
6884
 
6885
+ ## createBrowserDecisionModel()
6886
+
6887
+ ### Overview
6888
+
6889
+ Creates an explicitly loaded browser model for Laya typed decisions in FP16 or
6890
+ Julia-1 in FP32. The shared Worker owns Transformers.js loading, full-input
6891
+ encoding, batched inference, complete results, cancellation and resource lifetime.
6892
+ Applications own model selection, questions, option meanings and decision policy.
6893
+ Existing chat and speech providers are unchanged.
6894
+
6895
+ ### Signature and result
6896
+
6897
+ ```js
6898
+ import {createBrowserDecisionModel} from 'arcane-os/ai/browser-decisions';
6899
+
6900
+ const decisions = createBrowserDecisionModel(
6901
+ {
6902
+ family: 'laya',
6903
+ model: 'onnx-community/laya-typed-decisions-ONNX',
6904
+ device: 'webgpu'
6905
+ }
6906
+ );
6907
+ ```
6908
+
6909
+ Construction starts no model download. The returned client exposes
6910
+ `load({signal})`, `evaluate(rows, {signal})`, `status()`,
6911
+ `subscribe(listener, {emitCurrent: true, signal})`, `unload()` and `dispose()`.
6912
+ Each row contains its complete `state`, `question`, string `options`, and
6913
+ optional `type` (`choice`, `score`, or `noul`). `evaluate()` returns
6914
+ `{decisions, outputs}` with all graph outputs and raw, unrounded probabilities.
6915
+ See the [complete browser decision contract](ai/browser-decisions.md) for
6916
+ precision, tokenization, output meanings, lifecycle and model limitations.
6917
+
6918
+ ### Availability and normalization
6919
+
6920
+ Browser module Workers plus the selected Transformers.js backend are required
6921
+ on explicit use. Import and construction do not activate a model. Laya fixes
6922
+ `dtype: 'fp16'`; Julia fixes `dtype: 'fp32'`; there is no precision fallback.
6923
+ Cancellation terminates that client's Worker and rejects its in-flight work.
6924
+ No decisions are inserted into chat history or durable storage.
6925
+
6926
+ ### Example
6927
+
6928
+ ```js
6929
+ runButton.addEventListener(
6930
+ 'click',
6931
+ async function askTeaRobot() {
6932
+ const result = await decisions.evaluate(
6933
+ [
6934
+ {
6935
+ state: 'The dragon is asleep. The tea robot has a very loud kettle.',
6936
+ question: 'Should the robot boil tea now?',
6937
+ options: ['Wait quietly', 'Boil the kettle']
6938
+ }
6939
+ ]
6940
+ );
6941
+ output.textContent = result.decisions[0].value;
6942
+ }
6943
+ );
6944
+ ```
6945
+
6672
6946
  ## createBrowserWasmLlmProvider()
6673
6947
 
6674
6948
  ### Overview