arcane-os 0.88.1 → 0.89.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/browser-runtime/ai/browser-decisions.mjs +31 -4
  3. package/browser-runtime/ai/core-local.mjs +105 -25
  4. package/browser-runtime/ai/decision-runtime.mjs +7 -0
  5. package/browser-runtime/ai/decision-worker.mjs +9 -1
  6. package/browser-runtime/core/client.mjs +6 -0
  7. package/browser-runtime/core/contracts.mjs +10 -0
  8. package/docs/reference/ai/browser-decisions.md +89 -7
  9. package/docs/reference/core-client.md +59 -0
  10. package/docs/reference/core-native-packaging.md +57 -10
  11. package/docs/reference/core-repositories.md +47 -3
  12. package/docs/reference/inventory/package-api.json +15 -15
  13. package/docs/reference/inventory/runtime-components.json +1 -1
  14. package/docs/reference/inventory/runtime-modules.json +4 -4
  15. package/docs/reference/local-ai.md +86 -3
  16. package/docs/reference/mcp-stdio.md +76 -1
  17. package/docs/reference/native-app-control.md +17 -5
  18. package/docs/reference/protocols.md +14 -0
  19. package/docs/reference/runtime-modules.md +9 -3
  20. package/docs/reference/sdk-api.md +135 -23
  21. package/package.json +2 -2
  22. package/runtime/arcane/modules/RiskSignalAnalyzer.js +1 -5
  23. package/schemas/arcane-app.schema.json +13 -3
  24. package/schemas/arcane-package.schema.json +10 -1
  25. package/src/app-descriptor.mjs +6 -2
  26. package/src/cli/app-control.mjs +1 -1
  27. package/src/core/hosts/windows/ArcaneHost.cs +273 -5
  28. package/src/core/hosts/windows/ArcaneLauncher.cs +9 -0
  29. package/src/core/hosts/windows/ArcaneWindowControl.cs +7 -7
  30. package/src/core/repositories.mjs +11 -1
  31. package/src/core/services/local-ai.mjs +183 -22
  32. package/src/installed-sdk-runtime.mjs +2 -0
  33. package/src/local-ai/config.mjs +16 -0
  34. package/src/local-ai/dev.mjs +2 -2
  35. package/src/local-ai/discover.mjs +3 -0
  36. package/src/local-ai/install.mjs +130 -20
  37. package/src/local-ai/llama-execution-windows.ps1 +158 -0
  38. package/src/local-ai/llama-execution.mjs +169 -0
  39. package/src/local-ai/server.mjs +38 -8
  40. package/src/native/portable-layout.mjs +13 -3
  41. package/src/workspace-runtime.mjs +97 -1
@@ -75,7 +75,8 @@ Save this in the consuming application and configure the MCP client's subprocess
75
75
  command as `node` with that application's script path. Client configuration
76
76
  file formats and process launch policy remain client-owned. Change `menu` to
77
77
  change the complete result; no model, repository, or native host is needed for
