arcane-os 0.57.0 → 0.59.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 +37 -0
- package/README.md +6 -2
- package/browser-runtime/ai/core-onnx.mjs +96 -0
- package/browser-runtime/ai/onnx-tensors.mjs +85 -0
- package/browser-runtime/core/client.mjs +152 -17
- package/docs/architecture.md +5 -2
- package/docs/platform-targets.md +30 -13
- package/docs/reference/README.md +22 -3
- package/docs/reference/availability-and-normalization.md +14 -7
- package/docs/reference/cli.md +22 -10
- package/docs/reference/core-client.md +87 -0
- package/docs/reference/core-native-packaging.md +129 -9
- 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 +205 -23
- package/docs/reference/local-ai.md +145 -11
- package/docs/reference/protocols.md +28 -19
- package/docs/reference/pwa.md +74 -4
- package/docs/reference/sdk-api.md +589 -39
- package/package.json +11 -3
- package/schemas/arcane-app.schema.json +3 -3
- package/schemas/arcane-package.schema.json +2 -2
- package/schemas/native-build-plan.schema.json +27 -1
- package/schemas/target-adapter.schema.json +2 -0
- package/src/app-descriptor.mjs +1 -1
- package/src/cli/main.mjs +14 -4
- package/src/constants.mjs +2 -0
- package/src/core/host.mjs +14 -5
- 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/ArcaneLauncher.cs +4 -1
- package/src/core/services/local-ai.mjs +82 -4
- 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 +2 -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 +9 -4
- package/src/index.mjs +1 -0
- package/src/local-ai/config.mjs +1 -1
- package/src/local-ai/install.mjs +134 -19
- package/src/local-ai/onnx-worker.mjs +85 -0
- package/src/local-ai/onnx.mjs +368 -0
- package/src/native/macos-provider.mjs +291 -0
- package/src/native/portable-layout.mjs +10 -2
- package/src/native/portable-provider.mjs +10 -5
- package/src/native-plan.mjs +9 -1
- package/src/native-provider-loader.mjs +3 -1
- package/src/process.mjs +123 -17
- 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 +42 -13
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import {mkdir, readFile, writeFile} from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import {startDevServer} from '../../dev-server.mjs';
|
|
4
|
+
import {serializeCoreError} from '../../../browser-runtime/core/contracts.mjs';
|
|
5
|
+
|
|
6
|
+
/** Serve one packaged web root inside its existing Core lifetime. */
|
|
7
|
+
export function createPackagedWebService({artifactRoot}, context = {}) {
|
|
8
|
+
let server;
|
|
9
|
+
let closing = false;
|
|
10
|
+
let lifetime;
|
|
11
|
+
return {
|
|
12
|
+
name: 'packaged-web',
|
|
13
|
+
async start(runtime) {
|
|
14
|
+
const manifest = JSON.parse(await readFile(path.join(artifactRoot, 'arcane-native.json'), 'utf8'));
|
|
15
|
+
// The launcher chooses app state independently of its installation.
|
|
16
|
+
// Forward the application's launch file unchanged; the fallback is
|
|
17
|
+
// a separate native argument, not a rewritten application payload.
|
|
18
|
+
const stateFlag = process.argv.indexOf('--arcane-host-state-root');
|
|
19
|
+
const stateRoot = context.stateRoot ?? (stateFlag < 0 ? undefined : process.argv[stateFlag + 1]);
|
|
20
|
+
if (typeof stateRoot !== 'string' || !stateRoot) {
|
|
21
|
+
throw new TypeError('Packaged web serving requires the launcher-selected stateRoot.');
|
|
22
|
+
}
|
|
23
|
+
await mkdir(stateRoot, {recursive: true});
|
|
24
|
+
const originFile = path.join(stateRoot, 'packaged-web-origin.json');
|
|
25
|
+
let port = 0;
|
|
26
|
+
let saved = false;
|
|
27
|
+
try {
|
|
28
|
+
const origin = JSON.parse(await readFile(originFile, 'utf8'));
|
|
29
|
+
port = origin.port;
|
|
30
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
31
|
+
throw new TypeError('The saved packaged origin needs its previously selected listener port.');
|
|
32
|
+
}
|
|
33
|
+
saved = true;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
if (error.code !== 'ENOENT') throw error;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
server = await startDevServer({
|
|
39
|
+
mode: 'packaged', http: true,
|
|
40
|
+
releaseRoot: path.resolve(artifactRoot, manifest.webRoot),
|
|
41
|
+
host: '127.0.0.1', port
|
|
42
|
+
});
|
|
43
|
+
// Only a first successful listener selects a port. A later bind
|
|
44
|
+
// conflict remains an error instead of moving saved browser data
|
|
45
|
+
// to a different origin. Concurrent first launches cannot replace
|
|
46
|
+
// one another's selection.
|
|
47
|
+
if (!saved) {
|
|
48
|
+
await writeFile(originFile, JSON.stringify({host: '127.0.0.1', port: server.port}) + '\n', {flag: 'wx'});
|
|
49
|
+
}
|
|
50
|
+
const url = new URL(manifest.start, server.origin).href;
|
|
51
|
+
runtime.emit('core.web.ready', {origin: server.origin, url, port: server.port});
|
|
52
|
+
lifetime = server.lifecycle.then(
|
|
53
|
+
function packagedServerEnded() {
|
|
54
|
+
if (!closing) {
|
|
55
|
+
runtime.emit('core.web.failed', serializeCoreError(
|
|
56
|
+
new Error('The packaged application listener closed unexpectedly.')
|
|
57
|
+
));
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
function packagedServerFailed(error) {
|
|
61
|
+
if (!closing) runtime.emit('core.web.failed', serializeCoreError(error));
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
// Retain the original rejection for drain while observing it
|
|
66
|
+
// now; the native diagnostic event owns immediate reporting.
|
|
67
|
+
lifetime.catch(function observePackagedServerFailure() {});
|
|
68
|
+
} catch (error) {
|
|
69
|
+
closing = true;
|
|
70
|
+
if (server) {
|
|
71
|
+
try { await server.close(); }
|
|
72
|
+
catch (closeError) {
|
|
73
|
+
throw new AggregateError([error, closeError], 'Packaged application startup and shutdown failed.');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
async drain() {
|
|
80
|
+
closing = true;
|
|
81
|
+
if (!server) return;
|
|
82
|
+
const results = await Promise.allSettled([server.close(), server.closed, lifetime]);
|
|
83
|
+
const failures = [...new Set(results.filter(function rejected(result) {
|
|
84
|
+
return result.status === 'rejected';
|
|
85
|
+
}).map(function reason(result) {return result.reason;}))];
|
|
86
|
+
if (failures.length) throw new AggregateError(failures, 'Packaged application serving shutdown failed.');
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import {mkdir, mkdtemp, open, readFile, rename, rmdir, unlink} from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import Is from 'strong-type';
|
|
4
|
+
|
|
5
|
+
const is = new Is(false);
|
|
6
|
+
|
|
7
|
+
// A selected file has one read/modify/write order within this Core process,
|
|
8
|
+
// including when separate service instances select the same file.
|
|
9
|
+
const fileOperations = new Map();
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Native implementation of the existing Arcane.preferences methods.
|
|
13
|
+
* The application selects its file; namespaces, defaults and preference schemas
|
|
14
|
+
* remain with the caller. Factory construction performs no I/O.
|
|
15
|
+
*
|
|
16
|
+
* Writes have service lifetime. Once accepted, renderer cancellation cannot
|
|
17
|
+
* discard them. drain()/dispose() stop acceptance and await owned operations.
|
|
18
|
+
* Success follows a flushed file replacement, not a promise of filesystem
|
|
19
|
+
* survival across every possible operating-system or hardware failure.
|
|
20
|
+
*/
|
|
21
|
+
export function createPreferencesService({file} = {}) {
|
|
22
|
+
if (!is.string(file) || file === '') {
|
|
23
|
+
throw new TypeError('Preferences require an application-selected file path.');
|
|
24
|
+
}
|
|
25
|
+
const filename = path.resolve(file);
|
|
26
|
+
const pending = new Set();
|
|
27
|
+
let closing = null;
|
|
28
|
+
|
|
29
|
+
function accept(operation) {
|
|
30
|
+
if (closing) {
|
|
31
|
+
const error = new Error('The preferences service is closing.');
|
|
32
|
+
error.code = 'CORE_CLOSING';
|
|
33
|
+
return Promise.reject(error);
|
|
34
|
+
}
|
|
35
|
+
const result = orderFileOperation(filename, operation);
|
|
36
|
+
pending.add(result);
|
|
37
|
+
function releaseOperation() { pending.delete(result); }
|
|
38
|
+
result.then(releaseOperation, releaseOperation);
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function list(parameters, {signal} = {}) {
|
|
43
|
+
return accept(async function readKeys() {
|
|
44
|
+
const document = await readPreferences(filename, signal);
|
|
45
|
+
return {keys: Object.keys(document.entries).sort()};
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function get({key}, {signal} = {}) {
|
|
50
|
+
return accept(async function readValue() {
|
|
51
|
+
requireKey(key);
|
|
52
|
+
const document = await readPreferences(filename, signal);
|
|
53
|
+
const found = Object.hasOwn(document.entries, key);
|
|
54
|
+
return {key, found, value: found ? document.entries[key] : null};
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function set({key, value}) {
|
|
59
|
+
return accept(async function saveValue() {
|
|
60
|
+
requireKey(key);
|
|
61
|
+
const document = await readPreferences(filename);
|
|
62
|
+
setEntry(document.entries, key, value);
|
|
63
|
+
await writePreferences(filename, document);
|
|
64
|
+
return {key, value};
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function setMany({entries}) {
|
|
69
|
+
return accept(async function saveBatch() {
|
|
70
|
+
if (!entries || !is.object(entries) || is.array(entries)) {
|
|
71
|
+
throw new TypeError('Preference entries must be a JSON object.');
|
|
72
|
+
}
|
|
73
|
+
const document = await readPreferences(filename);
|
|
74
|
+
const batch = Object.entries(entries);
|
|
75
|
+
for (const [key, value] of batch) setEntry(document.entries, key, value);
|
|
76
|
+
await writePreferences(filename, document);
|
|
77
|
+
return {keys: batch.map(function entryKey([key]) { return key; }).sort(), count: batch.length};
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function deletePreference({key}) {
|
|
82
|
+
return accept(async function removeValue() {
|
|
83
|
+
requireKey(key);
|
|
84
|
+
const document = await readPreferences(filename);
|
|
85
|
+
const deleted = Object.hasOwn(document.entries, key);
|
|
86
|
+
if (deleted) {
|
|
87
|
+
delete document.entries[key];
|
|
88
|
+
await writePreferences(filename, document);
|
|
89
|
+
}
|
|
90
|
+
return {key, deleted};
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function drain() {
|
|
95
|
+
if (closing) return closing;
|
|
96
|
+
closing = Promise.allSettled([...pending]).then(function operationsDrained(results) {
|
|
97
|
+
const failures = results.filter(function failed(result) {
|
|
98
|
+
return result.status === 'rejected';
|
|
99
|
+
}).map(function reason(result) { return result.reason; });
|
|
100
|
+
if (failures.length) throw new AggregateError(failures, 'Preference operations failed while draining.');
|
|
101
|
+
});
|
|
102
|
+
return closing;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
name: 'preferences',
|
|
107
|
+
methods: {
|
|
108
|
+
'preferences.list': list,
|
|
109
|
+
'preferences.get': get,
|
|
110
|
+
'preferences.set': {lifetime: 'service', handle: set},
|
|
111
|
+
'preferences.setMany': {lifetime: 'service', handle: setMany},
|
|
112
|
+
'preferences.delete': {lifetime: 'service', handle: deletePreference}
|
|
113
|
+
},
|
|
114
|
+
drain,
|
|
115
|
+
dispose: drain
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function orderFileOperation(file, operation) {
|
|
120
|
+
const previous = fileOperations.get(file) ?? Promise.resolve();
|
|
121
|
+
const result = previous.then(operation, operation);
|
|
122
|
+
function releaseQueue() {
|
|
123
|
+
if (fileOperations.get(file) === tail) fileOperations.delete(file);
|
|
124
|
+
}
|
|
125
|
+
// The caller retains the rejecting result. This fulfilled scheduling tail
|
|
126
|
+
// lets a later operation proceed after an earlier reported failure.
|
|
127
|
+
const tail = result.then(releaseQueue, releaseQueue);
|
|
128
|
+
fileOperations.set(file, tail);
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function readPreferences(file, signal) {
|
|
133
|
+
signal?.throwIfAborted();
|
|
134
|
+
let source;
|
|
135
|
+
try {
|
|
136
|
+
source = await readFile(file, {encoding: 'utf8', signal});
|
|
137
|
+
} catch (error) {
|
|
138
|
+
if (error.code !== 'ENOENT') throw error;
|
|
139
|
+
signal?.throwIfAborted();
|
|
140
|
+
return {schemaVersion: 1, entries: {}};
|
|
141
|
+
}
|
|
142
|
+
const document = JSON.parse(source);
|
|
143
|
+
if (!document || document.schemaVersion !== 1 || !document.entries
|
|
144
|
+
|| !is.object(document.entries) || is.array(document.entries)) {
|
|
145
|
+
throw new TypeError(`Preferences at ${file} do not contain the existing schemaVersion 1 entries record.`);
|
|
146
|
+
}
|
|
147
|
+
return document;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function requireKey(key) {
|
|
151
|
+
if (!is.string(key)) throw new TypeError('A preference key must be a string.');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function setEntry(entries, key, value) {
|
|
155
|
+
// Define an ordinary own data property: "__proto__" is a preference key,
|
|
156
|
+
// not an instruction to change the entries object's prototype.
|
|
157
|
+
Object.defineProperty(entries, key, {value, enumerable: true, writable: true, configurable: true});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function jsonValue(key, value) {
|
|
161
|
+
const kind = typeof value;
|
|
162
|
+
if (value === undefined || kind === 'function' || kind === 'symbol'
|
|
163
|
+
|| (kind === 'number' && !Number.isFinite(value))) {
|
|
164
|
+
throw new TypeError(`Preference value at ${JSON.stringify(key)} cannot be represented completely in JSON.`);
|
|
165
|
+
}
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async function writePreferences(file, document) {
|
|
170
|
+
// Serialization happens before any filesystem write. The JSON boundary
|
|
171
|
+
// reports unrepresentable values instead of silently omitting them.
|
|
172
|
+
const source = JSON.stringify(document, jsonValue);
|
|
173
|
+
const directory = path.dirname(file);
|
|
174
|
+
await mkdir(directory, {recursive: true});
|
|
175
|
+
const temporaryDirectory = await mkdtemp(path.join(directory, '.arcane-preferences-'));
|
|
176
|
+
const temporary = path.join(temporaryDirectory, 'preferences.json');
|
|
177
|
+
const failures = [];
|
|
178
|
+
let handle = null;
|
|
179
|
+
try {
|
|
180
|
+
handle = await open(temporary, 'w');
|
|
181
|
+
await handle.writeFile(source, 'utf8');
|
|
182
|
+
await handle.sync();
|
|
183
|
+
await handle.close();
|
|
184
|
+
handle = null;
|
|
185
|
+
await rename(temporary, file);
|
|
186
|
+
} catch (error) {
|
|
187
|
+
failures.push(error);
|
|
188
|
+
} finally {
|
|
189
|
+
if (handle) {
|
|
190
|
+
try { await handle.close(); } catch (error) { failures.push(error); }
|
|
191
|
+
}
|
|
192
|
+
try { await unlink(temporary); } catch (error) {
|
|
193
|
+
if (error.code !== 'ENOENT') failures.push(error);
|
|
194
|
+
}
|
|
195
|
+
try { await rmdir(temporaryDirectory); } catch (error) { failures.push(error); }
|
|
196
|
+
}
|
|
197
|
+
if (failures.length === 1) throw failures[0];
|
|
198
|
+
if (failures.length > 1) throw new AggregateError(failures, 'Preference replacement and cleanup failed.');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export default createPreferencesService;
|
|
@@ -5,7 +5,7 @@ import {readFile} from 'node:fs/promises';
|
|
|
5
5
|
* The two owned modules have declaration exports and two explicit imports;
|
|
6
6
|
* this projection is deliberately not a general JavaScript bundler.
|
|
7
7
|
*/
|
|
8
|
-
export async function createCoreClassicSource({eventOwnerModuleURL,replayRuntimeState=false}={}){
|
|
8
|
+
export async function createCoreClassicSource({eventOwnerModuleURL,replayRuntimeState=false,webKitDocumentLifecycle=false}={}){
|
|
9
9
|
if(typeof eventOwnerModuleURL!=='string'||!eventOwnerModuleURL){
|
|
10
10
|
throw new TypeError('The classic Core client needs the served SDK event-manager module URL.');
|
|
11
11
|
}
|
|
@@ -37,7 +37,7 @@ ${implementation}
|
|
|
37
37
|
},{once:true});
|
|
38
38
|
})
|
|
39
39
|
:loadSharedEventOwner();
|
|
40
|
-
installCoreClient(global,{eventOwner:arcaneEvents,eventOwnerReady,replayRuntimeState:${replayRuntimeState===true}});
|
|
40
|
+
installCoreClient(global,{eventOwner:arcaneEvents,eventOwnerReady,replayRuntimeState:${replayRuntimeState===true}${webKitDocumentLifecycle===true?',webKitDocumentLifecycle:true':''}});
|
|
41
41
|
})(globalThis);
|
|
42
42
|
`;
|
|
43
43
|
}
|
package/src/dev-server.mjs
CHANGED
|
@@ -831,7 +831,7 @@ async function resolveDevelopmentTls({workspaceRoot,tls,certPath,keyPath,signal}
|
|
|
831
831
|
}catch(error){
|
|
832
832
|
if(error.code==='ENOENT'){
|
|
833
833
|
fail(
|
|
834
|
-
`Arcane development and packaged previews
|
|
834
|
+
`Arcane development and packaged previews default to HTTPS. `
|
|
835
835
|
+`Provide a certificate at ${certificatePath} and a key at ${privateKeyPath}, `
|
|
836
836
|
+'or select existing files with --cert and --key.',
|
|
837
837
|
'ARCANE_DEV_TLS_MISSING'
|
|
@@ -873,12 +873,9 @@ async function startOwnedDevServer({
|
|
|
873
873
|
if (!is.boolean(http)) {
|
|
874
874
|
fail('http must be a boolean.', 'ARCANE_USAGE');
|
|
875
875
|
}
|
|
876
|
-
if (http && mode !== 'source') {
|
|
877
|
-
fail('HTTP serving is supported only in source development mode.', 'ARCANE_USAGE');
|
|
878
|
-
}
|
|
879
876
|
if (http && (requestedHttps === true || (tls !== undefined && tls !== null && tls !== false)
|
|
880
877
|
|| certPath !== undefined || keyPath !== undefined || httpPort !== 0)) {
|
|
881
|
-
fail('HTTP
|
|
878
|
+
fail('HTTP serving cannot combine TLS options or a separate httpPort; select its listener with port.', 'ARCANE_USAGE');
|
|
882
879
|
}
|
|
883
880
|
const protocol = http ? 'http:' : 'https:';
|
|
884
881
|
const requestedRuntimeMode=mode==='source'&&sdkRuntimeSourceRoot!==undefined
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import {fileURLToPath} from 'node:url';
|
|
3
|
+
import {mkdir} from 'node:fs/promises';
|
|
4
|
+
import Is from 'strong-type';
|
|
5
|
+
import {runProcess} from '../process.mjs';
|
|
6
|
+
|
|
7
|
+
const is = new Is(false);
|
|
8
|
+
|
|
9
|
+
/** Build this host's first-party helper against its selected upstream runtime. */
|
|
10
|
+
export async function buildDiarizationHelper({runtime, outputRoot, signal, onEvent} = {}) {
|
|
11
|
+
if (!is.string(runtime?.cmakeDirectory) || !is.string(outputRoot)) {
|
|
12
|
+
throw new TypeError('The selected NeMo runtime cmakeDirectory and helper outputRoot are required.');
|
|
13
|
+
}
|
|
14
|
+
const root = path.resolve(outputRoot);
|
|
15
|
+
const build = path.join(root, 'build');
|
|
16
|
+
const source = fileURLToPath(new URL('./native/', import.meta.url));
|
|
17
|
+
await mkdir(root, {recursive: true});
|
|
18
|
+
const options = {signal, onEvent};
|
|
19
|
+
const configure = await runProcess('cmake', [
|
|
20
|
+
'-S', source,
|
|
21
|
+
'-B', build,
|
|
22
|
+
`-DNeMoSpeech_DIR=${path.resolve(runtime.cmakeDirectory)}`,
|
|
23
|
+
`-DCMAKE_INSTALL_PREFIX=${root}`,
|
|
24
|
+
'-DCMAKE_BUILD_TYPE=Release'
|
|
25
|
+
], options);
|
|
26
|
+
const compile = await runProcess('cmake', ['--build', build, '--config', 'Release'], options);
|
|
27
|
+
const install = await runProcess('cmake', ['--install', build, '--config', 'Release'], options);
|
|
28
|
+
return {
|
|
29
|
+
platform: process.platform,
|
|
30
|
+
architecture: process.arch,
|
|
31
|
+
root,
|
|
32
|
+
executable: path.join(root, 'bin', process.platform === 'win32' ? 'arcane-diarization.exe' : 'arcane-diarization'),
|
|
33
|
+
diagnostics: {configure, compile, install}
|
|
34
|
+
};
|
|
35
|
+
}
|