arcane-os 0.62.0 → 0.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +1 -1
  3. package/browser-runtime/core/client.mjs +7 -2
  4. package/docs/reference/README.md +7 -0
  5. package/docs/reference/cli.md +5 -1
  6. package/docs/reference/core-client.md +11 -2
  7. package/docs/reference/core-native-packaging.md +57 -8
  8. package/docs/reference/core-repositories.md +149 -0
  9. package/docs/reference/inventory/package-api.json +163 -9
  10. package/docs/reference/local-ai.md +51 -7
  11. package/docs/reference/local-image-flux.md +154 -0
  12. package/docs/reference/local-image-generation.md +12 -0
  13. package/docs/reference/local-image-sdxl.md +139 -0
  14. package/docs/reference/local-whisper.md +219 -0
  15. package/docs/reference/native-speech.md +163 -0
  16. package/docs/reference/runtime-modules.md +16 -2
  17. package/docs/reference/sdk-api.md +335 -6
  18. package/package.json +5 -1
  19. package/runtime/arcane/components/speech.html +15 -3
  20. package/runtime/arcane/components/voice-transcription.html +19 -3
  21. package/runtime/arcane/modules/AI.js +250 -27
  22. package/runtime/arcane/modules/AIProviderRuntime.js +20 -3
  23. package/runtime/arcane/modules/AIRuntimeState.js +15 -2
  24. package/runtime/arcane/modules/ComponentContracts.js +3 -0
  25. package/schemas/arcane-app.schema.json +53 -2
  26. package/schemas/arcane-package.schema.json +53 -2
  27. package/src/core/repositories.mjs +210 -0
  28. package/src/core/services/speech.mjs +361 -0
  29. package/src/local-ai/config.mjs +9 -3
  30. package/src/local-ai/dev.mjs +32 -2
  31. package/src/local-ai/image-library.mjs +9 -0
  32. package/src/local-ai/image-models/flux.mjs +31 -0
  33. package/src/local-ai/image-models/sdxl.mjs +18 -0
  34. package/src/local-ai/install.mjs +26 -7
  35. package/src/local-ai/whisper/build.mjs +48 -0
  36. package/src/local-ai/whisper/config.mjs +61 -0
  37. package/src/local-ai/whisper/index.mjs +515 -0
  38. package/src/local-ai/whisper/install.mjs +274 -0
  39. package/src/local-ai/whisper/native/CMakeLists.txt +98 -0
  40. package/src/local-ai/whisper/native/NOTICE +18 -0
  41. package/src/local-ai/whisper/native/README.md +104 -0
  42. package/src/local-ai/whisper/native/main.cpp +489 -0
  43. package/src/native/portable-layout.mjs +37 -7
  44. package/src/native/windows-provider.mjs +39 -15
package/CHANGELOG.md CHANGED
@@ -1,5 +1,45 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.64.0
4
+
5
+ - Add retained native Whisper transcription through the existing Core speech
6
+ service and AI API, with actual model readiness, complete recordings and
7
+ transcripts, native progress, joined cancellation, and one eligible
8
+ accelerated-inference recovery on the prepared CPU runtime.
9
+ - Preserve the same accepted transcription through internal recovery using
10
+ its actual Core request identity. Shared AI and speech controls report
11
+ recovering/error states honestly without discarding the original request
12
+ or turning its terminal native failure into cancellation.
13
+ - Add the SDXL Base 1.0 text-to-image descriptor and correct the shared native
14
+ image binding's asynchronous worker stack allocation while preserving
15
+ existing model selection, complete inputs and native lifecycle.
16
+ - Add `arcane-os/core/repositories` with per-user `ArcaneData/Repos` defaults
17
+ and connected working-repository open/status/pull/push/drain ownership.
18
+ Explicit paths and existing data remain unchanged; applications own
19
+ connection selection, remotes and product records. No data migration.
20
+ - Keep optional NPU, repository file-write orchestration, generic development
21
+ Core composition, Codex/MCP and Ollama lifecycle drafts outside this release.
22
+ The npm dependency tree is unchanged; native resources use their documented
23
+ upstream installation and matching numeric-release helper assets.
24
+
25
+ ## 0.63.0
26
+
27
+ - Add the approved FLUX.2 Klein 4B text-to-image model descriptor to the
28
+ existing retained local image runtime, with its separate diffusion, VAE
29
+ and text-encoder resources and four-step Euler defaults. Applications keep
30
+ their model choice, complete prompts and image persistence.
31
+ - Name assembled Windows launchers from the application display name, with a
32
+ matching executable configuration and manifest-selected launch path.
33
+ Preserve supported spaces, case and Unicode, existing generic artifacts,
34
+ icon embedding and the unchanged shared host archive.
35
+ - Add `createSpeechService({stt, tts, signal})` through `arcane-os/core/speech`
36
+ for independently supplied native engines, immediate service registration,
37
+ sticky role state, complete requests/results, cancellation and joined close.
38
+ This service does not install or select a speech engine.
39
+ - Preserve existing image generation/editing and native host behavior. No
40
+ additional GPU setup, SDXL, Whisper engine, Kokoro/Sherpa adoption or browser
41
+ AI native-speech readiness correction is included in this increment.
42
+
3
43
  ## 0.62.0
