arcane-os 0.59.0 → 0.60.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.
@@ -3898,7 +3898,7 @@
3898
3898
  "summary": "Projects a Core client into the established application-facing Arcane namespace.",
3899
3899
  "availability": "Browser and native WebView JavaScript hosts with a Core client",
3900
3900
  "protocol": "arcane/1 compatibility facade",
3901
- "normalization": "Routes existing namespace methods through client.invoke while retaining operation-specific parameters, correlation, streaming callbacks, timeouts and cancellation"
3901
+ "normalization": "Routes namespace methods through client.invoke while retaining operation-specific parameters, correlation, streaming callbacks, timeouts and cancellation; window.setTheme(presentation,{signal}?) forwards the complete per-window backgroundColor/textColor record, with omitted fields unchanged and null reset, and returns the host's actual applied/unsupported result without changing system appearance"
3902
3902
  },
3903
3903
  {
3904
3904
  "id": "core-client:installCoreClient",
@@ -4052,7 +4052,7 @@
4052
4052
  "summary": "Assembles selected application services and browser content with the SDK-owned Windows x64 WebView2 and SEA host.",
4053
4053
  "availability": "Node for assembly; Windows x64 with WebView2 Runtime for execution",
4054
4054
  "protocol": "arcane-native-builder/1 windows-x64 provider",
4055
- "normalization": "Uses a selected hostDirectory or the exact installed SDK version's numeric release asset; preserves complete payloads; run cancellation closes stdin and waits for host-owned graceful shutdown"
4055
+ "normalization": "Uses a selected hostDirectory or the exact installed SDK version's numeric release asset; preserves complete payloads; native.icon PNG/ICO derives the copied executable and host.icon without an app compiler, while other formats retain assembly with native.icon.unsupported and executableIcon:false; the matching host loads the selected window/taskbar icon and handles window.setTheme with per-field applied/unsupported results; run cancellation closes stdin and waits for host-owned graceful shutdown"
4056
4056
  },
4057
4057
  {
4058
4058
  "id": "native-windows-provider:arcaneNativeBuilderProvider",
@@ -30,7 +30,7 @@
30
30
  "availability": "Browser + native bridge + TWiN Cloud",
31
31
  "protocol": "arcane-ai-browser-speech-configuration/1, AIProviderRuntime arcane-ai-provider/2 routes, globalThis.arcaneEvents, TWiN Cloud HTTPS, Arcane.ollama, Arcane.speech, Android WebView bridge",
32
32
  "normalization": "Complete mutable caller-owned browser speech authority, SDK-owned provider registration/replacement/disposal, explicit STT/TTS activation, normalized Whisper STT and Kokoro TTS execution with default capacities 1 and 4 respectively, explicit provider-neutral execution snapshots through status(role,{execution:true}), sticky readiness, canonical window.user readiness without compatibility-event object-identity admission or polling, exact ordered structural calls with required arguments.message, atomic nonblank all-ID tool-result sequencing, complete all-choice streaming/data validation, native Ollama structural adaptation, complete-response then all validated tool callbacks then completion ordering, observed async callbacks, Blob/File transcription, automatic repeated-formatting-mark removal from cloned outbound TTS input while caller and visible content stays exact, immediate exact-segment synthesis, per-call voice/speed capture, optional final-segment pause on the existing audio clock, optional per-call terminal playback completion, detached preparation with complete semantic DBOPFS audio reuse and same-owner pending request sharing, independent prepared playback without a model load for cached audio, ordered audio-clock scheduling, playable audio, active-generation TTS operation-failure routing, mute, and cancellation are normalized; provider/model/runtime/voice policy remains caller-owned. Both speech roles default execution.device to auto: webnn-npu when navigator.ml.createContext is exposed, then webgpu when navigator.gpu is exposed, then wasm for CPU execution. Failed backend loads clean up the pool before trying fresh Workers with the same prepared model and dtype; explicit devices never fall back. STT capacity only accepts 1; TTS accepts 1 through 4. Execution snapshots expose requestedDevice, selectedDevice, maxConcurrentRequests, and activeRequestCount for both roles; selectedDevice is null while unloaded and names the successful upstream session backend request when loaded. It does not prove every operation used the physical NPU: WebNN unsupported operations may use WASM, and compatibility depends on the browser, driver, hardware, and graph.",
33
- "surface": "prepareTTSPlayback(payload,signal) silently returns a real Blob or native-speech descriptor; native controls expose finished/released/state/error/pause/resume/stop, and actual release owns the playback lane. fetchTTS and durable prepareTTS report ARCANE_AI_TTS_AUDIO_EXPORT_UNAVAILABLE for native voices. Request-local model overrides remain exact and never mutate the configured model. Browser-speech protocol/event/error/reason constants; default `AI`; read-only `providerRuntime`, `browserSpeechConfiguration`, and `browserSpeechDescriptor`; explicit `providerRuntime.status(role,{execution:true})` snapshots; `streamTTS(text,end,options={})` with optional voice, speed, pauseAfterMs, and waitForPlayback; automatic speech-input cleanup with SDK-internal preparation metadata; `prepareTTS({parts,storage,identity,signal,onState})` returning ordered segments, state, ready, getAudio(index), and cancel(); `playPreparedTTS(prepared,{signal,onState})` returning state, error, finished, pause(), resume(), and stop() with one playback lane per AI and observational state/error callbacks; configure/dispose speech, route lifecycle, declaration-validated chat/stream requests with exact ordered calls; optional streamRequest toolText:{name,field} and onToolText(text,call,displayId) for decoded selected argument text with actual call identity, distinct from ordinary prose and terminal tool execution; synthesis/transcription and playback controls; initializes from current canonical user readiness, installs `window.ai`, and projects `ai-ready` plus active-generation `ai-tts-failure`."
33
+ "surface": "Native fetchTTS(payload,signal) and fetchSTT(audio,signal) forward caller cancellation separately from their complete Core speech payloads, normalize aborts to AbortError and suppress late results; actual engine interruption remains service-owned. prepareTTSPlayback(payload,signal) silently returns a real Blob or native-speech descriptor; native controls expose finished/released/state/error/pause/resume/stop, and actual release owns the playback lane. fetchTTS and durable prepareTTS report ARCANE_AI_TTS_AUDIO_EXPORT_UNAVAILABLE for native voices. Request-local model overrides remain exact and never mutate the configured model. Browser-speech protocol/event/error/reason constants; default `AI`; read-only `providerRuntime`, `browserSpeechConfiguration`, and `browserSpeechDescriptor`; explicit `providerRuntime.status(role,{execution:true})` snapshots; `streamTTS(text,end,options={})` with optional voice, speed, pauseAfterMs, and waitForPlayback; automatic speech-input cleanup with SDK-internal preparation metadata; `prepareTTS({parts,storage,identity,signal,onState})` returning ordered segments, state, ready, getAudio(index), and cancel(); `playPreparedTTS(prepared,{signal,onState})` returning state, error, finished, pause(), resume(), and stop() with one playback lane per AI and observational state/error callbacks; configure/dispose speech, route lifecycle, declaration-validated chat/stream requests with exact ordered calls; optional streamRequest toolText:{name,field} and onToolText(text,call,displayId) for decoded selected argument text with actual call identity, distinct from ordinary prose and terminal tool execution; synthesis/transcription and playback controls; initializes from current canonical user readiness, installs `window.ai`, and projects `ai-ready` plus active-generation `ai-tts-failure`."
34
34
  },