78
- this example.
78
+ this example. A native package can instead use its
79
+ [existing bundled runtime](#launch-from-a-native-package).
79
80
 
80
81
  The application explicitly converts its domain record into an MCP result.
81
82
  The SDK does not guess from `content`, `message`, or other domain field names.
@@ -255,6 +256,80 @@ The adapter uses `-32700` for malformed JSON, `-32600` for invalid requests,
255
256
  `-32603` for internal failures, and `-32002` for a missing resource. Its
256
257
  `-32000` lifecycle error requests initialization before ordinary operations.
257
258
 
259
+ ## Launch from a native package
260
+
261
+ The generated `runtime/arcane-core.mjs` accepts
262
+ `--arcane-app-entry <app-relative-module>` to import an application-owned entry
263
+ instead of starting ordinary Core. Include the entry and its complete local
264
+ source closure in the application's `package.nativeResources`, for example:
265
+
266
+ ```json
267
+ {
268
+ "package": {
269
+ "nativeResources": {
270
+ "include": ["native", "src", "package.json"]
271
+ }
272
+ }
273
+ }
274
+ ```
275
+
276
+ Save the complete example above as `native/moon-mcp.mjs`. Native packaging copies
277
+ the selected files beneath the artifact's `app/` directory. It does not discover
278
+ entry dependencies from this runtime argument or execute the entry during
279
+ packaging. Public imports such as `arcane-os/mcp/stdio` use the artifact's
280
+ existing SDK package and Node's ordinary package resolution.
281
+
282
+ Configure the MCP client's command and argument array for the selected artifact:
283
+
284
+ | Artifact | Command | Arguments |
285
+ | --- | --- | --- |
286
+ | Windows | `<artifact-root>/runtime/ArcaneCore.exe` | `["--arcane-app-entry", "native/moon-mcp.mjs"]` |
287
+ | macOS | `<artifact-root>/runtime/node` | `["<artifact-root>/runtime/arcane-core.mjs", "--arcane-app-entry", "native/moon-mcp.mjs"]` |
288
+ | Portable | The host's supported Node executable | `["<artifact-root>/runtime/arcane-core.mjs", "--arcane-app-entry", "native/moon-mcp.mjs"]` |
289
+
290
+ These are placeholders for the actual native paths. For macOS, `artifact-root`
291
+ is `<app-id>.app/Contents/Resources`. The portable provider supplies no Node
292
+ executable. Windows uses its existing SEA executable and filesystem loader;
293
+ do not pass `arcane-core.mjs` as a script argument to that executable. These
294
+ commands select the runtime directly, not the GUI launcher, and create no
295
+ window or second Core host.
296
+
297
+ The module path resolves from the artifact's `app/`, independently of the
298
+ client's working directory. Native path separators, spaces, Unicode, `#` and
299
+ `%` retain their filesystem meaning through file-URL conversion. The original
300
+ `process.argv` remains complete and unchanged, including this flag, its path,
301
+ and every app argument. The flag is read from user arguments starting at index
302
+ 2 for both normal Node and SEA. A missing or empty value throws `TypeError`;
303
+ module-loading failures remain actual errors and never start ordinary Core.
304
+
305
+ This is a dynamic import: the entry runs its top-level code and observes its
306
+ own session lifetime, as the example's `server.start()` and `await server.closed`
307
+ do. Do not put its only startup behind `if (import.meta.main)`; the imported
308
+ module is not Node's main entry. The SDK calls no default export or factory.
309
+
310
+ App-entry mode skips ordinary Core launch-context loading, manifest service
311
+ composition, state-directory creation, local-AI startup, shared-host startup,
312
+ and Core signal handlers. If the application wants the existing explicit launch
313
+ JSON or host state-root arguments, append them to the same argument array and
314
+ read them deliberately in its entry:
315
+
316
+ ```javascript
317
+ import {readCoreLaunchContext} from 'arcane-os/core/host';
318
+
319
+ const context = await readCoreLaunchContext();
320
+ ```
321
+
322
+ For example, append `"--arcane-launch-config", "<selected-launch.json>"`.
323
+ Relative launch JSON paths retain their caller-working-directory meaning. The
324
+ application chooses defaults, services and any connection to an existing Core;
325
+ the entry selector neither reads nor applies the manifest's launch defaults.
326
+
327
+ The application owns process signals, graceful MCP drain, and its underlying
328
+ service shutdown. Keep stdout exclusively for MCP JSON-RPC and diagnostics on
329
+ stderr; the ordinary Core `arcane/1` transport must not share those MCP pipes.
330
+ When the flag is absent, ordinary Core startup and service lifecycle are
331
+ unchanged. See [native entry composition](core-native-packaging.md#app-owned-runtime-entry).
332
+
258
333
  ## Evidence boundary
259
334
 
260
335
  `test/mcp-stdio-server.test.mjs` contains focused in-memory stream fixtures for
@@ -73,11 +73,11 @@ connection or other business result.
73
73
  | Member | Contract |
74
74
  | --- | --- |
75
75
  | `connectAppControl({endpoint, signal?, onError?})` | Connect once to the explicit running host. It never launches an app, creates Core, changes a profile or reconnects automatically. |
76
- | `status(options?)` | Returns app identity, platform/host, current URL, document generation, readiness, window title/state/client dimensions and available operations. Readiness describes the document, not models or application services. |
76
+ | `status(options?)` | Returns app identity, platform/host, current URL, document generation, readiness, window title/state/client dimensions and available operations. Window state is `Normal`, `Maximized`, `Minimized`, or `Fullscreen`. Readiness describes the document, not models or application services. |
77
77
  | `inspect(parameters={}, options?)` | Optional `shadowPath` selects an open shadow root. Optional CSS `selector` selects zero or more elements within the selected root; omission selects the whole root. Optional `documentGeneration` selects the expected document. Returns complete HTML/text, live control state and DOM-derived role/name hints. |
78
78
  | `capture(parameters={}, options?)` | Returns `{mimeType:'image/png', data, documentGeneration, url}`. `data` contains the complete base64 PNG. Optional `documentGeneration` selects the expected document. |
79
79
  | `act(parameters, options?)` | Requires `documentGeneration`, one unambiguous CSS `selector` within the root selected by optional `shadowPath`, and the action fields below. |
80
- | `key(parameters, options?)` | Requires `documentGeneration` and `key:'Tab'`, `'Enter'`, or `'Space'`. Optional `shiftKey:true` is supported only for Tab. Sends one ordered press/release pair to the selected WebView's current focus. |
80
+ | `key(parameters, options?)` | Requires `documentGeneration` and `key:'Tab'`, `'Enter'`, `'Space'`, or `'Escape'`. Optional `shiftKey:true` is supported only for Tab. Sends one ordered press/release pair to the selected WebView's current focus. |
81
81
  | `resize(parameters, options?)` | Requires positive integral native client `width` and `height` supported by WinForms. Optional `documentGeneration` selects the expected document. Resizes only a Normal window and returns immediate previous/actual client dimensions plus the subsequently observed CSS viewport. |
82
82
  | `close()` | Closes this caller's connection and cancels its pending requests. It never closes the app or Core. Returns the connection's completion promise. |
83
83
  | `closed` | Connection lifetime promise; actual transport failures remain observable. |
@@ -207,6 +207,8 @@ const moved = await app.key({documentGeneration: page.documentGeneration, key: '
207
207
  console.log(moved.previous.focusPath, moved.actual.focusPath);
208
208
  await app.key({documentGeneration: moved.documentGeneration, key: 'Tab', shiftKey: true});
209
209
  await app.key({documentGeneration: moved.documentGeneration, key: 'Enter'});
210
+ const current = await app.inspect();
211
+ await app.key({documentGeneration: current.documentGeneration, key: 'Escape'});
210
212
  ```
211
213
 
212
214
  Keys use the selected WebView's current focus. No selector, shadow path, frame
@@ -214,7 +216,10 @@ selection, focus assignment or desktop activation is performed. Tab and
214
216
  Shift+Tab use a fixed Tab `rawKeyDown`/`keyUp` pair, with the Shift modifier on
215
217
  both events for Shift+Tab. Enter and Space use `keyDown` with their corresponding
216
218
  text, followed by `keyUp`, preserving browser default actions and application
217
- `preventDefault` handling. Shift+Tab does not send a separate Shift key pair.
219
+ `preventDefault` handling. Escape uses `key:'Escape'`, `code:'Escape'` and native
220
+ virtual key 27 in a `rawKeyDown`/`keyUp` pair, without text fields. It follows the
221
+ selected WebView's normal Escape handling; it does not promise that a particular
222
+ dialog closes. Shift+Tab does not send a separate Shift key pair.
218
223
  The API exposes these fixed keys, not an arbitrary protocol method or script.
219
224
 
220
225
  The result contains `key`, `shiftKey`, `previous` and `actual` document views,
@@ -264,7 +269,7 @@ origin. Read `viewport` for the resulting CSS dimensions instead of assuming a
264
269
  particular DPI or zoom conversion.
265
270
 
266
271
  Immediately before the UI-thread mutation, the host checks the actual
267
- `WindowState` and records `previous:{title,state,width,height}`. It records
272
+ window state and records `previous:{title,state,width,height}`. It records
268
273
  `actual` in the same shape immediately after the native setter, then observes
269
274
  the CSS `viewport` asynchronously. The result also contains `requested`,
270
275
  `resizeAttempted`, `resizeCompleted`, `documentGeneration` and `url`.
@@ -274,13 +279,20 @@ native snapshot and the document observation; these records are not an atomic
274
279
  native/CSS snapshot. Completion does not establish that asynchronous application
275
280
  resize handlers have settled.
276
281
 
277
- Maximized or minimized windows return `ARCANE_APP_CONTROL_FAILED` before any
282
+ Maximized, minimized or fullscreen windows return `ARCANE_APP_CONTROL_FAILED` before any
278
283
  size mutation, with `reason:'unsupported-window-state'`,
279
284
  `supportedWindowState:'Normal'` and the complete current `window` in the error's
280
285
  `data` entries. The host never automatically restores, maximizes or minimizes a
281
286
  window to satisfy this request. Invalid dimensions return `INVALID_ARGUMENT`.
282
287
  The same state rule applies to explicit restoration.
283
288
 
289
+ Native fullscreen reports `Fullscreen`, including while its underlying WinForms
290
+ state is Normal. A minimized fullscreen window reports `Minimized`. The
291
+ requesting document can select its state through
292
+ [`Arcane.window.setState({state})`](core-client.md#current-window-state); app-control
293
+ does not add a separate state-setting operation. That facade uses lowercase
294
+ state values, while app-control preserves its existing capitalized values.
295
+
284
296
  Restore using the actual `previous.width` and `previous.height` from the
285
297
  operation being reversed, never a historical status snapshot or CSS viewport
286
298
  dimensions. Restoration is an explicit second request; cancellation does not
@@ -475,6 +475,20 @@ the selected runtime content. The lock document describes the selected
475
475
  installation and projected roots; it is not a content-identity or admission
476
476
  record.
477
477
 
478
+ Both runtime materializers accept explicit `browserDecisions: true` to acquire
479
+ the upstream bundled Transformers.js 4.3.0 entry, matching ONNX Runtime
480
+ 1.31.0-dev.20260914-8d85527a0 asyncify module/WASM, and license files into
481
+ `arcane/sdk/ai/decisions-runtime/` before replacement. Default `false` performs
482
+ no optional acquisition. The complete selected files remain unchanged;
483
+ `workspace.decisions.started`/`workspace.decisions.progress` count completed
484
+ files. Cancellation, HTTP failures and observer failures join acquisition
485
+ cleanup and preserve the previous projection. Retain the option on each refresh
486
+ that needs the closure. The optional `browserDecisions` result describes its
487
+ directory, versions and filenames; installed materialization nests it under
488
+ `workspaceRuntime`. Model/tokenizer data remain upstream and cache-owned.
489
+ See [extension-local decisions](ai/browser-decisions.md#extension-local-executables-manifest-v3)
490
+ for the separate `runtime.local: true` browser selection.
491
+
478
492
  `upgradeApplication()` and `arcane upgrade` run the application's ordinary
479
493
  `npm upgrade` command. They do not independently reconcile the installed SDK
480
494
  projection, semantic Arcane lock, or managed import map.
@@ -128,7 +128,7 @@ own asynchronous work, cancellation, and backpressure.
128
128
  | [`RecordLinkIndex.js`](#recordlinkindexjs) | esm | Parses record links and builds their normalized index. | Cross-host | Fully normalized. |
129
129
  | [`RecordPassageIndex.js`](#recordpassageindexjs) | esm | Indexes text lines, page markers, dates, rules, and excerpts for record review. | Cross-host | Fully normalized. |
130
130
  | [`RecordReviewStore.js`](#recordreviewstorejs) | esm | Stores normalized record-review decisions through native storage or app-scoped local fallback. | Browser/native hybrid | Complete records preserved; unreadable stored content fails observably. |
131
- | [`RiskSignalAnalyzer.js`](#risksignalanalyzerjs) | esm | Matches configured risk signals and levels against complete text. | Cross-host | Fully normalized. |
131
+ | [`RiskSignalAnalyzer.js`](#risksignalanalyzerjs) | esm | Matches configured risk signals and levels against complete text. | Cross-host | Complete literal text; existing non-string conversion only. |
132
132
  | [`ScamRiskPolicy.js`](#scamriskpolicyjs) | esm | Combines deterministic scam signals with optional Arcane blocked-domain evidence and safety guidance. | Cross-host | Complete mutable results; blocked-domain policy requires `secure:true`. |
133
133
  | [`ScopedOPFSCache.js`](#scopedopfscachejs) | esm | Provides a narrow exact-key JSON cache inside one app-owned OPFS namespace. | Browser / native WebView | Filename-safe keys, complete JSON values, and malformed-cache cleanup normalized; storage errors mixed. |
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. |
@@ -1386,7 +1386,11 @@ transcription-model load.
1386
1386
  **Cross-host state contract.** States are `unavailable`, `unloaded`, `loading`,
1387
1387
  `recovering`, `ready`, `unloading`, `error`, and `disposed`. Recovery remains
1388
1388
  `loaded: false`; `recovering` and `error` may retain `busy: true` with an actual
1389
- `operationId` until the pending request settles. Revisions increase monotonically.
1389
+ `operationId` until the pending request settles. During `unloading`, an already
1390
+ loaded role may retain `busy: true` with its actual `operationId` while captured
1391
+ requests settle. That observation grants no readiness or permission for a new
1392
+ request and is not a `continuesAIRuntimeOperation` recovery state.
1393
+ Revisions increase monotonically.
1390
1394
  The events `arcane-ai-runtime-state`, `arcane-ai-runtime-intent`, and
1391
1395
  `arcane-ai-runtime-startup-settled` normalize observation only: receiving one
1392
1396
  does not grant a native capability, prove browser support, or load a provider.
@@ -4010,9 +4014,11 @@ Matches configured risk signals and levels against complete text.
4010
4014
 
4011
4015
  Exact exports: `DEFAULT_LEVELS`, `analyzeRiskSignals`.
4012
4016
 
4017
+ `analyzeRiskSignals(input, {signals, levels})` scans the complete `String(input ?? '')` without Unicode normalization or whitespace changes. Fullwidth characters and decomposed characters remain as supplied. Each signal's `RegExp.lastIndex` resets before testing; signal order, weights and selected levels determine the mutable `{level, matches, score, textLength}` result. `textLength` is the JavaScript string length after the existing non-string conversion; `null` and `undefined` become an empty string. Ordinary `ScamRiskPolicy.assessScamRisk()` uses this same literal-text path.
4018
+
4013
4019
  ### Availability and normalization
4014
4020
 
4015
- **Cross-host.** Fully normalized. Transport: In-process only. [Deep protocol details](protocols.md).
4021
+ **Cross-host.** Complete literal text; existing non-string conversion only. Transport: In-process only. [Deep protocol details](protocols.md).
4016
4022
 
4017
4023
  ### Example
4018
4024
 
@@ -1857,7 +1857,7 @@ create `arcane.lock.json` before serving, refreshing app import maps, or packagi
1857
1857
  ### Signature and result
1858
1858
 
1859
1859
  ```text
1860
- async materializeInstalledSdkRuntime({workspaceRoot,sdkPackageSource,workspaceOperationLease,signal,onEvent}={})
1860
+ async materializeInstalledSdkRuntime({workspaceRoot,sdkPackageSource,browserDecisions=false,workspaceOperationLease,signal,onEvent}={})
1861
1861
  ```
1862
1862
 
1863
1863
  Import it through the exact dependency key declared by the workspace: normally
@@ -1868,6 +1868,16 @@ whole-tree replacement. The mutable result includes the installed-package
1868
1868
  location, materialized workspace runtime paths, and `workspaceLock` path and
1869
1869
  document. It does not install dependencies or merge application source.
1870
1870
 
1871
+ Explicit `browserDecisions: true` also acquires the bundled Transformers.js
1872
+ 4.3.0 entry and matching ONNX Runtime 1.31.0-dev.20260914-8d85527a0 asyncify
1873
+ module/WASM and license files from their upstream distributions into
1874
+ `arcane/sdk/ai/decisions-runtime/`. It returns their `directory`,
1875
+ `transformersVersion`, `onnxRuntimeVersion` and `files` under
1876
+ `workspaceRuntime.browserDecisions`. The default `false` performs no optional
1877
+ acquisition. Select this option on each refresh that should retain those files.
1878
+ The [extension-local decision guide](ai/browser-decisions.md#extension-local-executables-manifest-v3)
1879
+ describes `runtime.local: true`, complete resource ownership and MV3 usage.
1880
+
1871
1881
  Ordinary acquisition automatically recovers a workspace-operation lock when
1872
1882
  the recorded owner process is confirmed absent, without waiting solely for its
1873
1883
  six-hour expiry. Retry this public operation normally; `workspaceOperationLease`
@@ -1910,13 +1920,24 @@ the installed-package lock document owned by `materializeInstalledSdkRuntime()`.
1910
1920
  ### Signature and result
1911
1921
 
1912
1922
  ```text
1913
- async materializeWorkspaceRuntimeContent({workspaceRoot,runtimeRoot=path.join(getSdkRoot(), 'runtime'),browserRuntimeRoot=getSdkBrowserRuntimeRoot(),signal,onEvent}={})
1923
+ async materializeWorkspaceRuntimeContent({workspaceRoot,runtimeRoot=path.join(getSdkRoot(), 'runtime'),browserRuntimeRoot=getSdkBrowserRuntimeRoot(),sdkVersion=SDK_VERSION,browserDecisions=false,signal,onEvent}={})
1914
1924
  ```
1915
1925
 
1916
1926
  The operation stages the complete projection, replaces the prior tree at the
1917
1927
  commit boundary, restores it if commit fails, and removes paths absent from the
1918
1928
  selected sources.
1919
1929
 
1930
+ `browserDecisions: true` acquires the same upstream executable closure described
1931
+ by `materializeInstalledSdkRuntime()` before replacement. Its result is at
1932
+ `result.browserDecisions` because this lower-level operation returns the
1933
+ workspace runtime directly. Full downloaded content remains unchanged; model
1934
+ and tokenizer data are not materialized. `workspace.decisions.started` and
1935
+ `workspace.decisions.progress` report completed files and the fixed total.
1936
+ Cancellation, HTTP failures and throwing/rejecting observers abort and join
1937
+ pending acquisitions before returning; the prior runtime remains in place.
1938
+ An HTTP failure retains its complete response in `error.response`, or in the
1939
+ corresponding member of `AggregateError.errors` when several operations fail.
1940
+
1920
1941
  ### Availability and normalization
1921
1942
 
1922
1943
  **Node.** Complete workspace runtime content and a mutable materialization result. Deep protocol: [Installed SDK runtime materialization](protocols.md#installed-sdk-runtime-materialization).
@@ -7122,6 +7143,21 @@ no engine. The native routes of `AI.fetchTTS(payload, signal)` and
7122
7143
  `AI.fetchSTT(audio, signal)` forward their signals through these calls and
7123
7144
  normalize cancellation to `AbortError` with `ARCANE_AI_REQUEST_ABORTED`.
7124
7145
 
7146
+ `facade.window.state({signal}?)` reads the calling document's native window;
7147
+ `facade.window.setState({state}, {signal}?)` selects `normal`, `maximized` or
7148
+ `fullscreen` for that same window. The matching Windows host returns
7149
+ `{platform:'windows', supported:true, state}`, with observed `state` also able
7150
+ to be `minimized`. Fullscreen removes the frame and fills the selected monitor;
7151
+ leaving it restores the preceding normal bounds and frame controls before any
7152
+ requested maximization. Visible state transitions prevent activation/focus
7153
+ assignment to the requesting window without changing TopMost, Core, origin or
7154
+ profile. Optional `native.window.state` selects startup state after initial
7155
+ sizing; omission preserves host behavior. Saved Settings remain application-owned.
7156
+ Cancellation does not undo an already-applied change. Other hosts retain their
7157
+ actual unavailable-method/transport errors; the facade provides no fallback.
7158
+ See [current-window state](core-client.md#current-window-state) for complete
7159
+ native errors, partial-state evidence, navigation and cleanup ownership.
7160
+
7125
7161
  `facade.window.setTheme(presentation, {signal}?)` forwards the complete
7126
7162
  presentation to the current native window, independently of OS-user appearance.
7127
7163
  Optional `backgroundColor` and `textColor` accept `{red,green,blue,alpha}` or
@@ -7777,6 +7813,17 @@ published SDK/runtime dependencies and the canonical Core entry/client into a
7777
7813
  fresh output directory. Service factories are imported only when a real native
7778
7814
  host later launches the generated Core entry, never during packaging.
7779
7815
 
7816
+ The generated `runtime/arcane-core.mjs` also accepts
7817
+ `--arcane-app-entry <app-relative-module>` through the host's supported Node
7818
+ executable; the portable provider supplies no executable. Include that module
7819
+ and its complete source closure through `package.nativeResources`. The flag
7820
+ imports it from the packaged `app/` directory, preserves complete `process.argv`,
7821
+ and runs its top-level work rather than invoking an export or making it
7822
+ `import.meta.main`. The entry owns explicit launch-context reads, services,
7823
+ signals and shutdown; ordinary Core startup is skipped only in this mode.
7824
+ See [app-owned runtime entry](core-native-packaging.md#app-owned-runtime-entry)
7825
+ and [packaged MCP commands and lifetime](mcp-stdio.md#launch-from-a-native-package).
7826
+
7780
7827
  Explicit `native.launchContext.coreListener:{endpoint}` also composes one passive
7781
7828
  model observation service after `startCoreHost()` and before listener binding,
7782
7829
  using that runtime and existing services exposing `localai.status`, `image.status`
@@ -7784,11 +7831,13 @@ and `decisions.status`. Missing owners remain `null`; renderer attachment stays
7784
7831
  application-owned. Ordinary stdio and shared/headless branches gain no model
7785
7832
  startup or readiness barrier. See [native observation composition](core-native-packaging.md#launch-time-locations).
7786
7833
 
7787
- An optional `appDescriptor.native.window` record carries `width`, `height` and
7788
- `resizable` into `manifest.window`. Dimensions are positive integral logical
7789
- client units; `resizable` is an optional boolean. Omitted fields remain omitted.
7790
- The portable payload records the selection; the selected platform host owns
7791
- its window behavior. See [initial native window size](core-native-packaging.md#initial-native-window-size).
7834
+ An optional `appDescriptor.native.window` record carries `width`, `height`,
7835
+ `resizable` and `state` into `manifest.window`. Dimensions are positive integral
7836
+ logical client units; `resizable` is an optional boolean, and `state` selects
7837
+ `normal`, `maximized` or `fullscreen`. Omitted fields remain omitted. The portable
7838
+ payload records the selection; the matching Windows host applies it, while
7839
+ current other-platform hosts retain their existing window behavior. See
7840
+ [initial native window size and state](core-native-packaging.md#initial-native-window-size).
7792
7841
 
7793
7842
  ### Availability and normalization
7794
7843
 
@@ -7905,11 +7954,25 @@ The matching Windows host consumes `appDescriptor.native.window` through
7905
7954
  `manifest.window`. Optional `width` and `height` select initial client dimensions
7906
7955
  in 96-DPI logical units; the host scales them for its actual DPI and fits the
7907
7956
  outer window within the current screen's usable area. Optional `resizable:false`
7908
- selects a fixed-size border and disables maximizing. Omitted fields preserve
7909
- the existing host defaults. Initial sizing preserves a window already restored
7910
- to a non-normal state and does not add saved-bounds storage. The initial-fit
7911
- logic is not reapplied during later user resizing. See [initial native window size](core-native-packaging.md#initial-native-window-size)
7912
- for a complete descriptor example and the other-platform boundary.
7957
+ selects a fixed-size border and disables the maximize control. Optional `state`
7958
+ selects `normal`, `maximized` or `fullscreen`; the host applies an explicit state
7959
+ after its initial sizing pass and before the composing launcher's `Load` handler.
7960
+ Initial sizing runs only for a Normal window. Omitted fields preserve existing
7961
+ host choices, including the current state when `state` is omitted. Fullscreen
7962
+ retains normal bounds and frame controls for restoration. No saved-bounds store
7963
+ is added, and initial-fit logic is not reapplied during later user resizing.
7964
+ See [initial native window size and state](core-native-packaging.md#initial-native-window-size)
7965
+ for the complete descriptor and unchanged other-platform behavior.
7966
+
7967
+ The packaged `runtime/ArcaneCore.exe` also accepts
7968
+ `--arcane-app-entry <app-relative-module>` directly, without a script argument
7969
+ or the GUI launcher. Include the entry and complete source closure through
7970
+ `package.nativeResources`. It imports the selected packaged `app/` module with
7971
+ complete `process.argv` unchanged, running top-level work without invoking an
7972
+ export or making it `import.meta.main`. The entry owns explicit launch-context
7973
+ reads, services, signals and shutdown; this mode skips ordinary Core startup,
7974
+ while omission retains it. See [app-owned runtime entry](core-native-packaging.md#app-owned-runtime-entry)
7975
+ and [packaged MCP commands and lifetime](mcp-stdio.md#launch-from-a-native-package).
7913
7976
 
7914
7977
  The returned `arcane-native-builder/1` provider exposes `describe`, `doctor`,
7915
7978
  `prepare`, `build`, `verify` and `run`. Build returns `{app,target,manifest}`
@@ -8285,7 +8348,7 @@ explicit existing path. The application owns the remote, branch and Core API.
8285
8348
  ### Signature and result
8286
8349
 
8287
8350
  ```text
8288
- createRepositoryWorkspace({name,directory,dataRoot,remote,branch,longPaths,gitIdentity,onEvent,run=runProcess}={})
8351
+ createRepositoryWorkspace({name,directory,dataRoot,remote,branch,longPaths,cloneIdentity,gitIdentity,onEvent,run=runProcess}={})
8289
8352
  ```
8290
8353
 
8291
8354
  Returns `{directory,open,status,configuration,pull,push,write,close,drain,dispose}`. Construction does
@@ -8304,6 +8367,16 @@ unchanged; no global setting or data migration is performed. Git's ordinary
8304
8367
  configuration precedence, hooks and single-clone lifecycle remain in effect.
8305
8368
  See [Windows long paths](core-repositories.md#windows-long-paths-for-a-new-checkout).
8306
8369
 
8370
+ Optional `cloneIdentity:{name?,email?}` captures exact author strings and saves
8371
+ only supplied fields in a newly created checkout through Git's `clone --config`
8372
+ before its first checkout, on every supported platform. Empty strings are
8373
+ explicit values; omitted or `undefined` fields preserve inherited and template
8374
+ configuration. Existing repositories are never reconfigured. Unrepresentable
8375
+ process arguments fail without changing the supplied text. This option changes
8376
+ no global configuration, credentials, remote or branch, and does not identify
8377
+ the authenticated account. Command-local `gitIdentity` remains independent.
8378
+ See [clone-local author selection](core-repositories.md#clone-local-author-selection).
8379
+
8307
8380
  Optional `gitIdentity:{name?,email?,username?}` captures explicit non-secret
8308
8381
  settings for child Git operations without writing global/local configuration.
8309
8382
  Selected author fields override inherited child author/committer fields;
@@ -8396,15 +8469,16 @@ Construction selects no model and installs no runtime or transport.
8396
8469
  ### Signature and result
8397
8470
 
8398
8471
  ```text
8399
- createCoreLocalAIProvider({client,id='llama.cpp'}={})
8472
+ createCoreLocalAIProvider({client,id='llama.cpp',prepareModel}={})
8400
8473
  ```
8401
8474
 
8402
8475
  Import it from `arcane-os/ai/core-local`. The provider implements
8403
8476
  `arcane-ai-provider/2` and exposes `catalog`, `status`, `inspect`, `load`,
8404
8477
  `request`, `unload` and `dispose`. Register it with the shared AI provider runtime,
8405
8478
  select the exact provider/model with `localOnly:true`, and load that selection.
8406
- Requests wait for the requested model's actual readiness, preserve complete
8407
- payloads and parsed streaming chunks, and cancel on observed readiness loss.
8479
+ `load()` waits for the selected model's actual readiness; inference requests
8480
+ require that load to have completed successfully. Requests preserve complete
8481
+ payloads and parsed streaming chunks and cancel on observed readiness loss.
8408
8482
  Missing Core reports unavailability; it does not choose a browser or cloud route.
8409
8483
  Dispose/unregister at the caller's owning lifecycle boundary.
8410
8484
 
@@ -8418,6 +8492,17 @@ client, so never-loaded and already-unloaded providers send no native unload.
8418
8492
  The provider/2 runtime reconciles status at its operation boundaries; this
8419
8493
  does not add an idle role-state subscription.
8420
8494
 
8495
+ Optional `prepareModel({selection,signal,progress})` runs at actual load and
8496
+ returns `{assetProjectionId,resourcePaths,executionTarget,release?}`. Direct
8497
+ `load` fields with those names override preparation when defined; an explicit
8498
+ `executionTarget:null` requests the runtime default. Preparation release is
8499
+ awaited after native load settles, including failure, cancellation and late
8500
+ preparation results. The current successfully completed load owns readiness
8501
+ and inference; a failed replacement cannot reuse an older model's ready state.
8502
+ Native cleanup owns the last dispatched selection, while preparation alone
8503
+ creates no native unload obligation. `status().execution` forwards native
8504
+ execution diagnostics, including configured and observed targets separately.
8505
+
8421
8506
  ```javascript
8422
8507
  import {createCoreLocalAIProvider} from 'arcane-os/ai/core-local';
8423
8508
  import {getAIProviderRuntime} from 'arcane-os/ai-provider-runtime';
@@ -8440,7 +8525,7 @@ separate states; prompts, models and application policy remain caller-owned.
8440
8525
  ### Signature and result
8441
8526
 
8442
8527
  ```text
8443
- createLocalAIService(configuration,{appRoot,runtimes=[],signal,onEvent,prepare}={})
8528
+ createLocalAIService(configuration,{appRoot,runtimes=[],signal,onEvent,prepare,executionDevices}={})
8444
8529
  ```
8445
8530
 
8446
8531
  Import it from `arcane-os/core/local-ai`. `configuration` is the authored local-AI
@@ -8473,6 +8558,19 @@ Explicit load retains startup and exact catalog-membership checks.
8473
8558
  carry original parsed chunks with `streamId`; terminal responses remain complete.
8474
8559
  There is no background health polling or implicit model choice.
8475
8560
 
8561
+ For managed llama.cpp loading, `llama.load` also accepts `assetProjectionId`,
8562
+ `resourcePaths:{model}` and `executionTarget`. The existing model-assets owner
8563
+ retains the exact projected GGUF through actual server exit. An omitted target
8564
+ retains the same model's selection or configured default; `null` requests the
8565
+ runtime default. `{deviceId}` uses this computer's execution-device catalog.
8566
+ Windows NVIDIA selection resolves that physical device to its CUDA identity;
8567
+ unsupported or unavailable targets report their actual failure. Runtime
8568
+ `execution` reports requested, resolved and configured targets with
8569
+ `observedTarget:null`; configuration does not establish physical execution.
8570
+ An optional `executionDevices` catalog is borrowed by ONNX and llama.cpp; its
8571
+ supplying owner retains disposal responsibility. Existing external listeners
8572
+ retain their own model/device selection and reject managed reconfiguration.
8573
+
8476
8574
  ```javascript
8477
8575
  import {createLocalAIService} from 'arcane-os/core/local-ai';
8478
8576
 
@@ -9156,7 +9254,8 @@ portable Node local IPC; other native host adapters do not yet implement these
9156
9254
  document operations. No application is launched, no desktop window is activated,
9157
9255
  and no automatic reconnect or action retry occurs.
9158
9256
 
9159
- `status(options)` reports current app/window/document readiness.
9257
+ `status(options)` reports current app/window/document readiness, including
9258
+ observed window state `Normal`, `Maximized`, `Minimized` or `Fullscreen`.
9160
9259
  `inspect(parameters={},options)` returns complete selected DOM HTML/text
9161
9260
  and live control state. Inspection and actions accept optional `shadowPath`, an
9162
9261
  ordered array of unique CSS host selectors through open shadow roots; their
@@ -9171,7 +9270,8 @@ of the rendered viewport. `act(parameters,options)` requires a returned
9171
9270
  fields.
9172
9271
 
9173
9272
  `key(parameters,options)` requires the observed `documentGeneration` and
9174
- `key:'Tab'`, `'Enter'` or `'Space'`; `shiftKey:true` is supported only for Tab.
9273
+ `key:'Tab'`, `'Enter'`, `'Space'` or `'Escape'`; `shiftKey:true` is supported only
9274
+ for Tab.
9175
9275
  It sends a fixed ordered press/release pair to the selected WebView's current
9176
9276
  focus, without selecting an element or activating the desktop window. Accepted
9177
9277
  pairs share one keyboard owner. Once a press is attempted, its matching release
@@ -9183,9 +9283,9 @@ or navigation can change between phases.
9183
9283
 
9184
9284
  `resize(parameters,options)` accepts positive integral native client `width`
9185
9285
  and `height` supported by WinForms, plus optional `documentGeneration`. It changes
9186
- only `ClientSize` while the actual window is `Normal`; maximized or minimized
9187
- windows fail before size mutation. Results retain immediate `previous`/`actual`
9188
- native dimensions, requested dimensions, attempted/completed flags and a later
9286
+ only `ClientSize` while the actual window is `Normal`; maximized, minimized or
9287
+ fullscreen windows fail before size mutation. Results retain immediate
9288
+ `previous`/`actual` native dimensions, requested dimensions, attempted/completed flags and a later
9189
9289
  observed CSS `viewport`. Platform constraints can change actual dimensions;
9190
9290
  native and CSS observations are not an atomic snapshot. Restore explicitly with
9191
9291
  the same operation's `previous.width` and `previous.height`, not CSS dimensions
@@ -9990,9 +10090,21 @@ selections report its failure without precision fallback. For Laya FP32, pass
9990
10090
  Cancellation terminates that client's Worker and rejects its in-flight work.
9991
10091
  No decisions are inserted into chat history or durable storage.
9992
10092
 
10093
+ For explicitly selected extension-local execution, supply `runtime: {local:
10094
+ true}` after materializing with `browserDecisions: true`. The SDK directly
10095
+ imports its deployment-local `decisions-runtime/transformers.min.js` and
10096
+ matched asyncify module/WASM. Explicit `runtime.moduleUrl` and
10097
+ `runtime.wasmPaths: {mjs, wasm}` may select other compatible files in that same
10098
+ deployment; a directory string is also accepted for `wasmPaths`. This mode
10099
+ disables executable Blob preparation and upstream WASM cache/proxy creation,
10100
+ selects one WASM thread, and preserves the caller's model, precision and
10101
+ inference backend. With `store`, only the exact selected executable URLs bypass
10102
+ it; model, tokenizer, configuration and external-data resources retain that
10103
+ store. Local mode is opt-in; default browser behavior remains unchanged.
10104
+
9993
10105
  Optional `store` is an existing SDK DBOPFS model or speech store exposing
9994
10106
  `fetchResource(input, options)`. It remains outside cloned Worker configuration.
9995
- Explicit activation first stores the complete selected `runtime.moduleUrl`
10107
+ Without `runtime.local`, explicit activation first stores the complete selected `runtime.moduleUrl`
9996
10108
  entry and materializes it as a JavaScript object URL without rewriting source.
9997
10109
  The configured original URL remains the resource selection for later loads.
9998
10110
  The selected loader also routes its actual model/configuration/tokenizer
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-os",
3
- "version": "0.88.1",
3
+ "version": "0.89.0",
4
4
  "description": "Arcane OS JavaScript SDK, project-local CLI, browser runtime, and repository-portable application packager.",
5
5
  "type": "module",
6
6
  "main": "./src/index.mjs",
@@ -129,7 +129,7 @@
129
129
  "scripts": {
130
130
  "test": "npm run test:unit && npm run test:functional && npm run test:integration && npm run test:regression",
131
131
  "test:release": "node ./bin/arcane-test.mjs test/npm-release.test.mjs",
132
- "test:unit": "node ./bin/arcane-test.mjs test/app-descriptor.test.mjs test/app-schema.test.mjs test/app-selection.test.mjs test/contracts.test.mjs test/conversation-closing-report.test.mjs test/doctor.test.mjs test/mail-credentials.test.mjs test/mail-outbox.test.mjs test/mail-public-api.test.mjs test/mail-send.test.mjs test/mail-transport.test.mjs test/native-windows-icon.test.mjs test/targets.test.mjs test/workspace-operation-lock.test.mjs",
132
+ "test:unit": "node ./bin/arcane-test.mjs test/app-descriptor.test.mjs test/app-schema.test.mjs test/app-selection.test.mjs test/contracts.test.mjs test/conversation-closing-report.test.mjs test/doctor.test.mjs test/mail-credentials.test.mjs test/mail-outbox.test.mjs test/mail-public-api.test.mjs test/mail-send.test.mjs test/mail-transport.test.mjs test/native-windows-icon.test.mjs test/risk-signal-analyzer.test.mjs test/targets.test.mjs test/workspace-operation-lock.test.mjs",
133
133
  "test:functional": "node ./bin/arcane-test.mjs test/ai-ollama-readiness.test.mjs test/core-ollama-lifecycle.test.mjs test/ai-request-model.test.mjs test/ai-request-retry.test.mjs test/ai-stream-cancellation.test.mjs test/browser-decisions.test.mjs test/browser-kokoro-complete-input.test.mjs test/browser-speech-providers.test.mjs test/browser-speech-artifacts.test.mjs test/browser-speech-resource-bridge.test.mjs test/browser-wasm-gpu-notice.test.mjs test/browser-wasm-download-resume.test.mjs test/chat-input.test.mjs test/chat-stream-speech.test.mjs test/chat-transcript-scroll.test.mjs test/chat-transient-retention.test.mjs test/cli.test.mjs test/continuous-voice-capture.test.mjs test/codex-app-server.test.mjs test/mcp-stdio-server.test.mjs test/core-classic-source.test.mjs test/core-client.test.mjs test/core-client-installation.test.mjs test/core-ai-installation.test.mjs test/core-llama-lifecycle.test.mjs test/core-development.test.mjs test/core-host.test.mjs test/core-shared-host.test.mjs test/core-model-assets.test.mjs test/core-native-services.test.mjs test/core-packaged-web.test.mjs test/core-runtime.test.mjs test/core-stdio.test.mjs test/dbopfs-committed-events.test.mjs test/dbopfs-document-library.test.mjs test/dbopfs-model-resources.test.mjs test/dbopfs-png.test.mjs test/dbopfs.test.mjs test/dev-server.test.mjs test/dev-pwa.test.mjs test/document-acquisition.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/execution-devices.test.mjs test/file-preview.test.mjs test/import-map.test.mjs test/local-image-editing.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/markdown-editor.test.mjs test/markdown-media.test.mjs test/markdown-source-map.test.mjs test/modal.test.mjs test/model-resource-bridge.test.mjs test/native-decisions.test.mjs test/native-onnx.test.mjs test/native-module-packaging.test.mjs test/native-module-resource-references.test.mjs test/packaging.test.mjs test/pwa-packaging.test.mjs test/pwa-client.test.mjs test/pwa-install.test.mjs test/pwa-worker.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/rendered-print.test.mjs test/runtime-api-behavior.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/speech-playback.test.mjs test/site.test.mjs test/theme-manager.test.mjs test/twin-cloud-images.test.mjs test/twin-cloud.test.mjs test/websocket-client-import-map.test.mjs test/websocket.test.mjs test/update-check.test.mjs test/user-explicit-updates.test.mjs",
134
134
  "test:integration": "node ./bin/arcane-test.mjs test/installed-package-runtime.test.mjs test/root-app-layout.test.mjs test/integrated-shared.test.mjs test/integrated-workspace.test.mjs test/mail-browser.test.mjs test/native-macos-provider.test.mjs test/native-plan.test.mjs test/native-portable-provider.test.mjs test/native-provider-loader.test.mjs test/npm-release.test.mjs test/release-bundle.test.mjs test/release-capability-smoke.test.mjs test/shared-payload-batch.test.mjs test/tarball.test.mjs test/browser-wasm-cpu.test.mjs test/wllama-webgpu-runtime.test.mjs",
135
135
  "test:regression": "node ./bin/arcane-test.mjs test/channel-workflows.test.mjs test/html-import-registration.test.mjs test/html-import-packaged-script.test.mjs test/logging-regression.test.mjs test/markdown-speech.test.mjs test/prepared-speech.test.mjs test/ai-audio-output.test.mjs test/native-provider-generation.test.mjs test/speech-queue-regression.test.mjs test/testing.test.mjs test/test-sets.test.mjs",
@@ -8,12 +8,8 @@ const DEFAULT_LEVELS=[
8
8
  {minimum:0,id:'low'},
9
9
  ];
10
10
 
11
- function normalizeText(value){
12
- return String(value??'').normalize('NFKC');
13
- }
14
-
15
11
  export function analyzeRiskSignals(input,{signals=[],levels=DEFAULT_LEVELS}={}){
16
- const text=normalizeText(input);
12
+ const text=String(input??'');
17
13
  const matches=[];
18
14
  let score=0;
19
15
 
@@ -139,11 +139,12 @@
139
139
  "window": {
140
140
  "type": "object",
141
141
  "additionalProperties": false,
142
- "description": "Initial native client dimensions in logical pixels at 96 DPI, and whether the user can resize the window. Omitted fields retain the host defaults.",
142
+ "description": "Initial normal client dimensions in logical pixels at 96 DPI, resizing behavior, and optional native window state. Omitted fields retain the host defaults.",
143
143
  "properties": {
144
144
  "width": { "type": "integer", "minimum": 1 },
145
145
  "height": { "type": "integer", "minimum": 1 },
146
- "resizable": { "type": "boolean" }
146
+ "resizable": { "type": "boolean" },
147
+ "state": { "enum": ["normal", "maximized", "fullscreen"] }
147
148
  }
148
149
  },
149
150
  "bundledApps": {
@@ -283,7 +284,9 @@
283
284
  "properties": {
284
285
  "id": { "enum": ["llama.cpp", "ollama", "onnx", "stable-diffusion.cpp"] },
285
286
  "version": { "type": "string" },
286
- "url": { "type": "string" }
287
+ "url": { "type": "string" },
288
+ "backend": { "type": "string", "description": "llama.cpp: auto, cpu or cuda. Image runtimes: auto, metal or cpu." },
289
+ "companionUrl": { "type": "string", "description": "Explicit CUDA runtime companion archive for a custom llama.cpp CUDA URL." }
287
290
  }
288
291
  },
289
292
  { "$ref": "#/$defs/whisperRuntime" }
@@ -295,6 +298,13 @@
295
298
  "properties": {
296
299
  "url": { "type": "string" },
297
300
  "model": { "type": "string" },
301
+ "alias": { "type": "string" },
302
+ "executionTarget": {
303
+ "oneOf": [
304
+ { "type": "null" },
305
+ { "type": "object", "required": ["deviceId"], "properties": { "deviceId": { "type": "string" } } }
306
+ ]
307
+ },
298
308
  "modelsDirectory": { "type": "string" },
299
309
  "args": { "type": "array", "items": { "type": "string" } }
300
310
  }
@@ -163,7 +163,9 @@
163
163
  "properties": {
164
164
  "id": { "enum": ["llama.cpp", "ollama", "onnx", "stable-diffusion.cpp"] },
165
165
  "version": { "type": "string" },
166
- "url": { "type": "string" }
166
+ "url": { "type": "string" },
167
+ "backend": { "type": "string", "description": "llama.cpp: auto, cpu or cuda. Image runtimes: auto, metal or cpu." },
168
+ "companionUrl": { "type": "string", "description": "Explicit CUDA runtime companion archive for a custom llama.cpp CUDA URL." }
167
169
  }
168
170
  },
169
171
  { "$ref": "#/$defs/whisperRuntime" }
@@ -175,6 +177,13 @@
175
177
  "properties": {
176
178
  "url": { "type": "string" },
177
179
  "model": { "type": "string" },
180
+ "alias": { "type": "string" },
181
+ "executionTarget": {
182
+ "oneOf": [
183
+ { "type": "null" },
184
+ { "type": "object", "required": ["deviceId"], "properties": { "deviceId": { "type": "string" } } }
185
+ ]
186
+ },
178
187
  "modelsDirectory": { "type": "string" },
179
188
  "args": { "type": "array", "items": { "type": "string" } }
180
189
  }