arcane-os 0.88.0 → 0.89.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 +32 -0
- package/README.md +1 -1
- package/browser-runtime/ai/browser-decisions.mjs +31 -4
- package/browser-runtime/ai/core-local.mjs +105 -25
- package/browser-runtime/ai/decision-runtime.mjs +7 -0
- package/browser-runtime/ai/decision-worker.mjs +9 -1
- package/browser-runtime/core/client.mjs +6 -0
- package/browser-runtime/core/contracts.mjs +10 -0
- package/docs/reference/ai/browser-decisions.md +89 -7
- package/docs/reference/cli.md +10 -0
- package/docs/reference/core-client.md +59 -0
- package/docs/reference/core-native-packaging.md +57 -10
- package/docs/reference/core-repositories.md +47 -3
- package/docs/reference/inventory/package-api.json +15 -15
- package/docs/reference/inventory/runtime-components.json +1 -1
- package/docs/reference/inventory/runtime-modules.json +4 -4
- package/docs/reference/local-ai.md +86 -3
- package/docs/reference/mcp-stdio.md +76 -1
- package/docs/reference/native-app-control.md +17 -5
- package/docs/reference/protocols.md +14 -0
- package/docs/reference/runtime-modules.md +9 -3
- package/docs/reference/sdk-api.md +146 -23
- package/package.json +2 -2
- package/runtime/arcane/modules/RiskSignalAnalyzer.js +1 -5
- package/schemas/arcane-app.schema.json +13 -3
- package/schemas/arcane-package.schema.json +10 -1
- package/src/app-descriptor.mjs +6 -2
- package/src/cli/app-control.mjs +1 -1
- package/src/core/hosts/windows/ArcaneHost.cs +273 -5
- package/src/core/hosts/windows/ArcaneLauncher.cs +9 -0
- package/src/core/hosts/windows/ArcaneWindowControl.cs +7 -7
- package/src/core/repositories.mjs +11 -1
- package/src/core/services/local-ai.mjs +183 -22
- package/src/installed-sdk-runtime.mjs +2 -0
- package/src/local-ai/config.mjs +16 -0
- package/src/local-ai/dev.mjs +2 -2
- package/src/local-ai/discover.mjs +3 -0
- package/src/local-ai/install.mjs +130 -20
- package/src/local-ai/llama-execution-windows.ps1 +158 -0
- package/src/local-ai/llama-execution.mjs +169 -0
- package/src/local-ai/server.mjs +38 -8
- package/src/native/portable-layout.mjs +13 -3
- package/src/workspace-operation-lock.mjs +23 -10
- package/src/workspace-runtime.mjs +97 -1
|
@@ -85,15 +85,96 @@ async function removeTemporaryTree(location){
|
|
|
85
85
|
await rm(location,{recursive:true,force:true}).catch(()=>{});
|
|
86
86
|
}
|
|
87
87
|
|
|
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
|
+
|
|
88
167
|
export async function materializeWorkspaceRuntimeContent({
|
|
89
168
|
workspaceRoot,
|
|
90
169
|
runtimeRoot=path.join(getSdkRoot(),'runtime'),
|
|
91
170
|
browserRuntimeRoot=getSdkBrowserRuntimeRoot(),
|
|
92
171
|
sdkVersion=SDK_VERSION,
|
|
172
|
+
browserDecisions=false,
|
|
93
173
|
signal,
|
|
94
174
|
onEvent
|
|
95
175
|
}={}){
|
|
96
176
|
if(!workspaceRoot)fail('workspaceRoot is required to materialize a workspace runtime.');
|
|
177
|
+
if(!is.boolean(browserDecisions))throw new TypeError('browserDecisions must be a boolean.');
|
|
97
178
|
throwIfAborted(signal);
|
|
98
179
|
const workspace=await realDirectory(workspaceRoot,'Workspace root');
|
|
99
180
|
const runtime=await realDirectory(runtimeRoot,'SDK runtime root');
|
|
@@ -109,6 +190,7 @@ export async function materializeWorkspaceRuntimeContent({
|
|
|
109
190
|
const backupRoot=path.join(workspace,`${BACKUP_PREFIX}${token}`);
|
|
110
191
|
let backedUp=false;
|
|
111
192
|
let promoted=false;
|
|
193
|
+
let decisionDistribution;
|
|
112
194
|
|
|
113
195
|
await mkdir(stagingRoot);
|
|
114
196
|
try{
|
|
@@ -134,6 +216,14 @@ export async function materializeWorkspaceRuntimeContent({
|
|
|
134
216
|
);
|
|
135
217
|
}
|
|
136
218
|
|
|
219
|
+
if (browserDecisions) {
|
|
220
|
+
decisionDistribution = await materializeBrowserDecisions(
|
|
221
|
+
path.join(sdkDestination, 'ai', 'decisions-runtime'),
|
|
222
|
+
signal,
|
|
223
|
+
onEvent
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
137
227
|
throwIfAborted(signal);
|
|
138
228
|
try{
|
|
139
229
|
const existing=await lstat(destinationRoot);
|
|
@@ -160,7 +250,13 @@ export async function materializeWorkspaceRuntimeContent({
|
|
|
160
250
|
return {
|
|
161
251
|
kind:'arcane-workspace-runtime-content',
|
|
162
252
|
workspaceRoot:workspace,
|
|
163
|
-
runtimeRoot:destinationRoot
|
|
253
|
+
runtimeRoot:destinationRoot,
|
|
254
|
+
...(decisionDistribution ? {
|
|
255
|
+
browserDecisions: {
|
|
256
|
+
...decisionDistribution,
|
|
257
|
+
directory: path.join(destinationRoot, 'sdk', 'ai', 'decisions-runtime')
|
|
258
|
+
}
|
|
259
|
+
} : {})
|
|
164
260
|
};
|
|
165
261
|
}catch(error){
|
|
166
262
|
if(promoted)await removeTemporaryTree(destinationRoot);
|