35
35
  {
36
36
  "file": "runtime/arcane/modules/AIModelSelectionController.js",
@@ -1364,7 +1364,7 @@
1364
1364
  "availability": "Browser/native hybrid",
1365
1365
  "protocol": "ThemeManager + host Arcane.events projected once through the per-realm globalThis.arcaneEvents authority",
1366
1366
  "normalization": "Theme state normalized; storage/native errors mixed.",
1367
- "surface": "`bootstrapArcaneTheme()`, `disposeArcaneThemeBootstrap()`, `arcaneThemeReady`, and default ready promise. Shared bootstrap replays an already-ready User and disposes both appearance and user-ready subscriptions; presentation cache is nonauthoritative. Its module graph does not guarantee restoration before first paint; use the classic ThemePresentation entry after app-id and before CSS."
1367
+ "surface": "`bootstrapArcaneTheme()`, `disposeArcaneThemeBootstrap()`, `arcaneThemeReady`, and default ready promise. Shared bootstrap replays an already-ready User. In native hosts it independently forwards computed --background/--text-color through Arcane.window.setTheme, observing shared theme events, root/body presentation attributes, stylesheets, device scheme and page restoration; browser CSS resolution retains alpha and converts modern colors to sRGB. Disposal releases appearance/user/theme subscriptions, native sampling observers and listeners, and pending window requests. Ordinary browsers remain silent. Presentation cache is nonauthoritative; use classic ThemePresentation after app-id and before CSS for early restoration."
1368
1368
  },
