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
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
import {stat} from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import {throwIfAborted} from './errors.mjs';
|
|
5
|
+
|
|
6
|
+
const is=new Is(false);
|
|
7
|
+
let installedDirectory=null;
|
|
8
|
+
|
|
9
|
+
// Git for Windows records its chosen location for third-party integrations.
|
|
10
|
+
// Read both installation scopes/views in one owned Windows process. No guessed
|
|
11
|
+
// installation paths or changes to the registry/environment are needed.
|
|
12
|
+
const READ_INSTALLATIONS=String.raw`
|
|
13
|
+
$ErrorActionPreference = 'Stop'
|
|
14
|
+
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)
|
|
15
|
+
$installations = [System.Collections.Generic.List[string]]::new()
|
|
16
|
+
$views = @([Microsoft.Win32.RegistryView]::Registry32)
|
|
17
|
+
if ([Environment]::Is64BitOperatingSystem) {
|
|
18
|
+
$views = @([Microsoft.Win32.RegistryView]::Registry64, [Microsoft.Win32.RegistryView]::Registry32)
|
|
19
|
+
}
|
|
20
|
+
foreach ($hive in @([Microsoft.Win32.RegistryHive]::CurrentUser, [Microsoft.Win32.RegistryHive]::LocalMachine)) {
|
|
21
|
+
foreach ($view in $views) {
|
|
22
|
+
$base = [Microsoft.Win32.RegistryKey]::OpenBaseKey($hive, $view)
|
|
23
|
+
try {
|
|
24
|
+
$key = $base.OpenSubKey('Software\GitForWindows')
|
|
25
|
+
if ($null -ne $key) {
|
|
26
|
+
try {
|
|
27
|
+
$location = $key.GetValue('InstallPath')
|
|
28
|
+
if ($location -is [string] -and $location.Length -gt 0 -and -not $installations.Contains($location)) {
|
|
29
|
+
$installations.Add($location)
|
|
30
|
+
}
|
|
31
|
+
} finally { $key.Dispose() }
|
|
32
|
+
}
|
|
33
|
+
} finally { $base.Dispose() }
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
ConvertTo-Json -InputObject @($installations.ToArray()) -Compress
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
function environmentKey(environment,name){
|
|
40
|
+
return Object.keys(environment).sort().find(function matchingKey(key){
|
|
41
|
+
return key.toLowerCase()===name;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function appendWindowsGitDirectory(environment,directory){
|
|
46
|
+
const keys=Object.keys(environment).filter(function pathKey(key){
|
|
47
|
+
return key.toLowerCase()==='path';
|
|
48
|
+
}).sort();
|
|
49
|
+
const selectedKey=keys[0]??'Path';
|
|
50
|
+
// Node chooses the first case-insensitive key before omitting undefined.
|
|
51
|
+
// libuv uses the parent's PATH if the child has none; null becomes 'null'.
|
|
52
|
+
const selected=environment[selectedKey];
|
|
53
|
+
const original=selected===undefined
|
|
54
|
+
?process.env[environmentKey(process.env,'path')]??'':selected;
|
|
55
|
+
const result={...environment};
|
|
56
|
+
for(const key of keys)delete result[key];
|
|
57
|
+
const originalPath=`${original}`;
|
|
58
|
+
result[selectedKey]=`${originalPath}${originalPath?';':''}"${directory}"`;
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function installedGitExists(directory){
|
|
63
|
+
try{
|
|
64
|
+
return (await stat(path.win32.join(directory,'git.exe'))).isFile();
|
|
65
|
+
}catch(error){
|
|
66
|
+
if(error.code==='ENOENT'||error.code==='ENOTDIR')return false;
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function windowsGitEnvironment(environment,{run,signal,onEvent}={}){
|
|
72
|
+
throwIfAborted(signal);
|
|
73
|
+
const retained=installedDirectory;
|
|
74
|
+
if(retained){
|
|
75
|
+
const available=await installedGitExists(retained);
|
|
76
|
+
throwIfAborted(signal);
|
|
77
|
+
if(available)return appendWindowsGitDirectory(environment,retained);
|
|
78
|
+
if(installedDirectory===retained)installedDirectory=null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const systemRoot=process.env[environmentKey(process.env,'systemroot')];
|
|
82
|
+
if(!systemRoot)return environment;
|
|
83
|
+
const powershell=path.win32.join(systemRoot,'System32','WindowsPowerShell','v1.0','powershell.exe');
|
|
84
|
+
const result=await run(powershell,['-NoProfile','-NonInteractive','-Command',READ_INSTALLATIONS],{
|
|
85
|
+
signal,onEvent,emitOutputEvents:false
|
|
86
|
+
});
|
|
87
|
+
throwIfAborted(signal);
|
|
88
|
+
const locations=JSON.parse(result.stdout);
|
|
89
|
+
if(!is.array(locations))throw new TypeError('Git installation discovery did not return a location list.');
|
|
90
|
+
for(const location of locations){
|
|
91
|
+
if(!is.string(location)||!path.win32.isAbsolute(location))continue;
|
|
92
|
+
const directory=path.win32.join(location,'cmd');
|
|
93
|
+
const available=await installedGitExists(directory);
|
|
94
|
+
throwIfAborted(signal);
|
|
95
|
+
if(available){
|
|
96
|
+
// Only successful, still-present discovery is retained. Concurrent
|
|
97
|
+
// first callers own separate lookups and cancellation independently.
|
|
98
|
+
installedDirectory=directory;
|
|
99
|
+
return appendWindowsGitDirectory(environment,directory);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return environment;
|
|
103
|
+
}
|
|
@@ -2,6 +2,7 @@ import Is from 'strong-type';
|
|
|
2
2
|
import {randomUUID} from 'node:crypto';
|
|
3
3
|
import {copyFile,lstat,mkdir,readFile,readdir,realpath,rename,rm,writeFile} from 'node:fs/promises';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
+
import {materializeBrowserDecisions} from './browser-decisions-distribution.mjs';
|
|
5
6
|
import {SDK_VERSION} from './constants.mjs';
|
|
6
7
|
import {rewriteAssetReferences} from './import-map.mjs';
|
|
7
8
|
import {getSdkRoot} from './runtime.mjs';
|
|
@@ -85,85 +86,6 @@ async function removeTemporaryTree(location){
|
|
|
85
86
|
await rm(location,{recursive:true,force:true}).catch(()=>{});
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
async function materializeBrowserDecisions(destination, signal, onEvent) {
|
|
89
|
-
const transformers = 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@4.3.0/';
|
|
90
|
-
const onnx = 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.31.0-dev.20260914-8d85527a0/';
|
|
91
|
-
const files = [
|
|
92
|
-
{name: 'transformers.min.js', url: `${transformers}dist/transformers.min.js`},
|
|
93
|
-
{name: 'ort-wasm-simd-threaded.asyncify.mjs', url: `${onnx}dist/ort-wasm-simd-threaded.asyncify.mjs`},
|
|
94
|
-
{name: 'ort-wasm-simd-threaded.asyncify.wasm', url: `${onnx}dist/ort-wasm-simd-threaded.asyncify.wasm`},
|
|
95
|
-
{name: 'TRANSFORMERS-LICENSE', url: `${transformers}LICENSE`},
|
|
96
|
-
{name: 'ONNX-RUNTIME-LICENSE', url: `${onnx}LICENSE`}
|
|
97
|
-
];
|
|
98
|
-
const controller = new AbortController();
|
|
99
|
-
function cancelDistribution() {
|
|
100
|
-
controller.abort(signal.reason);
|
|
101
|
-
}
|
|
102
|
-
signal?.addEventListener('abort', cancelDistribution, {once: true});
|
|
103
|
-
if (signal?.aborted) cancelDistribution();
|
|
104
|
-
let completed = 0;
|
|
105
|
-
try {
|
|
106
|
-
throwIfAborted(controller.signal);
|
|
107
|
-
await emit(
|
|
108
|
-
onEvent,
|
|
109
|
-
{type: 'workspace.decisions.started', completed, total: files.length}
|
|
110
|
-
);
|
|
111
|
-
throwIfAborted(controller.signal);
|
|
112
|
-
await mkdir(destination, {recursive: true});
|
|
113
|
-
async function acquireDistributionFile(file) {
|
|
114
|
-
try {
|
|
115
|
-
throwIfAborted(controller.signal);
|
|
116
|
-
const response = await fetch(file.url, {signal: controller.signal});
|
|
117
|
-
const content = new Uint8Array(await response.arrayBuffer());
|
|
118
|
-
if (!response.ok) {
|
|
119
|
-
const error = new Error(`Browser decision distribution returned HTTP ${response.status} ${response.statusText}.`);
|
|
120
|
-
error.code = 'ARCANE_DECISION_DISTRIBUTION_DOWNLOAD_FAILED';
|
|
121
|
-
error.response = {
|
|
122
|
-
url: response.url,
|
|
123
|
-
status: response.status,
|
|
124
|
-
statusText: response.statusText,
|
|
125
|
-
headers: [...response.headers],
|
|
126
|
-
content
|
|
127
|
-
};
|
|
128
|
-
throw error;
|
|
129
|
-
}
|
|
130
|
-
throwIfAborted(controller.signal);
|
|
131
|
-
// Upstream distribution content is opaque, including its own
|
|
132
|
-
// imports and license text. No SDK source rewriting applies.
|
|
133
|
-
await writeFile(path.join(destination, file.name), content);
|
|
134
|
-
throwIfAborted(controller.signal);
|
|
135
|
-
completed += 1;
|
|
136
|
-
await emit(
|
|
137
|
-
onEvent,
|
|
138
|
-
{type: 'workspace.decisions.progress', file: file.name, url: file.url, completed, total: files.length}
|
|
139
|
-
);
|
|
140
|
-
} catch (error) {
|
|
141
|
-
controller.abort(error);
|
|
142
|
-
throw error;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
// One fixed distribution, acquired once for the selected projection;
|
|
146
|
-
// no model/app/architecture multiplier or installation script.
|
|
147
|
-
const outcomes = await Promise.allSettled(files.map(acquireDistributionFile));
|
|
148
|
-
const failures = new Set();
|
|
149
|
-
for (const outcome of outcomes) {
|
|
150
|
-
if (outcome.status === 'rejected') failures.add(outcome.reason);
|
|
151
|
-
}
|
|
152
|
-
if (failures.size === 1) throw [...failures][0];
|
|
153
|
-
if (failures.size > 1) {
|
|
154
|
-
throw new AggregateError([...failures], 'Browser decision distribution acquisition failed.');
|
|
155
|
-
}
|
|
156
|
-
throwIfAborted(controller.signal);
|
|
157
|
-
} finally {
|
|
158
|
-
signal?.removeEventListener('abort', cancelDistribution);
|
|
159
|
-
}
|
|
160
|
-
return {
|
|
161
|
-
transformersVersion: '4.3.0',
|
|
162
|
-
onnxRuntimeVersion: '1.31.0-dev.20260914-8d85527a0',
|
|
163
|
-
files: files.map(function distributionFilename(file) { return file.name; })
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
|
|
167
89
|
export async function materializeWorkspaceRuntimeContent({
|
|
168
90
|
workspaceRoot,
|
|
169
91
|
runtimeRoot=path.join(getSdkRoot(),'runtime'),
|