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.
- package/CHANGELOG.md +33 -0
- package/README.md +1 -1
- package/docs/reference/ai/browser-decisions.md +45 -18
- package/docs/reference/core-repositories.md +87 -4
- package/docs/reference/git-text-snapshot.md +47 -3
- package/docs/reference/inventory/package-api.json +9 -9
- package/docs/reference/model-assets.md +63 -24
- package/docs/reference/native-decisions.md +19 -4
- package/docs/reference/sdk-api.md +95 -16
- package/package.json +1 -1
- package/src/browser-decisions-distribution.mjs +95 -0
- package/src/core/repositories.mjs +60 -3
- package/src/core/services/model-assets.mjs +256 -76
- package/src/git-text-snapshot.mjs +25 -5
- package/src/packager/core.mjs +29 -2
- package/src/process.mjs +25 -1
- package/src/repository.mjs +25 -1
- package/src/windows-git-executable.mjs +103 -0
- package/src/workspace-runtime.mjs +1 -79
|
@@ -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.
|
|
8429
|
-
|
|
8430
|
-
|
|
8431
|
-
reports `
|
|
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})`
|
|
9016
|
-
ordered `{path,url}` members and returns their ready projection.
|
|
9017
|
-
|
|
9018
|
-
|
|
9019
|
-
|
|
9020
|
-
|
|
9021
|
-
|
|
9022
|
-
|
|
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
|
|
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
|
@@ -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) {
|