arcane-os 0.96.0 → 0.97.1

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.
@@ -481,6 +481,9 @@ The remaining data-only subpaths are eight JSON Schemas and package metadata.
481
481
  | `KOKORO_SAMPLE_RATE` | constant | `arcane-os/local-ai/kokoro` | Core native speech | Native PCM sample rate |
482
482
  | `KOKORO_VOICES` | constant | `arcane-os/local-ai/kokoro` | Core native speech | Complete 28-voice US/GB selection |
483
483
  | `createNemotronRuntime()` | function | `arcane-os/local-ai/nemotron` | Core native speech | Node with a matching first-party helper, selected NeMo ASR runtime and models; Windows/Linux/macOS source, Android host adaptation |
484
+ | `NEMO_SPEECH_MODELS` | constant | `arcane-os/local-ai/nemotron` | Core native speech | Node; selected upstream model catalog, no acquisition at import |
485
+ | `prepareNemotronModels()` | function | `arcane-os/local-ai/nemotron` | Core native speech | Node with the shared model-assets service |
486
+ | `prepareMagpieModels()` | function | `arcane-os/local-ai/nemotron` | Core native speech | Node with the shared model-assets service |
484
487
  | `createNemotronRuntime default export` | function | `arcane-os/local-ai/nemotron` | Core native speech | Same named function |
485
488
  | `buildNemotronHelper()` | function | `arcane-os/local-ai/nemotron/build` | Core native speech | Node with CMake 3.26+, C++17 toolchain and platform-matching public NeMo ASR headers/libraries/CMake package |
486
489
  | `buildNemotronHelper default export` | function | `arcane-os/local-ai/nemotron/build` | Core native speech | Same named function |
@@ -494,6 +497,9 @@ The remaining data-only subpaths are eight JSON Schemas and package metadata.
494
497
  | `buildWhisperOpenVinoRuntime()` | function | `arcane-os/local-ai/whisper/openvino-build` | Core native speech | Windows x64 Node with installed matching Whisper/OpenVINO sources and CMake/MSVC toolchain |
495
498
  | `createSpeechService default export` | function | `arcane-os/core/speech` | Core native speech | Same shared speech service factory |
496
499
  | `prepareCoreModelAssets()` | function | `arcane-os/ai/core-model-assets` | Core model assets | Browser with complete Blob/File members and available Core service |
500
+ | `discoverCoreModelAssets()` | function | `arcane-os/ai/core-model-assets` | Core model assets | Browser with an available model-assets Core service |
501
+ | `openExistingCoreModelAssets()` | function | `arcane-os/ai/core-model-assets` | Core model assets | Browser with an available model-assets Core service |
502
+ | `downloadCoreModelAssets()` | function | `arcane-os/ai/core-model-assets` | Core model assets | Browser with an available model-assets Core service |
497
503
  | `createModelAssetService()` | function | `arcane-os/core/model-assets` | Core model assets | Node Core with an application-selected working directory |
498
504
  | `createModelAssetService default export` | function | `arcane-os/core/model-assets` | Core model assets | Same native working-file service factory |
499
505
  | `createLocalAIService default export` | function | `arcane-os/core/local-ai` | Core local AI | Same native service factory |
@@ -7923,7 +7929,12 @@ reports `ARCANE_NATIVE_RUN_UNSUPPORTED`.
7923
7929
 
7924
7930
  `build()` copies the complete selected app and dependency releases, the
7925
7931
  published SDK/runtime dependencies and the canonical Core entry/client into a
