Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .pipelines/templates/build-js-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ steps:
Expand-Archive -Path $zip -DestinationPath $extractDir -Force

# Overwrite FLC binary in the npm-installed location
$destDir = "$(repoRoot)/sdk/js/packages/@foundry-local-core/$platformKey"
$destDir = "$(repoRoot)/sdk/js/node_modules/@foundry-local-core/$platformKey"
New-Item -ItemType Directory -Path $destDir -Force | Out-Null
$nativeDir = "$extractDir/runtimes/$rid/native"
if (Test-Path $nativeDir) {
Get-ChildItem $nativeDir -File | ForEach-Object {
Expand Down
3 changes: 2 additions & 1 deletion .pipelines/templates/test-js-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ steps:
Copy-Item $nupkg.FullName $zip -Force
Expand-Archive -Path $zip -DestinationPath $extractDir -Force

$destDir = "$(repoRoot)/sdk/js/packages/@foundry-local-core/$platformKey"
$destDir = "$(repoRoot)/sdk/js/node_modules/@foundry-local-core/$platformKey"
New-Item -ItemType Directory -Path $destDir -Force | Out-Null
$nativeDir = "$extractDir/runtimes/$rid/native"
if (Test-Path $nativeDir) {
Get-ChildItem $nativeDir -File | ForEach-Object {
Expand Down
6 changes: 0 additions & 6 deletions sdk/js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,6 @@
"koffi": "^2.9.0",
"adm-zip": "^0.5.16"
},
"optionalDependencies": {
"@foundry-local-core/darwin-arm64": "file:packages/@foundry-local-core/darwin-arm64",
"@foundry-local-core/linux-x64": "file:packages/@foundry-local-core/linux-x64",
"@foundry-local-core/win32-arm64": "file:packages/@foundry-local-core/win32-arm64",
"@foundry-local-core/win32-x64": "file:packages/@foundry-local-core/win32-x64"
},
"devDependencies": {
"@types/chai": "^5.2.3",
"@types/mocha": "^10.0.10",
Expand Down
18 changes: 11 additions & 7 deletions sdk/js/script/install-utils.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ const PLATFORM_MAP = {
};
const platformKey = `${os.platform()}-${os.arch()}`;
const RID = PLATFORM_MAP[platformKey];
const BIN_DIR = path.join(__dirname, '..', 'packages', '@foundry-local-core', platformKey);
// Install binaries into node_modules/@foundry-local-core/<platform> so they
// are shared across foundry-local-sdk and foundry-local-sdk-winml.
const BIN_DIR = path.join(__dirname, '..', 'node_modules', '@foundry-local-core', platformKey);
const EXT = os.platform() === 'win32' ? '.dll' : os.platform() === 'darwin' ? '.dylib' : '.so';

const REQUIRED_FILES = [
Expand Down Expand Up @@ -104,7 +106,7 @@ async function getBaseAddress(feedUrl) {
return baseAddress.endsWith('/') ? baseAddress : baseAddress + '/';
}

async function installPackage(artifact, tempDir) {
async function installPackage(artifact, tempDir, binDir) {
const pkgName = artifact.name;
const pkgVer = artifact.version;

Expand All @@ -127,7 +129,7 @@ async function installPackage(artifact, tempDir) {

if (entries.length > 0) {
entries.forEach(entry => {
zip.extractEntryTo(entry, BIN_DIR, false, true);
zip.extractEntryTo(entry, binDir, false, true);
console.log(` Extracted ${entry.name}`);
});
} else {
Expand All @@ -136,7 +138,7 @@ async function installPackage(artifact, tempDir) {

// Update platform package.json version for Core packages
if (pkgName.startsWith('Microsoft.AI.Foundry.Local.Core')) {
const pkgJsonPath = path.join(BIN_DIR, 'package.json');
const pkgJsonPath = path.join(binDir, 'package.json');
if (fs.existsSync(pkgJsonPath)) {
const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'));
pkgJson.version = pkgVer;
Expand All @@ -145,13 +147,15 @@ async function installPackage(artifact, tempDir) {
}
}

async function runInstall(artifacts) {
async function runInstall(artifacts, options) {
if (!RID) {
console.warn(`[foundry-local] Unsupported platform: ${platformKey}. Skipping.`);
return;
}

if (fs.existsSync(BIN_DIR) && REQUIRED_FILES.every(f => fs.existsSync(path.join(BIN_DIR, f)))) {
const force = options && options.force;

if (!force && fs.existsSync(BIN_DIR) && REQUIRED_FILES.every(f => fs.existsSync(path.join(BIN_DIR, f)))) {
console.log(`[foundry-local] Native libraries already installed.`);
return;
}
Expand All @@ -162,7 +166,7 @@ async function runInstall(artifacts) {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'foundry-install-'));
try {
for (const artifact of artifacts) {
await installPackage(artifact, tempDir);
await installPackage(artifact, tempDir, BIN_DIR);
}
console.log('[foundry-local] Installation complete.');
} finally {
Expand Down
8 changes: 7 additions & 1 deletion sdk/js/script/install-winml.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
// Licensed under the MIT License.

// Install script for foundry-local-sdk-winml variant.
//
// This package is a thin wrapper around foundry-local-sdk. It downloads
// WinML-specific native binaries (Core.WinML, ORT, GenAI) into the shared
// node_modules/@foundry-local-core/<platform> directory, overriding the
// standard binaries that foundry-local-sdk's install script placed there.

'use strict';

Expand All @@ -15,7 +20,8 @@ const ARTIFACTS = [

(async () => {
try {
await runInstall(ARTIFACTS);
// Force override since standard binaries were already installed by foundry-local-sdk
await runInstall(ARTIFACTS, { force: true });
} catch (err) {
console.error('Failed to install WinML artifacts:', err);
process.exit(1);
Expand Down
12 changes: 10 additions & 2 deletions sdk/js/script/pack.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,16 @@ try {
const pkg = JSON.parse(original);
if (isWinML) {
pkg.name = 'foundry-local-sdk-winml';
pkg.scripts.install = 'node script/install-winml.cjs';
pkg.files = ['dist', 'script/install-winml.cjs', 'script/install-utils.cjs', 'script/preinstall.cjs'];
pkg.description = 'Foundry Local JavaScript SDK – WinML variant';
// The winml package is a thin wrapper: it depends on the standard SDK for all JS code
// and only overrides the native binaries at install time.
pkg.dependencies = { 'foundry-local-sdk': pkg.version };
pkg.scripts = { install: 'node script/install-winml.cjs' };
// No dist/ or preinstall needed — the standard SDK provides the JS code
pkg.files = ['script/install-winml.cjs', 'script/install-utils.cjs'];
delete pkg.main;
delete pkg.types;
delete pkg.optionalDependencies;
} else {
pkg.files = ['dist', 'script/install-standard.cjs', 'script/install-utils.cjs', 'script/preinstall.cjs'];
}
Expand Down
2 changes: 1 addition & 1 deletion sdk/js/script/preinstall.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ console.log('[foundry-local] Preinstall: creating platform package skeletons...'

const platformKey = `${os.platform()}-${os.arch()}`;

const packagesRoot = path.join(__dirname, '..', 'packages', '@foundry-local-core');
const packagesRoot = path.join(__dirname, '..', 'node_modules', '@foundry-local-core');

const dir = path.join(packagesRoot, platformKey);

Expand Down
14 changes: 6 additions & 8 deletions sdk/js/src/detail/coreInterop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import koffi from 'koffi';
import path from 'path';
import fs from 'fs';
import { fileURLToPath } from 'url';
import { createRequire } from 'module';
import { Configuration } from '../configuration.js';

koffi.struct('RequestBuffer', {
Expand Down Expand Up @@ -49,15 +48,14 @@ export class CoreInterop {
}

private static _resolveDefaultCorePath(config: Configuration): string | null {
const require = createRequire(import.meta.url);
const platform = process.platform;
const arch = process.arch;
// Matches names generated by preinstall.cjs
const packageName = `@foundry-local-core/${platform}-${arch}`;

// Resolve the package path.
const packagePath = require.resolve(`${packageName}/package.json`);
const packageDir = path.dirname(packagePath);
const platformKey = `${platform}-${arch}`;

// Resolve the platform package directory at node_modules/@foundry-local-core/<platform>,
// the shared location where install scripts place the native binaries.
const sdkRoot = path.resolve(__dirname, '..', '..');
const packageDir = path.join(sdkRoot, 'node_modules', '@foundry-local-core', platformKey);
const ext = CoreInterop._getLibraryExtension();

const corePath = path.join(packageDir, `Microsoft.AI.Foundry.Local.Core${ext}`);
Expand Down
Loading