1369
1369
  {
1370
1370
  "file": "runtime/arcane/modules/ThemeManager.js",
@@ -0,0 +1,79 @@
1
+ # Local image edit inputs
2
+
3
+ The SDK input decoder prepares a PNG raster for the shared native image
4
+ runtime. Decoding does not load a model or perform inference. The runtime owns
5
+ model selection, supported editing operations, native calls and their complete
6
+ results. Applications retain the original image and decide whether to save a
7
+ newly generated result.
8
+
9
+ ## Decoder contract
10
+
11
+ `src/local-ai/image-editing.mjs` exports the internal worker function
12
+ `decodeImage({data, mediaType, signal})`.
13
+
14
+ | Field | Contract |
15
+ | --- | --- |
16
+ | `data` | Complete encoded PNG in a `Uint8Array`; a Node `Buffer` is also accepted. Only the supplied view is read. |
17
+ | `mediaType` | `image/png`, an empty string, or omitted. The PNG signature is read from the actual input. Other declared formats report unsupported input. |
18
+ | `signal` | Optional `AbortSignal` belonging to the image request. |
19
+
20
+ The promise returns `{width, height, channel, data}`. Dimensions come from the
21
+ source raster; `channel` is `3` for RGB or `4` for RGBA. Returned `data` is a
22
+ separate contiguous `Uint8Array` containing interleaved samples, with pixels
23
+ ordered left to right and rows ordered top to bottom. The native request owner
24
+ retains this allocation until the native operation actually completes,
25
+ including after a cancellation request.
26
+
27
+ Input decoding accepts static, non-interlaced, 8-bit RGB and RGBA PNGs, all
28
+ five PNG row filters, and image data spread across multiple `IDAT` chunks.
29
+ RGB transparent-color information is represented as RGBA. An optional suggested
30
+ palette on an RGB or RGBA image does not change its color type.
31
+
32
+ Indexed-color, grayscale, 16-bit, interlaced and animated PNGs currently report
33
+ unsupported input. JPEG and WebP are also unsupported by this decoder. The
34
+ decoder does not silently convert those formats or select one animation frame.
35
+
36
+ The original encoded image is copied for the operation and never modified or
37
+ detached. Decoding preserves stored color samples and straight alpha, including
38
+ RGB values underneath transparent pixels. It does not composite onto a chosen
39
+ background, rotate pixels from metadata, apply a color-profile conversion,
40
+ resize, crop or create a file. Metadata remains in the original image; the
41
+ native raster record contains pixels and dimensions only.
42
+
43
+ ## Execution and cancellation
44
+
45
+ Invoke the decoder inside the shared image runtime's existing worker.
46
+ Inflation uses asynchronous Node zlib. Row reconstruction yields between
47
+ scanlines so the worker can receive cancellation. An abort during inflation is
48
+ observed after that native operation settles; it does not claim instant
49
+ interruption. A cancelled decode returns no raster for inference.
50
+
51
+ `ARCANE_IMAGE_INPUT_UNSUPPORTED` describes an unavailable input format or
52
+ encoding. `ARCANE_IMAGE_DECODE_FAILED` describes unreadable PNG structure or
53
+ scanlines. Node zlib failures retain their complete original errors, and
54
+ cancellation retains the owning signal's reason or Node `AbortError`. A decode
55
+ failure never returns partial imagery or substitutes a different image.
56
+
57
+ ## Editing semantics at the native owner
58
+
59
+ Whole-image img2img uses an initial image, prompt and strength. Masked editing
60
+ adds a separate mask; instruction/reference editing uses a model that supports
61
+ reference conditioning. These are distinct operations and must be advertised
62
+ only when the selected model and native path implement them. Ordinary img2img
63
+ does not require LoRA training. The candidate engine documents this directly
64
+ with its base SD1.4 model in the
65
+ [tagged img2img example](https://github.com/leejet/stable-diffusion.cpp/blob/master-929-3f8527a/docs/sd.md#img2img-example).
66
+
67
+ Source dimensions are decoder output, not an implicit request to change the
68
+ generation dimensions. The model owner documents its actual canvas adaptation
69
+ and reports actual output dimensions. In the candidate engine, temporary
70
+ initial images use model preprocessing while caller images remain unchanged;
71
+ even `mode=none` does not suppress all later model adaptation. See the
72
+ [native preprocessing contract](https://github.com/leejet/stable-diffusion.cpp/blob/master-929-3f8527a/docs/image_preprocessing.md).
73
+
74
+ An RGB-only model such as the selected SD1.4 candidate consumes the stored RGB
75
+ and does not preserve alpha. The SDK must not silently choose a compositing
76
+ background or claim that passing RGBA preserves its displayed appearance.
77
+ Strength zero is also not an exact-copy operation: native img2img still uses
78
+ the model's encode, sampling and decode path. These model behaviors are
79
+ separate from the decoder preserving the original input.
@@ -0,0 +1,144 @@
1
+ # Native working files from stored model assets
2
+
3
+ The selected `0.60.0` package contains the model-assets helpers as internal
4
+ preparation. The public imports and Core registration shown below belong to
5
+ the pending local-image integration and are unavailable through `0.60.0`.
6
+ These examples document that integration's intended public contract.
7
+
8
+ `prepareCoreModelAssets()` streams complete browser `File` or `Blob` members
9
+ through the existing Core connection into native working files. DBOPFS keeps
10
+ the authoritative originals. The helper performs no model download and changes
11
+ neither stored content nor the model format.
12
+
13
+ Use complete members returned by `createDbopfsModelStore().ensure()` or files
14
+ read from the application's existing DBOPFS owner. The browser model store
15
+ already assembles persisted Range parts into one logical Blob per upstream
16
+ member. Preserve that member order and the original relative filenames,
17
+ including companion files required by a model.
18
+
19
+ ## Browser preparation
20
+
21
+ ```javascript
22
+ import {prepareCoreModelAssets} from 'arcane-os/ai/core-model-assets';
23
+ import {createCoreImageRuntime} from 'arcane-os/ai/core-image';
24
+
25
+ const stored = await modelStore.ensure(selectedSource, {signal});
26
+ const projection = await prepareCoreModelAssets({
27
+ client,
28
+ workingDirectory: selectedWorkingDirectory,
29
+ members: [{path: 'sd-v1-4.ckpt', file: stored.files[0]}],
30
+ signal,
31
+ onProgress: renderPreparationProgress
32
+ });
33
+ const image = createCoreImageRuntime({client});
34
+ try {
35
+ await image.load({
36
+ model: 'sd14',
37
+ assetProjectionId: projection.id,
38
+ resourcePaths: {model: 'sd-v1-4.ckpt'},
39
+ signal
40
+ });
41
+ } finally {
42
+ // Native loading takes its own retain handle before using these files.
43
+ await projection.release();
44
+ }
45
+ const result = await image.generate({
46
+ model: 'sd14',
47
+ prompt: 'A dignified raccoon who has been put in charge of the moon.',
48
+ signal
49
+ });
50
+ // Display or save the complete returned image through the application owner.
51
+ await image.unload();
52
+ ```
53
+
54
+ This example assumes that the application selected the `sd14` model and its
55
+ complete checkpoint source. Model choice, download approval, prompts, output
56
+ storage and the selected working directory remain application-owned.
57
+
58
+ `prepareCoreModelAssets({client,workingDirectory,members,signal,onProgress})`
59
+ requires an available Core connection exposing the model-assets service.
60
+ `client` defaults to the installed Core client. Every member is
61
+ `{path,file}`, where `path` is its relative filename or companion-file path and
62
+ `file` is the complete stored Blob or File. Relative working-directory paths
63
+ resolve from the native service's `appRoot`; an application may explicitly
64
+ select an absolute working directory.
65
+
66
+ The result contains `id`, `directory`, ordered
67
+ `members: [{path,nativePath}]`, and an idempotent asynchronous `release()`.
68
+ The operation creates a unique child directory under the selected working
69
+ directory. Member paths identify files inside that child directory. Original
70
+ DBOPFS files remain untouched.
71
+
72
+ Each incoming Blob stream chunk is encoded only for the existing JSON Core
73
+ transport. The helper waits for the corresponding native write before reading
74
+ the next chunk of that member. Independent members transfer concurrently;
75
+ the complete member set is returned only after every write and file close
76
+ finishes. There is no complete-model transport buffer or application content
77
+ limit. Progress reports actual preparation phases and member paths.
78
+
79
+ Cancellation stops active readers and requests. Failure joins the participating
80
+ transfers and requests native cleanup; that cleanup joins actual file writes
81
+ before removing the projection. Cleanup uses its own uncancelled operation so
82
+ an already-aborted preparation signal cannot skip it. Original failures and
83
+ cleanup failures remain observable.
84
+
85
+ ## Native ownership
86
+
87
+ ```javascript
88
+ import {createModelAssetService} from 'arcane-os/core/model-assets';
89
+
90
+ const modelAssets = createModelAssetService({appRoot});
91
+ // Register this same service with Core and pass it to the native engine owner.
92
+ const use = modelAssets.retain(projectionId);
93
+ try {
94
+ // Load and use the complete files from use.members.
95
+ await ownNativeModelLifetime(use.members);
96
+ } finally {
97
+ // ownNativeModelLifetime must join actual model release before returning.
98
+ await use.release();
99
+ }
100
+ ```
101
+
102
+ `createModelAssetService({appRoot})` returns a Core service with `current()`,
103
+ `retain(id)` and `dispose()`. `retain()` accepts only a completed projection
104
+ and returns `{id,directory,members,release}`. A native engine takes this handle
105
+ before loading and releases it after actual unload, failed-load cleanup or
106
+ worker exit. A rejected inference/load promise alone does not establish native
107
+ release. Multiple contexts can retain one prepared set, and repeated inference
108
+ on a retained context reuses its files.
109
+
110
+ The browser's `projection.release()` relinquishes preparation ownership. It
111
+ does not delete files retained by a native engine. Deletion follows the final
112
+ native release and removes only that operation's working directory. Core closes
113
+ independent services concurrently, so the model-assets service waits for all
114
+ native retain handles during disposal instead of assuming service order.
115
+ Owners must release their handles after joining their actual engine lifetime.
116
+
117
+ Closing a browser accessor does not by itself establish native unload.
118
+ Explicitly release unused prepared projections. Core disposal also releases
119
+ preparation ownership and cleans up after retained engine uses end.
120
+
121
+ `current()` returns `{closing,projections}`. Each projection reports its `id`,
122
+ `directory`, `state`, ordered `members`, `preparationOwned`, number of native
123
+ `uses`, and `error`. Core emits `modelAssets.state` for lifecycle changes.
124
+
125
+ ## Core transport operations
126
+
127
+ | Method | Parameters | Result |
128
+ | --- | --- | --- |
129
+ | `modelAssets.open` | `{id,workingDirectory,members:[{path}]}` | Preparing projection and native member paths |
130
+ | `modelAssets.write` | `{id,memberIndex,contentBase64}` | `{id,memberIndex,written:true}` after the native write |
131
+ | `modelAssets.complete` | `{id}` | Ready projection after all files close |
132
+ | `modelAssets.release` | `{id}` | Released preparation ownership; native uses may retain the files |
133
+ | `modelAssets.status` | `{}` | Current projection lifecycle records |
134
+
135
+ The browser helper owns this transport sequence. Correlation IDs identify
136
+ operations; they are unrelated to content identity. Original model files remain
137
+ separate and complete. A retry creates a new working projection from the stored
138
+ assets; it does not redownload them or replace the authoritative DBOPFS record.
139
+
140
+ The implementation uses browser streams, the existing portable Core JSON
141
+ transport and Node filesystem operations. Native paths and cleanup follow the
142
+ host's Windows, Linux or macOS filesystem behavior. Android requires its host's
143
+ Core/filesystem adaptation. These are source-level platform contracts, not a
144
+ claim of execution on every target.
@@ -387,8 +387,12 @@ existing `audioFormat` when the catalog does not declare response formats. When
387
387
  the selected model declares `speech.responseFormats`, that setting is used only when supported; if
388
388
  the setting is the instance's `opus` default and the model rejects it, the catalog's
389
389
  `speech.defaultResponseFormat` is used, while any other unsupported setting is
390
- rejected. It propagates the caller-owned signal and returns a playable `Blob`;
391
- it does not independently choose a provider, cloud fallback, model, runtime, or
390
+ rejected. It propagates the caller-owned signal and returns a playable `Blob`.
391
+ The native `LOCAL_SPEACH` route forwards that signal separately from its
392
+ synthesis payload to `Arcane.speech.synthesize(request, {signal})`; Core aborts
393
+ are normalized to `AbortError` with `ARCANE_AI_REQUEST_ABORTED`. Actual engine
394
+ interruption belongs to the registered service. It does not independently
395
+ choose a provider, cloud fallback, model, runtime, or
392
396
  voice policy for the application. Every call removes repeated same formatting
393
397
  marks from a cloned outbound input before delegation; the caller's payload stays
394
398
  unchanged. The third `preparation` argument is reserved for SDK-internal
@@ -529,8 +533,11 @@ operation boundary, generation, and stable reason. Muting, explicit
529
533
  cancellation, permission waiting, and superseded generations do not emit a
530
534
  failure. The operation event does not rewrite provider readiness; the consuming
531
535
  Chat/Speech surface owns its visible mute and recovery state.
532
- `fetchSTT(audioFile,signal)` propagates the caller-owned signal;
533
- provider routes accept a `Blob` or `File` directly and leave media decoding,
536
+ `fetchSTT(audioFile,signal)` propagates the caller-owned signal, including the
537
+ native `Arcane.speech.transcribe(request, {signal})` route. The native signal
538
+ remains separate from the complete audio request; Core aborts are normalized
539
+ to `AbortError` with `ARCANE_AI_REQUEST_ABORTED`.
540
+ Provider routes accept a `Blob` or `File` directly and leave media decoding,
534
541
  PCM normalization, and WAV construction to the selected shared provider;
535
542
  delivery suppression is guaranteed after abort, while underlying provider-stop
536
543
  claims remain limited to that provider's cancellation contract.
@@ -4168,7 +4175,9 @@ creating a profile or migrating saved data.
4168
4175
  Exact exports: `arcaneThemeReady`, `bootstrapArcaneTheme`, `default`, and
4169
4176
  `disposeArcaneThemeBootstrap`.
4170
4177
 
4171
- `disposeArcaneThemeBootstrap()` removes both bootstrap-owned subscriptions.
4178
+ `disposeArcaneThemeBootstrap()` removes bootstrap-owned subscriptions,
4179
+ native-window theme observers and listeners, and cancels its pending window
4180
+ request.
4172
4181
  The cache is a presentation hint, not the authority for preferences or user
4173
4182
  data. Preference loading and User readiness independently reconcile it; cache
4174
4183
  failures are logged without blocking the page.
@@ -4178,6 +4187,29 @@ does not establish restoration before the first paint. Use the classic
4178
4187
  [ThemePresentation head entry](#themepresentationjs) before CSS for that early
4179
4188
  restoration. Neither entry imports User or starts its storage lifecycle.
4180
4189
 
4190
+ When a native host exposes `Arcane.window.setTheme`, the shared bootstrap
4191
+ samples the app body's inherited `--background` and `--text-color`. It resolves
4192
+ CSS variables, named colors, HSL and other browser-supported color forms through
4193
+ computed style. Modern color spaces use the browser's sRGB canvas conversion;
4194
+ the resolved alpha is retained separately, including translucency close to one.
4195
+ Authored styles remain unchanged. Missing semantic properties are omitted.
4196
+
4197
+ One listener on the shared `arcane-theme-change` owner, root/body presentation
4198
+ attribute observers, stylesheet-load events and device-color-scheme changes
4199
+ schedule samples. Identical channel values do not issue another request.
4200
+ Initial sampling and preference/profile reconciliation run independently of
4201
+ rendering and native completion. Page hide cancels the pending renderer wait;
4202
+ page restoration samples again. Print presentation is excluded. The host keeps
4203
+ its last accepted colors across navigation until the next document changes
4204
+ them. No additional theme bus, polling, storage or system-appearance mutation is
4205
+ introduced by this forwarding path.
4206
+
4207
+ Ordinary browsers and facades without the window method install no native
4208
+ sampler. An older host's unavailable-method response is recorded once in
4209
+ developer diagnostics and stops that sampler; genuine bridge failures retain
4210
+ their complete diagnostics. See the [current-window contract](core-client.md#current-window-theme)
4211
+ for per-field results, cancellation and actual adapter availability.
4212
+
4181
4213
  ### Availability and normalization
4182
4214
 
4183
4215
  **Browser/native hybrid.** Theme state normalized; storage/native errors mixed. Transport: ThemeManager + Arcane.events. [Deep protocol details](protocols.md).
@@ -4563,6 +4563,12 @@ The object includes `importMap(options)`, which merges defaults with explicit
4563
4563
  call options and refreshes every directly navigable descriptor-selected browser
4564
4564
  document for one selected app. The equivalent generic route is
4565
4565
  `execute('import-map', options)`.
4566
+ For a standalone root app with `pwa.enabled:false`, ordinary refresh removes
4567
+ marked SDK-generated PWA references from selected documents. An explicit
4568
+ `importMap({retireGeneratedPwa:true})` also retires the four standard root PWA
4569
+ outputs and matching older manifest references after the application owner
4570
+ confirms they are generated. See [disabled-PWA retirement](pwa.md#disable-source-pwa-generation-and-retire-generated-output)
4571
+ for the required source-selection adjustment and preserved content.
4566
4572
  It also includes `upgrade(options)`, which performs the explicit installed-SDK
4567
4573
  consumer upgrade described by `upgradeApplication()`, and
4568
4574
  `updateCheck(options)`, which invokes `checkSdkUpdate()` once. Constructing the
@@ -4685,6 +4691,25 @@ documents through sequential writes and has no supported dry-run or
4685
4691
  all-file transaction. An error or cancellation can leave completed writes in
4686
4692
  place; rerun the operation after resolving the cause.
4687
4693
 
4694
+ For a standalone `appsRoot:'.'` app with `pwa.enabled:false`, ordinary refresh
4695
+ removes active generated registration scripts and matching manifest relationships
4696
+ marked `data-arcane-manifest`. Unmarked references and existing PWA files remain.
4697
+ Set `retireGeneratedPwa:true` only after confirming generated ownership of the
4698
+ matching root manifest references and all four standard outputs:
4699
+ `arcane.webmanifest`, `arcane-offline.json`, `arcane-sw.js` and `arcane-pwa.mjs`.
4700
+ Remove those generated outputs from required `package.include` entries first,
4701
+ and confirm that unselected documents no longer need them. The operation writes
4702
+ selected reference changes before deleting these files; its
4703
+ `import-map.root-files.completed` event reports actual removed paths in
4704
+ `retiredPwa`. Repeated retirement accepts already-absent output.
4705
+
4706
+ An omitted PWA record selects no retirement; an enabled record keeps normal
4707
+ generation. The option belongs only to this explicit import-map API route.
4708
+ Ordinary development refresh does not forward file-retirement authority, and
4709
+ there is no new CLI flag. Other files, unselected/inactive HTML, authored content
4710
+ and browser registrations, caches and saved data keep their existing ownership.
4711
+ See the complete [source PWA contract](pwa.md#disable-source-pwa-generation-and-retire-generated-output).
4712
+
4688
4713
  The exact command `'upgrade'` dispatches `upgradeApplication(options)`. It is
4689
4714
  external-workspace-only and runs that application's ordinary `npm upgrade`
4690
4715
  command. It does not independently reconcile the installed SDK projection,
@@ -6899,6 +6924,18 @@ Import it from `arcane-os/core/client`. The result includes `runtime`, `events`,
6899
6924
  `Error` and the existing `ai`, `environment`, `mail`, `speech`, `localAI`,
6900
6925
  `ollama`, application, platform, storage and other host namespaces.
6901
6926
 
6927
+ `facade.speech.synthesize(request, {signal})` and
6928
+ `facade.speech.transcribe(request, {signal})` accept an optional `AbortSignal`
6929
+ through the same correlated request lifetime. Each complete request and existing
6930
+ 180,000 ms timeout remain unchanged. A pre-aborted signal sends no speech
6931
+ request; an in-flight abort emits that request's `request.cancel`, rejects with
6932
+ `ARCANE_REQUEST_ABORTED` and leaves unrelated requests active. Late responses
6933
+ cannot settle the cancelled request. Actual native synthesis or transcription
6934
+ interruption belongs to the registered service and engine; this facade supplies
6935
+ no engine. The native routes of `AI.fetchTTS(payload, signal)` and
6936
+ `AI.fetchSTT(audio, signal)` forward their signals through these calls and
6937
+ normalize cancellation to `AbortError` with `ARCANE_AI_REQUEST_ABORTED`.
6938
+
6902
6939
  ### Availability and normalization
6903
6940
 
6904
6941
  **Browser and native WebView JavaScript hosts with a Core client.** Creating the
@@ -7560,8 +7597,9 @@ import createDiarizationService from 'arcane-os/core/diarization';
7560
7597
 
7561
7598
  ### Overview
7562
7599
 
7563
- Reads only the complete JSON object explicitly selected by
7564
- `--arcane-launch-config <path>`; it does not search for application configuration.
7600
+ Reads the complete JSON object explicitly selected by
7601
+ `--arcane-launch-config <path>`, with an optional separately supplied native host
7602
+ state-directory default. It does not search for application configuration.
7565
7603
 
7566
7604
  ### Signature and result
7567
7605
 
@@ -7569,11 +7607,15 @@ Reads only the complete JSON object explicitly selected by
7569
7607
  async readCoreLaunchContext({argv=process.argv.slice(2)}={})
7570
7608
  ```
7571
7609
 
7572
- Import it from `arcane-os/core/host`. The promise resolves to `{}` when the flag
7573
- is absent, or the complete parsed object when present. A missing flag value,
7574
- unreadable file, malformed JSON or non-object value rejects. Relative paths use
7575
- the process working directory. The reader does not rewrite content or mutate
7576
- the environment.
7610
+ Import it from `arcane-os/core/host`. `--arcane-host-state-root <directory>`
7611
+ supplies a `stateRoot` default; every field from the explicit launch JSON object
7612
+ then takes precedence unchanged, including a relative, null or other explicitly
7613
+ present `stateRoot`. With neither argument, the promise resolves to `{}`.
7614
+ A missing argument value, unreadable launch file, malformed JSON or non-object
7615
+ value rejects. Relative launch-file paths use the process working directory.
7616
+ The reader does not choose, resolve or validate the state directory, rewrite
7617
+ content, discover or migrate stored data, or mutate the environment. An
7618
+ application-selected `preferencesFile` remains a separate unchanged field.
7577
7619
 
7578
7620
  ```javascript
7579
7621
  import {readCoreLaunchContext} from 'arcane-os/core/host';
@@ -7584,7 +7626,10 @@ const launchContext = await readCoreLaunchContext();
7584
7626
  The generated entry supplies artifact-derived `appRoot`, then applies the whole
7585
7627
  explicit context and passes the same object as every service factory's second
7586
7628
  argument. Authored service options remain the first argument. Workspace/state
7587
- locations and additional fields belong to the launcher/application. See
7629
+ locations and additional fields belong to the launcher/application. Windows and
7630
+ Mac launchers forward their actual host-selected state directory through the
7631
+ separate argument; other composing hosts may use the same seam. This JavaScript
7632
+ contract does not establish a compiled host or matching release archive. See
7588
7633
  [launch-time locations](core-native-packaging.md#launch-time-locations).
7589
7634
 
7590
7635
  ## createCoreLocalAIProvider()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-os",
3
- "version": "0.59.0",
3
+ "version": "0.60.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",
@@ -107,8 +107,8 @@
107
107
  "scripts": {
108
108
  "test": "npm run test:unit && npm run test:functional && npm run test:integration && npm run test:regression",
109
109
  "test:release": "node ./bin/arcane-test.mjs test/npm-release.test.mjs",
110
- "test:unit": "node ./bin/arcane-test.mjs test/app-descriptor.test.mjs test/app-schema.test.mjs test/app-selection.test.mjs test/contracts.test.mjs test/conversation-closing-report.test.mjs test/doctor.test.mjs test/mail-credentials.test.mjs test/mail-outbox.test.mjs test/mail-public-api.test.mjs test/mail-send.test.mjs test/mail-transport.test.mjs test/targets.test.mjs test/workspace-operation-lock.test.mjs",
111
- "test:functional": "node ./bin/arcane-test.mjs test/ai-request-model.test.mjs test/ai-request-retry.test.mjs test/ai-stream-cancellation.test.mjs test/browser-decisions.test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-gpu-notice.test.mjs test/browser-wasm-download-resume.test.mjs test/chat-input.test.mjs test/chat-stream-speech.test.mjs test/chat-transcript-scroll.test.mjs test/chat-transient-retention.test.mjs test/cli.test.mjs test/continuous-voice-capture.test.mjs test/core-classic-source.test.mjs test/core-client.test.mjs test/core-host.test.mjs test/core-packaged-web.test.mjs test/core-runtime.test.mjs test/core-stdio.test.mjs test/dbopfs-document-library.test.mjs test/dbopfs-png.test.mjs test/dbopfs.test.mjs test/dev-server.test.mjs test/dev-pwa.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/file-preview.test.mjs test/import-map.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/markdown-editor.test.mjs test/markdown-media.test.mjs test/markdown-source-map.test.mjs test/modal.test.mjs test/native-module-packaging.test.mjs test/native-module-resource-references.test.mjs test/packaging.test.mjs test/pwa-packaging.test.mjs test/pwa-client.test.mjs test/pwa-install.test.mjs test/pwa-worker.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/rendered-print.test.mjs test/runtime-api-behavior.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/speech-playback.test.mjs test/site.test.mjs test/theme-manager.test.mjs test/twin-cloud-images.test.mjs test/twin-cloud.test.mjs test/websocket-client-import-map.test.mjs test/websocket.test.mjs test/update-check.test.mjs test/user-explicit-updates.test.mjs",
110
+ "test:unit": "node ./bin/arcane-test.mjs test/app-descriptor.test.mjs test/app-schema.test.mjs test/app-selection.test.mjs test/contracts.test.mjs test/conversation-closing-report.test.mjs test/doctor.test.mjs test/mail-credentials.test.mjs test/mail-outbox.test.mjs test/mail-public-api.test.mjs test/mail-send.test.mjs test/mail-transport.test.mjs test/native-windows-icon.test.mjs test/targets.test.mjs test/workspace-operation-lock.test.mjs",
111
+ "test:functional": "node ./bin/arcane-test.mjs test/ai-request-model.test.mjs test/ai-request-retry.test.mjs test/ai-stream-cancellation.test.mjs test/browser-decisions.test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-gpu-notice.test.mjs test/browser-wasm-download-resume.test.mjs test/chat-input.test.mjs test/chat-stream-speech.test.mjs test/chat-transcript-scroll.test.mjs test/chat-transient-retention.test.mjs test/cli.test.mjs test/continuous-voice-capture.test.mjs test/core-classic-source.test.mjs test/core-client.test.mjs test/core-host.test.mjs test/core-packaged-web.test.mjs test/core-runtime.test.mjs test/core-stdio.test.mjs test/dbopfs-document-library.test.mjs test/dbopfs-png.test.mjs test/dbopfs.test.mjs test/dev-server.test.mjs test/dev-pwa.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/file-preview.test.mjs test/import-map.test.mjs test/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/native-module-packaging.test.mjs test/native-module-resource-references.test.mjs test/packaging.test.mjs test/pwa-packaging.test.mjs test/pwa-client.test.mjs test/pwa-install.test.mjs test/pwa-worker.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/rendered-print.test.mjs test/runtime-api-behavior.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/speech-playback.test.mjs test/site.test.mjs test/theme-manager.test.mjs test/twin-cloud-images.test.mjs test/twin-cloud.test.mjs test/websocket-client-import-map.test.mjs test/websocket.test.mjs test/update-check.test.mjs test/user-explicit-updates.test.mjs",
112
112
  "test:integration": "node ./bin/arcane-test.mjs test/installed-package-runtime.test.mjs test/root-app-layout.test.mjs test/integrated-shared.test.mjs test/integrated-workspace.test.mjs test/mail-browser.test.mjs test/native-macos-provider.test.mjs test/native-plan.test.mjs test/native-portable-provider.test.mjs test/native-provider-loader.test.mjs test/npm-release.test.mjs test/release-bundle.test.mjs test/release-capability-smoke.test.mjs test/shared-payload-batch.test.mjs test/tarball.test.mjs test/browser-wasm-cpu.test.mjs test/wllama-webgpu-runtime.test.mjs",
113
113
  "test:regression": "node ./bin/arcane-test.mjs test/channel-workflows.test.mjs test/html-import-registration.test.mjs test/html-import-packaged-script.test.mjs test/logging-regression.test.mjs test/markdown-speech.test.mjs test/prepared-speech.test.mjs test/native-provider-generation.test.mjs test/speech-queue-regression.test.mjs test/testing.test.mjs test/test-sets.test.mjs",
114
114
  "check": "node tools/check-source.mjs && npm test",
@@ -4084,11 +4084,19 @@ class AI {
4084
4084
  if(signal?.aborted){
4085
4085
  throw normalizeAIRequestAbort(signal.reason);
4086
4086
  }
4087
- const response=await nativeSpeech.transcribe({
4088
- audioBase64:this.#arrayBufferToBase64(audioBytes),
4089
- mimeType,
4090
- model
4091
- });
4087
+ let response;
4088
+ try{
4089
+ response=await nativeSpeech.transcribe({
4090
+ audioBase64:this.#arrayBufferToBase64(audioBytes),
4091
+ mimeType,
4092
+ model
4093
+ },{signal});
4094
+ }catch(error){
4095
+ if(isAIRequestAbort(error,signal)){
4096
+ throw normalizeAIRequestAbort(error);
4097
+ }
4098
+ throw error;
4099
+ }
4092
4100
  if(signal?.aborted){
4093
4101
  throw normalizeAIRequestAbort(signal.reason);
4094
4102
  }
@@ -4138,13 +4146,21 @@ class AI {
4138
4146
  const speed=is.finite(payload.speed)?payload.speed:this.voiceSpeed;
4139
4147
  const nativeSpeech=this.#nativeSpeech(this.ttsService,'tts');
4140
4148
  if(nativeSpeech){
4141
- const response=await nativeSpeech.synthesize({
4142
- model,
4143
- voice,
4144
- input,
4145
- responseFormat,
4146
- speed
4147
- });
4149
+ let response;
4150
+ try{
4151
+ response=await nativeSpeech.synthesize({
4152
+ model,
4153
+ voice,
4154
+ input,
4155
+ responseFormat,
4156
+ speed
4157
+ },{signal});
4158
+ }catch(error){
4159
+ if(isAIRequestAbort(error,signal)){
4160
+ throw normalizeAIRequestAbort(error);
4161
+ }
4162
+ throw error;
4163
+ }
4148
4164
  if(signal?.aborted){
4149
4165
  throw normalizeAIRequestAbort(signal.reason);
4150
4166
  }