7926
- fresh output directory. Service factories are imported only when a real native
7932
+ temporary assembly, then publishes it at `<outputRoot>/<app-id>/`. Later
7933
+ successful builds replace only that app's generated output. Publication retains
7934
+ the previous output until the completion callback and cancellation boundary
7935
+ accept the replacement; failure restores it. Models and saved state belong in
7936
+ their separate persistent directories. See [stable output and recovery](core-native-packaging.md#output-and-host-contract).
7937
+ Service factories are imported only when a real native
7927
7938
  host later launches the generated Core entry, never during packaging.
7928
7939
 
7929
7940
  The generated `runtime/arcane-core.mjs` also accepts
@@ -8063,6 +8074,11 @@ the selected output root. There is no compiler or OS checkout requirement for
8063
8074
  application builds. The build machine needs its normal Node/npm toolchain and
8064
8075
  `tar`; execution needs Windows x64, .NET Framework 4.6.2 or later and WebView2.
8065
8076
 
8077
+ Successful builds publish the complete payload at `<outputRoot>/<app-id>/`,
8078
+ replacing that app's prior generated artifact through the same
8079
+ [joined publication lifecycle](core-native-packaging.md#output-and-host-contract).
8080
+ Runtime caches, models, saved profiles and unrelated outputs remain separate.
8081
+
8066
8082
  The matching Windows host consumes `appDescriptor.native.window` through
8067
8083
  `manifest.window`. Optional `width` and `height` select initial client dimensions
8068
8084
  in 96-DPI logical units; the host scales them for its actual DPI and fits the
@@ -8158,6 +8174,9 @@ asset is published or its Mac runtime has been executed.
8158
8174
 
8159
8175
  Build preserves the complete portable payload inside the bundle's Resources
8160
8176
  directory (`target.rootDir`) and returns its `.app` location as `bundleRoot`.
8177
+ The accepted bundle is `<outputRoot>/<app-id>.app/`; a later successful build
8178
+ replaces that bundle through the shared [publication lifecycle](core-native-packaging.md#output-and-host-contract),
8179
+ preserving separate saved state and model directories.
8161
8180
  The bundle supplies the SDK launcher and selected Node runtime. `verify()`
8162
8181
  reads assembled files; `run()` directly launches the bundled executable only on
8163
8182
  the matching Darwin architecture, observes diagnostics and waits for graceful
@@ -8321,8 +8340,9 @@ import createDiarizationService from 'arcane-os/core/diarization';
8321
8340
 
8322
8341
  ### Overview
8323
8342
 
8324
- Resolves one application's native state, workspace and optional shared endpoint
8325
- through the same public owner used by its packaged executable and external MCP.
8343
+ Resolves one application's native state, workspace and optional shared endpoint,
8344
+ plus a same-user shared model directory, through the same public owner used by
8345
+ its packaged executable and external MCP.
8326
8346
  This synchronous function performs no I/O, saved-state discovery, process start
8327
8347
  or migration.
8328
8348
 
@@ -8333,7 +8353,7 @@ resolveNativeLaunchContext({appId,context={}}={})
8333
8353
  ```
8334
8354
 
8335
8355
  Import from `arcane-os/core/host`. The result is a new complete context with
8336
- omitted fields filled. Windows defaults to `%LOCALAPPDATA%/Arcane/<appId>`
8356
+ omitted fields filled. `stateRoot` defaults on Windows to `%LOCALAPPDATA%/Arcane/<appId>`
8337
8357
  (home `AppData/Local` fallback), macOS to
8338
8358
  `~/Library/Application Support/Arcane/<appId>`, and portable Linux Node to
8339
8359
  absolute `$XDG_DATA_HOME/Arcane/<appId>` or `~/.local/share/Arcane/<appId>`.
@@ -8341,6 +8361,21 @@ Android and other adapted hosts provide their actual `stateRoot` and own native
8341
8361
  IPC/process adaptation.
8342
8362
 
8343
8363
  An omitted `workspaceRoot` becomes `<absolute selected stateRoot>/Workspace`.
8364
+ An omitted `modelsDirectory` uses the operating-system user's shared Arcane
8365
+ model directory: `%LOCALAPPDATA%/Arcane/Models` on Windows (home `AppData/Local`
8366
+ fallback), `~/Library/Application Support/Arcane/Models` on macOS, and absolute
8367
+ `$XDG_DATA_HOME/Arcane/Models` or `~/.local/share/Arcane/Models` on Linux. This
8368
+ default remains shared when the application explicitly selects another
8369
+ `stateRoot`; application state and workspace stay separate. Explicit
8370
+ `modelsDirectory` values remain unchanged. Other adapted hosts may supply a
8371
+ shared directory explicitly; their omitted value remains
8372
+ `<absolute selected stateRoot>/Models`.
8373
+
8374
+ This resolver supplies a location to its consumers; it neither changes every
8375
+ provider's store nor creates, moves or migrates model files. Services select
8376
+ that directory as the shared model-assets working directory, while applications
8377
+ may also discover their existing app-local originals. Model storage remains
8378
+ separate from replaceable native build output. See [persistent model locations](model-assets.md).
8344
8379
  Only a selected `sharedHost` object receives a default endpoint and log file:
8345
8380
  Windows uses a named pipe containing the URL-encoded complete absolute state
8346
8381
  path; Linux/macOS use `<absolute selected stateRoot>/core.sock`. The log is
@@ -8667,7 +8702,7 @@ separate states; prompts, models and application policy remain caller-owned.
8667
8702
  ### Signature and result
8668
8703
 
8669
8704
  ```text
8670
- createLocalAIService(configuration,{appRoot,runtimes=[],signal,onEvent,prepare,executionDevices}={})
8705
+ createLocalAIService(configuration,{appRoot,runtimes=[],signal,onEvent,prepare,executionDevices,autoStart=true}={})
8671
8706
  ```
8672
8707
 
8673
8708
  Import it from `arcane-os/core/local-ai`. `configuration` is the authored local-AI
@@ -8691,6 +8726,16 @@ asset services keep their own lifetimes. Pass only llama.cpp/Ollama/ONNX
8691
8726
  requirements to this factory; `createLocalImageService()` owns selected image
8692
8727
  requirements. The managed development and native entrypoints separate them.
8693
8728
 
8729
+ `autoStart:false` leaves these selected engines unprepared and unstarted during
8730
+ Core startup. Call `client.invoke('localai.prepare', {}, {signal})` when the
8731
+ application explicitly requests preparation. The operation invokes the
8732
+ configured `prepare` owner, emits its complete events as `localai.preparation`,
8733
+ starts configured engines and returns current state. Concurrent callers share
8734
+ in-flight preparation; completed preparation is reused. Engine/model readiness
8735
+ remains separate, so this result alone does not establish inference readiness.
8736
+ The default `autoStart:true` preserves startup preparation. No model is selected
8737
+ by this option.
8738
+
8694
8739
  The service provides `localai.status`, explicit `localai.services.recover`,
8695
8740
  `llama.status/models/load/unload/chat`, `onnx.status/load/run/unload`, and the documented native Ollama methods.
8696
8741
  `localai.state` reports runtime/model changes. `llama.status` and `llama.models`
@@ -8995,7 +9040,8 @@ microphone, loading a model or starting inference at construction.
8995
9040
  ```javascript
8996
9041
  createNemotronRuntime({
8997
9042
  runtime, prepare, modelId = 'nemotron-3.5-asr-streaming-0.6b',
8998
- modelPath, diarizationModelPath, gpu, onEvent
9043
+ modelPath, diarizationModelPath, modelAssets, assetProjectionId,
9044
+ resourcePaths, gpu, onEvent
8999
9045
  } = {})
9000
9046
  ```
9001
9047
 
@@ -9005,6 +9051,14 @@ explicitly (native ordinal, or `-1` for CPU). Model paths may come from the
9005
9051
  descriptor; omit the diarization path when speaker labels are not requested.
9006
9052
  Preparation, models and device selection remain caller-owned.
9007
9053
 
9054
+ Alternatively supply the existing `modelAssets` service and a completed
9055
+ `assetProjectionId`, with `resourcePaths:{model,diarization?}` naming exact
9056
+ projection members. `load()` retains that projection before yielding and keeps
9057
+ it through actual helper cleanup; the caller can release preparation ownership
9058
+ after loading begins. Explicit load accepts these selection fields, and an
9059
+ active selection must be unloaded before replacement. Direct paths remain
9060
+ supported. See [shared catalog preparation](#preparenemotronmodels).
9061
+
9008
9062
  ### Returned members and lifetime
9009
9063
 
9010
9064
  The engine exposes `current/subscribe/load/unload/transcribe/openStream/close`.
@@ -9057,6 +9111,58 @@ callback rules and cancellation/reset outcomes.
9057
9111
  The default export from `arcane-os/local-ai/nemotron` is the same
9058
9112
  `createNemotronRuntime` function, with identical inputs, results and lifetime.
9059
9113
 
9114
+ ## `NEMO_SPEECH_MODELS`
9115
+
9116
+ Import this catalog from `arcane-os/local-ai/nemotron`. `stt` describes the
9117
+ selected Nemotron ASR and diarization GGUF companions; `tts` describes Magpie,
9118
+ NanoCodec and the matching ten tokenizer/configuration members. Each selection
9119
+ contains `modelId`, `providerId`, `name`, ordinary `members`, `resourcePaths`
9120
+ and optional `archives`. The upstream selections come from NVIDIA's
9121
+ NeMo-Speech.cpp 0.2.0 catalog. Importing the catalog performs no I/O and installs
9122
+ no runtime or model. See [the exact companion contract](native-speech.md#selected-nemo-model-acquisition).
9123
+
9124
+ ## prepareNemotronModels()
9125
+
9126
+ ```text
9127
+ prepareNemotronModels({modelAssets,workingDirectory,directories,id,signal,onProgress,refresh=false}={})
9128
+ ```
9129
+
9130
+ Import from `arcane-os/local-ai/nemotron`. Explicitly prepares the catalog's
9131
+ complete ASR and diarization selection through the existing model-assets
9132
+ service. Optional `directories` are searched first when `refresh` is false;
9133
+ the first complete matching catalog record is opened without downloading.
9134
+ Otherwise the shared `prepare` owner acquires the complete selection beneath
9135
+ `workingDirectory/model-assets/`. `refresh:true` requests a separate acquisition.
9136
+
9137
+ The promise resolves to `{assetProjectionId,directory,members,resourcePaths,release}`.
9138
+ An omitted `id` is generated. Ordered asynchronous `onProgress` receives full
9139
+ file-based semantic progress; existing selections report `reuse` then `ready`.
9140
+ Native acquisition additionally reports its shared resume, ownership-wait,
9141
+ activity and terminal states described under [`createModelAssetService()`](#createmodelassetservice).
9142
+ Completed members and saved partial transfers remain available for retry;
9143
+ HTTP continuation depends on the source response. Direct installed-directory
9144
+ reuse keeps its existing phase/file-count callback shape.
9145
+ Call the idempotent asynchronous `release()` to relinquish preparation ownership
9146
+ after the engine has retained it. Complete acquisitions and borrowed originals
9147
+ remain stored. Cancellation and callback failures join cleanup and preserve
9148
+ actual failures. The wrapper selects no device, installs no native runtime and
9149
+ starts no microphone or inference. See [native model acquisition](native-speech.md#selected-nemo-model-acquisition).
9150
+
9151
+ ## prepareMagpieModels()
9152
+
9153
+ ```text
9154
+ prepareMagpieModels({modelAssets,workingDirectory,directories,id,signal,onProgress,refresh=false}={})
9155
+ ```
9156
+
9157
+ Import from `arcane-os/local-ai/nemotron`. It has the same preparation,
9158
+ discovery, progress, cancellation and release contract as `prepareNemotronModels`,
9159
+ using the catalog's complete Magpie/NanoCodec/tokenizer selection. Its returned
9160
+ `resourcePaths` contains `model`, `codec` and `tokenizerConfig`. The shared TAR
9161
+ reader extracts the ten selected tokenizer members from the catalog's selected
9162
+ upstream archive ranges; offsets stay transport-local. Pass the completed
9163
+ projection to the existing Magpie engine. Voice, language and device selection
9164
+ remain caller-owned; preparation performs no synthesis.
9165
+
9060
9166
  ## buildNemotronHelper()
9061
9167
 
9062
9168
  ### Overview and syntax
@@ -9320,7 +9426,7 @@ through `encoder: 'openvino-npu'`; they do not run this producer at startup.
9320
9426
 
9321
9427
  ### Overview and usage
9322
9428
 
9323
- `createSpeechService({stt,tts,signal}={})` from `arcane-os/core/speech` composes
9429
+ `createSpeechService({stt,tts,signal,autoLoad=true}={})` from `arcane-os/core/speech` composes
9324
9430
  independently selected STT and TTS engines as one Core service. Supply either
9325
9431
  role or both. Construction downloads, installs and loads nothing; the host
9326
9432
  owns engine creation, model/device selection and supported formats.
@@ -9363,6 +9469,9 @@ The returned object has `name: 'speech'`, `current`, `subscribe`, `close`,
9363
9469
  - `start(context)` subscribes and starts both configured engine loads
9364
9470
  independently, returning immediately. Core and status remain responsive
9365
9471
  during loading; one role's failure leaves the other usable.
9472
+ With `autoLoad:false`, subscriptions and role capabilities remain available
9473
+ while startup requests no engine load. Explicit `speech.load` activates
9474
+ the selected role. The default preserves automatic startup loading.
9366
9475
  - `current()` and `methods['speech.status']()` return the same snapshot:
9367
9476
  `ready`, `transcriptionAvailable`, `synthesisAvailable`, `status`,
9368
9477
  `sttEngine`, `ttsEngine`, `roles.stt`, `roles.tts` and `closed`.
@@ -9443,24 +9552,82 @@ engine. See [complete preparation and cleanup usage](model-assets.md).
9443
9552
 
9444
9553
  `createModelAssetService({appRoot=process.cwd()}={})` from
9445
9554
  `arcane-os/core/model-assets` returns the Core service for
9446
- `modelAssets.open/write/complete/release/status` and `modelAssets.state`.
9555
+ `modelAssets.open/write/complete/release/status`,
9556
+ `modelAssets.discover/openExisting/prepare/cancelPrepare`, and `modelAssets.state`.
9447
9557
  Relative working directories resolve from `appRoot`; explicit absolute
9448
9558
  directories remain caller-selected. Each projection has its own child
9449
9559
  directory and complete member files.
9450
9560
 
9451
9561
  `current()` returns `{closing,projections}`. `retain(id)` accepts a completed
9452
9562
  projection and returns `{id,directory,members,release}` for a native owner.
9453
- Native `prepare({id,workingDirectory,members,signal,onProgress,refresh=false})`
9454
- accepts ordered `{path,url}` members and returns their ready projection.
9563
+ Native `prepare({id,workingDirectory,members=[],archives=[],signal,onProgress,refresh=false})`
9564
+ accepts ordered `{path,url}` members and optional uncompressed TAR selections,
9565
+ returning their complete ready projection. An archive declares
9566
+ `{url,format:'tar',ranges?,members:[{path,member}]}`. Optional inclusive
9567
+ `{start,end,stopBefore?}` ranges use HTTP partial responses; the parser handles
9568
+ ordinary and PAX member paths and preserves each selected file completely.
9569
+ All declared companions must finish before readiness. Range framing stays
9570
+ transport-local.
9455
9571
  Complete native acquisitions persist beneath `workingDirectory/model-assets/`
9456
9572
  through unload, disposal and restart; ordinary calls reuse the exact complete
9457
9573
  ordered source selection without a network freshness check. Explicit
9458
9574
  `refresh:true` acquires a separate complete set without replacing active files.
9459
- Independent members transfer concurrently and progress reports phases and
9460
- completed files. Matching same-process preparations share acquisition with
9461
- independent callbacks and cancellation; the last interested cancellation joins
9462
- unfinished I/O and removes only that attempt. Separate processes may acquire
9463
- the same selection independently. Startup downloads nothing.
9575
+ Independent members transfer concurrently. Interrupted or cancelled acquisitions
9576
+ retain completed members and closed partial files for retry. A retry reuses the
9577
+ same recorded attempt and downloads only missing members. Ordinary-file HTTP
9578
+ continuation uses its retained strong ETag or Last-Modified validator with
9579
+ `Range` and `If-Range`; a matching `206` response appends. A full `200`, `416`,
9580
+ missing validator or prior encoded response restarts only that member and
9581
+ reports `restart`. One prior partial remains until its replacement completes.
9582
+ TAR selections replay the required segment framing while preserving already
9583
+ completed companions. HTTP framing remains internal to the transfer, not
9584
+ model identity or user-facing progress.
9585
+
9586
+ Matching same-process preparations share acquisition with independent callbacks
9587
+ and cancellation; cancelling one interested caller leaves the others running.
9588
+ The last interested cancellation joins I/O while retaining resumable data.
9589
+ Matching selections in separate processes coordinate their recorded transfer
9590
+ owner, report `waiting`, then reuse or resume after that owner releases or exits.
9591
+ Unrelated acquisitions remain concurrent. Member completion follows stream/file
9592
+ closure and promotion; whole-acquisition readiness follows all selected members.
9593
+ Startup downloads nothing, and retry remains an explicit preparation request.
9594
+
9595
+ Native acquisition progress is
9596
+ `{phase,state,message,completed,total,unit:'files',memberIndex?,path?,reason?,recovery?,error?,activity?}`.
9597
+ Phases are `open`, `download`, `reuse`, `resume`, `restart`, `complete`, `ready`,
9598
+ `waiting`, `heartbeat`, `stalled`, `interrupted`, `cancelled` and `failed`.
9599
+ States are `waiting`, `downloading`, `stalled`, `interrupted`, `cancelled`,
9600
+ `failed` and `ready`. A five-second heartbeat keeps active work observable;
9601
+ `stalled` means no source activity arrived for fifteen seconds, not a diagnosed
9602
+ outage. Waiting may include the other owner's observed `activity`. Plain
9603
+ `message` and `recovery` belong in ordinary status; complete `error` details
9604
+ remain diagnostic data. Progress uses phases and completed-file counts, not
9605
+ invented percentages. Terminal acquisition state does not imply that a
9606
+ cancelled subscriber receives callbacks after its cancellation boundary.
9607
+
9608
+ `discover({directories,catalog=[],recursive=true,signal})` reads only explicit
9609
+ installed directories and returns `{directories,models}`. Directory observations
9610
+ contain `{directory,exists,error?}`. Each model record has
9611
+ `{directory,entryPath,members:[{path,nativePath,available}],missingMembers,complete,source,catalogId?}`.
9612
+ The source is `directory`, `catalog` or `acquisition`. Split GGUF filename sets
9613
+ are one numerically ordered selection, including missing expected shards and
9614
+ the first shard as entry. This grouping also applies to completed acquisitions;
9615
+ all declared companions remain present. Ordinary readable symlinked files and
9616
+ directories are followed, with real-path cycle detection.
9617
+
9618
+ Catalog entries `{id,members,archives?,entryPath?}` declare exact companion sets.
9619
+ Acquisition-backed matching honors supplied source URLs and archive member
9620
+ names; path-only catalogs and ordinary directory discovery make no origin or
9621
+ runtime-readiness claim. No files are downloaded, loaded or moved by discovery.
9622
+
9623
+ `openExisting({id,directory,members:[{path}],signal})` opens a complete borrowed
9624
+ projection using those existing files. Missing members reject with
9625
+ `MODEL_ASSET_MEMBERS_MISSING` and the complete missing-member list. Release
9626
+ never deletes or copies borrowed originals. The three new operations also have
9627
+ matching Core RPC methods. Request-scoped `modelAssets.progress` carries
9628
+ `{id,progress}` with full file-based semantic progress; `cancelPrepare` aborts
9629
+ and joins actual acquisition cleanup. The browser helpers below preserve the
9630
+ request correlation and cancellation joins.
9464
9631
  `release(id)` relinquishes live preparation ownership. Native retains continue
9465
9632
  through actual engine release; completed native acquisitions remain stored.
9466
9633
  Browser `open/write/complete` projections retain their temporary lifetime and
@@ -9472,6 +9639,53 @@ handle only after its actual context/worker use ends. Original stored model
9472
9639
  files remain with their application owner. See
9473
9640
  [working-file service and wire operations](model-assets.md#native-ownership).
9474
9641
 
9642
+ ## discoverCoreModelAssets()
9643
+
9644
+ ```text
9645
+ discoverCoreModelAssets({client=getInstalledCoreClient(),directories,catalog,recursive,signal}={})
9646
+ ```
9647
+
9648
+ Import from `arcane-os/ai/core-model-assets`. Resolves the native `discover`
9649
+ result described above through the installed Core connection. Directories and
9650
+ catalog selections remain application-owned. Complete shard and companion
9651
+ availability is filesystem evidence, not a selected or loaded model. See
9652
+ [discovery records](model-assets.md).
9653
+
9654
+ ## openExistingCoreModelAssets()
9655
+
9656
+ ```text
9657
+ openExistingCoreModelAssets({client=getInstalledCoreClient(),directory,members,signal}={})
9658
+ ```
9659
+
9660
+ Import from `arcane-os/ai/core-model-assets`. Opens selected complete existing
9661
+ files through Core and returns `{id,directory,members,release}`. The helper
9662
+ generates its projection ID; `release()` is asynchronous and idempotent.
9663
+ Native engines retain their own use; borrowed original files remain intact.
9664
+ Cancellation joins uncancelled cleanup before rejecting.
9665
+
9666
+ ## downloadCoreModelAssets()
9667
+
9668
+ ```text
9669
+ downloadCoreModelAssets({client=getInstalledCoreClient(),workingDirectory,members,archives,refresh=false,signal,onProgress}={})
9670
+ ```
9671
+
9672
+ Import from `arcane-os/ai/core-model-assets`. Explicitly invokes native
9673
+ acquisition for complete ordinary and optional TAR-selected members and returns
9674
+ `{id,directory,members,release}`. It generates the ID, observes only that request's
9675
+ complete progress, and awaits asynchronous callbacks in order. Cancellation or
9676
+ a callback failure joins native `cancelPrepare` cleanup and local callback
9677
+ delivery before settlement; actual cleanup failures remain observable.
9678
+ When Core rejects preparation, the helper first delivers already queued
9679
+ terminal progress before its internal cleanup cancellation and rejection.
9680
+ Explicit caller cancellation retains its no-late-callback boundary.
9681
+ Release relinquishes preparation ownership while completed downloads remain
9682
+ stored. Interrupted/cancelled native transfers retain completed members and
9683
+ saved partials for an explicit retry; the shared owner's HTTP continuation and
9684
+ member-restart rules apply. Progress forwards its full ownership-wait,
9685
+ heartbeat/stall and terminal records without inventing completion. No model,
9686
+ runtime or device is selected implicitly. See
9687
+ [download and progress usage](model-assets.md).
9688
+
9475
9689
  ## createModelAssetService default export
9476
9690
 
9477
9691
  The default export from `arcane-os/core/model-assets` is the same
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-os",
3
- "version": "0.96.0",
3
+ "version": "0.97.1",
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",
package/src/core/host.mjs CHANGED
@@ -9,37 +9,41 @@ export {startCoreListener, startSharedCoreHost, connectSharedCoreHost, runShared
9
9
 
10
10
  const is = new Is(false);
11
11
 
12
- /** Resolve one app's native locations without creating or migrating data. */
12
+ function userDataDirectory() {
13
+ const home = homedir();
14
+ switch (process.platform) {
15
+ case 'win32': return process.env.LOCALAPPDATA || path.join(home, 'AppData', 'Local');
16
+ case 'darwin': return path.join(home, 'Library', 'Application Support');
17
+ case 'linux': {
18
+ const xdg = process.env.XDG_DATA_HOME;
19
+ return xdg && path.isAbsolute(xdg) ? xdg : path.join(home, '.local', 'share');
20
+ }
21
+ default: return null;
22
+ }
23
+ }
24
+
25
+ /** Resolve app-private state and same-user shared models without moving data. */
13
26
  export function resolveNativeLaunchContext({appId, context = {}} = {}) {
14
27
  if (!is.string(appId) || !appId) throw new TypeError('Native launch resolution requires an appId.');
15
28
  if (context === null || !is.object(context) || is.array(context)) {
16
29
  throw new TypeError('Native launch context must be an object.');
17
30
  }
31
+ const userDirectory = userDataDirectory();
18
32
  let stateRoot = context.stateRoot;
19
33
  if (stateRoot === undefined) {
20
- const home = homedir();
21
- switch (process.platform) {
22
- case 'win32':
23
- stateRoot = path.join(process.env.LOCALAPPDATA || path.join(home, 'AppData', 'Local'), 'Arcane', appId);
24
- break;
25
- case 'darwin':
26
- stateRoot = path.join(home, 'Library', 'Application Support', 'Arcane', appId);
27
- break;
28
- case 'linux': {
29
- const xdg = process.env.XDG_DATA_HOME;
30
- stateRoot = path.join(xdg && path.isAbsolute(xdg) ? xdg : path.join(home, '.local', 'share'), 'Arcane', appId);
31
- break;
32
- }
33
- default:
34
- throw new TypeError('This native host must supply its persistent stateRoot.');
35
- }
34
+ if (!userDirectory) throw new TypeError('This native host must supply its persistent stateRoot.');
35
+ stateRoot = path.join(userDirectory, 'Arcane', appId);
36
36
  }
37
37
  if (!is.string(stateRoot) || !stateRoot) throw new TypeError('Native stateRoot must be a nonempty directory path.');
38
38
  const root = path.resolve(stateRoot);
39
39
  const resolved = {
40
40
  ...context,
41
41
  stateRoot,
42
- modelsDirectory: context.modelsDirectory === undefined ? path.join(root, 'Models') : context.modelsDirectory,
42
+ // Model files are reusable resources; preferences, profiles and chat stay
43
+ // under the application's stateRoot. Other hosts supply their shared path.
44
+ modelsDirectory: context.modelsDirectory === undefined
45
+ ? userDirectory ? path.join(userDirectory, 'Arcane', 'Models') : path.join(root, 'Models')
46
+ : context.modelsDirectory,
43
47
  workspaceRoot: context.workspaceRoot === undefined ? path.join(root, 'Workspace') : context.workspaceRoot
44
48
  };
45
49
  if (context.sharedHost !== undefined) {