arcane-os 0.90.0 → 0.92.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.
@@ -1044,6 +1044,25 @@ ordinary browser output remain unchanged. See
1044
1044
  [native-module package output](protocols.md#native-module-package-output)
1045
1045
  for resource handling and the static transformation boundary.
1046
1046
 
1047
+ `browserDecisions` defaults to `false`. Explicit `browserDecisions: true`
1048
+ acquires the bundled Transformers.js 4.3.0 entry, matching ONNX Runtime
1049
+ 1.31.0-dev.20260914-8d85527a0 asyncify module/WASM and both licenses into
1050
+ the package stage beside the selected SDK `ai/browser-decisions.mjs`, under
1051
+ `decisions-runtime/`. Installed-package routes retain their configured
1052
+ dependency path, including aliases; source and installed dependencies remain
1053
+ unchanged, with no workspace-root `arcane/` projection. The selected SDK decision
1054
+ module must be included in the package. Acquisition happens after native-module
1055
+ and asset rewriting, preserving upstream content unchanged in both module
1056
+ formats. The distribution joins the returned and release-manifest inventories
1057
+ and any enabled PWA's ordinary offline selection. The default and dry runs
1058
+ perform no optional acquisition; dry runs report selected inputs. Repeat this
1059
+ option on each package build that should acquire the closure. Cancellation and
1060
+ HTTP or observer failures abort/join acquisition before stage cleanup and
1061
+ preserve previous output. The existing `workspace.decisions.started` and
1062
+ `workspace.decisions.progress` events report file progress. See the
1063
+ [extension-local decision guide](ai/browser-decisions.md#extension-local-executables-manifest-v3)
1064
+ for `runtime.local: true`, upstream versions and complete error details.
1065
+
1047
1066
  An operation may override `outputDirectory` without changing the saved app
1048
1067
  configuration. For example, package a complete application beneath an
1049
1068
  application-owned extension manifest and launcher:
@@ -1875,6 +1894,11 @@ module/WASM and license files from their upstream distributions into
1875
1894
  `transformersVersion`, `onnxRuntimeVersion` and `files` under
1876
1895
  `workspaceRuntime.browserDecisions`. The default `false` performs no optional
1877
1896
  acquisition. Select this option on each refresh that should retain those files.
1897
+ For applications with installed-package routes, use
1898
+ `packageApp({workspaceRoot, appId, browserDecisions: true})` to place the
1899
+ distribution beside the actual deployed SDK module. This physical materializer
1900
+ continues to own only the separate `arcane/` projection; it does not populate or
1901
+ modify `node_modules`.
1878
1902
  The [extension-local decision guide](ai/browser-decisions.md#extension-local-executables-manifest-v3)
1879
1903
  describes `runtime.local: true`, complete resource ownership and MV3 usage.
1880
1904
 
@@ -5385,7 +5409,7 @@ a dedicated bare Git cache. It does not create or alter a working checkout.
5385
5409
  ### Signature, lifecycle, and result
5386
5410
 
5387
5411
  ```text
5388
- createGitTextSnapshot({cacheDirectory,remote,remoteBase,ref,selectPath,gitIdentity,onEvent,run=runProcess}={})
5412
+ createGitTextSnapshot({cacheDirectory,remote,remoteBase,ref,selectPath,allowUnborn=false,gitIdentity,onEvent,run=runProcess}={})
5389
5413
  ```
5390
5414
 
5391
5415
  Import from `arcane-os`. The application owns the cache location, remote, ref,
@@ -5397,6 +5421,14 @@ await accepted refresh/process cleanup. Errors remain observable instead of
5397
5421
  returning stale or partial success. See [Git text snapshots](git-text-snapshot.md)
5398
5422
  for complete inputs, text semantics, errors, events and Core service composition.
5399
5423
 
5424
+ Optional `allowUnborn:true` observes the complete remote advertisement on every
5425
+ acquisition. Only successful empty output returns
5426
+ `{revision:null,files:[],unborn:true}`; committed results add `unborn:false` and
5427
+ retain the actual commit even for an empty tree. Any advertised HEAD, branch
5428
+ or tag continues through ordinary selected-ref fetch; missing refs and actual
5429
+ Git failures remain errors. Omitted/false preserves the prior result and commands.
5430
+ See [unborn remotes](git-text-snapshot.md#unborn-remotes).
5431
+
5400
5432
  Optional `remoteBase` explicitly selects `remote` as a local filesystem locator.
5401
5433
  Only its Git fetch argument is derived using `path.resolve(remoteBase, remote)`,
5402
5434
  once at construction, independently of the cache location and later changes to
@@ -5452,6 +5484,28 @@ once and stdin remains open until cancellation or a callback/input failure
5452
5484
  requests shutdown. On Microsoft NT, `npm` and `npx` are normalized to their Node
5453
5485
  CLI entrypoints.
5454
5486
 
5487
+ For the literal `git` command on Windows, the default runner reads Git for
5488
+ Windows' registered `InstallPath` in the current-user and machine registry
5489
+ views. When that installation's `cmd/git.exe` exists, its `cmd` directory is
5490
+ appended only to this child's effective PATH. Existing entries and native
5491
+ command lookup retain priority; duplicate `Path`/`PATH` spellings follow Node's
5492
+ lexical selection. Other environment fields, explicit executable paths,
5493
+ custom process adapters, other commands and other platforms keep their existing
5494
+ behavior. No global environment or registry setting is changed, and no Git
5495
+ download, installation or command retry occurs.
5496
+
5497
+ One successful location is retained in memory for this process while its
5498
+ executable remains present. A removed executable triggers fresh discovery;
5499
+ absent, failed and cancelled lookups are not retained. Concurrent cold callers
5500
+ own independent discovery and cancellation. The standard Windows registry
5501
+ helper uses the existing process owner; its lifecycle callbacks have
5502
+ `process.git.discovery.*` event names, and its captured metadata is separate
5503
+ from the requested command's output. Missing registration leaves ordinary
5504
+ lookup unchanged. Discovery failure emits `process.git.discovery.unavailable`
5505
+ with the complete error before ordinary lookup continues. Cancellation or an
5506
+ event-callback failure stops the operation before Git starts. Normal Git
5507
+ errors and missing-working-directory errors remain actual command failures.
5508
+
5455
5509
  An `AsyncIterable` input instead feeds stdin with awaited writes and closes it
5456
5510
  when the producer finishes. Its `return()` must cooperate with cancellation of
5457
5511
  an outstanding `next()`; the process owner drains both input and output work.
@@ -8376,7 +8430,7 @@ explicit existing path. The application owns the remote, branch and Core API.
8376
8430
  ### Signature and result
8377
8431
 
8378
8432
  ```text
8379
- createRepositoryWorkspace({name,directory,dataRoot,remote,remoteBase,branch,longPaths,cloneIdentity,gitIdentity,onEvent,run=runProcess}={})
8433
+ createRepositoryWorkspace({name,directory,dataRoot,remote,remoteBase,branch,initialBranch,longPaths,cloneIdentity,gitIdentity,onEvent,run=runProcess}={})
8380
8434
  ```
8381
8435
 
8382
8436
  Returns `{directory,open,status,configuration,pull,push,write,close,drain,dispose}`. Construction does
@@ -8387,6 +8441,17 @@ work and preserves the checkout. No CLI cwd, launch state, preference, snapshot
8387
8441
  cache or existing user-data location changes. See the [complete inputs, results,
8388
8442
  errors and lifecycle](core-repositories.md#one-connected-working-checkout).
8389
8443
 
8444
+ Optional `initialBranch` selects `refs/heads/<initialBranch>` only after a new
8445
+ clone, successful complete empty remote advertisement, explicit local
8446
+ initial-state observation and a successful empty local-ref listing. Any local
8447
+ ref supplied by a Git template or hook remains unchanged. Existing destinations and committed/advertised
8448
+ clones keep their branches; `branch` still means Git's existing-branch/tag clone
8449
+ selection. New-clone `open` results with this option add complete ordered
8450
+ preparation `outputs`; subsequent failures retain completed outputs and their
8451
+ original cause. Omission adds no command or result field. See
8452
+ [first-publication composition](core-repositories.md#first-publication-from-an-unborn-remote)
8453
+ for the direct first commit/push without an implicit pull.
8454
+
8390
8455
  Optional factory `remoteBase` explicitly selects the initial-clone `remote` as
8391
8456
  a local filesystem locator. Only its Git argument is derived through the host's
8392
8457
  native `path.resolve(remoteBase, remote)`, once at construction. Relative bases,
@@ -8422,13 +8487,17 @@ omitted fields remain inherited. Username remains a credential hint, with
8422
8487
  authentication owned by ordinary Git and its configured helper.
8423
8488
 
8424
8489
  `configuration({signal})` observes an existing working root without clone,
8425
- initialization or fetch. It returns `{repositoryRoot,headRef,origin,upstream}`:
8490
+ initialization or fetch. It returns `{repositoryRoot,headRef,revision,unborn,origin,upstream}`:
8426
8491
  full symbolic HEAD (including unborn, null when detached), origin URL/pushURL
8427
8492
  arrays and current branch remote/merge/URL/pushURL arrays. Unset, empty and
8428
- repeated configuration values remain distinct. These are ordinary configured
8429
- values, not authentication or endpoint proof, and are not atomic with later
8430
- operations. Raw stdout is decoded without replacement; unrepresentable text
8431
- reports `ARCANE_GIT_CONFIGURATION_NOT_TEXT` with full diagnostics.
8493
+ repeated configuration values remain distinct. `revision:null,unborn:true`
8494
+ comes only from Git's explicit porcelain-v2 initial state; committed and
8495
+ detached states retain their current revision with `unborn:false`. Missing
8496
+ branch-state output reports `ARCANE_REPOSITORY_HEAD_UNAVAILABLE`. These are
8497
+ ordinary configured values and local branch observations, not authentication
8498
+ or endpoint proof, and are not atomic with later operations. Raw stdout is
8499
+ decoded without replacement; unrepresentable text reports
8500
+ `ARCANE_GIT_CONFIGURATION_NOT_TEXT` with full diagnostics.
8432
8501
 
8433
8502
  `pull({target,signal})`, `push({target,signal})` and
8434
8503
  `write({files:[{path,content}],message,target,signal})` accept optional
@@ -9012,14 +9081,22 @@ directory and complete member files.
9012
9081
 
9013
9082
  `current()` returns `{closing,projections}`. `retain(id)` accepts a completed
9014
9083
  projection and returns `{id,directory,members,release}` for a native owner.
9015
- Native `prepare({id,workingDirectory,members,signal,onProgress})` accepts
9016
- ordered `{path,url}` members and returns their ready projection. Explicit calls
9017
- stream complete upstream responses through the same file owner; startup
9018
- downloads nothing. Independent members transfer concurrently and progress
9019
- reports phases and completed files. `release(id)` relinquishes preparation
9020
- ownership; cancellation, release and disposal join fetches and writes before
9021
- cleanup. Native retain handles keep completed files alive until actual engine
9022
- release. See [native preparation](model-assets.md#native-ownership).
9084
+ Native `prepare({id,workingDirectory,members,signal,onProgress,refresh=false})`
9085
+ accepts ordered `{path,url}` members and returns their ready projection.
9086
+ Complete native acquisitions persist beneath `workingDirectory/model-assets/`
9087
+ through unload, disposal and restart; ordinary calls reuse the exact complete
9088
+ ordered source selection without a network freshness check. Explicit
9089
+ `refresh:true` acquires a separate complete set without replacing active files.
9090
+ Independent members transfer concurrently and progress reports phases and
9091
+ completed files. Matching same-process preparations share acquisition with
9092
+ independent callbacks and cancellation; the last interested cancellation joins
9093
+ unfinished I/O and removes only that attempt. Separate processes may acquire
9094
+ the same selection independently. Startup downloads nothing.
9095
+ `release(id)` relinquishes live preparation ownership. Native retains continue
9096
+ through actual engine release; completed native acquisitions remain stored.
9097
+ Browser `open/write/complete` projections retain their temporary lifetime and
9098
+ are removed only after all native uses end. See
9099
+ [native preparation](model-assets.md#native-ownership).
9023
9100
  `dispose()` releases preparation ownership and joins file writes, closes and
9024
9101
  all native retain lifetimes before cleanup. The native owner releases its
9025
9102
  handle only after its actual context/worker use ends. Original stored model
@@ -10146,7 +10223,9 @@ Cancellation terminates that client's Worker and rejects its in-flight work.
10146
10223
  No decisions are inserted into chat history or durable storage.
10147
10224
 
10148
10225
  For explicitly selected extension-local execution, supply `runtime: {local:
10149
- true}` after materializing with `browserDecisions: true`. The SDK directly
10226
+ true}` after `packageApp({workspaceRoot, appId, browserDecisions: true})` for
10227
+ installed-package routes, or after opting into the existing physical runtime
10228
+ materializer. The SDK directly
10150
10229
  imports its deployment-local `decisions-runtime/transformers.min.js` and
10151
10230
  matched asyncify module/WASM. Explicit `runtime.moduleUrl` and
10152
10231
  `runtime.wasmPaths: {mjs, wasm}` may select other compatible files in that same
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-os",
3
- "version": "0.90.0",
3
+ "version": "0.92.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",
@@ -0,0 +1,95 @@
1
+ import Is from 'strong-type';
2
+ import {mkdir, writeFile} from 'node:fs/promises';
3
+ import path from 'node:path';
4
+
5
+ const is = new Is(false);
6
+
7
+ function throwIfAborted(signal) {
8
+ if (!signal?.aborted) return;
9
+ const error = signal.reason instanceof Error ? signal.reason : new Error('Operation cancelled.');
10
+ error.code = error.code || 'ARCANE_CANCELLED';
11
+ throw error;
12
+ }
13
+
14
+ async function emit(onEvent, event) {
15
+ if (is.function(onEvent)) await onEvent(event);
16
+ }
17
+
18
+ export async function materializeBrowserDecisions(destination, signal, onEvent) {
19
+ const transformers = 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@4.3.0/';
20
+ const onnx = 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.31.0-dev.20260914-8d85527a0/';
21
+ const files = [
22
+ {name: 'transformers.min.js', url: `${transformers}dist/transformers.min.js`},
23
+ {name: 'ort-wasm-simd-threaded.asyncify.mjs', url: `${onnx}dist/ort-wasm-simd-threaded.asyncify.mjs`},
24
+ {name: 'ort-wasm-simd-threaded.asyncify.wasm', url: `${onnx}dist/ort-wasm-simd-threaded.asyncify.wasm`},
25
+ {name: 'TRANSFORMERS-LICENSE', url: `${transformers}LICENSE`},
26
+ {name: 'ONNX-RUNTIME-LICENSE', url: `${onnx}LICENSE`}
27
+ ];
28
+ const controller = new AbortController();
29
+ function cancelDistribution() {
30
+ controller.abort(signal.reason);
31
+ }
32
+ signal?.addEventListener('abort', cancelDistribution, {once: true});
33
+ if (signal?.aborted) cancelDistribution();
34
+ let completed = 0;
35
+ try {
36
+ throwIfAborted(controller.signal);
37
+ await emit(
38
+ onEvent,
39
+ {type: 'workspace.decisions.started', completed, total: files.length}
40
+ );
41
+ throwIfAborted(controller.signal);
42
+ await mkdir(destination, {recursive: true});
43
+ async function acquireDistributionFile(file) {
44
+ try {
45
+ throwIfAborted(controller.signal);
46
+ const response = await fetch(file.url, {signal: controller.signal});
47
+ const content = new Uint8Array(await response.arrayBuffer());
48
+ if (!response.ok) {
49
+ const error = new Error(`Browser decision distribution returned HTTP ${response.status} ${response.statusText}.`);
50
+ error.code = 'ARCANE_DECISION_DISTRIBUTION_DOWNLOAD_FAILED';
51
+ error.response = {
52
+ url: response.url,
53
+ status: response.status,
54
+ statusText: response.statusText,
55
+ headers: [...response.headers],
56
+ content
57
+ };
58
+ throw error;
59
+ }
60
+ throwIfAborted(controller.signal);
61
+ // Upstream distribution content is opaque, including its own
62
+ // imports and license text. No SDK source rewriting applies.
63
+ await writeFile(path.join(destination, file.name), content);
64
+ throwIfAborted(controller.signal);
65
+ completed += 1;
66
+ await emit(
67
+ onEvent,
68
+ {type: 'workspace.decisions.progress', file: file.name, url: file.url, completed, total: files.length}
69
+ );
70
+ } catch (error) {
71
+ controller.abort(error);
72
+ throw error;
73
+ }
74
+ }
75
+ // One fixed distribution, acquired once for the selected projection or
76
+ // package; no model/app/architecture multiplier or installation script.
77
+ const outcomes = await Promise.allSettled(files.map(acquireDistributionFile));
78
+ const failures = new Set();
79
+ for (const outcome of outcomes) {
80
+ if (outcome.status === 'rejected') failures.add(outcome.reason);
81
+ }
82
+ if (failures.size === 1) throw [...failures][0];
83
+ if (failures.size > 1) {
84
+ throw new AggregateError([...failures], 'Browser decision distribution acquisition failed.');
85
+ }
86
+ throwIfAborted(controller.signal);
87
+ } finally {
88
+ signal?.removeEventListener('abort', cancelDistribution);
89
+ }
90
+ return {
91
+ transformersVersion: '4.3.0',
92
+ onnxRuntimeVersion: '1.31.0-dev.20260914-8d85527a0',
93
+ files: files.map(function distributionFilename(file) { return file.name; })
94
+ };
95
+ }
@@ -5,7 +5,7 @@ import Is from 'strong-type';
5
5
  import {ArcaneError, throwIfAborted} from '../errors.mjs';
6
6
  import {runProcess} from '../process.mjs';
7
7
  import {captureRepositoryRemote, captureRepositoryTarget, repositoryConfiguration, pullRepositoryTarget, pushRepositoryTarget,
8
- repositoryPushArguments, repositoryStatus} from '../repository.mjs';
8
+ repositoryHeadArguments, repositoryHeadState, repositoryPushArguments, repositoryStatus} from '../repository.mjs';
9
9
  import {createGitIdentityRunner} from '../git-identity.mjs';
10
10
 
11
11
  export {readGitIdentity} from '../git-identity.mjs';
@@ -45,7 +45,7 @@ export function resolveArcaneDataPaths({dataRoot} = {}) {
45
45
 
46
46
  /** One connected checkout, composed into an application's own Core service. */
47
47
  export function createRepositoryWorkspace(
48
- {name, directory, dataRoot, remote, remoteBase, branch, longPaths, cloneIdentity = {}, gitIdentity, onEvent, run = runProcess} = {}
48
+ {name, directory, dataRoot, remote, remoteBase, branch, initialBranch, longPaths, cloneIdentity = {}, gitIdentity, onEvent, run = runProcess} = {}
49
49
  ) {
50
50
  let selected = directory;
51
51
  if (selected === undefined) {
@@ -59,6 +59,12 @@ export function createRepositoryWorkspace(
59
59
  if (remote !== undefined) requireString(remote, 'remote');
60
60
  const remoteArgument = captureRepositoryRemote(remote, remoteBase);
61
61
  if (branch !== undefined) requireString(branch, 'branch');
62
+ if (initialBranch !== undefined) {
63
+ requireString(initialBranch, 'initialBranch');
64
+ if (!initialBranch.isWellFormed() || initialBranch.includes('\0')) {
65
+ throw new TypeError('initialBranch must be text representable as a native process argument.');
66
+ }
67
+ }
62
68
  if (longPaths !== undefined && !is.boolean(longPaths)) {
63
69
  throw new TypeError('longPaths must be a boolean when supplied.');
64
70
  }
@@ -126,9 +132,60 @@ export function createRepositoryWorkspace(
126
132
  arguments_,
127
133
  {cwd: path.dirname(repositoryDirectory), signal, onEvent}
128
134
  );
135
+ let outputs;
136
+ if (initialBranch !== undefined) {
137
+ const options = {cwd: repositoryDirectory, signal, onEvent};
138
+ outputs = [];
139
+ function completed(operation, observation) {
140
+ outputs.push({operation, stdout: observation.stdout, stderr: observation.stderr,
141
+ code: observation.code, signal: observation.signal ?? null});
142
+ }
143
+ completed('clone', result);
144
+ try {
145
+ throwIfAborted(signal);
146
+ const advertised = await prepareRun('git', ['ls-remote', '--symref', '--', remoteArgument],
147
+ {cwd: path.dirname(repositoryDirectory), signal, onEvent});
148
+ completed('observeRemote', advertised);
149
+ throwIfAborted(signal);
150
+ if (advertised.code !== 0) {
151
+ throw new ArcaneError('ARCANE_OPERATION_FAILED', 'Git remote observation failed.', {details: advertised});
152
+ }
153
+ if (advertised.stdout === '') {
154
+ const state = await prepareRun('git', [...repositoryHeadArguments], options);
155
+ completed('observeHead', state);
156
+ throwIfAborted(signal);
157
+ if (state.code !== 0) {
158
+ throw new ArcaneError('ARCANE_OPERATION_FAILED', 'Git branch state observation failed.', {details: state});
159
+ }
160
+ if (repositoryHeadState(state.stdout, state).unborn) {
161
+ const references = await prepareRun('git', ['for-each-ref', '--format=%(refname)'], options);
162
+ completed('observeRefs', references);
163
+ throwIfAborted(signal);
164
+ if (references.code !== 0) {
165
+ throw new ArcaneError('ARCANE_OPERATION_FAILED', 'Git local ref observation failed.', {details: references});
166
+ }
167
+ // Git templates or hooks can supply local refs even
168
+ // when the remote and this checkout's HEAD are unborn.
169
+ if (references.stdout === '') {
170
+ const selection = await prepareRun('git', ['symbolic-ref', 'HEAD', `refs/heads/${initialBranch}`], options);
171
+ completed('selectInitialBranch', selection);
172
+ throwIfAborted(signal);
173
+ if (selection.code !== 0) {
174
+ throw new ArcaneError('ARCANE_OPERATION_FAILED', 'Git initial branch selection failed.', {details: selection});
175
+ }
176
+ }
177
+ }
178
+ }
179
+ } catch (cause) {
180
+ throw new ArcaneError(cause?.code ?? 'ARCANE_REPOSITORY_PREPARE_FAILED',
181
+ cause instanceof Error ? cause.message : String(cause),
182
+ {cause, details: {directory: repositoryDirectory, cloned: true, outputs}, exitCode: cause?.exitCode});
183
+ }
184
+ }
129
185
  throwIfAborted(signal);
130
186
  opened = true;
131
- return {directory: repositoryDirectory, cloned: true, stdout: result.stdout, stderr: result.stderr};
187
+ return {directory: repositoryDirectory, cloned: true, stdout: result.stdout, stderr: result.stderr,
188
+ ...(outputs === undefined ? {} : {outputs})};
132
189
  }
133
190
 
134
191
  function accept(operation, signal) {