4
44
 
5
45
  - Add whole-image PNG editing through the existing local image runtime, Core
package/README.md CHANGED
@@ -20,7 +20,7 @@ selected SDK projection or an explicit live SDK source mount. Both profiles
20
20
  share the theme, packaging, event, cancellation,
21
21
  and browser run contracts while retaining their selected application layout.
22
22
 
23
- This checkout defines the `0.62.0` SDK contract. Development applications declare
23
+ This checkout defines the `0.64.0` SDK contract. Development applications declare
24
24
  `arcane-os` as `latest` and retain their lockfile. Exact SDK pins begin when Roshi
25
25
  designates a production build. Follow [Consumer updates](docs/consumer-updates.md)
26
26
  to refresh and compare the installed SDK and lockfile with the published channel;
@@ -459,7 +459,10 @@ export function createCoreClient({
459
459
  if(eventOwnerFailure)return Promise.reject(eventOwnerFailure);
460
460
  let selected;
461
461
  try{selected=connect();}catch(error){return Promise.reject(error);}
462
- const {signal,timeoutMs=10*60*1000}=options??{};
462
+ const {signal,timeoutMs=10*60*1000,onRequest}=options??{};
463
+ if(onRequest!==undefined&&typeof onRequest!=='function'){
464
+ return Promise.reject(new TypeError('Arcane request observer must be a function.'));
465
+ }
463
466
  if(signal&&(typeof signal.aborted!=='boolean'
464
467
  ||typeof signal.addEventListener!=='function'
465
468
  ||typeof signal.removeEventListener!=='function')){
@@ -483,6 +486,8 @@ export function createCoreClient({
483
486
  if(!settle(id,failure))report(failure);
484
487
  }
485
488
  try{
489
+ if(onRequest)Promise.resolve(onRequest({requestId:id})).catch(report);
490
+ if(!pending.has(id))return promise;
486
491
  Promise.resolve(selected.send(frame)).catch(sendFailed);
487
492
  }catch(error){sendFailed(error);}
488
493
  return promise;
@@ -569,7 +574,7 @@ export function createCoreFacade(client){
569
574
  mail:{send:request=>invoke('mail.send',request??{},{timeoutMs:450000})},
570
575
  speech:{status:()=>invoke('speech.status',{},{timeoutMs:10000}),
571
576
  synthesize:(request,options)=>invoke('speech.synthesize',request??{},{timeoutMs:180000,signal:options?.signal}),
572
- transcribe:(request,options)=>invoke('speech.transcribe',request??{},{timeoutMs:180000,signal:options?.signal})},
577
+ transcribe:(request,options)=>invoke('speech.transcribe',request??{},{timeoutMs:180000,signal:options?.signal,onRequest:options?.onRequest})},
573
578
  localAI:{status:()=>invoke('localai.status',{},{timeoutMs:15000}),
574
579
  ensurePlatform:()=>invoke('localai.platform.ensure',{},long),recover:request=>invoke('localai.services.recover',request??{},long),
575
580
  setParallelRequests:request=>invoke('localai.parallel.requests.set',request??{},long),
@@ -55,6 +55,11 @@ alone does not make bare module names resolve in a browser.
55
55
  | Cancel one Core speech synthesis request without changing its payload | [Speech request lifetime](core-client.md#events-and-request-lifetime) and [Core facade](sdk-api.md#createcorefacade) |
56
56
  | Compose native Core dispatch, service lifecycle, and stdio hosting | [Native Core runtime](core-runtime.md) |
57
57
  | Run application-selected llama.cpp, Ollama or ONNX through Core | [Local AI through Core](local-ai.md) |
58
+ | Generate complete local PNG images with a retained native model | [Local image generation](local-image-generation.md) |
59
+ | Select FLUX.2 Klein 4B and its three complementary model resources | [FLUX.2 Klein 4B through Core](local-image-flux.md) |
60
+ | Compose independently loaded transcription and synthesis engines | [Native speech service](native-speech.md) |
61
+ | Edit an original PNG with a complete prompt and explicit strength | [Local image editing](local-image-editing.md) |
62
+ | Project complete stored model files into native working files | [Model assets through Core](model-assets.md) |
58
63
  | Retain a Nemotron model and diarize caller-fed audio streams | [Native speaker diarization](diarization.md) |
59
64
  | Persist application-selected preferences through Core | [Core preferences service](core-preferences.md) |
60
65
  | Read complete selected Git text without changing a checkout | [Git text snapshots](git-text-snapshot.md) |
@@ -223,6 +228,8 @@ Ollama, Wllama, Whisper, Kokoro, native, or cloud transport:
223
228
  | Run a caller-selected GGUF LLM locally | [`arcane-os/ai/browser-wasm`](ai/browser-wasm.md) | Browser secure context with WebAssembly and OPFS/DBOPFS; explicit CPU selection or WebGPU with full offload and no automatic CPU fallback. |
224
229
  | Run application-selected native llama.cpp/Ollama chat | [`arcane-os/ai/core-local`, `arcane-os/core/local-ai`](local-ai.md) | Explicit Core connection and selected native runtimes; installation, availability and loaded-model readiness remain distinct. |
225
230
  | Run a local ONNX graph with named tensors | [`arcane-os/local-ai/onnx`, `arcane-os/ai/core-onnx`](local-ai.md#native-onnx-sessions) | Retained native workers; browser access requires an available Core ONNX service. |
231
+ | Generate local images from complete prompts and selected model resources | [`arcane-os/local-ai/image`, `arcane-os/ai/core-image`](local-image-generation.md) | Prepared native image runtime; browser access requires its Core service. CPU Windows/Linux and Mac Metal/CPU paths have distinct actual host requirements. |
232
+ | Supply complete stored model members to a native engine | [`arcane-os/ai/core-model-assets`, `arcane-os/core/model-assets`](model-assets.md) | Available Core service; DBOPFS originals stay authoritative while native owners retain working files. |
226
233
  | Run caller-selected Whisper/Kokoro locally | [`arcane-os/ai/browser-speech`](ai/browser-speech.md) | Browser with DBOPFS, Web Locks, Workers and selected upstream sources; automatic WebNN NPU, WebGPU, then WASM loading, or an explicit backend. |
227
234
  | Use native browser recognition/voices or selected cloud TTS | [Speech provider choices](ai/browser-speech.md) | Native APIs depend on the browser and may use remote services; cloud TTS requires the application key and endpoint access. |
228
235
  | Send complete chat, System One or image requests without retained history | [`arcane-os/ai/twin-cloud`](ai/twin-cloud.md) | Node or browser with Fetch and explicit model/credentials; image results contain every returned image as a Blob. |
@@ -49,7 +49,7 @@ meaning and cardinality rules:
49
49
  | `--app` | app id or label | Workspace/app operations except shared scope and `verify-bundle`; optional diagnostic label for `mail serve`. |
50
50
  | `--apps-root` | `.` or `apps` | `new`, `init`; standalone setup defaults to the repository root. |
51
51
  | `--sdk-runtime-source` | SDK checkout directory | `dev` only; maps live SDK source through the selected browser destinations for that server process. |
52
- | `--local-ai` | comma-separated runtime IDs | `dev` only; adds `llama.cpp`, `ollama` and/or `onnx` requirements to application configuration and prepares missing runtimes alongside serving. See [local AI through Core](local-ai.md). |
52
+ | `--local-ai` | comma-separated runtime IDs | `dev` only; adds `llama.cpp`, `ollama`, `onnx` and/or `stable-diffusion.cpp` requirements to application configuration and prepares missing runtimes alongside serving. See [local AI through Core](local-ai.md). |
53
53
  | `--arcane-root` | directory | `doctor`, native `build`/`run`, `native-doctor`, `native-prepare` |
54
54
  | `--host` / `--port` | host / integer 0–65535 | Browser `dev`/`run` default to HTTPS at `127.0.0.1:8000`; `mail serve` defaults to HTTPS with HTTP/2 at `0.0.0.0:4433` and accepts an explicit bind host. |
55
55
  | `--http-port` | integer 0–65535 | Browser `dev`/`run` HTTP redirect listener; defaults to `0`, which selects an available port. |
@@ -375,6 +375,10 @@ arcane dev [--app <id>] [--public] [--http | --https] [--cert <file> --key <file
375
375
  reuse them. Available services and executables are reused; missing runtimes
376
376
  are installed inside the application while serving starts independently.
377
377
  Applications choose their model files and optional browser Core connection.
378
+ `--local-ai stable-diffusion.cpp` prepares the selected native image runtime;
379
+ configure its `models` separately in the application's runtime record.
380
+ The [image service](local-image-generation.md) reports installation and model
381
+ readiness independently, with complete PNG results and explicit cancellation.
378
382
  See [local AI through Core](local-ai.md) for configuration and native bundling.
379
383
 
380
384
  ### Lifecycle
@@ -67,7 +67,7 @@ current dispatcher and service state for a newly connected document, without
67
67
  restarting services. Repeated `connect()` calls on the same connection do not
68
68
  send another replay. See [runtime replay](core-runtime.md#state-and-frames).
69
69
 
70
- `client.invoke(method, parameters, {signal, timeoutMs})` returns the actual
70
+ `client.invoke(method, parameters, {signal, timeoutMs, onRequest})` returns the actual
71
71
  response result or rejects with `CoreError`. Parameters, result fields and
72
72
  event data retain their complete supplied content. JSON encoding belongs only
73
73
  to transports that require it; values crossing those transports must be
@@ -77,6 +77,14 @@ The compatibility facade retains its operation-specific timeouts and streaming
77
77
  callbacks. Streaming IDs and isolated-operation IDs are separate protocol
78
78
  correlation fields alongside the supplied request fields.
79
79
 
80
+ The optional `onRequest({requestId})` observer runs synchronously after the
81
+ client owns the request and before transport dispatch. It exposes the actual
82
+ Core correlation ID without adding fields to the supplied payload. A
83
+ pre-aborted request never calls the observer. A synchronous observer failure
84
+ rejects the request before sending; a returned promise is observed for errors
85
+ without delaying dispatch. If the observer cancels or closes the request,
86
+ the client does not subsequently send it.
87
+
80
88
  `Arcane.speech.synthesize(request, {signal})` forwards the optional cancellation
81
89
  signal through the same request lifetime. Existing one-argument calls retain
82
90
  the 180,000 ms timeout and pass the complete request unchanged. A pre-aborted
@@ -87,12 +95,13 @@ registered speech service and its engine; the facade supplies no speech engine.
87
95
  call and normalizes cancellation to `AbortError` with
88
96
  `ARCANE_AI_REQUEST_ABORTED`, preserving the original error as its cause.
89
97
 
90
- `Arcane.speech.transcribe(request, {signal})` forwards cancellation through the
98
+ `Arcane.speech.transcribe(request, {signal, onRequest})` forwards cancellation through the
91
99
  same request lifetime and retains its 180,000 ms timeout and complete request.
92
100
  `AI.fetchSTT(audio, signal)` carries that signal into the native call. A
93
101
  pre-aborted signal sends no transcription request; an in-flight abort sends
94
102
  `request.cancel` and suppresses late responses. The registered transcription
95
103
  service owns interruption and release of its actual engine operation.
104
+ Its optional request observer uses the same pre-dispatch correlation contract.
96
105
 
97
106
  ## Current-window theme
98
107
 
@@ -248,8 +248,9 @@ to the artifact root. Only the explicitly configured entry imports
248
248
  `createLocalAIService` from `arcane-os/core/local-ai`. It resolves those bundled
249
249
  locations against the installed artifact and supplies them in the launch
250
250
  context's `runtimes` array, alongside `appRoot`, before applying explicit launch
251
- configuration. It passes the complete authored `native.localAI` record to the
252
- factory. Applications without that selection have no generated local-AI import
251
+ configuration. It passes chat/ONNX requirements to that factory and routes
252
+ selected image requirements to their separate service as described below.
253
+ Applications without that selection have no generated local-AI import
253
254
  or service. Availability of a particular engine belongs to the selected
254
255
  local-AI installer and service; a generic ONNX runtime is not a speech model.
255
256
 
@@ -260,6 +261,42 @@ service exposes retained worker sessions through `onnx.load/run/unload/status`;
260
261
  model files remain caller-selected application resources. See
261
262
  [native ONNX sessions](local-ai.md#native-onnx-sessions).
262
263
 
264
+ Selected `stable-diffusion.cpp` additionally composes
265
+ `createLocalImageService` from `arcane-os/core/image` and one shared
266
+ `createModelAssetService` from `arcane-os/core/model-assets`. The image factory
267
+ receives the full authored selection plus that same model-assets instance.
268
+ Library, Koffi binding and variant paths resolve from the artifact root;
269
+ ordinary browser imports use `arcane-os/ai/core-image` and
270
+ `arcane-os/ai/core-model-assets` through the managed import map.
271
+
272
+ The runtime bundle preserves the complete selected native distribution and
273
+ binding tree. It does not load or download a model. Original model URL
274
+ descriptors remain available for preparation after launch; runtime-contained
275
+ model paths relocate with the artifact. An external native working path
276
+ reports its portability incompatibility. Supply those files through the
277
+ application's native resources or the shared
278
+ [stored-model projection](model-assets.md). Native use retains that projection
279
+ until actual unload or shutdown completes. See
280
+ [local image generation](local-image-generation.md) for selection, complete
281
+ results and CPU/Metal platform boundaries.
282
+
283
+ ### Injected native speech engines
284
+
285
+ An application-owned service factory can return
286
+ `createSpeechService({stt,tts,signal})` from `arcane-os/core/speech`, supplying
287
+ either role or both. Include that factory through the existing
288
+ `native.services` and `package.nativeResources` composition above. The host
289
+ constructs its selected engines; this shared service installs no engine,
290
+ downloads no model and selects no browser or native speech default.
291
+
292
+ Core starts both configured role loads independently and remains responsive.
293
+ `speech.status` and replaying service subscriptions report actual loaded-model
294
+ state separately for transcription and synthesis. Complete requests/results
295
+ are forwarded unchanged. Request cancellation reaches its engine independently
296
+ of the service lifetime; `close`/`drain` abort and join both engines and their
297
+ pending work. Engines must settle cancelled inference before Core reaches
298
+ service cleanup. See the [engine interface, progress and shutdown contract](native-speech.md).
299
+
263
300
  ## Windows executable
264
301
 
265
302
  The ordinary application command is:
@@ -293,12 +330,24 @@ host output; downstream applications use the published package and matching
293
330
  release asset. `doctor()` reports the selected prerequisites and missing files;
294
331
  it does not download the host or probe the installed WebView runtime.
295
332
 
296
- The assembled directory contains `Arcane.exe`, the unchanged `app/` payload,
297
- Core runtime and semantic `arcane-native.json`. Launch `Arcane.exe` on Windows
298
- x64 with the Microsoft Edge WebView2 Runtime installed. It opens the selected
333
+ The assembled directory contains the app-named launcher, its matching
334
+ `.exe.config`, the unchanged `app/` payload, Core runtime and semantic
335
+ `arcane-native.json`. `manifest.host.executable` is the authoritative relative
336
+ launcher name for shortcuts and direct launch. Assembly uses
337
+ `appDescriptor.displayName` plus `.exe`, such as `Moon Cheese Hotline.exe`;
338
+ low-level compositions without a nonempty string display name use the app ID.
339
+ Windows-reserved filename characters and controls become underscores, and
340
+ reserved DOS device basenames receive an underscore prefix. Supported Unicode,
341
+ case and spaces remain; the original descriptor and title are unchanged.
342
+ The reusable host archive/cache retains `Arcane.exe` and `Arcane.exe.config`;
343
+ the internal `runtime/ArcaneCore.exe` also keeps its original name.
344
+
345
+ Launch the manifest-selected executable on Windows x64 with the Microsoft
346
+ Edge WebView2 Runtime installed. It opens the selected
299
347
  app in WebView2 and owns its framed connection to the bundled Core process.
300
348
  `verify()` observes the assembled files and manifest; it does not execute the
301
- window or prove application behavior. `run()` launches the executable and
349
+ window or prove application behavior. `run()` reads the saved manifest and
350
+ launches that executable, so existing generic-name artifacts remain usable. It
302
351
  observes complete diagnostics and exit. Cancelling that operation closes its
303
352
  input, allowing the window and accepted Core service work to drain without a
304
353
  forced process termination.
@@ -311,7 +360,7 @@ into a derived `runtime/arcane-app.ico` with 16, 32, 48 and 256-pixel images.
311
360
  Aspect ratio and transparency are preserved. An ICO selection keeps its
312
361
  authored image set. The original application asset remains unchanged.
313
362
 
314
- The provider embeds the selected images in the copied `Arcane.exe` and records
363
+ The provider embeds the selected images in the copied app-named executable and records
315
364
  `manifest.host.icon` and `manifest.host.executableIcon:true`. It replaces the
316
365
  executable's main icon group while preserving other groups, languages, resources
317
366
  and file content. Conversion uses Node standard capabilities on every assembly
@@ -370,7 +419,7 @@ for the facade and browser behavior.
370
419
  For explicit user-selected workspace/state locations, launch:
371
420
 
372
421
  ```sh
373
- Arcane.exe --arcane-launch-config path/to/launch.json
422
+ "Moon Cheese Hotline.exe" --arcane-launch-config path/to/launch.json
374
423
  ```
375
424
 
376
425
  The complete JSON object reaches the service factories as their second
@@ -0,0 +1,149 @@
1
+ # Native repository workspaces
2
+
3
+ `arcane-os/core/repositories` owns a persistent native location for connected
4
+ repositories, separate from application code and application preferences.
5
+ Applications choose their connection names, remotes, branches, files and Core
6
+ methods. Importing the module and constructing an owner perform no I/O.
7
+
8
+ ## Persistent locations
9
+
10
+ `resolveArcaneDataPaths({dataRoot}={})` returns absolute
11
+ `{dataRoot,repositoriesRoot}` paths without creating directories:
12
+
13
+ | Host | Default dataRoot | repositoriesRoot |
14
+ |---|---|---|
15
+ | Windows | `%LOCALAPPDATA%/ArcaneData`, or `~/AppData/Local/ArcaneData` when that variable is empty | `<dataRoot>/Repos` |
16
+ | Linux | `$XDG_DATA_HOME/ArcaneData` when XDG_DATA_HOME is absolute, otherwise `~/.local/share/ArcaneData` | `<dataRoot>/Repos` |
17
+ | macOS | `~/Library/Application Support/ArcaneData` | `<dataRoot>/Repos` |
18
+ | Android or another adapted host | Explicit `dataRoot` supplied by the host, such as its app files directory followed by `ArcaneData` | `<dataRoot>/Repos` |
19
+
20
+ An explicit `dataRoot` selects that directory directly; the SDK does not append
21
+ another `ArcaneData`. Relative explicit paths resolve from the process working
22
+ directory. Unsupported default platforms report `ARCANE_DATA_ROOT_REQUIRED`.
23
+ The Android host also supplies Git/process execution through the existing
24
+ process-adapter contract; this module does not install Git or choose shared
25
+ Android storage.
26
+
27
+ The factory's first actual operation creates necessary parent directories.
28
+ No existing data is moved, copied, deleted, renamed or migrated. `appRoot`,
29
+ `stateRoot`, preferences, OPFS and the existing CLI/workspace defaults remain
30
+ independent and unchanged.
31
+
32
+ ## One connected working checkout
33
+
34
+ ```javascript
35
+ import {createRepositoryWorkspace} from 'arcane-os/core/repositories';
36
+
37
+ const repository = createRepositoryWorkspace({
38
+ name: 'moon-cheese-dispatches',
39
+ remote: applicationConnection.remote,
40
+ branch: applicationConnection.branch
41
+ });
42
+
43
+ const opened = await repository.open({signal});
44
+ // opened.directory is <ArcaneData>/Repos/moon-cheese-dispatches.
45
+ const status = await repository.status({signal});
46
+ await repository.close();
47
+ ```
48
+
49
+ `createRepositoryWorkspace({name,directory,dataRoot,remote,branch,onEvent,run}={})`
50
+ returns `{directory,open,status,pull,push,close,drain,dispose}`. The `directory`
51
+ property is the absolute selected working path.
52
+
53
+ - Omit `directory` to select `<repositoriesRoot>/<name>`. The application supplies
54
+ one nonempty directory name for each distinct connection; the SDK neither
55
+ derives it from a remote nor maintains a connection registry. Names are one
56
+ component, excluding `.`/`..` and slash/backslash separators. Choose distinct
57
+ names under the host filesystem's ordinary case rules.
58
+ - Supply `directory` to use an existing application-selected path instead.
59
+ This takes precedence over `name` and `dataRoot`; relative paths resolve from
60
+ the process working directory. The path is not relocated or rewritten.
61
+ - `remote` is required only when a missing or empty destination needs cloning.
62
+ `branch`, when supplied, is passed unchanged to Git's `clone --branch` option;
63
+ otherwise Git selects the remote's default branch. Existing checkouts keep
64
+ their own branch, remote, tracked files, untracked files and local changes.
65
+ - `onEvent` and optional `run` use the existing SDK process owner. The default
66
+ adapter is `runProcess`; Git must be available on PATH. Credentials and
67
+ authentication remain with Git and the native host. The SDK adds no download,
68
+ credential store, polling, network retry or process supervisor.
69
+
70
+ All operation methods accept `{signal}={}` and return promises:
71
+
72
+ | Method | Result and side effect |
73
+ |---|---|
74
+ | `open` | For a missing/empty destination, runs one clone and returns `{directory,cloned:true,stdout,stderr}` with complete process output. For an existing working repository root, returns `{directory,cloned:false}` after read-only inspection. Later opens on that owner reuse preparation. |
75
+ | `status` | Prepares the checkout if needed, then returns the existing `repositoryStatus` result unchanged. |
76
+ | `pull` | Prepares the checkout if needed, then runs the existing clean-checkout, fast-forward-only `repositoryPull` operation unchanged. |
77
+ | `push` | Prepares the checkout if needed, then runs the existing `repositoryPush` operation unchanged, preserving its support for unrelated uncommitted working files. |
78
+ | `close`, `drain`, `dispose` | The same idempotent operation: stop accepting new calls and await accepted work and its process/event cleanup. They retain the repository on disk. |
79
+
80
+ Opening an existing repository never pulls, switches branches, resets, changes
81
+ its remote or rewrites files. A nonempty destination that is a bare repository,
82
+ a subdirectory of another checkout, or ordinary non-repository data is left
83
+ untouched and reports its Git error or `ARCANE_REPOSITORY_DIRECTORY_INVALID`.
84
+ A failed or cancelled clone reports the actual failure; any remaining directory
85
+ is retained for application-owned inspection. There is no automatic deletion or
86
+ destructive retry. Filesystem failures and complete Git diagnostics propagate.
87
+
88
+ ## Ownership, concurrency and shutdown
89
+
90
+ Calls targeting the same resolved path spelling in one Node process run in
91
+ acceptance order, including separate owners selecting that path. Windows keys
92
+ are case-insensitive. The queue does not resolve symlink aliases or macOS case
93
+ variants; applications use one consistent path for a shared connection.
94
+ This prevents overlapping Git/index writes and duplicate successful cloning.
95
+ Different directories proceed
96
+ independently. Applications coordinate separate processes and their own direct
97
+ file/Git writes; this module does not create a daemon or cross-process lock.
98
+
99
+ A pre-aborted call starts no work. A queued aborted operation does not run when
100
+ its turn arrives. Active cancellation reaches the existing process owner, which
101
+ terminates its owned process tree and joins complete output/event cleanup.
102
+ Shutdown drains accepted operations rather than deleting data or terminating
103
+ the host early. Calls after close reject with `CORE_CLOSING`; a failed operation
104
+ still pending when close begins rejects that drain through an `AggregateError`.
105
+ The caller retains each operation's complete result or failure separately.
106
+
107
+ The cold path is one selected connection, one parent-directory creation and one
108
+ Git clone. Opening an existing checkout uses one read-only Git command. A
109
+ prepared owner's status/pull/push use their existing repository operation graph.
110
+ There is no scan across applications, connections, models or platforms. Git
111
+ progress, process-starting/completion, heartbeat and cancellation events use
112
+ the existing `onEvent` owner with complete output and backpressure.
113
+ An awaited event callback must not await another operation or shutdown for the
114
+ same directory, including calls through another workspace owner: that operation
115
+ needs the observing callback to finish. Schedule such follow-up without awaiting
116
+ it inside that callback, and retain/observe its promise at the application owner.
117
+
118
+ Compose this owner inside an application-selected Core service. Bind only the
119
+ application's chosen methods, pass each request's `context.signal`, and return
120
+ `drain: repository.drain` and `dispose: repository.dispose` from that service.
121
+ Keep initialization at the repository operation that needs it; page rendering
122
+ and unrelated services do not wait for a clone. This module installs no browser
123
+ RPC, chooses no application service and changes no Core launch configuration.
124
+
125
+ ## Bare snapshots stay separate
126
+
127
+ [`createGitTextSnapshot`](git-text-snapshot.md) continues to require its explicit
128
+ dedicated bare `cacheDirectory`. It neither becomes a working checkout nor
129
+ changes existing callers' caches. A new native caller can place that distinct
130
+ cache under the shared location without changing the snapshot contract:
131
+
132
+ ```javascript
133
+ import path from 'node:path';
134
+ import {createGitTextSnapshot} from 'arcane-os';
135
+ import {resolveArcaneDataPaths} from 'arcane-os/core/repositories';
136
+
137
+ const {repositoriesRoot} = resolveArcaneDataPaths();
138
+ const snapshot = createGitTextSnapshot({
139
+ cacheDirectory: path.join(repositoriesRoot, 'moon-cheese-reader-cache'),
140
+ remote: applicationConnection.remote,
141
+ ref: applicationConnection.ref,
142
+ selectPath: applicationSelectPath
143
+ });
144
+ ```
145
+
146
+ Never assign the same directory to a bare snapshot and a writable workspace.
147
+ Applications retain remote/ref selection, document parsing, scores, messages,
148
+ saved connection state and refresh policy. Existing explicit repository paths
149
+ continue to operate where they already are.