arcane-os 0.56.0 → 0.58.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 +43 -0
- package/README.md +6 -2
- package/browser-runtime/ai/core-local.mjs +306 -0
- package/browser-runtime/ai/core-onnx.mjs +96 -0
- package/browser-runtime/ai/onnx-tensors.mjs +85 -0
- package/browser-runtime/core/client.mjs +151 -16
- package/docs/architecture.md +5 -2
- package/docs/platform-targets.md +30 -13
- package/docs/reference/README.md +38 -3
- package/docs/reference/availability-and-normalization.md +9 -6
- package/docs/reference/cli.md +29 -9
- package/docs/reference/core-client.md +80 -0
- package/docs/reference/core-native-packaging.md +304 -12
- package/docs/reference/core-preferences.md +49 -0
- package/docs/reference/diarization.md +206 -0
- package/docs/reference/git-text-snapshot.md +104 -0
- package/docs/reference/inventory/package-api.json +330 -22
- package/docs/reference/local-ai.md +331 -0
- package/docs/reference/protocols.md +97 -20
- package/docs/reference/pwa.md +5 -2
- package/docs/reference/runtime-modules.md +6 -5
- package/docs/reference/sdk-api.md +611 -63
- package/package.json +15 -3
- package/runtime/arcane/modules/LocalAIReadiness.js +3 -1
- package/schemas/arcane-app.schema.json +55 -1
- package/schemas/arcane-package.schema.json +44 -0
- package/schemas/native-build-plan.schema.json +27 -1
- package/schemas/target-adapter.schema.json +2 -0
- package/src/app-descriptor.mjs +18 -2
- package/src/cli/main.mjs +20 -4
- package/src/constants.mjs +2 -0
- package/src/core/host.mjs +23 -0
- package/src/core/hosts/macos/ArcaneCoreProcess.h +85 -0
- package/src/core/hosts/macos/ArcaneCoreProcess.m +357 -0
- package/src/core/hosts/macos/ArcaneHost.h +86 -0
- package/src/core/hosts/macos/ArcaneHost.m +455 -0
- package/src/core/hosts/macos/ArcaneLauncher.m +432 -0
- package/src/core/hosts/windows/ArcaneCoreProcess.cs +3 -3
- package/src/core/hosts/windows/ArcaneHost.cs +695 -0
- package/src/core/hosts/windows/ArcaneHost.manifest +22 -0
- package/src/core/hosts/windows/ArcaneLauncher.cs +239 -0
- package/src/core/services/local-ai.mjs +621 -0
- package/src/core/services/packaged-web.mjs +89 -0
- package/src/core/services/preferences.mjs +201 -0
- package/src/core-classic-source.mjs +2 -2
- package/src/dev-server.mjs +9 -5
- package/src/diarization/build.mjs +35 -0
- package/src/diarization/index.mjs +432 -0
- package/src/diarization/native/CMakeLists.txt +9 -0
- package/src/diarization/native/main.cpp +269 -0
- package/src/diarization/service.mjs +129 -0
- package/src/git-text-snapshot.mjs +265 -0
- package/src/import-map.mjs +2 -0
- package/src/index.mjs +1 -0
- package/src/local-ai/archive.mjs +52 -0
- package/src/local-ai/config.mjs +62 -0
- package/src/local-ai/dev.mjs +390 -0
- package/src/local-ai/discover.mjs +71 -0
- package/src/local-ai/http.mjs +106 -0
- package/src/local-ai/install.mjs +459 -0
- package/src/local-ai/onnx-worker.mjs +85 -0
- package/src/local-ai/onnx.mjs +368 -0
- package/src/local-ai/server.mjs +262 -0
- package/src/native/macos-provider.mjs +291 -0
- package/src/native/portable-layout.mjs +37 -4
- package/src/native/portable-provider.mjs +44 -8
- package/src/native/windows-provider.mjs +262 -0
- package/src/native-plan.mjs +9 -1
- package/src/native-provider-loader.mjs +10 -2
- package/src/packager/core.mjs +6 -2
- package/src/process.mjs +184 -20
- package/src/scaffold.mjs +1 -1
- package/src/targets/index.mjs +11 -1
- package/src/templates/workspace-template.mjs +6 -5
- package/src/toolchain.mjs +33 -5
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import {createWriteStream} from 'node:fs';
|
|
2
|
+
import {mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, stat, writeFile} from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import {Readable} from 'node:stream';
|
|
5
|
+
import {pipeline} from 'node:stream/promises';
|
|
6
|
+
import Is from 'strong-type';
|
|
7
|
+
import {ArcaneError, ERROR_CODES, throwIfAborted} from '../errors.mjs';
|
|
8
|
+
import {runProcess} from '../process.mjs';
|
|
9
|
+
import {createPortableNativeProvider} from './portable-provider.mjs';
|
|
10
|
+
import {writeOutput} from './portable-layout.mjs';
|
|
11
|
+
|
|
12
|
+
const is = new Is(false);
|
|
13
|
+
const PROTOCOL = 'arcane-native-builder/1';
|
|
14
|
+
const MANIFEST = 'arcane-native.json';
|
|
15
|
+
const HOST_ASSET = 'arcane-native-windows-x64.tar.gz';
|
|
16
|
+
const HOST_FILES = [
|
|
17
|
+
'Arcane.exe',
|
|
18
|
+
'Arcane.exe.config',
|
|
19
|
+
'Microsoft.Web.WebView2.Core.dll',
|
|
20
|
+
'Microsoft.Web.WebView2.WinForms.dll',
|
|
21
|
+
'WebView2Loader.dll',
|
|
22
|
+
'runtime/ArcaneCore.exe',
|
|
23
|
+
'runtime/arcane-core-loader.cjs',
|
|
24
|
+
'runtime/NODE-LICENSE',
|
|
25
|
+
'WEBVIEW2-LICENSE',
|
|
26
|
+
'LICENSE',
|
|
27
|
+
'COMMERCIAL-LICENSE.md',
|
|
28
|
+
'NOTICE'
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
function windowsTarget(value) {
|
|
32
|
+
if (value?.target !== 'windows-x64' || value.platform !== 'windows'
|
|
33
|
+
|| value.architecture !== 'x64' || value.format !== 'exe') {
|
|
34
|
+
throw new ArcaneError(ERROR_CODES.targetUnavailable, 'The Windows provider assembles windows-x64 executables.');
|
|
35
|
+
}
|
|
36
|
+
return {...value};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function portableRequest(target) {
|
|
40
|
+
return {...target, target: 'portable', format: 'portable'};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function emit(onEvent, event) {
|
|
44
|
+
if (is.function(onEvent)) await onEvent(event);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function hostFilesMissing(directory) {
|
|
48
|
+
const missing = [];
|
|
49
|
+
for (const relative of HOST_FILES) {
|
|
50
|
+
try {
|
|
51
|
+
if (!(await stat(path.join(directory, relative))).isFile()) missing.push(relative);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (error.code !== 'ENOENT') throw error;
|
|
54
|
+
missing.push(relative);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return missing;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function requireHostDirectory(directory) {
|
|
61
|
+
const resolved = await realpath(directory);
|
|
62
|
+
const missing = await hostFilesMissing(resolved);
|
|
63
|
+
if (missing.length) {
|
|
64
|
+
throw new ArcaneError(ERROR_CODES.prerequisiteMissing, 'The selected Windows host assets are incomplete.', {
|
|
65
|
+
details: {hostDirectory: resolved, missing}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return resolved;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function removeOwnedDirectory(directory, error) {
|
|
72
|
+
try { await rm(directory, {recursive: true, force: true}); }
|
|
73
|
+
catch (cleanupError) {
|
|
74
|
+
throw new AggregateError([error, cleanupError], `Windows preparation failed; incomplete output remains at ${directory}.`);
|
|
75
|
+
}
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function releasedHostDirectory(outputRoot, version, {signal, onEvent}) {
|
|
80
|
+
const cache = path.join(outputRoot, '.arcane-native-hosts', version);
|
|
81
|
+
const destination = path.join(cache, 'windows-x64');
|
|
82
|
+
try { return await requireHostDirectory(destination); }
|
|
83
|
+
catch (error) { if (error.code !== 'ENOENT') throw error; }
|
|
84
|
+
throwIfAborted(signal);
|
|
85
|
+
await mkdir(cache, {recursive: true});
|
|
86
|
+
const temporary = await mkdtemp(path.join(cache, 'preparing-windows-x64-'));
|
|
87
|
+
const archive = path.join(temporary, HOST_ASSET);
|
|
88
|
+
const extracted = path.join(temporary, 'host');
|
|
89
|
+
const url = `https://github.com/TheWizardNexus/arcane-os-sdk/releases/download/${version}/${HOST_ASSET}`;
|
|
90
|
+
try {
|
|
91
|
+
await emit(onEvent, {type: 'native.host.download.started', target: 'windows-x64', version, url});
|
|
92
|
+
throwIfAborted(signal);
|
|
93
|
+
const response = await fetch(url, {signal});
|
|
94
|
+
if (!response.ok) {
|
|
95
|
+
throw new ArcaneError(ERROR_CODES.prerequisiteMissing, `The SDK Windows host download returned HTTP ${response.status}.`, {
|
|
96
|
+
details: {url, status: response.status, response: await response.text()}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (!response.body) throw new ArcaneError(ERROR_CODES.operationFailed, 'The SDK Windows host download returned no content.', {details: {url}});
|
|
100
|
+
await pipeline(Readable.fromWeb(response.body), createWriteStream(archive, {flags: 'wx'}), {signal});
|
|
101
|
+
throwIfAborted(signal);
|
|
102
|
+
await mkdir(extracted);
|
|
103
|
+
await runProcess('tar', ['-xzf', archive, '-C', extracted], {cwd: temporary, signal, onEvent});
|
|
104
|
+
await requireHostDirectory(extracted);
|
|
105
|
+
throwIfAborted(signal);
|
|
106
|
+
try { await rename(extracted, destination); }
|
|
107
|
+
catch (error) {
|
|
108
|
+
// Another preparation may have finished this exact version while
|
|
109
|
+
// this download was in flight. Preserve its complete asset tree.
|
|
110
|
+
if (!['EEXIST', 'ENOTEMPTY', 'EPERM'].includes(error.code)) throw error;
|
|
111
|
+
try { await requireHostDirectory(destination); }
|
|
112
|
+
catch { throw error; }
|
|
113
|
+
}
|
|
114
|
+
await rm(temporary, {recursive: true, force: true});
|
|
115
|
+
await emit(onEvent, {type: 'native.host.download.completed', target: 'windows-x64', version, hostDirectory: destination});
|
|
116
|
+
throwIfAborted(signal);
|
|
117
|
+
return destination;
|
|
118
|
+
} catch (error) {
|
|
119
|
+
return removeOwnedDirectory(temporary, error);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function contains(root, candidate) {
|
|
124
|
+
const relative = path.relative(root, candidate);
|
|
125
|
+
return relative === '' || (!path.isAbsolute(relative) && relative !== '..' && !relative.startsWith(`..${path.sep}`));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function copyHostAssets(source, root, files, signal, relative = '', ancestors = new Set()) {
|
|
129
|
+
throwIfAborted(signal);
|
|
130
|
+
const canonical = await realpath(source);
|
|
131
|
+
const output = await realpath(root);
|
|
132
|
+
if (contains(canonical, output) || contains(output, canonical) || ancestors.has(canonical)) {
|
|
133
|
+
throw new ArcaneError(ERROR_CODES.usage, 'Windows host assets overlap their output or contain a directory cycle.', {
|
|
134
|
+
details: {source, outputRoot: root}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
const parents = new Set([...ancestors, canonical]);
|
|
138
|
+
for (const entry of await readdir(source, {withFileTypes: true})) {
|
|
139
|
+
throwIfAborted(signal);
|
|
140
|
+
const selected = path.join(source, entry.name);
|
|
141
|
+
const destination = relative ? `${relative}/${entry.name}` : entry.name;
|
|
142
|
+
const information = await stat(selected);
|
|
143
|
+
if (information.isDirectory()) {
|
|
144
|
+
await mkdir(path.join(root, destination), {recursive: true});
|
|
145
|
+
await copyHostAssets(selected, root, files, signal, destination, parents);
|
|
146
|
+
} else if (information.isFile()) {
|
|
147
|
+
await writeOutput(root, destination, await readFile(selected, {signal}), files, signal);
|
|
148
|
+
} else {
|
|
149
|
+
throw new ArcaneError(ERROR_CODES.operationFailed, `Cannot copy Windows host asset ${selected}.`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Compose app-owned services with the SDK's precompiled Windows host. */
|
|
155
|
+
export function createWindowsNativeProvider({services, hostDirectory} = {}) {
|
|
156
|
+
const portable = createPortableNativeProvider(services === undefined ? {} : {services});
|
|
157
|
+
return {
|
|
158
|
+
protocol: PROTOCOL,
|
|
159
|
+
async describe() {
|
|
160
|
+
return {
|
|
161
|
+
protocol: PROTOCOL,
|
|
162
|
+
id: 'arcane-sdk-windows-x64',
|
|
163
|
+
targets: ['windows-x64'],
|
|
164
|
+
executable: true,
|
|
165
|
+
serviceConfiguration: 'explicit release module factories'
|
|
166
|
+
};
|
|
167
|
+
},
|
|
168
|
+
async doctor({targetRequest, signal, onEvent} = {}) {
|
|
169
|
+
throwIfAborted(signal);
|
|
170
|
+
const target = windowsTarget(targetRequest);
|
|
171
|
+
const core = await portable.doctor({targetRequest: portableRequest(target), signal});
|
|
172
|
+
const missing = hostDirectory === undefined ? [] : await hostFilesMissing(path.resolve(hostDirectory));
|
|
173
|
+
const result = {
|
|
174
|
+
target: 'windows-x64', executable: true, ready: core.ready && missing.length === 0,
|
|
175
|
+
sdkRoot: core.sdkRoot, missing: [...core.missing, ...missing],
|
|
176
|
+
hostDirectory: hostDirectory === undefined ? null : path.resolve(hostDirectory),
|
|
177
|
+
hostSource: hostDirectory === undefined ? 'sdk-release' : 'selected-directory',
|
|
178
|
+
downloadRequired: hostDirectory === undefined,
|
|
179
|
+
runtimePrerequisite: 'Microsoft Edge WebView2 Runtime',
|
|
180
|
+
buildPrerequisite: hostDirectory === undefined ? 'tar' : null
|
|
181
|
+
};
|
|
182
|
+
await emit(onEvent, {type: 'native.doctor.completed', ...result});
|
|
183
|
+
throwIfAborted(signal);
|
|
184
|
+
return result;
|
|
185
|
+
},
|
|
186
|
+
async prepare({targetRequest, signal, onEvent} = {}) {
|
|
187
|
+
throwIfAborted(signal);
|
|
188
|
+
const target = windowsTarget(targetRequest);
|
|
189
|
+
const selection = await portable.prepare({targetRequest: portableRequest(target), signal});
|
|
190
|
+
const selected = hostDirectory === undefined ? undefined : await requireHostDirectory(hostDirectory);
|
|
191
|
+
// Downloads belong to build(), which has the caller's selected
|
|
192
|
+
// outputRoot. Preparation never invents a machine-wide cache.
|
|
193
|
+
const result = {...selection, target, executable: true, ...(selected ? {hostDirectory: selected} : {})};
|
|
194
|
+
await emit(onEvent, {type: 'native.prepared', target: 'windows-x64', sdkVersion: selection.sdkVersion});
|
|
195
|
+
throwIfAborted(signal);
|
|
196
|
+
return result;
|
|
197
|
+
},
|
|
198
|
+
async build(request = {}) {
|
|
199
|
+
const {signal, onEvent} = request;
|
|
200
|
+
throwIfAborted(signal);
|
|
201
|
+
const target = windowsTarget(request.targetRequest);
|
|
202
|
+
const selected = hostDirectory ?? request.toolchain?.hostDirectory;
|
|
203
|
+
const selectedHost = selected === undefined ? null : await requireHostDirectory(selected);
|
|
204
|
+
const artifact = await portable.build({
|
|
205
|
+
...request,
|
|
206
|
+
targetRequest: portableRequest(target),
|
|
207
|
+
async onEvent(event) {
|
|
208
|
+
if (event.type !== 'native.payload.completed') await emit(onEvent, {...event, target: 'windows-x64'});
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
const root = artifact.target.rootDir;
|
|
212
|
+
try {
|
|
213
|
+
const host = selectedHost ?? await releasedHostDirectory(path.resolve(request.outputRoot), artifact.manifest.sdk.version, {signal, onEvent});
|
|
214
|
+
const files = [...artifact.manifest.files];
|
|
215
|
+
await copyHostAssets(host, root, files, signal);
|
|
216
|
+
const manifest = {
|
|
217
|
+
...artifact.manifest,
|
|
218
|
+
kind: 'arcane-windows-native',
|
|
219
|
+
target,
|
|
220
|
+
host: {
|
|
221
|
+
executable: 'Arcane.exe',
|
|
222
|
+
platform: 'windows', architecture: 'x64', runtime: 'webview2',
|
|
223
|
+
coreExecutable: 'runtime/ArcaneCore.exe',
|
|
224
|
+
coreLoader: 'runtime/arcane-core-loader.cjs'
|
|
225
|
+
},
|
|
226
|
+
files
|
|
227
|
+
};
|
|
228
|
+
await writeFile(path.join(root, MANIFEST), `${JSON.stringify(manifest, null, 2)}\n`, {signal});
|
|
229
|
+
throwIfAborted(signal);
|
|
230
|
+
await emit(onEvent, {type: 'native.payload.completed', target: 'windows-x64', appId: request.appDescriptor.id, outputRoot: root});
|
|
231
|
+
throwIfAborted(signal);
|
|
232
|
+
return {...artifact, target: {...target, rootDir: root}, manifest};
|
|
233
|
+
} catch (error) {
|
|
234
|
+
return removeOwnedDirectory(root, error);
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
async verify({artifact, targetRequest, signal, onEvent} = {}) {
|
|
238
|
+
throwIfAborted(signal);
|
|
239
|
+
const target = windowsTarget(targetRequest);
|
|
240
|
+
const result = await portable.verify({artifact, targetRequest: portableRequest(target), signal});
|
|
241
|
+
await requireHostDirectory(result.outputRoot);
|
|
242
|
+
const verified = {...result, target: 'windows-x64', executable: true};
|
|
243
|
+
await emit(onEvent, {type: 'native.verified', target: 'windows-x64', outputRoot: result.outputRoot});
|
|
244
|
+
throwIfAborted(signal);
|
|
245
|
+
return verified;
|
|
246
|
+
},
|
|
247
|
+
async run({artifact, targetRequest, signal, onEvent} = {}) {
|
|
248
|
+
throwIfAborted(signal);
|
|
249
|
+
windowsTarget(targetRequest);
|
|
250
|
+
if (process.platform !== 'win32' || process.arch !== 'x64') {
|
|
251
|
+
throw new ArcaneError(ERROR_CODES.nativeRunUnsupported, 'Running this Windows x64 artifact requires a Windows x64 host.');
|
|
252
|
+
}
|
|
253
|
+
const root = await requireHostDirectory(artifact?.target?.rootDir);
|
|
254
|
+
return runProcess(path.join(root, 'Arcane.exe'), ['--close-on-stdin-eof'], {
|
|
255
|
+
cwd: root, signal, onEvent, cancellationMode: 'close-input'
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export const arcaneNativeBuilderProvider = createWindowsNativeProvider();
|
|
262
|
+
export default arcaneNativeBuilderProvider;
|
package/src/native-plan.mjs
CHANGED
|
@@ -12,7 +12,7 @@ export const NATIVE_BUILDER_PROTOCOL='arcane-native-builder/1';
|
|
|
12
12
|
|
|
13
13
|
const NATIVE_TARGETS={
|
|
14
14
|
portable:{
|
|
15
|
-
platforms:new Set(['windows','linux']),
|
|
15
|
+
platforms:new Set(['windows','linux','macos']),
|
|
16
16
|
architectures:new Set(['x64','arm64']),
|
|
17
17
|
format:'portable',
|
|
18
18
|
signingMode:'unsigned-local-test',
|
|
@@ -22,6 +22,14 @@ const NATIVE_TARGETS={
|
|
|
22
22
|
platforms:new Set(['windows']),architectures:new Set(['x64']),format:'exe',
|
|
23
23
|
signingMode:'unsigned-local-test',signingProfileId:null
|
|
24
24
|
},
|
|
25
|
+
'macos-arm64':{
|
|
26
|
+
platforms:new Set(['macos']),architectures:new Set(['arm64']),format:'app',
|
|
27
|
+
signingMode:'unsigned-local-test',signingProfileId:null
|
|
28
|
+
},
|
|
29
|
+
'macos-x64':{
|
|
30
|
+
platforms:new Set(['macos']),architectures:new Set(['x64']),format:'app',
|
|
31
|
+
signingMode:'unsigned-local-test',signingProfileId:null
|
|
32
|
+
},
|
|
25
33
|
'linux-x64':{
|
|
26
34
|
platforms:new Set(['linux']),architectures:new Set(['x64']),format:'deb',
|
|
27
35
|
signingMode:'unsigned-local-test',signingProfileId:null
|
|
@@ -22,6 +22,13 @@ const FIXED_NATIVE_PROVIDER_PATHS={
|
|
|
22
22
|
'android-arm64':providerPath('android-native-provider.mjs')
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
+
const SDK_NATIVE_PROVIDER_PATHS={
|
|
26
|
+
portable:'./native/portable-provider.mjs',
|
|
27
|
+
'windows-x64':'./native/windows-provider.mjs',
|
|
28
|
+
'macos-arm64':'./native/macos-provider.mjs',
|
|
29
|
+
'macos-x64':'./native/macos-provider.mjs'
|
|
30
|
+
};
|
|
31
|
+
|
|
25
32
|
export const ARCANE_NATIVE_PROVIDER_PATHS={
|
|
26
33
|
portable:[...FIXED_NATIVE_PROVIDER_PATHS.portable],
|
|
27
34
|
'windows-x64':[...FIXED_NATIVE_PROVIDER_PATHS['windows-x64']],
|
|
@@ -133,10 +140,11 @@ export async function loadArcaneNativeProvider(options={}){
|
|
|
133
140
|
target,
|
|
134
141
|
message:`Loading the Arcane ${String(target)} provider.`
|
|
135
142
|
});
|
|
136
|
-
const
|
|
143
|
+
const sdkProvider=SDK_NATIVE_PROVIDER_PATHS[target];
|
|
144
|
+
const location=arcaneRoot===undefined&&sdkProvider
|
|
137
145
|
?{
|
|
138
146
|
canonicalRoot:path.resolve(fileURLToPath(new URL('../',import.meta.url))),
|
|
139
|
-
providerPath:fileURLToPath(new URL(
|
|
147
|
+
providerPath:fileURLToPath(new URL(sdkProvider,import.meta.url)),
|
|
140
148
|
providerSource:'sdk-package'
|
|
141
149
|
}
|
|
142
150
|
:await resolveProviderLocation({arcaneRoot,target,inspect,canonicalize});
|
package/src/packager/core.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import path from 'node:path';
|
|
|
14
14
|
import {pathToFileURL} from 'node:url';
|
|
15
15
|
import {appRelativeRoot,resolveAppRoot,resolvePackageOutputRoot} from '../app-layout.mjs';
|
|
16
16
|
import {TARGET_IDS} from '../constants.mjs';
|
|
17
|
+
import {normalizeLocalAIConfig} from '../local-ai/config.mjs';
|
|
17
18
|
import {readInstalledSdkLayout} from '../sdk-runtime-layout.mjs';
|
|
18
19
|
import {withWorkspaceOperationLock} from '../workspace-operation-lock.mjs';
|
|
19
20
|
import {materializeNativeModules} from './native-modules.mjs';
|
|
@@ -321,7 +322,7 @@ function normalizeOptionalRecord(value,label){
|
|
|
321
322
|
export function validateAppConfig(value,appId,rootConfig,configPath=path.posix.join(appRelativeRoot(rootConfig,appId),APP_CONFIG_NAME)){
|
|
322
323
|
assertOnlyKeys(value,new Set([
|
|
323
324
|
'schemaVersion','id','displayName','version','entry','strategy','security',
|
|
324
|
-
'localAIModelPolicy','include','exclude','shared','adapter','pwa','outputDirectory','documents','nativeResources'
|
|
325
|
+
'localAIModelPolicy','localAI','include','exclude','shared','adapter','pwa','outputDirectory','documents','nativeResources'
|
|
325
326
|
]),`${appId}/${APP_CONFIG_NAME}`);
|
|
326
327
|
if(value.schemaVersion!==1)fail(`${appId}/${APP_CONFIG_NAME}.schemaVersion must be 1.`);
|
|
327
328
|
if(!is.string(value.id)||value.id!==appId||!APP_ID_PATTERN.test(value.id)){
|
|
@@ -390,6 +391,7 @@ export function validateAppConfig(value,appId,rootConfig,configPath=path.posix.j
|
|
|
390
391
|
value.localAIModelPolicy,
|
|
391
392
|
`${appId}/${APP_CONFIG_NAME}.localAIModelPolicy`
|
|
392
393
|
)}),
|
|
394
|
+
...(value.localAI===undefined?{}:{localAI:normalizeLocalAIConfig(value.localAI)}),
|
|
393
395
|
include,
|
|
394
396
|
exclude,
|
|
395
397
|
...(nativeResources===undefined?{}:{nativeResources}),
|
|
@@ -742,6 +744,7 @@ async function inspectContext(context,{signal,records}={}){
|
|
|
742
744
|
...(context.config.localAIModelPolicy===undefined?{}:{
|
|
743
745
|
localAIModelPolicy:copyJson(context.config.localAIModelPolicy)
|
|
744
746
|
}),
|
|
747
|
+
...(context.config.localAI===undefined?{}:{localAI:copyJson(context.config.localAI)}),
|
|
745
748
|
...(context.config.adapter===undefined?{}:{adapter:context.config.adapter}),
|
|
746
749
|
descriptor:await optionalDescriptor(context),
|
|
747
750
|
browserDocuments:documents,
|
|
@@ -871,7 +874,8 @@ function releaseManifest(context,files,pwaArtifacts,rootDocument){
|
|
|
871
874
|
...(context.config.security===undefined?{}:{security:copyJson(context.config.security)}),
|
|
872
875
|
...(context.config.localAIModelPolicy===undefined?{}:{
|
|
873
876
|
localAIModelPolicy:copyJson(context.config.localAIModelPolicy)
|
|
874
|
-
})
|
|
877
|
+
}),
|
|
878
|
+
...(context.config.localAI===undefined?{}:{localAI:copyJson(context.config.localAI)})
|
|
875
879
|
},
|
|
876
880
|
files:[...files]
|
|
877
881
|
};
|