arcane-os 0.60.0 → 0.62.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.
@@ -0,0 +1,267 @@
1
+ # Local image generation through Core
2
+
3
+ The SDK's local image service runs selected stable-diffusion.cpp models in a
4
+ retained native context. The browser uses Core for model lifecycle and complete
5
+ PNG results. Applications own image prompts, style choices, character identity,
6
+ associations and saved results.
7
+
8
+ Runtime installation, model asset preparation, model loading and image
9
+ generation are separate operations. The service starts promptly and retains
10
+ runtime preparation in the background. `image.status` remains callable during
11
+ preparation; rendering and unrelated Core services continue independently.
12
+
13
+ ## Selection and model assets
14
+
15
+ Select the runtime in `arcane-app.json` under `native.localAI`, or in the
16
+ corresponding package projection's `localAI` record:
17
+
18
+ ```json
19
+ {
20
+ "runtimes": [
21
+ {
22
+ "id": "stable-diffusion.cpp",
23
+ "version": "master-929-3f8527a",
24
+ "backend": "auto",
25
+ "models": ["sd14"]
26
+ }
27
+ ]
28
+ }
29
+ ```
30
+
31
+ `sd14` selects the Stable Diffusion 1.4 definition and its official
32
+ `sd-v1-4.ckpt` resource. A model definition contains `id`, `name`, `family`,
33
+ `resources`, `context`, `defaults` and `operations`. Selection supplies the
34
+ model's resource metadata; runtime installation does not independently download
35
+ or bundle model files. The shared model asset owner prepares selected browser
36
+ assets and supplies a Core working projection for native path-based loading.
37
+
38
+ The first published distribution path selects CPU on Windows and Linux.
39
+ On macOS, `auto` selects the same upstream universal runtime's built-in Metal
40
+ backend, with CPU fallback; explicit `cpu` remains available. A caller-supplied
41
+ runtime archive with `backend: 'auto'` uses its available accelerated device
42
+ with CPU fallback. Built-in Windows CUDA distribution preparation is a separate
43
+ pending addition. Actual backend/device availability and failures
44
+ come from the runtime, separately from hardware metadata or an installed archive.
45
+ Cancellation, invalid model input and inference failures retain their actual
46
+ errors. Model loading has no native cancellation handle before its constructor
47
+ returns; cancellation joins that call and releases its returned context before
48
+ the operation settles.
49
+
50
+ The complete prepared projection has an `id`, a `directory`, a `members` list
51
+ and `release()`. `resourcePaths` maps native model resource roles to exact
52
+ projection member paths. For the selected checkpoint, the role is `model`.
53
+ The member name must match the preparation result. See
54
+ [Model assets through Core](model-assets.md) for the shared preparation
55
+ lifecycle. Core acquires its own
56
+ retain before loading. The caller can release its preparation ownership after
57
+ successful `load()` acknowledgement: Core retains the files while its native
58
+ context needs them. Release caller ownership when loading fails too; native
59
+ cleanup keeps its own retain through actual completion. A later
60
+ `generate({model: 'sd14', ...})` reuses that prepared selection. Replacing or
61
+ unloading the context releases displaced projections
62
+ after actual native operations settle. Core shutdown joins owned operations
63
+ before releasing retained model files.
64
+
65
+ `model` also accepts a complete prepared model descriptor. Native callers can
66
+ supply actual resource paths directly. The browser projection arguments supply
67
+ the native paths through the shared asset service and preserve the remaining
68
+ descriptor fields. The image service creates no second model downloader or
69
+ durable model store.
70
+
71
+ ## Browser accessor
72
+
73
+ ```js
74
+ import {createCoreImageRuntime} from 'arcane-os/ai/core-image';
75
+ import {prepareCoreModelAssets} from 'arcane-os/ai/core-model-assets';
76
+ import {createBrowserModelSource, createDbopfsModelStore} from 'arcane-os/ai/browser-wasm';
77
+
78
+ const page = new AbortController();
79
+ window.addEventListener(
80
+ 'pagehide',
81
+ function detachImagePage() {
82
+ page.abort();
83
+ },
84
+ {once: true}
85
+ );
86
+
87
+ const images = createCoreImageRuntime(
88
+ {signal: page.signal}
89
+ );
90
+
91
+ images.subscribe(
92
+ function showImageStatus(snapshot) {
93
+ statusElement.textContent = snapshot.status ?? snapshot.state;
94
+ }
95
+ );
96
+
97
+ const selected = (await images.inspect()).models.find(
98
+ function selectedCheckpoint(model) {
99
+ return model.id === 'sd14';
100
+ }
101
+ );
102
+ const resource = selected.resources.model;
103
+ const source = createBrowserModelSource(
104
+ {
105
+ id: selected.id,
106
+ files: [
107
+ {name: resource.filename, url: resource.url}
108
+ ]
109
+ }
110
+ );
111
+ const store = createDbopfsModelStore(
112
+ {dbopfs, downloadConcurrency: 4}
113
+ );
114
+ const stored = await store.ensure(
115
+ source,
116
+ {signal: page.signal, offline: false}
117
+ );
118
+ const projection = await prepareCoreModelAssets(
119
+ {
120
+ workingDirectory: '.arcane/model-working',
121
+ members: source.files.map(
122
+ function preparedCheckpoint(member, index) {
123
+ return {path: member.name, file: stored.files[index]};
124
+ }
125
+ ),
126
+ signal: page.signal
127
+ }
128
+ );
129
+
130
+ try {
131
+ await images.load(
132
+ {
133
+ model: 'sd14',
134
+ assetProjectionId: projection.id,
135
+ resourcePaths: {
136
+ model: 'sd-v1-4.ckpt'
137
+ },
138
+ signal: page.signal
139
+ }
140
+ );
141
+ } finally {
142
+ await projection.release();
143
+ }
144
+
145
+ const result = await images.generate(
146
+ {
147
+ model: 'sd14',
148
+ prompt: 'Portrait of a dignified raccoon astronaut holding a tiny moon cactus.',
149
+ signal: page.signal,
150
+ onProgress(progress) {
151
+ console.log(progress);
152
+ }
153
+ }
154
+ );
155
+
156
+ for (const image of result.images) {
157
+ const url = URL.createObjectURL(image.blob);
158
+ const preview = new Image();
159
+ preview.alt = 'Generated raccoon astronaut portrait';
160
+ function releasePreviewURL() {
161
+ URL.revokeObjectURL(url);
162
+ }
163
+ preview.addEventListener(
164
+ 'load',
165
+ releasePreviewURL,
166
+ {once: true}
167
+ );
168
+ preview.addEventListener(
169
+ 'error',
170
+ releasePreviewURL,
171
+ {once: true}
172
+ );
173
+ preview.src = url;
174
+ imageContainer.append(preview);
175
+ }
176
+ ```
177
+
178
+ The example uses the application's existing `dbopfs` instance and existing
179
+ `statusElement` and `imageContainer` elements. The published model store accepts
180
+ the selected checkpoint as an ordinary resource: `ensure()` returns complete
181
+ ordered `Blob` or `File` members after its resumable download. Range support
182
+ allows concurrent transfer within a member; those transfer parts remain the
183
+ store's concern. Use `offline: true` to require an already complete stored model.
184
+ The store does not select or run the image engine. In source development,
185
+ load the development Core bootstrap described
186
+ in [Local AI through Core](local-ai.md#development) before constructing the
187
+ accessor. Native hosts install their Core client through the existing host path.
188
+ An ordinary browser without Core reports local image generation as unavailable.
189
+
190
+ | Member | Contract |
191
+ |---|---|
192
+ | `createCoreImageRuntime({client?, signal?, onEvent?})` | Uses the installed Core client by default, subscribes to lifecycle events and asynchronously reads one initial status snapshot. It returns immediately. |
193
+ | `load({model, context?, assetProjectionId?, resourcePaths?, signal?})` | Loads the selected model and returns authoritative service state after native completion. `context` supplies native context options. |
194
+ | `generate({model, prompt, parameters?, assetProjectionId?, resourcePaths?, signal?, onProgress?})` | Returns the complete result with `images: [{blob, mediaType, width, height}]`. Additional runtime result metadata remains present. |
195
+ | `unload({signal?})` | Explicitly unloads the shared selected native context and returns its resulting state. |
196
+ | `inspect({signal?})` | Reads current Core status without waiting for model or runtime preparation. |
197
+ | `current()` | Synchronously returns the retained lifecycle snapshot and this accessor's transient request status. |
198
+ | `subscribe(listener, {replay = true, signal?})` | Observes `image.state` and immediately replays the current snapshot by default; returns an unsubscribe function. |
199
+ | `close()` | Cancels this accessor's requests, removes subscriptions and joins its request promises. It leaves the shared Core client and selected model under their existing owners. |
200
+
201
+ Generation publishes `status: 'Thinking'` synchronously when accepted, before
202
+ transport, preparation, model loading or inference waits. This remains transient
203
+ status until the complete image result arrives. Native sampling progress is
204
+ reported as progress, with no fabricated image chunks or conversation turns.
205
+ The accessor's `requests` records contain method, stream ID, status and progress;
206
+ they contain no saved prompt or image history.
207
+
208
+ The authoritative lifecycle snapshot includes `selectedModel`, `loaded`,
209
+ `state`, `backend`, `progress`, `error`, native resource paths and device state.
210
+ Service metadata adds runtime `id`, installation/availability state and selected
211
+ model definitions, including their resource metadata before engine preparation
212
+ finishes. Installed files do not imply a loaded model. A late status
213
+ response never overwrites a newer lifecycle event.
214
+
215
+ Prompts and parameters pass unchanged to the native runtime. Native option
216
+ names, supported model operations and defaults belong to that runtime and the
217
+ selected model definition. A prompt containing U+0000 or an unpaired UTF-16
218
+ surrogate cannot pass unchanged through the native UTF-8 C-string boundary and
219
+ reports that incompatibility.
220
+
221
+ The request signal propagates through Core to the owning native operation.
222
+ Aborted requests produce no late image result or progress callback. Request
223
+ invocations use `timeoutMs: 0`; there is no arbitrary image-generation timeout.
224
+ Errors retain their actual details on rejected promises and diagnostic events.
225
+ Applications choose concise ordinary status text and keep complete engineering
226
+ details in their diagnostic surface, outside durable chat history.
227
+
228
+ `onEvent` observes `image.state`, `image.progress`, `image.request`,
229
+ `image.result` and `image.error` records. Observer failures are reported to the
230
+ developer console and do not replace inference results. Observers own their
231
+ asynchronous callback lifetimes. The SDK persists no prompt, result, transcript
232
+ or application-owned image association.
233
+
234
+ ## Core service and transport
235
+
236
+ `createLocalImageService(configuration, options)` is exported from
237
+ `arcane-os/core/image`. `configuration` is the selected `localAI` record.
238
+ Options are `appRoot`, installed `runtimes`, `signal`, `onEvent`, an optional
239
+ `prepare` callback and the existing `modelAssets` service instance.
240
+
241
+ `prepare({appRoot, configuration, requirement, signal, onEvent})` returns one
242
+ installed runtime record. Preparation runs once per service. That record carries
243
+ `libraryPath`, `bindingModulePath`, `backend`, `variants` and model definitions.
244
+ Runtime variants preserve their native backend, library path and runtime root.
245
+ The service retains one native runtime and subscribes to its current-state
246
+ replay. Expensive model execution belongs to that runtime's worker.
247
+
248
+ | Method/event | Parameters or result |
249
+ |---|---|
250
+ | `image.status` | Immediate lifecycle snapshot. |
251
+ | `image.load` | `{model, context?, assetProjectionId?, resourcePaths?}`; returns lifecycle snapshot. |
252
+ | `image.generate` | `{model, prompt, parameters?, streamId?, assetProjectionId?, resourcePaths?}`; returns complete encoded images. |
253
+ | `image.unload` | Empty parameters; returns lifecycle snapshot after unload. |
254
+ | `image.state` | Complete service lifecycle snapshot. Service and browser `subscribe()` provide current-state replay. |
255
+ | `image.progress` | `{streamId, requestId, status: 'Thinking', progress}` for the corresponding generation request. |
256
+
257
+ Core's JSON transport represents each complete PNG as
258
+ `{data, encoding: 'base64', mediaType: 'image/png', width, height}`. The browser
259
+ decodes that complete representation into a `Blob` and preserves its metadata.
260
+ There is no result resizing, clipping, storage write or application policy at
261
+ this transport boundary.
262
+
263
+ One service prepares one selected runtime, retains one selected native context
264
+ and performs one native generation per request. The native owner serializes
265
+ only competing operations on that context. Independent Core services and page
266
+ rendering remain concurrent. Native platform execution evidence and package
267
+ publication are separate from this source/API description.
@@ -1,9 +1,9 @@
1
1
  # Native working files from stored model assets
2
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.
3
+ These public APIs were first published in `arcane-os@0.61.0`. Browser
4
+ preparation is exported by `arcane-os/ai/core-model-assets`, and the native
5
+ service by `arcane-os/core/model-assets`. The image example below uses
6
+ `arcane-os/ai/core-image`, published in the same release.
7
7
 
8
8
  `prepareCoreModelAssets()` streams complete browser `File` or `Blob` members
9
9
  through the existing Core connection into native working files. DBOPFS keeps
@@ -42,13 +42,16 @@ try {
42
42
  // Native loading takes its own retain handle before using these files.
43
43
  await projection.release();
44
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();
45
+ try {
46
+ const result = await image.generate({
47
+ model: 'sd14',
48
+ prompt: 'A dignified raccoon who has been put in charge of the moon.',
49
+ signal
50
+ });
51
+ // Display or save the complete returned image through the application owner.
52
+ } finally {
53
+ await image.unload();
54
+ }
52
55
  ```
53
56
 
54
57
  This example assumes that the application selected the `sd14` model and its
@@ -6936,6 +6936,19 @@ no engine. The native routes of `AI.fetchTTS(payload, signal)` and
6936
6936
  `AI.fetchSTT(audio, signal)` forward their signals through these calls and
6937
6937
  normalize cancellation to `AbortError` with `ARCANE_AI_REQUEST_ABORTED`.
6938
6938
 
6939
+ `facade.window.setTheme(presentation, {signal}?)` forwards the complete
6940
+ presentation to the current native window, independently of OS-user appearance.
6941
+ Optional `backgroundColor` and `textColor` accept `{red,green,blue,alpha}` or
6942
+ `null` for a platform-default reset; omitted fields remain unchanged. The
6943
+ result is `{platform,supported,applied,unsupported}` with actual per-field
6944
+ acceptance, rather than a measured-pixel or atomic-update claim. Cancellation
6945
+ uses the existing request lifetime and does not undo settings already accepted.
6946
+ Shared ThemeBootstrap forwards the app's computed semantic colors without
6947
+ blocking rendering; applications using it need no duplicate listener. See the
6948
+ [current-window contract](core-client.md#current-window-theme) for channel
6949
+ values, errors, navigation, disposal and current host support. The facade does
6950
+ not add this operation to an older executable or an unsupported host.
6951
+
6939
6952
  ### Availability and normalization
6940
6953
 
6941
6954
  **Browser and native WebView JavaScript hosts with a Core client.** Creating the
@@ -7402,6 +7415,25 @@ including accepted service work, without a forced termination deadline. Missing
7402
7415
  prerequisites, download/extraction failures and host failures remain observable
7403
7416
  through the operation's error/event boundary.
7404
7417
 
7418
+ During assembly, `appDescriptor.native.icon` selects the app's existing image.
7419
+ PNG and ICO inputs produce a derived `runtime/arcane-app.ico` and update only
7420
+ the copied application's executable icon. Source assets, the selected host
7421
+ cache, other executable resources and the Core executable remain unchanged.
7422
+ `manifest.host.icon` identifies the selected runtime icon, while
7423
+ `manifest.host.executableIcon` records whether embedding succeeded.
7424
+
7425
+ The builder's `onEvent` receives `native.icon.completed` after successful
7426
+ embedding or `native.icon.unsupported` when the selected format or executable
7427
+ layout cannot provide it. Both carry `target`, `appId`, `icon` and `executable`;
7428
+ the unsupported event also carries the original `code` and complete `message`.
7429
+ Unsupported embedding preserves ordinary assembly and the original icon path.
7430
+ Unreadable files or malformed supported image data retain their ordinary errors.
7431
+ The matching host loads the window/taskbar icon independently of page and Core
7432
+ startup. PNG/ICO embedding and runtime codec support are separate boundaries;
7433
+ see [application icon and window colors](core-native-packaging.md#application-icon-and-window-colors)
7434
+ for formats, per-window colors, errors and platform limits. npm publication
7435
+ alone does not establish delivery or execution of the matching native archive.
7436
+
7405
7437
  ### Example
7406
7438
 
7407
7439
  ```javascript
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-os",
3
- "version": "0.60.0",
3
+ "version": "0.62.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",
@@ -41,6 +41,8 @@
41
41
  "./ai/browser-wasm": "./browser-runtime/ai/browser-wasm.mjs",
42
42
  "./ai/core-local": "./browser-runtime/ai/core-local.mjs",
43
43
  "./ai/core-onnx": "./browser-runtime/ai/core-onnx.mjs",
44
+ "./ai/core-image": "./browser-runtime/ai/core-image.mjs",
45
+ "./ai/core-model-assets": "./browser-runtime/ai/core-model-assets.mjs",
44
46
  "./ai/browser-decisions": "./browser-runtime/ai/browser-decisions.mjs",
45
47
  "./ai/tool-text-stream": "./browser-runtime/ai/tool-text-stream.mjs",
46
48
  "./ai/twin-cloud": "./browser-runtime/ai/twin-cloud.mjs",
@@ -63,10 +65,13 @@
63
65
  "./core/preferences": "./src/core/services/preferences.mjs",
64
66
  "./core/diarization": "./src/diarization/service.mjs",
65
67
  "./core/local-ai": "./src/core/services/local-ai.mjs",
68
+ "./core/image": "./src/core/services/image.mjs",
69
+ "./core/model-assets": "./src/core/services/model-assets.mjs",
66
70
  "./diarization": "./src/diarization/index.mjs",
67
71
  "./diarization/build": "./src/diarization/build.mjs",
68
72
  "./local-ai": "./src/local-ai/install.mjs",
69
73
  "./local-ai/onnx": "./src/local-ai/onnx.mjs",
74
+ "./local-ai/image": "./src/local-ai/image-runtime.mjs",
70
75
  "./integrated-provider": "./src/integrated-provider-loader.mjs",
71
76
  "./packager": "./src/packager/core.mjs",
72
77
  "./release-bundle": "./src/release-bundle.mjs",
@@ -262,12 +262,12 @@
262
262
  "type": "array",
263
263
  "items": {
264
264
  "oneOf": [
265
- { "enum": ["llama.cpp", "ollama", "onnx"] },
265
+ { "enum": ["llama.cpp", "ollama", "onnx", "stable-diffusion.cpp"] },
266
266
  {
267
267
  "type": "object",
268
268
  "required": ["id"],
269
269
  "properties": {
270
- "id": { "enum": ["llama.cpp", "ollama", "onnx"] },
270
+ "id": { "enum": ["llama.cpp", "ollama", "onnx", "stable-diffusion.cpp"] },
271
271
  "version": { "type": "string" },
272
272
  "url": { "type": "string" }
273
273
  }
@@ -156,12 +156,12 @@
156
156
  "type": "array",
157
157
  "items": {
158
158
  "oneOf": [
159
- { "enum": ["llama.cpp", "ollama", "onnx"] },
159
+ { "enum": ["llama.cpp", "ollama", "onnx", "stable-diffusion.cpp"] },
160
160
  {
161
161
  "type": "object",
162
162
  "required": ["id"],
163
163
  "properties": {
164
- "id": { "enum": ["llama.cpp", "ollama", "onnx"] },
164
+ "id": { "enum": ["llama.cpp", "ollama", "onnx", "stable-diffusion.cpp"] },
165
165
  "version": { "type": "string" },
166
166
  "url": { "type": "string" }
167
167
  }