arcane-os 0.55.0 → 0.57.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 (56) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +5 -3
  3. package/browser-runtime/ai/core-local.mjs +306 -0
  4. package/browser-runtime/core/client.mjs +75 -14
  5. package/browser-runtime/core/contracts.mjs +2 -1
  6. package/docs/consumer-updates.md +82 -0
  7. package/docs/publishing.md +41 -18
  8. package/docs/reference/README.md +31 -1
  9. package/docs/reference/availability-and-normalization.md +11 -3
  10. package/docs/reference/cli.md +9 -1
  11. package/docs/reference/core-client.md +45 -2
  12. package/docs/reference/core-native-packaging.md +195 -11
  13. package/docs/reference/core-runtime.md +10 -0
  14. package/docs/reference/inventory/package-api.json +160 -20
  15. package/docs/reference/local-ai.md +197 -0
  16. package/docs/reference/protocols.md +91 -14
  17. package/docs/reference/pwa.md +17 -0
  18. package/docs/reference/runtime-modules.md +6 -5
  19. package/docs/reference/sdk-api.md +165 -26
  20. package/package.json +5 -1
  21. package/runtime/arcane/modules/LocalAIReadiness.js +3 -1
  22. package/schemas/arcane-app.schema.json +64 -0
  23. package/schemas/arcane-package.schema.json +54 -0
  24. package/src/app-descriptor.mjs +35 -2
  25. package/src/app-layout.mjs +6 -2
  26. package/src/cli/main.mjs +8 -2
  27. package/src/core/host.mjs +23 -0
  28. package/src/core/hosts/arcane-core-loader.cjs +2 -0
  29. package/src/core/hosts/linux/arcane_core_process.c +568 -0
  30. package/src/core/hosts/linux/arcane_core_process.h +127 -0
  31. package/src/core/hosts/macos/ArcaneCoreProcess.h +85 -0
  32. package/src/core/hosts/macos/ArcaneCoreProcess.m +357 -0
  33. package/src/core/hosts/sea-launcher.cjs +17 -0
  34. package/src/core/hosts/windows/ArcaneCoreProcess.cs +416 -0
  35. package/src/core/hosts/windows/ArcaneHost.cs +695 -0
  36. package/src/core/hosts/windows/ArcaneHost.manifest +22 -0
  37. package/src/core/hosts/windows/ArcaneLauncher.cs +239 -0
  38. package/src/core/runtime.mjs +15 -3
  39. package/src/core/services/local-ai.mjs +543 -0
  40. package/src/core-classic-source.mjs +2 -2
  41. package/src/dev-server.mjs +7 -0
  42. package/src/import-map.mjs +1 -0
  43. package/src/local-ai/archive.mjs +52 -0
  44. package/src/local-ai/config.mjs +62 -0
  45. package/src/local-ai/dev.mjs +390 -0
  46. package/src/local-ai/discover.mjs +71 -0
  47. package/src/local-ai/http.mjs +106 -0
  48. package/src/local-ai/install.mjs +344 -0
  49. package/src/local-ai/server.mjs +262 -0
  50. package/src/native/portable-layout.mjs +29 -4
  51. package/src/native/portable-provider.mjs +39 -8
  52. package/src/native/windows-provider.mjs +262 -0
  53. package/src/native-provider-loader.mjs +8 -2
  54. package/src/packager/core.mjs +89 -15
  55. package/src/process.mjs +74 -12
  56. package/src/toolchain.mjs +38 -8
@@ -11,8 +11,12 @@ the npm `dev` dist-tag, while bare numeric stable versions select
11
11
 
12
12
  The package version and `publishConfig.tag` must agree exactly: `-dev` uses
13
13
  `dev`, and a bare numeric stable version uses `latest`. npm is the canonical
14
- SDK distribution: application repositories add an exact `arcane-os` project
15
- dependency and invoke its local CLI with `npm exec -- arcane`. A separate
14
+ SDK distribution: development applications declare `arcane-os` as `latest` and
15
+ invoke its local CLI with `npm exec -- arcane`. An exact application SDK pin
16
+ begins only when Roshi designates that application as a production build.
17
+ Keep the lockfile and explicitly refresh and compare its resolution and the
18
+ installed SDK with npm's published version before materializing or building;
19
+ see [Consumer updates](consumer-updates.md). A separate
16
20
  global installer, standalone SDK executable, NuGet package, Homebrew formula,
17
21
  or OS package is not part of this release surface.
18
22
 
@@ -30,8 +34,8 @@ agreement, and required license notices. One unprivileged producer packs one
30
34
  artifact with a recorded run id, artifact id, version, and source commit. It
31
35
  does not impose byte counts, hashes, digests, provenance receipts, or unrelated
32
36
  test suites as ordinary development gates. Broader integration, regression,
33
- platform, browser, presentation, and documentation work remains separately
34
- user selected.
37
+ and platform work remains separately user selected. Documentation and website
38
+ updates are required post-publication follow-through as described below.
35
39
 
36
40
  `publish-dev.yml` can run only when manually dispatched from `main` in
37
41
  `TheWizardNexus/arcane-os-sdk`. Dispatch supplies the exact successful Check
@@ -59,14 +63,15 @@ The unscoped package installs both `arcane` and `arcane-os`. The short command
59
63
  is the documented default; `arcane-os` is the collision-safe fallback. npm
60
64
  package names are unique, but executable names are not globally reserved.
61
65
 
62
- When `npm view arcane-os@dev version` reports the package unavailable, run
63
- `npm run pack:local` in this SDK checkout for local development, scaffold with
64
- `node ./bin/arcane.mjs new ...`, and install the resulting `.tgz` into the app
66
+ External applications consume published npm releases. An unavailable release
67
+ does not authorize them to use an unpublished SDK checkout or tarball. Only
68
+ tasks explicitly collaborating on an SDK update inside this project may use
69
+ the local `npm run pack:local` workflow and its resulting `.tgz`. That local
70
+ workflow can scaffold with `node ./bin/arcane.mjs new ...` and install the tarball
65
71
  with `npm install --save-dev --save-exact <path>`. Keep the tarball at the path
66
- recorded by `package-lock.json`; subsequent `npm ci` uses that declared package.
67
- Arcane reads the installed package's name and version against the root
68
- dependency declaration. A local directory `file:` install is intentionally unsupported because
69
- it may be linked.
72
+ recorded by `package-lock.json` for subsequent `npm ci`. Arcane reads the installed
73
+ package's name and version against the root dependency declaration. A local
74
+ directory `file:` install is unsupported because it may be linked.
70
75
 
71
76
  The npm package already has its trusted-publishing relationship. Each later
72
77
  release therefore follows the same direct selected-artifact path: push the
@@ -77,9 +82,11 @@ dist-tag after publication. Never rebuild or repack the artifact under
77
82
  publication authority, and never substitute a different source revision.
78
83
 
79
84
  Generated app CI uses `npm ci --ignore-scripts`, so its lock must exist and its
80
- dependency source must be reachable by the runner. A sibling local tarball is a
81
- workstation workflow, not a portable GitHub dependency source; switch to the
82
- exact registry release (or deliberately vendor the tarball) before remote CI.
85
+ dependency source must be reachable by the runner. External application CI uses
86
+ the published registry package recorded in the committed lockfile. A locked
87
+ install reproduces that selected version; it does not establish that the SDK is
88
+ currently npm's `latest`. Complete the development refresh before preparing and
89
+ committing managed application files and the updated lockfile for CI.
83
90
 
84
91
  ## Reusable application release workflow
85
92
 
@@ -111,8 +118,23 @@ GitHub release, and no release creates a Git branch for an npm dist-tag.
111
118
 
112
119
  ## Documentation publication
113
120
 
114
- Documentation publication occurs only when the user explicitly selects it. The
115
- Pages job checks out that selected `main` revision without persistent
121
+ After every successful npm release and its applicable requester notices, the
122
+ SDK owner updates documentation and the existing SDK website for all added,
123
+ removed, or modified features, APIs, members, methods, and affected public
124
+ contracts. Include the relevant signatures, inputs, outputs, defaults,
125
+ lifecycle, errors, platform availability, and usage examples. This standing
126
+ duty also applies when a release has no requesting applications. Record the
127
+ actual documentation and website delivery outcomes in the release handoff and
128
+ report any unfinished work. See [Consumer updates](consumer-updates.md) for
129
+ request intake and notice requirements.
130
+
131
+ Documentation and website content outside the selected npm payload does not
132
+ block npm publication. Prepare and deliver those updates through the existing
133
+ documentation/site workflow after publication; do not wait for consumer
134
+ adoption or application tests. This duty does not authorize ChatGPT Sites or
135
+ production-server administration.
136
+
137
+ The Pages job checks out the selected `main` revision without persistent
116
138
  credentials and uploads only the static `site/` tree. It does not automatically
117
139
  run the SDK test suite, checks, generators, or repository build code.
118
140
 
@@ -128,5 +150,6 @@ One producer creates the tarball. Publication names that producer's exact Check
128
150
  run, artifact, and version and does not rebuild from a later checkout. The
129
151
  release workflow checks only the publication contract and required legal
130
152
  inventory for that selected output.
131
- Platform matrices, full product regressions, Pages, and broader presentation
132
- work remain separate user-selected operations.
153
+ Platform matrices and full product regressions remain separate user-selected
154
+ operations. Documentation and the existing website are required post-release
155
+ follow-through, with their outcomes recorded separately from npm publication.
@@ -17,9 +17,14 @@ high-level page links to the relevant deep section instead of repeating it.
17
17
  Install the SDK in your application:
18
18
 
19
19
  ```sh
20
- npm install --save-exact arcane-os@latest
20
+ npm pkg set dependencies.arcane-os=latest
21
+ npm install
21
22
  ```
22
23
 
24
+ The development declaration tracks the current `latest` channel. The lockfile
25
+ and installed package record the exact version actually selected for the
26
+ workspace.
27
+
23
28
  For your first AI call, follow the [TWiN Cloud quick start](ai/twin-cloud.md).
24
29
  For local models, native browser voices or cloud speech, follow the [browser speech guide](ai/browser-speech.md)
25
30
  and the complete [browser AI demo](https://github.com/TheWizardNexus/arcane-os-sdk/tree/main/examples/wasm-ai-demo).
@@ -38,14 +43,19 @@ alone does not make bare module names resolve in a browser.
38
43
  | Use the `arcane` command | [CLI reference](cli.md) |
39
44
  | Install an app and cache selected resources offline | [Progressive web applications](pwa.md) |
40
45
  | Generate named browser imports or inspect the selected physical runtime | [`arcane import-map`](cli.md#arcane-import-map) and [browser runtime delivery](protocols.md#browser-runtime-delivery) |
46
+ | Connect an application through the shared WebSocket transport | [Shared WebSocket clients](websocket-client.md) |
41
47
  | Choose browser, native, cloud, or cross-host behavior | [Availability and normalization](availability-and-normalization.md) |
42
48
  | Import a shipped renderer module | [Runtime module catalog](runtime-modules.md) |
43
49
  | Use a shared entity | [Runtime entity modules](runtime-entities.md) and [exact export contracts](core/arcane-entities.md) |
44
50
  | Load a reusable HTML component | [Runtime component catalog](runtime-components.md) |
45
51
  | Submit complete speech parts immediately and play them in order | [`SpeechPlayback`](runtime-modules.md#speechplaybackjs) and the [basic browser example](ai/browser-speech.md#play-a-complete-array-with-speechplayback) |
46
52
  | Call `globalThis.Arcane` | [Arcane Core API](core/arcane-api.md) |
53
+ | Connect a browser to one Core transport | [Core browser client](core-client.md) |
54
+ | Compose native Core dispatch, service lifecycle, and stdio hosting | [Native Core runtime](core-runtime.md) |
55
+ | Build an installed-SDK portable Core payload | [Portable Core packaging](core-native-packaging.md) |
47
56
  | Subscribe to native events | [Arcane event reference](core/arcane-events.md) |
48
57
  | Use provider-neutral AI lifecycle, chat, speech, persistence, or document context | [Normalized AI](#normalized-ai) |
58
+ | Choose a normalized typed browser decision surface | [Browser typed decisions](ai/browser-decisions.md) |
49
59
  | Run a caller-selected local LLM in the browser | [Browser-WASM local AI](ai/browser-wasm.md) |
50
60
  | Run caller-selected Whisper/Kokoro, native browser recognition/voices or cloud TTS | [Browser speech providers](ai/browser-speech.md) |
51
61
  | Send TWiN chat, System One state/questions or image requests | [TWiN Cloud guide](ai/twin-cloud.md) |
@@ -101,6 +111,26 @@ The [changelog](../../CHANGELOG.md) records changes by version; the
101
111
  identify the corresponding published package source. A newer website does not
102
112
  change the version installed in your application.
103
113
 
114
+ ### Generate the selected reference site
115
+
116
+ The existing `node tools/build-reference-site.mjs --write` command reads the
117
+ live checkout. For release documentation while disjoint source work continues,
118
+ select the reviewed documentation commit explicitly:
119
+
120
+ ```sh
121
+ node tools/build-reference-site.mjs --write --source-ref <documentation-commit>
122
+ ```
123
+
124
+ The same option is accepted by `createReferenceSite({sourceRef})` and
125
+ `writeReferenceSite({sourceRef})`. It reads the selected commit's package
126
+ version, complete reference documents and inventories, inventory-selected
127
+ runtime sources, and authored site inputs directly from Git in memory. It
128
+ creates no checkout or export and leaves source drafts untouched. Rendering
129
+ uses the current canonical generator and its authored semantic contracts;
130
+ select a documentation commit whose contracts match the published package.
131
+ Generated output still belongs to the canonical `site/` tree and requires its
132
+ usual coordinated output ownership. Generation does not publish hosted Pages.
133
+
104
134
  ### Historical 0.3.4 publication record
105
135
 
106
136
  The following records describe that earlier release only. They do not identify
@@ -58,9 +58,12 @@ false when a probe throws; SDK branching continues through its owning error path
58
58
  policy, package-owned model policy, platform support, and dependency readiness
59
59
  are independent checks.
60
60
 
61
- The current native host/target matrix covers Microsoft NT, Linux, and Android
62
- where listed. It exposes no macOS target or Core host contract in this SDK
63
- version; WebKitGTK availability must not be generalized to macOS.
61
+ The current executable host/target matrix covers Microsoft NT, Linux, and
62
+ Android where listed. This SDK exposes no macOS executable target, native
63
+ bridge, artifact, or run contract; WebKitGTK availability must not be
64
+ generalized to macOS. The reusable Node Core runtime, framed stdio transport,
65
+ host composition, and portable payload can be used by a separately composed
66
+ macOS host, but they do not supply that native platform host or bridge.
64
67
 
65
68
  ## Capability-first matrix
66
69
 
@@ -68,7 +71,9 @@ version; WebKitGTK availability must not be generalized to macOS.
68
71
  | --- | --- | --- | --- |
69
72
  | Scaffold, inspect, test, package, bundle, build, verify, or run an app | `arcane` CLI or `arcane-os` package functions | **Node**; native targets invoke one explicit provider | CLI events and SDK errors/results are normalized by versioned SDK contracts. Tests and checks run only when explicitly selected; verification is separate and selected-output-specific. |
70
73
  | Publish application events or review a complete event history | `arcane-os/event-manager` | **Node** and **Browser**; optional DOM capture needs a browser DOM or compatible host | Live listeners receive original arguments. Ordinary `secure:false` recording preserves complete URLs, public details, and captured stack text in deeply frozen `arcane-event-stack/1` snapshots while credential-named fields remain redacted. The stack format is local diagnostic data, not a host transport. |
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. |
71
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
+ | 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. |
72
77
  | 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. |
73
78
  | 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. |
74
79
  | 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. |
@@ -81,6 +86,9 @@ version; WebKitGTK availability must not be generalized to macOS.
81
86
  | Print rendered editor content or file previews | `/arcane/modules/PrintView.js`, editor `print()`, and file/history `printPreview()` | **Browser / native WebView** with DOM and browser printing | Complete current rendered content, fonts, and resolved media are captured for print. Explicit requests await view preparation; native Print captures synchronously. Shared `print.css` supplies a light paper palette and one-inch margins; snapshots stay owned through `afterprint`. |
82
87
  | Search an app-owned document corpus for explicit chat context | `/arcane/modules/DBOPFSDocumentLibrary.js` | **Browser** or compatible injected DBOPFS adapter | Generation/manifest completion, complete lexical search, partial read failures, and untrusted context labels are normalized. Construction does not search; an explicitly wired context builder performs retrieval for each prepared chat send. |
83
88
  | Read host identity, capabilities, storage, preferences, appearance, or platform state | `globalThis.Arcane` | **Cross-host** where the method is implemented and admitted | Promise behavior and `Arcane.Error` are normalized. Result fields are normalized unless the method explicitly documents a platform-dependent snapshot. |
89
+ | Connect browser code to an existing Core transport | `arcane-os/core/client` and `arcane-os/core/contracts` | **Browser / native WebView** with an admitted transport; explicit development HTTP remains opt-in | The reusable client owns `arcane/1` correlation, readiness, cancellation, events, facades, and complete native error fidelity. It supplies no service, policy, or host process. |
90
+ | Compose native Core services and framed stdio hosting | `arcane-os/core/runtime`, `arcane-os/core/stdio`, and `arcane-os/core/host` | **Node** on Windows, Linux, or macOS; the composing native host supplies its process and bridge | The SDK owns reusable dispatch, per-service lifecycle, request/service work ownership, cooperative cancellation, drain, and stdio framing. Product identity, policy, privileges, models, storage, and services remain host-owned. |
91
+ | Assemble a portable Core payload from the installed SDK | `arcane-os/native/portable-provider` | **Node**; portable platform selection is currently Windows or Linux, while separately composed hosts may use the payload | The provider copies the selected app, dependencies, installed SDK runtime, Core client/runtime, and explicit service composition into a non-executable directory. It uses no `arcaneRoot` by default and does not prove host behavior or supply a platform bridge. |
84
92
  | Use local AI without coupling app code to Ollama HTTP | `Arcane.localAI`, `Arcane.ai`, or `/arcane/modules/Ollama.js` | Primarily **Native**; Android exposes a narrower admitted inference projection | Admission, errors, and managed-operation events are normalized. Direct Ollama response envelopes remain **Provider-native**. |
85
93
  | Use TWiN Cloud from the renderer profile | `/arcane/modules/AI.js` | **Cloud** from an allowed browser/native renderer | High-level chat behavior is normalized by the module. The TWiN access key authenticates remote LLM chat; raw provider diagnostics remain provider-specific. No automatic cloud fallback is inferred from local failure. |
86
94
  | Send one TWiN Cloud request with an explicit key and model | `fetchRequest` from `arcane-os/ai/twin-cloud` | **Node** and **Browser**, using standard Fetch and a remote HTTPS provider | Keeps complete messages and returns the full parsed provider JSON. Rejected Fetch and HTTP 529 share three retries after 3000 ms; HTTP 429 overload retains unlimited three-second retries. Optional `onRetry` reports waiting/requesting phases without blocking recovery. Shared structured-output mapping and cancellation match browser TWiN transport. No browser profile, AI/user singleton, DBOPFS, or retained request history is created. |
@@ -49,6 +49,7 @@ meaning and cardinality rules:
49
49
  | `--app` | app id or label | Workspace/app operations except shared scope and `verify-bundle`; optional diagnostic label for `mail serve`. |
50
50
  | `--apps-root` | `.` or `apps` | `new`, `init`; standalone setup defaults to the repository root. |
51
51
  | `--sdk-runtime-source` | SDK checkout directory | `dev` only; maps live SDK source through the selected browser destinations for that server process. |
52
+ | `--local-ai` | comma-separated runtime IDs | `dev` only; adds `llama.cpp` and/or `ollama` requirements to application configuration and prepares missing runtimes alongside serving. See [local AI through Core](local-ai.md). |
52
53
  | `--arcane-root` | directory | `doctor`, native `build`/`run`, `native-doctor`, `native-prepare` |
53
54
  | `--host` / `--port` | host / integer 0–65535 | Browser `dev`/`run` default to HTTPS at `127.0.0.1:8000`; `mail serve` defaults to HTTPS with HTTP/2 at `0.0.0.0:4433` and accepts an explicit bind host. |
54
55
  | `--http-port` | integer 0–65535 | Browser `dev`/`run` HTTP redirect listener; defaults to `0`, which selects an available port. |
@@ -366,9 +367,16 @@ An explicit live-source SDK mapping follows the selected browser destinations
366
367
  while reading canonical SDK source; it never replaces installed files.
367
368
 
368
369
  ```text
369
- arcane dev [--app <id>] [--public] [--http | --https] [--cert <file> --key <file>] [--host <address>] [--port 8000] [--http-port 0] [--sdk-runtime-source <sdk-root>]
370
+ arcane dev [--app <id>] [--public] [--http | --https] [--cert <file> --key <file>] [--host <address>] [--port 8000] [--http-port 0] [--sdk-runtime-source <sdk-root>] [--local-ai llama.cpp,ollama]
370
371
  ```
371
372
 
373
+ `--local-ai` saves the selected requirements in `native.localAI`, or in
374
+ `arcane-package.json.localAI` for a package-only app. Later development runs
375
+ reuse them. Available services and executables are reused; missing runtimes
376
+ are installed inside the application while serving starts independently.
377
+ Applications choose their model files and optional browser Core connection.
378
+ See [local AI through Core](local-ai.md) for configuration and native bundling.
379
+
372
380
  ### Lifecycle
373
381
 
374
382
  Startup refreshes the selected authored `arcane-app.json` projection into
@@ -1,7 +1,8 @@
1
1
  # Core browser client
2
2
 
3
3
  `arcane-os/core/client` is the browser-safe `arcane/1` RPC owner. It exports
4
- `createCoreClient`, `createCoreFacade` and `installCoreClient`.
4
+ `createCoreClient`, `createCoreFacade`, `installCoreClient` and
5
+ `getInstalledCoreClient`.
5
6
  `arcane-os/core/contracts` exports `CORE_PROTOCOL`, `CORE_READY_EVENTS`,
6
7
  `CORE_FRAME_CONTRACTS`, `CORE_METHOD_CONTRACTS`, `CoreError` and
7
8
  `serializeCoreError`. Contracts describe transport and existing method shapes;
@@ -25,6 +26,23 @@ remain available through this facade; their implementations and availability
25
26
  belong to the selected host. No repository, app list, model selection or service
26
27
  implementation is installed by importing this client.
27
28
 
29
+ An application using a host-installed client can read it without installing or
30
+ replacing anything:
31
+
32
+ ```js
33
+ import {getInstalledCoreClient} from 'arcane-os/core/client';
34
+
35
+ const client=getInstalledCoreClient();
36
+ // null means this global has no live SDK-installed client.
37
+ ```
38
+
39
+ `getInstalledCoreClient(global=globalThis)` returns the exact live SDK-installed
40
+ client, including one installed by classic document-created injection. It does
41
+ not connect, install a client or replace an existing `Arcane` object. Applications
42
+ need not inspect private installation fields. It returns `null` after that
43
+ installation closes or fails. A
44
+ foreign application's `Arcane` object is not evidence of an SDK installation.
45
+
28
46
  The native adapters select WebView2, WebKitGTK or Android WebView. Ordinary
29
47
  browsers remain `standalone`; they do not probe a local server. Development
30
48
  HTTP is selected only by the existing explicit `__ARCANE_DEV_HTTP__` flag.
@@ -41,6 +59,14 @@ without callable `send(frame)` remains disconnected and reports
41
59
  `ARCANE_TRANSPORT_INVALID`; it does not announce `transport.ready`.
42
60
  `autoConnect:false` defers connection until `connect()` or the first invocation.
43
61
 
62
+ `replayRuntimeState:true` sends one `runtime.replay` control after the transport's
63
+ receive listener and `transport.ready` are established. The default is `false`,
64
+ preserving existing hosts. The send is observed without delaying page startup;
65
+ delivery errors reach `onError`. A host supporting this control supplies its
66
+ current dispatcher and service state for a newly connected document, without
67
+ restarting services. Repeated `connect()` calls on the same connection do not
68
+ send another replay. See [runtime replay](core-runtime.md#state-and-frames).
69
+
44
70
  `client.invoke(method, parameters, {signal, timeoutMs})` returns the actual
45
71
  response result or rejects with `CoreError`. Parameters, result fields and
46
72
  event data retain their complete supplied content. JSON encoding belongs only
@@ -75,6 +101,20 @@ native callbacks, timers and pending renderer requests; it does not kill Core.
75
101
  Call `stop()` to remove an individual subscription and `client.close()` when
76
102
  the client owner ends its lifetime.
77
103
 
104
+ For an actual terminal child-process or transport failure, the host calls
105
+ `client.failTransport(error)`. Installed clients also own the native callback
106
+ `globalThis.__arcaneTransportFailed(error)`. This boundary rejects pending RPCs
107
+ and WebKit acknowledgements with the complete actual `CoreError`, reports that
108
+ failure once, releases callbacks/subscriptions/timers and rejects future
109
+ invocations with the same failure. It sends no cancellation frames to a failed
110
+ transport and does not invent response identifiers or results. A normal close
111
+ still uses cancellation rather than reporting a transport failure.
112
+
113
+ Closing or failing an installation restores its previous `Arcane` object and
114
+ native callbacks only when those globals still belong to that installation.
115
+ Another owner's later replacements remain unchanged. The read-only accessor
116
+ returns `null` before the installed failure is reported to `onError`.
117
+
78
118
  Errors retain complete native fields, including diagnostics and stack/cause
79
119
  information. WebView2 and Android bridge failures retain native error codes,
80
120
  messages and diagnostic fields; the request method and transport are added
@@ -90,7 +130,8 @@ transport/event-owner failures outside individual request promises.
90
130
  import {createCoreClassicSource} from 'arcane-os/core/classic-source';
91
131
 
92
132
  const source=await createCoreClassicSource({
93
- eventOwnerModuleURL:'/arcane/sdk/event-manager.mjs'
133
+ eventOwnerModuleURL:'/arcane/sdk/event-manager.mjs',
134
+ replayRuntimeState:true
94
135
  });
95
136
  // Supply source to the native host's existing classic-script injection owner.
96
137
  ```
@@ -100,6 +141,8 @@ installed SDK. It emits the same implementation as a classic script, without
100
141
  copying another client or adding a bundler. The caller supplies the actual
101
142
  served SDK event-manager URL; the example URL must match its selected layout.
102
143
  That module and its existing managed import map must be included by packaging.
144
+ Select `replayRuntimeState:true` only when composing a host with the current
145
+ runtime replay control; omitting it preserves the existing no-replay default.
103
146
 
104
147
  The generated facade, native receive callback and current-state methods install
105
148
  synchronously. When the shared event owner already exists, it is reused
@@ -1,22 +1,28 @@
1
1
  # Portable Core packaging
2
2
 
3
3
  `arcane-os/native/portable-provider` owns the portable native payload in the SDK
4
- package. It does not load Arcane OS source, choose models, download a runtime,
5
- or compile an executable. Windows, Linux and macOS hosts may compose this
4
+ package. It does not load Arcane OS source, choose models or compile an
5
+ executable. An application's explicit `native.localAI` selection can include
6
+ its selected upstream runtimes through the SDK local-AI installer. Without that
7
+ selection, assembly does no local-AI runtime preparation. Windows, Linux and macOS hosts may compose this
6
8
  Node-based payload; Android needs its separate native host adaptation. The
7
9
  current CLI's portable platform selections remain Windows and Linux. A portable
8
10
  artifact is not a Windows executable, Linux package or Android application.
9
11
 
10
12
  `loadArcaneNativeProvider({target:'portable'})` selects the installed SDK provider
11
13
  without an `arcaneRoot`. Supplying an explicit `arcaneRoot` retains the existing
12
- checkout-provider route. Other native targets remain with their actual platform
14
+ checkout-provider route. The SDK also owns the `windows-x64` executable provider
15
+ described below. Other native targets remain with their actual platform
13
16
  providers; the loader does not substitute this payload for an unavailable host.
14
17
 
15
18
  ## Provider and selected input
16
19
 
17
20
  The default export and `arcaneNativeBuilderProvider` are the same provider.
18
- `createPortableNativeProvider({services:[]})` creates one with application-owned
19
- service configuration. All implement `arcane-native-builder/1`:
21
+ `createPortableNativeProvider({services})` creates one with application-owned
22
+ service configuration. Without that override, the provider uses the selected
23
+ app descriptor's `native.services`, or an empty selection when omitted. An
24
+ explicit `services:[]` overrides the descriptor with no app services.
25
+ All implement `arcane-native-builder/1`:
20
26
 
21
27
  - `describe()` identifies the portable target and `executable:false`.
22
28
  - `doctor({targetRequest, signal, onEvent})` reports missing SDK Core source files.
@@ -42,6 +48,45 @@ receipts, hashes, content limits or security policy. The package-relative source
42
48
  root comes from the provider module's own location, not `toolchainRoot` or an
43
49
  Arcane OS machine bundle.
44
50
 
51
+ ## Native-only application resources
52
+
53
+ Select application service modules and their complete local source closure in
54
+ the authored schema-2 descriptor's `package.nativeResources`, separately from
55
+ its browser `include`/`exclude` selection:
56
+
57
+ ```json
58
+ {
59
+ "package": {
60
+ "nativeResources": {
61
+ "include": ["native", "src", "package.json"],
62
+ "exclude": ["native/drafts"]
63
+ }
64
+ }
65
+ }
66
+ ```
67
+
68
+ This is a descriptor excerpt for the app-owned service example below. The
69
+ projected schema-1 field is top-level `nativeResources`. Paths are literal and
70
+ app-relative; directories include descendants. Omission or an empty include
71
+ keeps previous selection and output behavior. The app supplies every required
72
+ source file explicitly; packaging does not discover or execute services.
73
+
74
+ Paired `buildApplication()` passes the actual native target to the selected app
75
+ and every explicitly bundled app. With a nonempty native include list, their
76
+ input releases use `dist/.native/<target>/<app-id>` instead of the saved browser
77
+ output, preserving existing browser/PWA artifacts. Each app's own selection is
78
+ applied; complete releases and actual roots are forwarded to the provider.
79
+ The provider then copies them unchanged into its artifact layout described below.
80
+
81
+ At the low-level `packageApp()` boundary, `target` defaults to `'browser'` and
82
+ is independent of `moduleFormat`. Nonbrowser selection disables generated PWA
83
+ content. Native-only files bypass browser document/module/asset transformations;
84
+ a file also in the ordinary browser selection retains that existing processing.
85
+ An explicit low-level `outputDirectory` still wins. Inspect the emitted input
86
+ with `verifyApp({workspaceRoot,appId,outputDirectory:release.output})`; neither
87
+ that inventory verification nor packaging launches the service or platform host.
88
+ See [the complete selection contract](protocols.md#native-only-application-resources).
89
+
45
90
  ## Output and host contract
46
91
 
47
92
  Each build creates a fresh `arcane-portable-*` directory beneath `outputRoot`.
@@ -85,7 +130,9 @@ host must:
85
130
  1. Mount `app/` at the root of its local application URL origin, preserving the
86
131
  selected start path and all navigable documents.
87
132
  2. Inject `runtime/arcane-api.js` at document creation. It is produced by the
88
- canonical `createCoreClassicSource()` generator, not a copied OS client.
133
+ canonical `createCoreClassicSource()` generator with `replayRuntimeState:true`.
134
+ Once its transport listener is attached, each document requests the current
135
+ Core and service state without starting services again.
89
136
  3. Start `runtime/arcane-core.mjs` with the host's supported Node runtime and
90
137
  connect the existing framed stdin/stdout transport.
91
138
  4. Close input and await Core's drain before terminating the child process.
@@ -100,7 +147,21 @@ is not the native serving contract. No host is launched during packaging.
100
147
 
101
148
  ## Explicit application services
102
149
 
103
- Pass native service modules already included in the selected app release:
150
+ For the ordinary SDK build command, select native service modules in the
151
+ application's authored descriptor. Include their source closure through
152
+ `package.nativeResources` as described above:
153
+
154
+ ```json
155
+ {
156
+ "native": {
157
+ "services": [
158
+ {"module":"native/moon-ledger.mjs", "options":{"ledgerName":"Cheese debts"}}
159
+ ]
160
+ }
161
+ }
162
+ ```
163
+
164
+ Direct SDK compositions can instead pass that selection to the provider:
104
165
 
105
166
  ```js
106
167
  import {createPortableNativeProvider} from 'arcane-os/native/portable-provider';
@@ -111,7 +172,8 @@ const nativeBuilder = createPortableNativeProvider({
111
172
  ```
112
173
 
113
174
  Each module default-exports a synchronous factory returning the existing Core
114
- service definition. Its options must be JSON-serializable data. Module imports
175
+ service definition. Its first argument is the complete authored options record;
176
+ its second is the shared launch context described below. Options must be JSON-serializable data. Module imports
115
177
  and factories run only when the generated Core entry is launched, never during
116
178
  packaging. Put asynchronous initialization in `start()`, not a top-level await
117
179
  or asynchronous factory, so unrelated services and dispatcher readiness remain
@@ -142,8 +204,130 @@ observable through `onError` and `closed`; no process is killed or forcibly exit
142
204
  See [the Core runtime contract](core-runtime.md) for request and service lifetime
143
205
  details and [the client contract](core-client.md) for native bridge integration.
144
206
 
145
- This source increment supplies portable assembly and service composition.
146
- Desktop WebView executables, platform child-process ownership, Android dispatch
147
- and executable build toolchains require their own completed adapters. Published
207
+ ## Launch-time locations
208
+
209
+ The generated Core entry accepts `--arcane-launch-config <path>`. The public
210
+ `readCoreLaunchContext({argv=process.argv.slice(2)}={})` function in
211
+ `arcane-os/core/host` reads that explicitly selected JSON object. Without the
212
+ flag it returns `{}`. Missing files, missing flag values and malformed JSON
213
+ report their actual errors; the reader does not search for configuration,
214
+ rewrite it or change the process environment.
215
+
216
+ The generated entry supplies an artifact-derived `appRoot` and then applies the
217
+ complete explicit launch context. Every service factory receives that same
218
+ object as its second argument, preserving its authored first argument. A
219
+ launcher can supply the user's selected `workspaceRoot` and writable
220
+ `stateRoot` at launch instead of embedding this machine's paths in an app
221
+ package. The host owns those selections; the SDK does not choose a product's
222
+ workspace, namespace, saved preferences or models. JSON values and additional
223
+ application-owned fields remain unchanged.
224
+
225
+ ## Selected local-AI runtimes
226
+
227
+ When `appDescriptor.native.localAI` is present, portable assembly calls the
228
+ SDK's `bundleLocalAIRuntimes()` owner with its `runtimes` selection and the
229
+ requested target platform/architecture. Its reusable installation directory is
230
+ `<outputRoot>/local-ai-runtimes`; each new payload receives the complete selected
231
+ runtime trees beneath `runtime/local-ai/`. Runtime preparation and app copying
232
+ proceed independently and both settle before assembly can clean up an incomplete
233
+ output. No application service or model executes during packaging.
234
+
235
+ `manifest.core.localAIRuntimes` records the bundled runtime locations relative
236
+ to the artifact root. Only the explicitly configured entry imports
237
+ `createLocalAIService` from `arcane-os/core/local-ai`. It resolves those bundled
238
+ locations against the installed artifact and supplies them in the launch
239
+ context's `runtimes` array, alongside `appRoot`, before applying explicit launch
240
+ configuration. It passes the complete authored `native.localAI` record to the
241
+ factory. Applications without that selection have no generated local-AI import
242
+ or service. Availability of a particular engine belongs to the selected
243
+ local-AI installer and service; a generic ONNX runtime is not a speech model.
244
+
245
+ ## Windows executable
246
+
247
+ The ordinary application command is:
248
+
249
+ ```sh
250
+ npm exec -- arcane build --target windows-x64
251
+ ```
252
+
253
+ `loadArcaneNativeProvider({target:'windows-x64'})` selects the SDK's own
254
+ `arcane-os/native/windows-provider` without an OS checkout or `arcaneRoot`.
255
+ Its default export and `arcaneNativeBuilderProvider` are the same provider;
256
+ `createWindowsNativeProvider({services,hostDirectory})` permits explicit
257
+ same-project composition. Service selection follows the portable provider's
258
+ descriptor/override contract above.
259
+
260
+ The provider assembles the selected app with the precompiled host asset
261
+ `arcane-native-windows-x64.tar.gz` from the numeric GitHub release matching the
262
+ builder's installed SDK version. The asset contains the launcher, WebView2
263
+ support libraries, Node SEA Core executable and required license files. It does
264
+ not select the newest host independently of that package. Downloads occur only
265
+ during `build()`, use the caller's output directory, and are reused from
266
+ `<outputRoot>/.arcane-native-hosts/<sdk-version>/windows-x64`. The build machine
267
+ needs the standard `tar` command for extraction; application builds do not need
268
+ a C# compiler, system Node installation for the generated executable, or host
269
+ source scripts. The SDK build command itself still runs through the application's
270
+ normal Node/npm toolchain.
271
+
272
+ An explicit `hostDirectory` selects an already-built complete host tree instead
273
+ of downloading one. This is useful for SDK collaborators verifying the next
274
+ host output; downstream applications use the published package and matching
275
+ release asset. `doctor()` reports the selected prerequisites and missing files;
276
+ it does not download the host or probe the installed WebView runtime.
277
+
278
+ The assembled directory contains `Arcane.exe`, the unchanged `app/` payload,
279
+ Core runtime and semantic `arcane-native.json`. Launch `Arcane.exe` on Windows
280
+ x64 with the Microsoft Edge WebView2 Runtime installed. It opens the selected
281
+ app in WebView2 and owns its framed connection to the bundled Core process.
282
+ `verify()` observes the assembled files and manifest; it does not execute the
283
+ window or prove application behavior. `run()` launches the executable and
284
+ observes complete diagnostics and exit. Cancelling that operation closes its
285
+ input, allowing the window and accepted Core service work to drain without a
286
+ forced process termination.
287
+
288
+ For explicit user-selected workspace/state locations, launch:
289
+
290
+ ```sh
291
+ Arcane.exe --arcane-launch-config path/to/launch.json
292
+ ```
293
+
294
+ The complete JSON object reaches the service factories as their second
295
+ argument. A supplied `stateRoot` also owns the WebView2 profile and diagnostic
296
+ directory. Otherwise the launcher uses the current user's local application
297
+ data under `Arcane/<app-id>`. The launcher does not invent an application
298
+ workspace. Relative launch-file paths resolve from the invocation's working
299
+ directory. `--close-on-stdin-eof` is an explicit process-owner option used by the
300
+ SDK runner; an ordinary double-clicked window closes through its own UI.
301
+
302
+ ## Windows host source and selected output
303
+
304
+ The SDK's `src/core/hosts/windows/ArcaneCoreProcess.cs` owns an explicitly
305
+ selected executable, argument string and working directory. It reads complete
306
+ framed Core messages and diagnostics, acknowledges ordered asynchronous writes,
307
+ and closes stdin before awaiting accepted Core work, final output and process
308
+ exit. It does not kill the child on an ordinary close.
309
+
310
+ `ArcaneHost.cs` composes that process with a WebView2 window through
311
+ `ArcaneHost.Run(options,onDiagnostic,onError)` or `ArcaneHostForm`. Options
312
+ select the app root/start path, stable virtual HTTPS origin, profile directory,
313
+ title, canonical classic-client source and Core process inputs. The form exposes
314
+ `Ready`, `Completion` and `CloseAsync()`. Page navigation, transport connection,
315
+ Core readiness and service readiness are separate states. Accepted work drains
316
+ before the window closes; complete engineering errors go to the supplied
317
+ diagnostic/error callbacks. Callbacks must not synchronously wait for the
318
+ window's lifetime promises.
319
+
320
+ `ArcaneLauncher.cs` supplies the executable entry point for that composition.
321
+ `tools/build-core-windows-host.mjs` builds the selected SDK host output from the
322
+ approved WebView2 package, existing .NET Framework compiler and selected Node
323
+ SEA output. It retains complete compiler diagnostics and produces a fresh
324
+ directory rather than overwriting an earlier artifact. The host requires
325
+ .NET Framework 4.6.2 or later. This is SDK release tooling, not an application
326
+ build requirement. Source compilation, selected host execution and real
327
+ application behavior are separate evidence boundaries; an assembled app is not
328
+ an installer or proof of its domain behavior.
329
+
330
+ Linux, macOS, Android dispatch and each platform's output verification retain
331
+ their separate delivery boundaries. Published
148
332
  consumers must adopt the numeric package that includes this increment; a source
149
333
  checkout or a successful source push is not that public package authority.
@@ -107,6 +107,16 @@ Events have `{protocol, type:'event', event, data, time}`:
107
107
  - `core.service.state`: a service's name, state and serialized error when present.
108
108
  - `core.error`: a lifecycle or transport diagnostic.
109
109
 
110
+ A newly connected document may send
111
+ `{protocol:'arcane/1', type:'control', control:'runtime.replay'}`. The runtime
112
+ publishes one current snapshot: `core.ready` only when the dispatcher is ready,
113
+ then `core.state`, followed by `core.service.state` for every registered service.
114
+ Complete service errors and active request state are retained. Replay does not
115
+ start or restart services, dispatch a request, poll readiness or create a second
116
+ lifecycle owner. The runtime completes that snapshot before publishing lifecycle
117
+ changes triggered reentrantly by its listeners. A draining runtime reports its
118
+ draining state rather than announcing readiness.
119
+
110
120
  Service states are `registered`, `starting`, `ready`, `failed`, `draining` and
111
121
  `closed`. Dispatcher states are `created`, `ready`, `draining` and `closed`.
112
122
  Complete diagnostics belong in the host's developer-facing error handling, not